While my startup is in dark mode I want all access except access to / to go to a screener page where users have enter a password given to them by a representative. I’ve come up with the following simple middleware to perform the task. Just to be clear, this is intended to ensure that users agree to keep the site in confidence before they are allowed to browse around rather than for use as a security system or .htaccess clone. However I would like to prevent them seeing any public pages (i.e those which are not decorated with @login_required) without knowing the screener password. The password_check function uses Django Auth to generate the hash of the input password to check against a db value.
Any thoughts/circumvention techniques that you guys can see? One idea I had was to change the login function to push the LicenceKey into the newly logged in users session, rather than giving logged in users an exemption. However since they can only create a new session by logging in, and logging in requires agreeing to the screener, it seems redundant.
Feedback appreciated.
The middleware looks like this:
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
import re
class LicenceScreener(object):
SCREENER_PATH = reverse("licence")
INDEX_PATH = reverse("index")
LICENCE_KEY = "commercial_licence"
def process_request(self, request):
""" Redirect any access not to the index page to a commercial access screener page
When the screener form is submitted, request.session[LICENCE_KEY] is set.
"""
if not LicenceScreener.LICENCE_KEY in request.session \
and not request.user.is_authenticated() \
and LicenceScreener.SCREENER_PATH != request.path\
and LicenceScreener.INDEX_PATH != request.path:
return HttpResponseRedirect(self.SCREENER_PATH)
And the view looks like this:
def licence(request):
c = RequestContext(request, {} )
if request.method == 'POST':
form = LicenceAgreementForm(request.POST)
if form.is_valid():
if password_check(form.cleaned_data["password"]):
request.session[LicenceScreener.LICENCE_KEY] = True
return HttpResponseRedirect(reverse("real-index"))
else:
form._errors["password"] = form.error_class([_("Sorry that password is incorrect")])
else:
form = LicenceAgreementForm()
c["form"] = form
return render_to_response('licence.html',c)
EDIT 1. Removed the Regexes as suggested by Tobu
Here is my solution. It is using not COOKIES but custom Auth Backend.
Step 1
It’s good to have a Django application for this:
settings.py:
Step 2
We need a Model to store your tokens. models.py:
Note: In my simple solution you will need to create and synchronize new Users and their SecurityKeys manually. But you can improve this in future.
Step 3
We need a custom Middleware that will require authentication from all users at all pages (except few special pages). Here is the middleware.py:
This middleware will redirect unauthorized users to the ‘key_auth_login’ page with auth form in it.
Step 4
Here are urls.py which maps ‘key_auth_login’ view:
And the global project’s urls.py:
As you can see – Admin Site is on (so you can also log in as admin).
Step 5
Here is our view (views.py):
I will not show ‘key_auth_form.html’ because it’s really simple form template, nothing special. But I’ll show form class
Step 6
Form class (forms.py):
As we see, authenticate() used here. This method will try to authenticate user with existent backends.
Step 7
Custom authentication backend. backend.py:
It’s very simple! Just check the key (token).
Here is it’s installation (settings.py):
The second one is left to keep Admin Site working.
Resume
That’s it!
You’re also able to use Admin Site and login/logout views free of key_auth ckeck.