Commit cc64fb5c authored by Jannis Leidel's avatar Jannis Leidel
Browse files

Fixed #8342 -- Removed code from the admin that assumed that you can't login...

Fixed #8342 -- Removed code from the admin that assumed that you can't login with an email address (nixed by r12634). Also refactored login code slightly to be DRY by using more of auth app's forms and views.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14769 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 07705ca1
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
from django import forms

from django.contrib.auth import authenticate
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.models import User

from django.utils.translation import ugettext_lazy, ugettext as _

ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. "
                              "Note that both fields are case-sensitive.")

class AdminAuthenticationForm(AuthenticationForm):
    """
    A custom authentication form used in the admin app.

    """
    this_is_the_login_form = forms.BooleanField(widget=forms.HiddenInput, initial=1,
        error_messages={'required': ugettext_lazy("Please log in again, because your session has expired.")})

    def clean(self):
        username = self.cleaned_data.get('username')
        password = self.cleaned_data.get('password')
        message = ERROR_MESSAGE

        if username and password:
            self.user_cache = authenticate(username=username, password=password)
            if self.user_cache is None:
                if username is not None and u'@' in username:
                    # Mistakenly entered e-mail address instead of username? Look it up.
                    try:
                        user = User.objects.get(email=username)
                    except (User.DoesNotExist, User.MultipleObjectsReturned):
                        # Nothing to do here, moving along.
                        pass
                    else:
                        if user.check_password(password):
                            message = _("Your e-mail address is not your username."
                                        " Try '%s' instead.") % user.username
                raise forms.ValidationError(message)
            elif not self.user_cache.is_active or not self.user_cache.is_staff:
                raise forms.ValidationError(message)
        self.check_for_test_cookie()
        return self.cleaned_data
+36 −73
Original line number Diff line number Diff line
import re
from django import http, template
from django.contrib.admin import ModelAdmin
from django.contrib.admin import actions
from django.contrib.auth import authenticate, login
from django.contrib.admin import ModelAdmin, actions
from django.contrib.admin.forms import AdminAuthenticationForm, ERROR_MESSAGE
from django.contrib.auth import REDIRECT_FIELD_NAME, authenticate, login
from django.views.decorators.csrf import csrf_protect
from django.db.models.base import ModelBase
from django.core.exceptions import ImproperlyConfigured
@@ -15,7 +15,6 @@ from django.utils.translation import ugettext_lazy, ugettext as _
from django.views.decorators.cache import never_cache
from django.conf import settings

ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
LOGIN_FORM_KEY = 'this_is_the_login_form'

class AlreadyRegistered(Exception):
@@ -32,7 +31,7 @@ class AdminSite(object):
    functions that present a full admin interface for the collection of registered
    models.
    """

    login_form = None
    index_template = None
    app_index_template = None
    login_template = None
@@ -127,12 +126,12 @@ class AdminSite(object):
        """
        return self._global_actions[name]

    @property
    def actions(self):
        """
        Get all the enabled actions as an iterable of (name, func).
        """
        return self._actions.iteritems()
    actions = property(actions)

    def has_permission(self, request):
        """
@@ -240,9 +239,9 @@ class AdminSite(object):
            )
        return urlpatterns

    @property
    def urls(self):
        return self.get_urls(), self.app_name, self.name
    urls = property(urls)

    def password_change(self, request):
        """
@@ -254,18 +253,22 @@ class AdminSite(object):
        else:
            url = reverse('admin:password_change_done', current_app=self.name)
        defaults = {
            'current_app': self.name,
            'post_change_redirect': url
        }
        if self.password_change_template is not None:
            defaults['template_name'] = self.password_change_template
        return password_change(request, **defaults)

    def password_change_done(self, request):
    def password_change_done(self, request, extra_context=None):
        """
        Displays the "success" page after a password change.
        """
        from django.contrib.auth.views import password_change_done
        defaults = {}
        defaults = {
            'current_app': self.name,
            'extra_context': extra_context or {},
        }
        if self.password_change_done_template is not None:
            defaults['template_name'] = self.password_change_done_template
        return password_change_done(request, **defaults)
