Commit aab3a418 authored by Jacob Kaplan-Moss's avatar Jacob Kaplan-Moss
Browse files

Merged multi-auth branch to trunk. See the authentication docs for the...

Merged multi-auth branch to trunk.  See the authentication docs for the ramifications of this change.  Many, many thanks to Joseph Kocherhans for the hard work! 


git-svn-id: http://code.djangoproject.com/svn/django/trunk@3226 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 4ea7a116
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -281,3 +281,9 @@ COMMENTS_FIRST_FEW = 0
# A tuple of IP addresses that have been banned from participating in various
# Django-powered features.
BANNED_IPS = ()

##################
# AUTHENTICATION #
##################

AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)
+9 −7
Original line number Diff line number Diff line
from django import http, template
from django.conf import settings
from django.contrib.auth.models import User, SESSION_KEY
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login
from django.shortcuts import render_to_response
from django.utils.translation import gettext_lazy
import base64, datetime, md5
@@ -69,10 +70,10 @@ def staff_member_required(view_func):
            return _display_login_form(request, message)

        # Check the password.
        username = request.POST.get('username', '')
        try:
            user = User.objects.get(username=username, is_staff=True)
        except User.DoesNotExist:
        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.
@@ -86,8 +87,9 @@ def staff_member_required(view_func):

        # The user data is correct; log in the user in and continue.
        else:
            if user.check_password(request.POST.get('password', '')):
                request.session[SESSION_KEY] = user.id
            if user.is_staff:
                login(request, user)
                # TODO: set last_login with an event.
                user.last_login = datetime.datetime.now()
                user.save()
                if request.POST.has_key('post_data'):
+69 −0
Original line number Diff line number Diff line
from django.core.exceptions import ImproperlyConfigured

SESSION_KEY = '_auth_user_id'
BACKEND_SESSION_KEY = '_auth_user_backend'
LOGIN_URL = '/accounts/login/'
REDIRECT_FIELD_NAME = 'next'

def load_backend(path):
    i = path.rfind('.')
    module, attr = path[:i], path[i+1:]
    try:
        mod = __import__(module, '', '', [attr])
    except ImportError, e:
        raise ImproperlyConfigured, 'Error importing authentication backend %s: "%s"' % (module, e)
    try:
        cls = getattr(mod, attr)
    except AttributeError:
        raise ImproperlyConfigured, 'Module "%s" does not define a "%s" authentication backend' % (module, attr)
    return cls()

def get_backends():
    from django.conf import settings
    backends = []
    for backend_path in settings.AUTHENTICATION_BACKENDS:
        backends.append(load_backend(backend_path))
    return backends

def authenticate(**credentials):
    """
    If the given credentials, return a user object.
    """
    for backend in get_backends():
        try:
            user = backend.authenticate(**credentials)
        except TypeError:
            # this backend doesn't accept these credentials as arguments, try the next one.
            continue
        if user is None:
            continue
        # annotate the user object with the path of the backend
        user.backend = str(backend.__class__)
        return user

def login(request, user):
    """
    Persist a user id and a backend in the request. This way a user doesn't
    have to reauthenticate on every request.
    """
    if user is None:
        user = request.user
    # TODO: It would be nice to support different login methods, like signed cookies.
    request.session[SESSION_KEY] = user.id
    request.session[BACKEND_SESSION_KEY] = user.backend

def logout(request):
    """
    Remove the authenticated user's id from request.
    """
    del request.session[SESSION_KEY]
    del request.session[BACKEND_SESSION_KEY]

def get_user(request):
    from django.contrib.auth.models import AnonymousUser
    try:
        user_id = request.session[SESSION_KEY]
        backend_path = request.session[BACKEND_SESSION_KEY]
        backend = load_backend(backend_path)
        user = backend.get_user(user_id) or AnonymousUser()
    except KeyError:
        user = AnonymousUser()
    return user
+21 −0
Original line number Diff line number Diff line
from django.contrib.auth.models import User, check_password

class ModelBackend:
    """
    Authenticate against django.contrib.auth.models.User
    """
    # TODO: Model, login attribute name and password attribute name should be
    # configurable.
    def authenticate(self, username=None, password=None):
        try:
            user = User.objects.get(username=username)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None
+5 −11
Original line number Diff line number Diff line
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
from django.contrib.sites.models import Site
from django.template import Context, loader
from django.core import validators
@@ -20,8 +21,7 @@ class AuthenticationForm(forms.Manipulator):
        self.fields = [
            forms.TextField(field_name="username", length=15, maxlength=30, is_required=True,
                validator_list=[self.isValidUser, self.hasCookiesEnabled]),
            forms.PasswordField(field_name="password", length=15, maxlength=30, is_required=True,
                validator_list=[self.isValidPasswordForUser]),
            forms.PasswordField(field_name="password", length=15, maxlength=30, is_required=True),
        ]
        self.user_cache = None

@@ -30,16 +30,10 @@ class AuthenticationForm(forms.Manipulator):
            raise validators.ValidationError, _("Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in.")

    def isValidUser(self, field_data, all_data):
        try:
            self.user_cache = User.objects.get(username=field_data)
        except User.DoesNotExist:
            raise validators.ValidationError, _("Please enter a correct username and password. Note that both fields are case-sensitive.")

    def isValidPasswordForUser(self, field_data, all_data):
        username = field_data
        password = all_data.get('password', None)
        self.user_cache = authenticate(username=username, password=password)
        if self.user_cache is None:
            return
        if not self.user_cache.check_password(field_data):
            self.user_cache = None
            raise validators.ValidationError, _("Please enter a correct username and password. Note that both fields are case-sensitive.")
        elif not self.user_cache.is_active:
            raise validators.ValidationError, _("This account is inactive.")
Loading