First working version of the code.

This commit is contained in:
Mikkel Hoegh 2010-06-02 21:33:05 +02:00
parent 74e9744bcf
commit face026842
4 changed files with 142 additions and 0 deletions

View file

@ -0,0 +1,24 @@
""" The password_required decorator for Django views """
from functools import update_wrapper, wraps
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.utils.decorators import available_attrs
from django.utils.http import urlquote
def password_required(view_func=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
Decorator for views that checks that the user has entered the password,
redirecting to the log-in page if necessary.
"""
def _wrapped_view(request, *args, **kwargs):
if request.session.get('password_required_auth', False):
return view_func(request, *args, **kwargs)
return HttpResponseRedirect('%s?%s=%s' % (
reverse('password_required.views.login'),
redirect_field_name,
urlquote(request.get_full_path()),
))
return wraps(view_func, assigned=available_attrs(view_func))(_wrapped_view)

View file

@ -0,0 +1,45 @@
from django import forms
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
class AuthenticationForm(forms.Form):
"""
Simple form to allow users to access a page via a password.
A copy of django.contrib.auth.forms.AuthenticationForm, adapted to this
much simpler use case.
"""
password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
def __init__(self, request=None, *args, **kwargs):
"""
If request is passed in, the form will validate that cookies are
enabled. Note that the request (a HttpRequest object) must have set a
cookie with the key TEST_COOKIE_NAME and value TEST_COOKIE_VALUE before
running this validation.
"""
self.request = request
super(AuthenticationForm, self).__init__(*args, **kwargs)
def clean(self):
"""
Validate that the password entered was correct.
"""
password = self.cleaned_data.get('password')
correct_password = getattr(settings, 'PASSWORD_REQUIRED_PASSWORD', None)
if not correct_password:
raise forms.ValidationError(_("PASSWORD_REQUIRED_PASSWORD is not set, and thus it is currently impossible to log in."))
if not (password == correct_password or
password.strip() == correct_password):
raise forms.ValidationError(_("Please enter the correct password. Note that the password is case-sensitive."))
# TODO: determine whether this should move to its own method.
if self.request:
if not self.request.session.test_cookie_worked():
raise forms.ValidationError(_("Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in."))
return self.cleaned_data

View file

@ -0,0 +1,6 @@
{% load i18n %}
<form id="password-required-login" action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="{% trans "Let me in" %}" />
</form>

View file

@ -0,0 +1,67 @@
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.sites.models import Site, RequestSite
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
from password_required.forms import AuthenticationForm
@csrf_protect
@never_cache
def login(request, template_name='password_required_login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm):
"""Displays the login form and handles the login action."""
redirect_to = _clean_redirect(request.REQUEST.get(redirect_field_name, ''))
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
# Mark the user as logged in via his session data.
request.session['password_required_auth'] = True
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
request.session.set_test_cookie()
if Site._meta.installed:
current_site = Site.objects.get_current()
else:
current_site = RequestSite(request)
return render_to_response(template_name, {
'form': form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}, context_instance=RequestContext(request))
def _clean_redirect(redirect_to):
"""
Perform a few security checks on the redirect destination.
Copied from django.contrib.auth.views.login. It really should be split
out from that.
"""
# Light security check -- make sure redirect_to isn't garbage.
if not redirect_to or ' ' in redirect_to:
redirect_to = settings.LOGIN_REDIRECT_URL
# Heavier security check -- redirects to http://example.com should
# not be allowed, but things like /view/?param=http://example.com
# should be allowed. This regex checks if there is a '//' *before* a
# question mark.
elif '//' in redirect_to and re.match(r'[^\?]*//', redirect_to):
redirect_to = settings.LOGIN_REDIRECT_URL
return redirect_to