@@ -283,69 +286,44 @@ class AdminSite(object):
            from django.views.i18n import null_javascript_catalog as javascript_catalog
        return javascript_catalog(request, packages='django.conf')

    def logout(self, request):
    @never_cache
    def logout(self, request, extra_context=None):
        """
        Logs out the user for the given HttpRequest.

        This should *not* assume the user is already logged in.
        """
        from django.contrib.auth.views import logout
        defaults = {}
        defaults = {
            'current_app': self.name,
            'extra_context': extra_context or {},
        }
        if self.logout_template is not None:
            defaults['template_name'] = self.logout_template
        return logout(request, **defaults)
    logout = never_cache(logout)

    def login(self, request):
    @never_cache
    def login(self, request, extra_context=None):
        """
        Displays the login form for the given HttpRequest.
        """
        from django.contrib.auth.models import User

        # If this isn't already the login page, display it.
        if LOGIN_FORM_KEY not in request.POST:
            if request.POST:
                message = _("Please log in again, because your session has expired.")
            else:
                message = ""
            return self.display_login_form(request, message)

        # Check that the user accepts cookies.
        if not request.session.test_cookie_worked():
            message = _("Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again.")
            return self.display_login_form(request, message)
        else:
            request.session.delete_test_cookie()

        # Check the password.
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        user = authenticate(username=username, password=password)
        if user is None:
            message = ERROR_MESSAGE
            if username is not None and u'@' in username:
                # Mistakenly entered e-mail address instead of username? Look it up.
                try:
                    user = User.objects.get(email=username)
                except (User.DoesNotExist, User.MultipleObjectsReturned):
                    message = _("Usernames cannot contain the '@' character.")
                else:
                    if user.check_password(password):
                        message = _("Your e-mail address is not your username."
                                    " Try '%s' instead.") % user.username
                    else:
                        message = _("Usernames cannot contain the '@' character.")
            return self.display_login_form(request, message)

        # The user data is correct; log in the user in and continue.
        else:
            if user.is_active and user.is_staff:
                login(request, user)
                return http.HttpResponseRedirect(request.get_full_path())
            else:
                return self.display_login_form(request, ERROR_MESSAGE)
    login = never_cache(login)
        from django.contrib.auth.views import login
        context = {
            'title': _('Log in'),
            'root_path': self.root_path,
            'app_path': request.get_full_path(),
            REDIRECT_FIELD_NAME: request.get_full_path(),
        }
        context.update(extra_context or {})
        defaults = {
            'extra_context': context,
            'current_app': self.name,
            'authentication_form': self.login_form or AdminAuthenticationForm,
            'template_name': self.login_template or 'admin/login.html',
        }
        return login(request, **defaults)

    @never_cache
    def index(self, request, extra_context=None):
        """
        Displays the main admin index page, which lists all of the installed
@@ -396,21 +374,6 @@ class AdminSite(object):
        return render_to_response(self.index_template or 'admin/index.html', context,
            context_instance=context_instance
        )
    index = never_cache(index)

    def display_login_form(self, request, error_message='', extra_context=None):
        request.session.set_test_cookie()
        context = {
            'title': _('Log in'),
            'app_path': request.get_full_path(),
            'error_message': error_message,
            'root_path': self.root_path,
        }
        context.update(extra_context or {})
        context_instance = template.RequestContext(request, current_app=self.name)
        return render_to_response(self.login_template or 'admin/login.html', context,
            context_instance=context_instance
        )

    def app_index(self, request, app_label, extra_context=None):
        user = request.user
+18 −4
Original line number Diff line number Diff line
@@ -12,17 +12,31 @@
{% block breadcrumbs %}{% endblock %}

{% block content %}
{% if error_message %}
<p class="errornote">{{ error_message }}</p>
{% if form.errors and not form.non_field_errors and not form.this_is_the_login_form.errors %}
<p class="errornote">
{% blocktrans count form.errors.items|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
</p>
{% endif %}

{% if form.non_field_errors or form.this_is_the_login_form.errors %}
{% for error in form.non_field_errors|add:form.this_is_the_login_form.errors %}
<p class="errornote">
    {{ error }}
</p>
{% endfor %}
{% endif %}

<div id="content-main">
<form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
  <div class="form-row">
    <label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" />
    {% if not form.this_is_the_login_form.errors %}{{ form.username.errors }}{% endif %}
    <label for="id_username" class="required">{% trans 'Username:' %}</label> {{ form.username }}
  </div>
  <div class="form-row">
    <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" />
    {% if not form.this_is_the_login_form.errors %}{{ form.password.errors }}{% endif %}
    <label for="id_password" class="required">{% trans 'Password:' %}</label> {{ form.password }}
    <input type="hidden" name="this_is_the_login_form" value="1" />
    <input type="hidden" name="next" value="{{ next }}" />
  </div>
  <div class="submit-row">
    <label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" />
+15 −55
Original line number Diff line number Diff line
@@ -3,22 +3,13 @@ try:
except ImportError:
    from django.utils.functional import wraps  # Python 2.4 fallback.

from django import http, template
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login
from django import template
from django.shortcuts import render_to_response
from django.utils.translation import ugettext_lazy, ugettext as _
from django.utils.translation import ugettext as _

ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
LOGIN_FORM_KEY = 'this_is_the_login_form'

def _display_login_form(request, error_message=''):
    request.session.set_test_cookie()
    return render_to_response('admin/login.html', {
        'title': _('Log in'),
        'app_path': request.get_full_path(),
        'error_message': error_message
    }, context_instance=template.RequestContext(request))
from django.contrib.admin.forms import AdminAuthenticationForm
from django.contrib.auth.views import login
from django.contrib.auth import REDIRECT_FIELD_NAME

def staff_member_required(view_func):
    """
