diff options
Diffstat (limited to 'django')
| -rw-r--r-- | django/conf/global_settings.py | 6 | ||||
| -rw-r--r-- | django/contrib/admin/views/decorators.py | 16 | ||||
| -rw-r--r-- | django/contrib/auth/__init__.py | 69 | ||||
| -rw-r--r-- | django/contrib/auth/backends.py | 21 | ||||
| -rw-r--r-- | django/contrib/auth/forms.py | 16 | ||||
| -rw-r--r-- | django/contrib/auth/middleware.py | 8 | ||||
| -rw-r--r-- | django/contrib/auth/models.py | 23 | ||||
| -rw-r--r-- | django/contrib/auth/views.py | 7 | ||||
| -rw-r--r-- | django/contrib/comments/views/comments.py | 4 |
9 files changed, 132 insertions, 38 deletions
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 640b290a6f..a1dff3c815 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -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',) diff --git a/django/contrib/admin/views/decorators.py b/django/contrib/admin/views/decorators.py index d984077dfb..250c585220 100644 --- a/django/contrib/admin/views/decorators.py +++ b/django/contrib/admin/views/decorators.py @@ -1,6 +1,7 @@ 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'): diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py index ac7b40aca6..dde7ea5c9c 100644 --- a/django/contrib/auth/__init__.py +++ b/django/contrib/auth/__init__.py @@ -1,2 +1,71 @@ +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 diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py new file mode 100644 index 0000000000..3b46b65b0a --- /dev/null +++ b/django/contrib/auth/backends.py @@ -0,0 +1,21 @@ +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 diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index 800c14375b..ef81268e2a 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -1,4 +1,5 @@ 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.") diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py index a1a0b2e834..a6a60780a7 100644 --- a/django/contrib/auth/middleware.py +++ b/django/contrib/auth/middleware.py @@ -4,12 +4,8 @@ class LazyUser(object): def __get__(self, request, obj_type=None): if self._user is None: - from django.contrib.auth.models import User, AnonymousUser, SESSION_KEY - try: - user_id = request.session[SESSION_KEY] - self._user = User.objects.get(pk=user_id) - except (KeyError, User.DoesNotExist): - self._user = AnonymousUser() + from django.contrib.auth import get_user + self._user = get_user(request) return self._user class AuthenticationMiddleware(object): diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index 65392695ae..e37f5a4497 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -4,7 +4,19 @@ from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext_lazy as _ import datetime -SESSION_KEY = '_auth_user_id' +def check_password(raw_password, enc_password): + """ + Returns a boolean of whether the raw_password was correct. Handles + encryption formats behind the scenes. + """ + algo, salt, hsh = enc_password.split('$') + if algo == 'md5': + import md5 + return hsh == md5.new(salt+raw_password).hexdigest() + elif algo == 'sha1': + import sha + return hsh == sha.new(salt+raw_password).hexdigest() + raise ValueError, "Got unknown password algorithm type in password." class SiteProfileNotAvailable(Exception): pass @@ -141,14 +153,7 @@ class User(models.Model): self.set_password(raw_password) self.save() return is_correct - algo, salt, hsh = self.password.split('$') - if algo == 'md5': - import md5 - return hsh == md5.new(salt+raw_password).hexdigest() - elif algo == 'sha1': - import sha - return hsh == sha.new(salt+raw_password).hexdigest() - raise ValueError, "Got unknown password algorithm type in password." + return check_password(raw_password, self.password) def get_group_permissions(self): "Returns a list of permission strings that this user has through his/her groups." diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py index 6d908ee025..97ecd6a3fd 100644 --- a/django/contrib/auth/views.py +++ b/django/contrib/auth/views.py @@ -3,7 +3,6 @@ from django.contrib.auth.forms import PasswordResetForm, PasswordChangeForm from django import forms from django.shortcuts import render_to_response from django.template import RequestContext -from django.contrib.auth.models import SESSION_KEY from django.contrib.sites.models import Site from django.http import HttpResponse, HttpResponseRedirect from django.contrib.auth.decorators import login_required @@ -19,7 +18,8 @@ def login(request, template_name='registration/login.html'): # Light security check -- make sure redirect_to isn't garbage. if not redirect_to or '://' in redirect_to or ' ' in redirect_to: redirect_to = '/accounts/profile/' - request.session[SESSION_KEY] = manipulator.get_user_id() + from django.contrib.auth import login + login(request, manipulator.get_user()) request.session.delete_test_cookie() return HttpResponseRedirect(redirect_to) else: @@ -33,8 +33,9 @@ def login(request, template_name='registration/login.html'): def logout(request, next_page=None, template_name='registration/logged_out.html'): "Logs out the user and displays 'You are logged out' message." + from django.contrib.auth import logout try: - del request.session[SESSION_KEY] + logout(request) except KeyError: return render_to_response(template_name, {'title': _('Logged out')}, context_instance=RequestContext(request)) else: diff --git a/django/contrib/comments/views/comments.py b/django/contrib/comments/views/comments.py index 316f3e719b..c32a82f4d8 100644 --- a/django/contrib/comments/views/comments.py +++ b/django/contrib/comments/views/comments.py @@ -5,7 +5,6 @@ from django.http import Http404 from django.core.exceptions import ObjectDoesNotExist from django.shortcuts import render_to_response from django.template import RequestContext -from django.contrib.auth.models import SESSION_KEY from django.contrib.comments.models import Comment, FreeComment, PHOTOS_REQUIRED, PHOTOS_OPTIONAL, RATINGS_REQUIRED, RATINGS_OPTIONAL, IS_PUBLIC from django.contrib.contenttypes.models import ContentType from django.contrib.auth.forms import AuthenticationForm @@ -219,7 +218,8 @@ def post_comment(request): # If user gave correct username/password and wasn't already logged in, log them in # so they don't have to enter a username/password again. if manipulator.get_user() and new_data.has_key('password') and manipulator.get_user().check_password(new_data['password']): - request.session[SESSION_KEY] = manipulator.get_user_id() + from django.contrib.auth import login + login(request, manipulator.get_user()) if errors or request.POST.has_key('preview'): class CommentFormWrapper(forms.FormWrapper): def __init__(self, manipulator, new_data, errors, rating_choices): |
