diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
index 83a0869..0cc92e3 100644
--- django/contrib/admin/sites.py
+++ django/contrib/admin/sites.py
@@ -1,7 +1,6 @@
 from functools import update_wrapper
 from django import http
 from django.contrib.admin import ModelAdmin, actions
-from django.contrib.admin.forms import AdminAuthenticationForm
 from django.contrib.auth import REDIRECT_FIELD_NAME
 from django.contrib.contenttypes import views as contenttype_views
 from django.views.decorators.csrf import csrf_protect
@@ -307,6 +306,7 @@ class AdminSite(object):
         Displays the login form for the given HttpRequest.
         """
         from django.contrib.auth.views import login
+        from django.contrib.admin.forms import AdminAuthenticationForm
         context = {
             'title': _('Log in'),
             'app_path': request.get_full_path(),
diff --git a/django/contrib/auth/base.py b/django/contrib/auth/base.py
new file mode 100644
index 0000000..c919822
--- /dev/null
+++ django/contrib/auth/base.py
@@ -0,0 +1,449 @@
+import urllib
+
+from django.core.exceptions import ImproperlyConfigured
+from django.core.mail import send_mail
+from django.db import models
+from django.db.models.manager import EmptyManager
+from django.utils.crypto import get_random_string
+from django.utils.encoding import smart_str
+from django.utils.translation import ugettext_lazy as _
+from django.utils import timezone
+
+from django.contrib import auth
+# UNUSABLE_PASSWORD is still imported here for backwards compatibility
+from django.contrib.auth.hashers import (
+    check_password, make_password, is_password_usable, UNUSABLE_PASSWORD)
+from django.contrib.auth.signals import user_logged_in
+from django.contrib.contenttypes.models import ContentType
+
+
+def update_last_login(sender, user, **kwargs):
+    """
+    A signal receiver which updates the last_login date for
+    the user logging in.
+    """
+    user.last_login = timezone.now()
+    user.save()
+user_logged_in.connect(update_last_login)
+
+
+class SiteProfileNotAvailable(Exception):
+    pass
+
+
+class PermissionManager(models.Manager):
+    def get_by_natural_key(self, codename, app_label, model):
+        return self.get(
+            codename=codename,
+            content_type=ContentType.objects.get_by_natural_key(app_label,
+                                                                model),
+        )
+
+
+class Permission(models.Model):
+    """
+    The permissions system provides a way to assign permissions to specific
+    users and groups of users.
+
+    The permission system is used by the Django admin site, but may also be
+    useful in your own code. The Django admin site uses permissions as follows:
+
+        - The "add" permission limits the user's ability to view the "add" form
+          and add an object.
+        - The "change" permission limits a user's ability to view the change
+          list, view the "change" form and change an object.
+        - The "delete" permission limits the ability to delete an object.
+
+    Permissions are set globally per type of object, not per specific object
+    instance. It is possible to say "Mary may change news stories," but it's
+    not currently possible to say "Mary may change news stories, but only the
+    ones she created herself" or "Mary may only change news stories that have a
+    certain status or publication date."
+
+    Three basic permissions -- add, change and delete -- are automatically
+    created for each Django model.
+    """
+    name = models.CharField(_('name'), max_length=50)
+    content_type = models.ForeignKey(ContentType)
+    codename = models.CharField(_('codename'), max_length=100)
+    objects = PermissionManager()
+
+    class Meta:
+        verbose_name = _('permission')
+        verbose_name_plural = _('permissions')
+        unique_together = (('content_type', 'codename'),)
+        ordering = ('content_type__app_label', 'content_type__model',
+                    'codename')
+
+    def __unicode__(self):
+        return u"%s | %s | %s" % (
+            unicode(self.content_type.app_label),
+            unicode(self.content_type),
+            unicode(self.name))
+
+    def natural_key(self):
+        return (self.codename,) + self.content_type.natural_key()
+    natural_key.dependencies = ['contenttypes.contenttype']
+
+
+class Group(models.Model):
+    """
+    Groups are a generic way of categorizing users to apply permissions, or
+    some other label, to those users. A user can belong to any number of
+    groups.
+
+    A user in a group automatically has all the permissions granted to that
+    group. For example, if the group Site editors has the permission
+    can_edit_home_page, any user in that group will have that permission.
+
+    Beyond permissions, groups are a convenient way to categorize users to
+    apply some label, or extended functionality, to them. For example, you
+    could create a group 'Special users', and you could write code that would
+    do special things to those users -- such as giving them access to a
+    members-only portion of your site, or sending them members-only email
+    messages.
+    """
+    name = models.CharField(_('name'), max_length=80, unique=True)
+    permissions = models.ManyToManyField(Permission,
+        verbose_name=_('permissions'), blank=True)
+
+    class Meta:
+        verbose_name = _('group')
+        verbose_name_plural = _('groups')
+
+    def __unicode__(self):
+        return self.name
+
+
+class UserManager(models.Manager):
+    def create_user(self, username, email=None, password=None):
+        """
+        Creates and saves a User with the given username, email and password.
+        """
+        now = timezone.now()
+
+        # Normalize the address by lowercasing the domain part of the email
+        # address.
+        email = email or ''
+        try:
+            email_name, domain_part = email.strip().split('@', 1)
+        except ValueError:
+            pass
+        else:
+            email = '@'.join([email_name, domain_part.lower()])
+
+        user = self.model(username=username, email=email, is_staff=False,
+                         is_active=True, is_superuser=False, last_login=now,
+                         date_joined=now)
+
+        user.set_password(password)
+        user.save(using=self._db)
+        return user
+
+    def create_superuser(self, username, email, password):
+        u = self.create_user(username, email, password)
+        u.is_staff = True
+        u.is_active = True
+        u.is_superuser = True
+        u.save(using=self._db)
+        return u
+
+    def make_random_password(self, length=10,
+                             allowed_chars='abcdefghjkmnpqrstuvwxyz'
+                                           'ABCDEFGHJKLMNPQRSTUVWXYZ'
+                                           '23456789'):
+        """
+        Generates a random password with the given length and given
+        allowed_chars. Note that the default value of allowed_chars does not
+        have "I" or "O" or letters and digits that look similar -- just to
+        avoid confusion.
+        """
+        return get_random_string(length, allowed_chars)
+
+
+# A few helper functions for common logic between User and AnonymousUser.
+def _user_get_all_permissions(user, obj):
+    permissions = set()
+    for backend in auth.get_backends():
+        if hasattr(backend, "get_all_permissions"):
+            if obj is not None:
+                permissions.update(backend.get_all_permissions(user, obj))
+            else:
+                permissions.update(backend.get_all_permissions(user))
+    return permissions
+
+
+def _user_has_perm(user, perm, obj):
+    anon = user.is_anonymous()
+    active = user.is_active
+    for backend in auth.get_backends():
+        if anon or active or backend.supports_inactive_user:
+            if hasattr(backend, "has_perm"):
+                if obj is not None:
+                    if backend.has_perm(user, perm, obj):
+                            return True
+                else:
+                    if backend.has_perm(user, perm):
+                        return True
+    return False
+
+
+def _user_has_module_perms(user, app_label):
+    anon = user.is_anonymous()
+    active = user.is_active
+    for backend in auth.get_backends():
+        if anon or active or backend.supports_inactive_user:
+            if hasattr(backend, "has_module_perms"):
+                if backend.has_module_perms(user, app_label):
+                    return True
+    return False
+
+
+class UserTemplate(models.Model):
+    """
+    Users within the Django authentication system are represented by this
+    model.
+
+    Username and password are required. Other fields are optional.
+    """
+    username = models.CharField(_('username'), max_length=30, unique=True,
+        help_text=_('Required. 30 characters or fewer. Letters, numbers and '
+                    '@/./+/-/_ characters'))
+    first_name = models.CharField(_('first name'), max_length=30, blank=True)
+    last_name = models.CharField(_('last name'), max_length=30, blank=True)
+    email = models.EmailField(_('e-mail address'), blank=True)
+    password = models.CharField(_('password'), max_length=128)
+    is_staff = models.BooleanField(_('staff status'), default=False,
+        help_text=_('Designates whether the user can log into this admin '
+                    'site.'))
+    is_active = models.BooleanField(_('active'), default=True,
+        help_text=_('Designates whether this user should be treated as '
+                    'active. Unselect this instead of deleting accounts.'))
+    is_superuser = models.BooleanField(_('superuser status'), default=False,
+        help_text=_('Designates that this user has all permissions without '
+                    'explicitly assigning them.'))
+    last_login = models.DateTimeField(_('last login'), default=timezone.now)
+    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
+    groups = models.ManyToManyField(Group, verbose_name=_('groups'),
+        blank=True, help_text=_('The groups this user belongs to. A user will '
+                                'get all permissions granted to each of '
+                                'his/her group.'))
+    user_permissions = models.ManyToManyField(Permission,
+        verbose_name=_('user permissions'), blank=True,
+        help_text='Specific permissions for this user.')
+    objects = UserManager()
+
+    class Meta:
+        abstract = True
+
+    def __unicode__(self):
+        return self.username
+
+    def get_absolute_url(self):
+        return "/users/%s/" % urllib.quote(smart_str(self.username))
+
+    def is_anonymous(self):
+        """
+        Always returns False. This is a way of comparing User objects to
+        anonymous users.
+        """
+        return False
+
+    def is_authenticated(self):
+        """
+        Always return True. This is a way to tell if the user has been
+        authenticated in templates.
+        """
+        return True
+
+    def get_full_name(self):
+        """
+        Returns the first_name plus the last_name, with a space in between.
+        """
+        full_name = u'%s %s' % (self.first_name, self.last_name)
+        return full_name.strip()
+
+    def set_password(self, raw_password):
+        self.password = make_password(raw_password)
+
+    def check_password(self, raw_password):
+        """
+        Returns a boolean of whether the raw_password was correct. Handles
+        hashing formats behind the scenes.
+        """
+        def setter(raw_password):
+            self.set_password(raw_password)
+            self.save()
+        return check_password(raw_password, self.password, setter)
+
+    def set_unusable_password(self):
+        # Sets a value that will never be a valid hash
+        self.password = make_password(None)
+
+    def has_usable_password(self):
+        return is_password_usable(self.password)
+
+    def get_group_permissions(self, obj=None):
+        """
+        Returns a list of permission strings that this user has through his/her
+        groups. This method queries all available auth backends. If an object
+        is passed in, only permissions matching this object are returned.
+        """
+        permissions = set()
+        for backend in auth.get_backends():
+            if hasattr(backend, "get_group_permissions"):
+                if obj is not None:
+                    permissions.update(backend.get_group_permissions(self,
+                                                                     obj))
+                else:
+                    permissions.update(backend.get_group_permissions(self))
+        return permissions
+
+    def get_all_permissions(self, obj=None):
+        return _user_get_all_permissions(self, obj)
+
+    def has_perm(self, perm, obj=None):
+        """
+        Returns True if the user has the specified permission. This method
+        queries all available auth backends, but returns immediately if any
+        backend returns True. Thus, a user who has permission from a single
+        auth backend is assumed to have permission in general. If an object is
+        provided, permissions for this specific object are checked.
+        """
+
+        # Active superusers have all permissions.
+        if self.is_active and self.is_superuser:
+            return True
+
+        # Otherwise we need to check the backends.
+        return _user_has_perm(self, perm, obj)
+
+    def has_perms(self, perm_list, obj=None):
+        """
+        Returns True if the user has each of the specified permissions. If
+        object is passed, it checks if the user has all required perms for this
+        object.
+        """
+        for perm in perm_list:
+            if not self.has_perm(perm, obj):
+                return False
+        return True
+
+    def has_module_perms(self, app_label):
+        """
+        Returns True if the user has any permissions in the given app label.
+        Uses pretty much the same logic as has_perm, above.
+        """
+        # Active superusers have all permissions.
+        if self.is_active and self.is_superuser:
+            return True
+
+        return _user_has_module_perms(self, app_label)
+
+    def email_user(self, subject, message, from_email=None):
+        """
+        Sends an email to this User.
+        """
+        send_mail(subject, message, from_email, [self.email])
+
+    def get_profile(self):
+        """
+        Returns site-specific profile for this user. Raises
+        SiteProfileNotAvailable if this site does not allow profiles.
+        """
+        if not hasattr(self, '_profile_cache'):
+            from django.conf import settings
+            if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
+                raise SiteProfileNotAvailable(
+                    'You need to set AUTH_PROFILE_MODULE in your project '
+                    'settings')
+            try:
+                app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
+            except ValueError:
+                raise SiteProfileNotAvailable(
+                    'app_label and model_name should be separated by a dot in '
+                    'the AUTH_PROFILE_MODULE setting')
+            try:
+                model = models.get_model(app_label, model_name)
+                if model is None:
+                    raise SiteProfileNotAvailable(
+                        'Unable to load the profile model, check '
+                        'AUTH_PROFILE_MODULE in your project settings')
+                self._profile_cache = model._default_manager.using(
+                                   self._state.db).get(user__id__exact=self.id)
+                self._profile_cache.user = self
+            except (ImportError, ImproperlyConfigured):
+                raise SiteProfileNotAvailable
+        return self._profile_cache
+
+
+class AnonymousUser(object):
+    id = None
+    username = ''
+    is_staff = False
+    is_active = False
+    is_superuser = False
+    _groups = EmptyManager()
+    _user_permissions = EmptyManager()
+
+    def __init__(self):
+        pass
+
+    def __unicode__(self):
+        return 'AnonymousUser'
+
+    def __str__(self):
+        return unicode(self).encode('utf-8')
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__)
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __hash__(self):
+        return 1 # instances always return the same hash value
+
+    def save(self):
+        raise NotImplementedError
+
+    def delete(self):
+        raise NotImplementedError
+
+    def set_password(self, raw_password):
+        raise NotImplementedError
+
+    def check_password(self, raw_password):
+        raise NotImplementedError
+
+    def _get_groups(self):
+        return self._groups
+    groups = property(_get_groups)
+
+    def _get_user_permissions(self):
+        return self._user_permissions
+    user_permissions = property(_get_user_permissions)
+
+    def get_group_permissions(self, obj=None):
+        return set()
+
+    def get_all_permissions(self, obj=None):
+        return _user_get_all_permissions(self, obj=obj)
+
+    def has_perm(self, perm, obj=None):
+        return _user_has_perm(self, perm, obj=obj)
+
+    def has_perms(self, perm_list, obj=None):
+        for perm in perm_list:
+            if not self.has_perm(perm, obj):
+                return False
+        return True
+
+    def has_module_perms(self, module):
+        return _user_has_module_perms(self, module)
+
+    def is_anonymous(self):
+        return True
+
+    def is_authenticated(self):
+        return False
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
index 4bb8cad..6291350 100644
--- django/contrib/auth/models.py
+++ django/contrib/auth/models.py
@@ -1,450 +1,49 @@
-import urllib
-
-from django.core.exceptions import ImproperlyConfigured
-from django.core.mail import send_mail
-from django.db import models
-from django.db.models.manager import EmptyManager
-from django.utils.crypto import get_random_string
-from django.utils.encoding import smart_str
+from django.conf import settings
 from django.utils.translation import ugettext_lazy as _
-from django.utils import timezone
-
-from django.contrib import auth
-# UNUSABLE_PASSWORD is still imported here for backwards compatibility
-from django.contrib.auth.hashers import (
-    check_password, make_password, is_password_usable, UNUSABLE_PASSWORD)
-from django.contrib.auth.signals import user_logged_in
-from django.contrib.contenttypes.models import ContentType
-
+from django.core.exceptions import ImproperlyConfigured
 
-def update_last_login(sender, user, **kwargs):
-    """
-    A signal receiver which updates the last_login date for
-    the user logging in.
-    """
-    user.last_login = timezone.now()
-    user.save()
-user_logged_in.connect(update_last_login)
+from django.contrib.auth.base import *
 
 
-class SiteProfileNotAvailable(Exception):
+class AuthNotAvailable(Exception):
     pass
 
 
-class PermissionManager(models.Manager):
-    def get_by_natural_key(self, codename, app_label, model):
-        return self.get(
-            codename=codename,
-            content_type=ContentType.objects.get_by_natural_key(app_label,
-                                                                model),
-        )
-
-
-class Permission(models.Model):
-    """
-    The permissions system provides a way to assign permissions to specific
-    users and groups of users.
-
-    The permission system is used by the Django admin site, but may also be
-    useful in your own code. The Django admin site uses permissions as follows:
-
-        - The "add" permission limits the user's ability to view the "add" form
-          and add an object.
-        - The "change" permission limits a user's ability to view the change
-          list, view the "change" form and change an object.
-        - The "delete" permission limits the ability to delete an object.
-
-    Permissions are set globally per type of object, not per specific object
-    instance. It is possible to say "Mary may change news stories," but it's
-    not currently possible to say "Mary may change news stories, but only the
-    ones she created herself" or "Mary may only change news stories that have a
-    certain status or publication date."
-
-    Three basic permissions -- add, change and delete -- are automatically
-    created for each Django model.
-    """
-    name = models.CharField(_('name'), max_length=50)
-    content_type = models.ForeignKey(ContentType)
-    codename = models.CharField(_('codename'), max_length=100)
-    objects = PermissionManager()
-
-    class Meta:
-        verbose_name = _('permission')
-        verbose_name_plural = _('permissions')
-        unique_together = (('content_type', 'codename'),)
-        ordering = ('content_type__app_label', 'content_type__model',
-                    'codename')
-
-    def __unicode__(self):
-        return u"%s | %s | %s" % (
-            unicode(self.content_type.app_label),
-            unicode(self.content_type),
-            unicode(self.name))
-
-    def natural_key(self):
-        return (self.codename,) + self.content_type.natural_key()
-    natural_key.dependencies = ['contenttypes.contenttype']
-
-
-class Group(models.Model):
-    """
-    Groups are a generic way of categorizing users to apply permissions, or
-    some other label, to those users. A user can belong to any number of
-    groups.
-
-    A user in a group automatically has all the permissions granted to that
-    group. For example, if the group Site editors has the permission
-    can_edit_home_page, any user in that group will have that permission.
-
-    Beyond permissions, groups are a convenient way to categorize users to
-    apply some label, or extended functionality, to them. For example, you
-    could create a group 'Special users', and you could write code that would
-    do special things to those users -- such as giving them access to a
-    members-only portion of your site, or sending them members-only email
-    messages.
-    """
-    name = models.CharField(_('name'), max_length=80, unique=True)
-    permissions = models.ManyToManyField(Permission,
-        verbose_name=_('permissions'), blank=True)
-
-    class Meta:
-        verbose_name = _('group')
-        verbose_name_plural = _('groups')
-
-    def __unicode__(self):
-        return self.name
-
-
-class UserManager(models.Manager):
-    def create_user(self, username, email=None, password=None):
-        """
-        Creates and saves a User with the given username, email and password.
-        """
-        now = timezone.now()
-
-        # Normalize the address by lowercasing the domain part of the email
-        # address.
-        email = email or ''
-        try:
-            email_name, domain_part = email.strip().split('@', 1)
-        except ValueError:
-            pass
-        else:
-            email = '@'.join([email_name, domain_part.lower()])
-
-        user = self.model(username=username, email=email, is_staff=False,
-                         is_active=True, is_superuser=False, last_login=now,
-                         date_joined=now)
-
-        user.set_password(password)
-        user.save(using=self._db)
-        return user
-
-    def create_superuser(self, username, email, password):
-        u = self.create_user(username, email, password)
-        u.is_staff = True
-        u.is_active = True
-        u.is_superuser = True
-        u.save(using=self._db)
-        return u
-
-    def make_random_password(self, length=10,
-                             allowed_chars='abcdefghjkmnpqrstuvwxyz'
-                                           'ABCDEFGHJKLMNPQRSTUVWXYZ'
-                                           '23456789'):
-        """
-        Generates a random password with the given length and given
-        allowed_chars. Note that the default value of allowed_chars does not
-        have "I" or "O" or letters and digits that look similar -- just to
-        avoid confusion.
-        """
-        return get_random_string(length, allowed_chars)
-
-
-# A few helper functions for common logic between User and AnonymousUser.
-def _user_get_all_permissions(user, obj):
-    permissions = set()
-    for backend in auth.get_backends():
-        if hasattr(backend, "get_all_permissions"):
-            if obj is not None:
-                permissions.update(backend.get_all_permissions(user, obj))
-            else:
-                permissions.update(backend.get_all_permissions(user))
-    return permissions
-
-
-def _user_has_perm(user, perm, obj):
-    anon = user.is_anonymous()
-    active = user.is_active
-    for backend in auth.get_backends():
-        if anon or active or backend.supports_inactive_user:
-            if hasattr(backend, "has_perm"):
-                if obj is not None:
-                    if backend.has_perm(user, perm, obj):
-                            return True
-                else:
-                    if backend.has_perm(user, perm):
-                        return True
-    return False
-
-
-def _user_has_module_perms(user, app_label):
-    anon = user.is_anonymous()
-    active = user.is_active
-    for backend in auth.get_backends():
-        if anon or active or backend.supports_inactive_user:
-            if hasattr(backend, "has_module_perms"):
-                if backend.has_module_perms(user, app_label):
-                    return True
-    return False
-
-
-class User(models.Model):
-    """
-    Users within the Django authentication system are represented by this
-    model.
-
-    Username and password are required. Other fields are optional.
-    """
-    username = models.CharField(_('username'), max_length=30, unique=True,
-        help_text=_('Required. 30 characters or fewer. Letters, numbers and '
-                    '@/./+/-/_ characters'))
-    first_name = models.CharField(_('first name'), max_length=60, blank=True)
-    last_name = models.CharField(_('last name'), max_length=60, blank=True)
-    email = models.EmailField(_('e-mail address'), max_length=255, blank=True)
-    password = models.CharField(_('password'), max_length=128)
-    is_staff = models.BooleanField(_('staff status'), default=False,
-        help_text=_('Designates whether the user can log into this admin '
-                    'site.'))
-    is_active = models.BooleanField(_('active'), default=True,
-        help_text=_('Designates whether this user should be treated as '
-                    'active. Unselect this instead of deleting accounts.'))
-    is_superuser = models.BooleanField(_('superuser status'), default=False,
-        help_text=_('Designates that this user has all permissions without '
-                    'explicitly assigning them.'))
-    last_login = models.DateTimeField(_('last login'), default=timezone.now)
-    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
-    groups = models.ManyToManyField(Group, verbose_name=_('groups'),
-        blank=True, help_text=_('The groups this user belongs to. A user will '
-                                'get all permissions granted to each of '
-                                'his/her group.'))
-    user_permissions = models.ManyToManyField(Permission,
-        verbose_name=_('user permissions'), blank=True,
-        help_text='Specific permissions for this user.')
-    objects = UserManager()
-
-    class Meta:
-        verbose_name = _('user')
-        verbose_name_plural = _('users')
-
-    def __unicode__(self):
-        return self.username
-
-    def get_absolute_url(self):
-        return "/users/%s/" % urllib.quote(smart_str(self.username))
-
-    def is_anonymous(self):
-        """
-        Always returns False. This is a way of comparing User objects to
-        anonymous users.
-        """
-        return False
-
-    def is_authenticated(self):
-        """
-        Always return True. This is a way to tell if the user has been
-        authenticated in templates.
-        """
-        return True
-
-    def get_full_name(self):
-        """
-        Returns the first_name plus the last_name, with a space in between.
-        """
-        full_name = u'%s %s' % (self.first_name, self.last_name)
-        return full_name.strip()
-
-    def set_password(self, raw_password):
-        self.password = make_password(raw_password)
-
-    def check_password(self, raw_password):
-        """
-        Returns a boolean of whether the raw_password was correct. Handles
-        hashing formats behind the scenes.
-        """
-        def setter(raw_password):
-            self.set_password(raw_password)
-            self.save()
-        return check_password(raw_password, self.password, setter)
-
-    def set_unusable_password(self):
-        # Sets a value that will never be a valid hash
-        self.password = make_password(None)
-
-    def has_usable_password(self):
-        return is_password_usable(self.password)
-
-    def get_group_permissions(self, obj=None):
-        """
-        Returns a list of permission strings that this user has through his/her
-        groups. This method queries all available auth backends. If an object
-        is passed in, only permissions matching this object are returned.
-        """
-        permissions = set()
-        for backend in auth.get_backends():
-            if hasattr(backend, "get_group_permissions"):
-                if obj is not None:
-                    permissions.update(backend.get_group_permissions(self,
-                                                                     obj))
-                else:
-                    permissions.update(backend.get_group_permissions(self))
-        return permissions
-
-    def get_all_permissions(self, obj=None):
-        return _user_get_all_permissions(self, obj)
-
-    def has_perm(self, perm, obj=None):
-        """
-        Returns True if the user has the specified permission. This method
-        queries all available auth backends, but returns immediately if any
-        backend returns True. Thus, a user who has permission from a single
-        auth backend is assumed to have permission in general. If an object is
-        provided, permissions for this specific object are checked.
-        """
-
-        # Active superusers have all permissions.
-        if self.is_active and self.is_superuser:
-            return True
-
-        # Otherwise we need to check the backends.
-        return _user_has_perm(self, perm, obj)
-
-    def has_perms(self, perm_list, obj=None):
-        """
-        Returns True if the user has each of the specified permissions. If
-        object is passed, it checks if the user has all required perms for this
-        object.
-        """
-        for perm in perm_list:
-            if not self.has_perm(perm, obj):
-                return False
-        return True
-
-    def has_module_perms(self, app_label):
-        """
-        Returns True if the user has any permissions in the given app label.
-        Uses pretty much the same logic as has_perm, above.
-        """
-        # Active superusers have all permissions.
-        if self.is_active and self.is_superuser:
-            return True
-
-        return _user_has_module_perms(self, app_label)
-
-    def email_user(self, subject, message, from_email=None):
-        """
-        Sends an email to this User.
-        """
-        send_mail(subject, message, from_email, [self.email])
-
-    def get_profile(self):
-        """
-        Returns site-specific profile for this user. Raises
-        SiteProfileNotAvailable if this site does not allow profiles.
-        """
-        if not hasattr(self, '_profile_cache'):
-            from django.conf import settings
-            if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
-                raise SiteProfileNotAvailable(
-                    'You need to set AUTH_PROFILE_MODULE in your project '
-                    'settings')
-            try:
-                app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
-            except ValueError:
-                raise SiteProfileNotAvailable(
-                    'app_label and model_name should be separated by a dot in '
-                    'the AUTH_PROFILE_MODULE setting')
-            try:
-                model = models.get_model(app_label, model_name)
-                if model is None:
-                    raise SiteProfileNotAvailable(
-                        'Unable to load the profile model, check '
-                        'AUTH_PROFILE_MODULE in your project settings')
-                self._profile_cache = model._default_manager.using(
-                                   self._state.db).get(user__id__exact=self.id)
-                self._profile_cache.user = self
-            except (ImportError, ImproperlyConfigured):
-                raise SiteProfileNotAvailable
-        return self._profile_cache
-
-
-class AnonymousUser(object):
-    id = None
-    username = ''
-    is_staff = False
-    is_active = False
-    is_superuser = False
-    _groups = EmptyManager()
-    _user_permissions = EmptyManager()
-
-    def __init__(self):
-        pass
-
-    def __unicode__(self):
-        return 'AnonymousUser'
-
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__)
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __hash__(self):
-        return 1 # instances always return the same hash value
-
-    def save(self):
-        raise NotImplementedError
-
-    def delete(self):
-        raise NotImplementedError
-
-    def set_password(self, raw_password):
-        raise NotImplementedError
-
-    def check_password(self, raw_password):
-        raise NotImplementedError
-
-    def _get_groups(self):
-        return self._groups
-    groups = property(_get_groups)
-
-    def _get_user_permissions(self):
-        return self._user_permissions
-    user_permissions = property(_get_user_permissions)
-
-    def get_group_permissions(self, obj=None):
-        return set()
-
-    def get_all_permissions(self, obj=None):
-        return _user_get_all_permissions(self, obj=obj)
-
-    def has_perm(self, perm, obj=None):
-        return _user_has_perm(self, perm, obj=obj)
-
-    def has_perms(self, perm_list, obj=None):
-        for perm in perm_list:
-            if not self.has_perm(perm, obj):
-                return False
-        return True
-
-    def has_module_perms(self, module):
-        return _user_has_module_perms(self, module)
-
-    def is_anonymous(self):
-        return True
-
-    def is_authenticated(self):
-        return False
+if hasattr(settings, 'AUTH_USER_MODULE'):
+    try:
+        app_label, model_name = settings.AUTH_USER_MODULE.split('.')
+    except ValueError:
+        raise AuthNotAvailable('app_label and model_name should'
+                ' be separated by a dot in the AUTH_USER_MODULE set'
+                'ting')
+
+    try:
+        # Grab the AUTH_USER_MODULE path and classname from the settings.
+        module = __import__(app_label + '.models', {}, {}, [''])
+        # Store the user model so it is accessible with the standard
+        # 'from django.contrib.auth.models import User'
+        User = getattr(module, model_name, None)
+
+        if User is None:
+            raise AuthNotAvailable('Unable to load the user '
+                'model, check AUTH_USER_MODULE in your project sett'
+                'ings')
+    except (ImportError, ImproperlyConfigured):
+        raise AuthNotAvailable
+
+    # Add te User model to the django models cache
+    # These two lines allow the custom auth_user model to play nicely with syncdb
+    # and other systems that rely on functions like
+    # django.db.models.loading.get_model(...)
+    from django.db.models.loading import cache
+    cache.register_models('auth', User)
+
+    # We need to remove whatever we used as the AUTH_USER_MODUlE from the
+    # db cache so apps like contenttypes don't think that it's part
+    # of contrib.auth
+    del cache.app_models['auth'][User.__name__.lower()]
+else:
+    class User(UserTemplate):
+        class Meta:
+            verbose_name = _('user')
+            verbose_name_plural = _('users')