@@ -31,45 +22,14 @@ def staff_member_required(view_func):
            return view_func(request, *args, **kwargs)

        assert hasattr(request, 'session'), "The Django admin requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."

        # If this isn't already the login page, display it.
        if LOGIN_FORM_KEY not in request.POST:
            if request.POST:
                message = _("Please log in again, because your session has expired.")
            else:
                message = ""
            return _display_login_form(request, message)

        # Check that the user accepts cookies.
        if not request.session.test_cookie_worked():
            message = _("Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again.")
            return _display_login_form(request, message)
        else:
            request.session.delete_test_cookie()

        # Check the password.
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        user = authenticate(username=username, password=password)
        if user is None:
            message = ERROR_MESSAGE
            if '@' in username:
                # Mistakenly entered e-mail address instead of username? Look it up.
                users = list(User.objects.filter(email=username))
                if len(users) == 1 and users[0].check_password(password):
                    message = _("Your e-mail address is not your username. Try '%s' instead.") % users[0].username
                else:
                    # Either we cannot find the user, or if more than 1
                    # we cannot guess which user is the correct one.
                    message = _("Usernames cannot contain the '@' character.")
            return _display_login_form(request, message)

        # The user data is correct; log in the user in and continue.
        else:
            if user.is_active and user.is_staff:
                login(request, user)
                return http.HttpResponseRedirect(request.get_full_path())
            else:
                return _display_login_form(request, ERROR_MESSAGE)

        defaults = {
            'template_name': 'admin/login.html',
            'authentication_form': AdminAuthenticationForm,
            'extra_context': {
                'title': _('Log in'),
                'app_path': request.get_full_path(),
                REDIRECT_FIELD_NAME: request.get_full_path(),
            },
        }
        return login(request, **defaults)
    return wraps(view_func)(_checklogin)
+7 −6
Original line number Diff line number Diff line
@@ -87,14 +87,15 @@ class AuthenticationForm(forms.Form):
                raise forms.ValidationError(_("Please enter a correct username and password. Note that both fields are case-sensitive."))
            elif not self.user_cache.is_active:
                raise forms.ValidationError(_("This account is inactive."))

        # 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."))

        self.check_for_test_cookie()
        return self.cleaned_data

    def check_for_test_cookie(self):
        if self.request and 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."))

    def get_user_id(self):
        if self.user_cache:
            return self.user_cache.id
Loading