Modified auth app so that login with alternate auth app is possible.

This commit is contained in:
Russell Keith-Magee 2012-06-04 20:41:37 +08:00
parent dabe362836
commit 507bb50a92
10 changed files with 71 additions and 39 deletions

View File

@ -9,6 +9,7 @@ from django.utils.translation import ugettext_lazy, ugettext as _
ERROR_MESSAGE = ugettext_lazy("Please enter the correct username and password " ERROR_MESSAGE = ugettext_lazy("Please enter the correct username and password "
"for a staff account. Note that both fields are case-sensitive.") "for a staff account. Note that both fields are case-sensitive.")
class AdminAuthenticationForm(AuthenticationForm): class AdminAuthenticationForm(AuthenticationForm):
""" """
A custom authentication form used in the admin app. A custom authentication form used in the admin app.

View File

@ -2,7 +2,7 @@ from functools import update_wrapper
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.contrib.admin import ModelAdmin, actions from django.contrib.admin import ModelAdmin, actions
from django.contrib.admin.forms import AdminAuthenticationForm from django.contrib.admin.forms import AdminAuthenticationForm
from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
from django.contrib.contenttypes import views as contenttype_views from django.contrib.contenttypes import views as contenttype_views
from django.views.decorators.csrf import csrf_protect from django.views.decorators.csrf import csrf_protect
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
@ -79,20 +79,23 @@ class AdminSite(object):
if model in self._registry: if model in self._registry:
raise AlreadyRegistered('The model %s is already registered' % model.__name__) raise AlreadyRegistered('The model %s is already registered' % model.__name__)
# If we got **options then dynamically construct a subclass of # Ignore the registration if the model has been
# admin_class with those **options. # swapped out.
if options: if not model._meta.swapped:
# For reasons I don't quite understand, without a __module__ # If we got **options then dynamically construct a subclass of
# the created class appears to "live" in the wrong place, # admin_class with those **options.
# which causes issues later on. if options:
options['__module__'] = __name__ # For reasons I don't quite understand, without a __module__
admin_class = type("%sAdmin" % model.__name__, (admin_class,), options) # the created class appears to "live" in the wrong place,
# which causes issues later on.
options['__module__'] = __name__
admin_class = type("%sAdmin" % model.__name__, (admin_class,), options)
# Validate (which might be a no-op) # Validate (which might be a no-op)
validate(admin_class, model) validate(admin_class, model)
# Instantiate the admin class to save in the registry # Instantiate the admin class to save in the registry
self._registry[model] = admin_class(model, self) self._registry[model] = admin_class(model, self)
def unregister(self, model_or_iterable): def unregister(self, model_or_iterable):
""" """
@ -317,6 +320,7 @@ class AdminSite(object):
REDIRECT_FIELD_NAME: request.get_full_path(), REDIRECT_FIELD_NAME: request.get_full_path(),
} }
context.update(extra_context or {}) context.update(extra_context or {})
defaults = { defaults = {
'extra_context': context, 'extra_context': context,
'current_app': self.name, 'current_app': self.name,

View File

@ -26,7 +26,7 @@
{% if user.is_active and user.is_staff %} {% if user.is_active and user.is_staff %}
<div id="user-tools"> <div id="user-tools">
{% trans 'Welcome,' %} {% trans 'Welcome,' %}
<strong>{% filter force_escape %}{% firstof user.first_name user.username %}{% endfilter %}</strong>. <strong>{% filter force_escape %}{% firstof user.get_short_name user.username %}{% endfilter %}</strong>.
{% block userlinks %} {% block userlinks %}
{% url 'django-admindocs-docroot' as docsroot %} {% url 'django-admindocs-docroot' as docsroot %}
{% if docsroot %} {% if docsroot %}

View File

@ -6,9 +6,10 @@ SESSION_KEY = '_auth_user_id'
BACKEND_SESSION_KEY = '_auth_user_backend' BACKEND_SESSION_KEY = '_auth_user_backend'
REDIRECT_FIELD_NAME = 'next' REDIRECT_FIELD_NAME = 'next'
def load_backend(path): def load_backend(path):
i = path.rfind('.') i = path.rfind('.')
module, attr = path[:i], path[i+1:] module, attr = path[:i], path[i + 1:]
try: try:
mod = import_module(module) mod = import_module(module)
except ImportError as e: except ImportError as e:
@ -21,6 +22,7 @@ def load_backend(path):
raise ImproperlyConfigured('Module "%s" does not define a "%s" authentication backend' % (module, attr)) raise ImproperlyConfigured('Module "%s" does not define a "%s" authentication backend' % (module, attr))
return cls() return cls()
def get_backends(): def get_backends():
from django.conf import settings from django.conf import settings
backends = [] backends = []
@ -30,6 +32,7 @@ def get_backends():
raise ImproperlyConfigured('No authentication backends have been defined. Does AUTHENTICATION_BACKENDS contain anything?') raise ImproperlyConfigured('No authentication backends have been defined. Does AUTHENTICATION_BACKENDS contain anything?')
return backends return backends
def authenticate(**credentials): def authenticate(**credentials):
""" """
If the given credentials are valid, return a User object. If the given credentials are valid, return a User object.
@ -46,6 +49,7 @@ def authenticate(**credentials):
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__) user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
return user return user
def login(request, user): def login(request, user):
""" """
Persist a user id and a backend in the request. This way a user doesn't Persist a user id and a backend in the request. This way a user doesn't
@ -69,6 +73,7 @@ def login(request, user):
request.user = user request.user = user
user_logged_in.send(sender=user.__class__, request=request, user=user) user_logged_in.send(sender=user.__class__, request=request, user=user)
def logout(request): def logout(request):
""" """
Removes the authenticated user's ID from the request and flushes their Removes the authenticated user's ID from the request and flushes their
@ -86,6 +91,16 @@ def logout(request):
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
request.user = AnonymousUser() request.user = AnonymousUser()
def get_user_model():
"Return the User model that is active in this project"
from django.conf import settings
from django.db.models import get_model
app_label, model_name = settings.AUTH_USER_MODEL.split('.')
return get_model(app_label, model_name)
def get_user(request): def get_user(request):
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
try: try:

View File

@ -1,4 +1,5 @@
from django.contrib.auth.models import User, Permission from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
class ModelBackend(object): class ModelBackend(object):
@ -10,10 +11,13 @@ class ModelBackend(object):
# configurable. # configurable.
def authenticate(self, username=None, password=None): def authenticate(self, username=None, password=None):
try: try:
user = User.objects.get(username=username) UserModel = get_user_model()
user = UserModel.objects.get(**{
getattr(UserModel, 'USERNAME_FIELD', 'username'): username
})
if user.check_password(password): if user.check_password(password):
return user return user
except User.DoesNotExist: except UserModel.DoesNotExist:
return None return None
def get_group_permissions(self, user_obj, obj=None): def get_group_permissions(self, user_obj, obj=None):
@ -58,8 +62,9 @@ class ModelBackend(object):
def get_user(self, user_id): def get_user(self, user_id):
try: try:
return User.objects.get(pk=user_id) UserModel = get_user_model()
except User.DoesNotExist: return UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None return None
@ -92,17 +97,23 @@ class RemoteUserBackend(ModelBackend):
user = None user = None
username = self.clean_username(remote_user) username = self.clean_username(remote_user)
UserModel = get_user_model()
# Note that this could be accomplished in one try-except clause, but # Note that this could be accomplished in one try-except clause, but
# instead we use get_or_create when creating unknown users since it has # instead we use get_or_create when creating unknown users since it has
# built-in safeguards for multiple threads. # built-in safeguards for multiple threads.
if self.create_unknown_user: if self.create_unknown_user:
user, created = User.objects.get_or_create(username=username) user, created = UserModel.objects.get_or_create(**{
getattr(UserModel, 'USERNAME_FIELD', 'username'): username
})
if created: if created:
user = self.configure_user(user) user = self.configure_user(user)
else: else:
try: try:
user = User.objects.get(username=username) user = UserModel.objects.get(**{
except User.DoesNotExist: getattr(UserModel, 'USERNAME_FIELD', 'username'): username
})
except UserModel.DoesNotExist:
pass pass
return user return user

View File

@ -5,10 +5,9 @@ import getpass
import locale import locale
import unicodedata import unicodedata
from django.contrib.auth import models as auth_app from django.contrib.auth import models as auth_app, get_user_model
from django.core import exceptions from django.core import exceptions
from django.db.models import get_models, signals from django.db.models import get_models, signals
from django.contrib.auth.models import User, get_user_model
def _get_permission_codename(action, opts): def _get_permission_codename(action, opts):
@ -106,7 +105,7 @@ def get_default_username(check_db=True):
""" """
# If the User model has been swapped out, we can't make any assumptions # If the User model has been swapped out, we can't make any assumptions
# about the default user name. # about the default user name.
if User._meta.swapped: if auth_app.User._meta.swapped:
return '' return ''
default_username = get_system_username() default_username = get_system_username()
@ -118,15 +117,15 @@ def get_default_username(check_db=True):
# Run the username validator # Run the username validator
try: try:
User._meta.get_field('username').run_validators(default_username) auth_app.User._meta.get_field('username').run_validators(default_username)
except exceptions.ValidationError: except exceptions.ValidationError:
return '' return ''
# Don't return the default username if it is already taken. # Don't return the default username if it is already taken.
if check_db and default_username: if check_db and default_username:
try: try:
User.objects.get(username=default_username) auth_app.User.objects.get(username=default_username)
except User.DoesNotExist: except auth_app.User.DoesNotExist:
pass pass
else: else:
return '' return ''

View File

@ -1,8 +1,8 @@
import getpass import getpass
from optparse import make_option from optparse import make_option
from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth.models import get_user_model
from django.db import DEFAULT_DB_ALIAS from django.db import DEFAULT_DB_ALIAS

View File

@ -6,8 +6,8 @@ import getpass
import sys import sys
from optparse import make_option from optparse import make_option
from django.contrib.auth import get_user_model
from django.contrib.auth.management import get_default_username from django.contrib.auth.management import get_default_username
from django.contrib.auth.models import get_user_model
from django.core import exceptions from django.core import exceptions
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from django.db import DEFAULT_DB_ALIAS from django.db import DEFAULT_DB_ALIAS

View File

@ -1,7 +1,6 @@
import re import re
import urllib import urllib
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.mail import send_mail from django.core.mail import send_mail
from django.core import validators from django.core import validators
@ -271,12 +270,6 @@ class AbstractBaseUser(models.Model):
raise NotImplementedError() raise NotImplementedError()
def get_user_model():
"Return the User model that is active in this project"
app_label, model_name = settings.AUTH_USER_MODEL.split('.')
return models.get_model(app_label, model_name)
class User(AbstractBaseUser): class User(AbstractBaseUser):
""" """
Users within the Django authentication system are represented by this Users within the Django authentication system are represented by this

View File

@ -70,6 +70,7 @@ def login(request, template_name='registration/login.html',
return TemplateResponse(request, template_name, context, return TemplateResponse(request, template_name, context,
current_app=current_app) current_app=current_app)
def logout(request, next_page=None, def logout(request, next_page=None,
template_name='registration/logged_out.html', template_name='registration/logged_out.html',
redirect_field_name=REDIRECT_FIELD_NAME, redirect_field_name=REDIRECT_FIELD_NAME,
@ -100,6 +101,7 @@ def logout(request, next_page=None,
# Redirect to this page until the session has been cleared. # Redirect to this page until the session has been cleared.
return HttpResponseRedirect(next_page or request.path) return HttpResponseRedirect(next_page or request.path)
def logout_then_login(request, login_url=None, current_app=None, extra_context=None): def logout_then_login(request, login_url=None, current_app=None, extra_context=None):
""" """
Logs out the user if he is logged in. Then redirects to the log-in page. Logs out the user if he is logged in. Then redirects to the log-in page.
@ -108,6 +110,7 @@ def logout_then_login(request, login_url=None, current_app=None, extra_context=N
login_url = settings.LOGIN_URL login_url = settings.LOGIN_URL
return logout(request, login_url, current_app=current_app, extra_context=extra_context) return logout(request, login_url, current_app=current_app, extra_context=extra_context)
def redirect_to_login(next, login_url=None, def redirect_to_login(next, login_url=None,
redirect_field_name=REDIRECT_FIELD_NAME): redirect_field_name=REDIRECT_FIELD_NAME):
""" """
@ -124,6 +127,7 @@ def redirect_to_login(next, login_url=None,
return HttpResponseRedirect(urlparse.urlunparse(login_url_parts)) return HttpResponseRedirect(urlparse.urlunparse(login_url_parts))
# 4 views for password reset: # 4 views for password reset:
# - password_reset sends the mail # - password_reset sends the mail
# - password_reset_done shows a success message for the above # - password_reset_done shows a success message for the above
@ -169,6 +173,7 @@ def password_reset(request, is_admin_site=False,
return TemplateResponse(request, template_name, context, return TemplateResponse(request, template_name, context,
current_app=current_app) current_app=current_app)
def password_reset_done(request, def password_reset_done(request,
template_name='registration/password_reset_done.html', template_name='registration/password_reset_done.html',
current_app=None, extra_context=None): current_app=None, extra_context=None):
@ -178,6 +183,7 @@ def password_reset_done(request,
return TemplateResponse(request, template_name, context, return TemplateResponse(request, template_name, context,
current_app=current_app) current_app=current_app)
# Doesn't need csrf_protect since no-one can guess the URL # Doesn't need csrf_protect since no-one can guess the URL
@sensitive_post_parameters() @sensitive_post_parameters()
@never_cache @never_cache
@ -191,7 +197,7 @@ def password_reset_confirm(request, uidb36=None, token=None,
View that checks the hash in a password reset link and presents a View that checks the hash in a password reset link and presents a
form for entering a new password. form for entering a new password.
""" """
assert uidb36 is not None and token is not None # checked by URLconf assert uidb36 is not None and token is not None # checked by URLconf
if post_reset_redirect is None: if post_reset_redirect is None:
post_reset_redirect = reverse('django.contrib.auth.views.password_reset_complete') post_reset_redirect = reverse('django.contrib.auth.views.password_reset_complete')
try: try:
@ -221,6 +227,7 @@ def password_reset_confirm(request, uidb36=None, token=None,
return TemplateResponse(request, template_name, context, return TemplateResponse(request, template_name, context,
current_app=current_app) current_app=current_app)
def password_reset_complete(request, def password_reset_complete(request,
template_name='registration/password_reset_complete.html', template_name='registration/password_reset_complete.html',
current_app=None, extra_context=None): current_app=None, extra_context=None):
@ -232,6 +239,7 @@ def password_reset_complete(request,
return TemplateResponse(request, template_name, context, return TemplateResponse(request, template_name, context,
current_app=current_app) current_app=current_app)
@sensitive_post_parameters() @sensitive_post_parameters()
@csrf_protect @csrf_protect
@login_required @login_required
@ -257,6 +265,7 @@ def password_change(request,
return TemplateResponse(request, template_name, context, return TemplateResponse(request, template_name, context,
current_app=current_app) current_app=current_app)
@login_required @login_required
def password_change_done(request, def password_change_done(request,
template_name='registration/password_change_done.html', template_name='registration/password_change_done.html',