Ticket #3011: #3011-extendable_auth_user-1.3.diff

File #3011-extendable_auth_user-1.3.diff, 41.5 KB (added by German M. Bravo, 12 years ago)

Updated for django 1.3

  • django/contrib/admin/sites.py

    diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
    index b03bce4..be60e96 100644
     
    11import re
    22from django import http, template
    33from django.contrib.admin import ModelAdmin, actions
    4 from django.contrib.admin.forms import AdminAuthenticationForm
    54from django.contrib.auth import REDIRECT_FIELD_NAME
    65from django.contrib.contenttypes import views as contenttype_views
    76from django.views.decorators.csrf import csrf_protect
    class AdminSite(object):  
    315314        Displays the login form for the given HttpRequest.
    316315        """
    317316        from django.contrib.auth.views import login
     317        from django.contrib.admin.forms import AdminAuthenticationForm
    318318        context = {
    319319            'title': _('Log in'),
    320320            'root_path': self.root_path,
  • new file django/contrib/auth/base.py

    diff --git a/django/contrib/auth/base.py b/django/contrib/auth/base.py
    new file mode 100644
    index 0000000..3465c64
    - +  
     1import datetime
     2import urllib
     3
     4from django.contrib import auth
     5from django.contrib.auth.signals import user_logged_in
     6from django.core.exceptions import ImproperlyConfigured
     7from django.db import models
     8from django.db.models.manager import EmptyManager
     9from django.contrib.contenttypes.models import ContentType
     10from django.utils.encoding import smart_str
     11from django.utils.hashcompat import md5_constructor, sha_constructor
     12from django.utils.translation import ugettext_lazy as _
     13from django.utils.crypto import constant_time_compare
     14from django.conf import settings
     15
     16
     17UNUSABLE_PASSWORD = '!' # This will never be a valid hash
     18
     19def get_hexdigest(algorithm, salt, raw_password):
     20    """
     21    Returns a string of the hexdigest of the given plaintext password and salt
     22    using the given algorithm ('md5', 'sha1' or 'crypt').
     23    """
     24    raw_password, salt = smart_str(raw_password), smart_str(salt)
     25    if algorithm == 'crypt':
     26        try:
     27            import crypt
     28        except ImportError:
     29            raise ValueError('"crypt" password algorithm not supported in this environment')
     30        return crypt.crypt(raw_password, salt)
     31
     32    if algorithm == 'md5':
     33        return md5_constructor(salt + raw_password).hexdigest()
     34    elif algorithm == 'sha1':
     35        return sha_constructor(salt + raw_password).hexdigest()
     36    raise ValueError("Got unknown password algorithm type in password.")
     37
     38def check_password(raw_password, enc_password):
     39    """
     40    Returns a boolean of whether the raw_password was correct. Handles
     41    encryption formats behind the scenes.
     42    """
     43    algo, salt, hsh = enc_password.split('$')
     44    return constant_time_compare(hsh, get_hexdigest(algo, salt, raw_password))
     45
     46def update_last_login(sender, user, **kwargs):
     47    """
     48    A signal receiver which updates the last_login date for
     49    the user logging in.
     50    """
     51    user.last_login = datetime.datetime.now()
     52    user.save()
     53user_logged_in.connect(update_last_login)
     54
     55class SiteProfileNotAvailable(Exception):
     56    pass
     57
     58class PermissionManager(models.Manager):
     59    def get_by_natural_key(self, codename, app_label, model):
     60        return self.get(
     61            codename=codename,
     62            content_type=ContentType.objects.get_by_natural_key(app_label, model)
     63        )
     64
     65class Permission(models.Model):
     66    """The permissions system provides a way to assign permissions to specific users and groups of users.
     67
     68    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:
     69
     70        - The "add" permission limits the user's ability to view the "add" form and add an object.
     71        - The "change" permission limits a user's ability to view the change list, view the "change" form and change an object.
     72        - The "delete" permission limits the ability to delete an object.
     73
     74    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."
     75
     76    Three basic permissions -- add, change and delete -- are automatically created for each Django model.
     77    """
     78    name = models.CharField(_('name'), max_length=50)
     79    content_type = models.ForeignKey(ContentType)
     80    codename = models.CharField(_('codename'), max_length=100)
     81    objects = PermissionManager()
     82
     83    class Meta:
     84        verbose_name = _('permission')
     85        verbose_name_plural = _('permissions')
     86        unique_together = (('content_type', 'codename'),)
     87        ordering = ('content_type__app_label', 'content_type__model', 'codename')
     88
     89    def __unicode__(self):
     90        return u"%s | %s | %s" % (
     91            unicode(self.content_type.app_label),
     92            unicode(self.content_type),
     93            unicode(self.name))
     94
     95    def natural_key(self):
     96        return (self.codename,) + self.content_type.natural_key()
     97    natural_key.dependencies = ['contenttypes.contenttype']
     98
     99class Group(models.Model):
     100    """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.
     101
     102    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.
     103
     104    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 e-mail messages.
     105    """
     106    name = models.CharField(_('name'), max_length=80, unique=True)
     107    permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True)
     108
     109    class Meta:
     110        verbose_name = _('group')
     111        verbose_name_plural = _('groups')
     112
     113    def __unicode__(self):
     114        return self.name
     115
     116class UserManager(models.Manager):
     117    def create_user(self, username, email, password=None):
     118        """
     119        Creates and saves a User with the given username, e-mail and password.
     120        """
     121        now = datetime.datetime.now()
     122
     123        # Normalize the address by lowercasing the domain part of the email
     124        # address.
     125        try:
     126            email_name, domain_part = email.strip().split('@', 1)
     127        except ValueError:
     128            pass
     129        else:
     130            email = '@'.join([email_name, domain_part.lower()])
     131
     132        user = self.model(username=username, email=email, is_staff=False,
     133                         is_active=True, is_superuser=False, last_login=now,
     134                         date_joined=now)
     135
     136        user.set_password(password)
     137        user.save(using=self._db)
     138        return user
     139
     140    def create_superuser(self, username, email, password):
     141        u = self.create_user(username, email, password)
     142        u.is_staff = True
     143        u.is_active = True
     144        u.is_superuser = True
     145        u.save(using=self._db)
     146        return u
     147
     148    def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
     149        "Generates a random password with the given length and given allowed_chars"
     150        # Note that default value of allowed_chars does not have "I" or letters
     151        # that look like it -- just to avoid confusion.
     152        from random import choice
     153        return ''.join([choice(allowed_chars) for i in range(length)])
     154
     155
     156# A few helper functions for common logic between User and AnonymousUser.
     157def _user_get_all_permissions(user, obj):
     158    permissions = set()
     159    anon = user.is_anonymous()
     160    for backend in auth.get_backends():
     161        if not anon or backend.supports_anonymous_user:
     162            if hasattr(backend, "get_all_permissions"):
     163                if obj is not None:
     164                    if backend.supports_object_permissions:
     165                        permissions.update(
     166                            backend.get_all_permissions(user, obj)
     167                        )
     168                else:
     169                    permissions.update(backend.get_all_permissions(user))
     170    return permissions
     171
     172
     173def _user_has_perm(user, perm, obj):
     174    anon = user.is_anonymous()
     175    active = user.is_active
     176    for backend in auth.get_backends():
     177        if (not active and not anon and backend.supports_inactive_user) or \
     178                    (not anon or backend.supports_anonymous_user):
     179            if hasattr(backend, "has_perm"):
     180                if obj is not None:
     181                    if (backend.supports_object_permissions and
     182                        backend.has_perm(user, perm, obj)):
     183                            return True
     184                else:
     185                    if backend.has_perm(user, perm):
     186                        return True
     187    return False
     188
     189
     190def _user_has_module_perms(user, app_label):
     191    anon = user.is_anonymous()
     192    active = user.is_active
     193    for backend in auth.get_backends():
     194        if (not active and not anon and backend.supports_inactive_user) or \
     195                    (not anon or backend.supports_anonymous_user):
     196            if hasattr(backend, "has_module_perms"):
     197                if backend.has_module_perms(user, app_label):
     198                    return True
     199    return False
     200
     201
     202class UserTemplate(models.Model):
     203    """
     204    Users within the Django authentication system are represented by this model.
     205
     206    Username and password are required. Other fields are optional.
     207    """
     208    username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))
     209    first_name = models.CharField(_('first name'), max_length=30, blank=True)
     210    last_name = models.CharField(_('last name'), max_length=30, blank=True)
     211    email = models.EmailField(_('e-mail address'), blank=True)
     212    password = models.CharField(_('password'), max_length=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
     213    is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
     214    is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts."))
     215    is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
     216    last_login = models.DateTimeField(_('last login'), default=datetime.datetime.now)
     217    date_joined = models.DateTimeField(_('date joined'), default=datetime.datetime.now)
     218    groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True,
     219        help_text=_("In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."))
     220    user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True)
     221    objects = UserManager()
     222
     223    class Meta:
     224        abstract = True
     225
     226    def __unicode__(self):
     227        return self.username
     228
     229    def get_absolute_url(self):
     230        return "/users/%s/" % urllib.quote(smart_str(self.username))
     231
     232    def is_anonymous(self):
     233        """
     234        Always returns False. This is a way of comparing User objects to
     235        anonymous users.
     236        """
     237        return False
     238
     239    def is_authenticated(self):
     240        """
     241        Always return True. This is a way to tell if the user has been
     242        authenticated in templates.
     243        """
     244        return True
     245
     246    def get_full_name(self):
     247        "Returns the first_name plus the last_name, with a space in between."
     248        full_name = u'%s %s' % (self.first_name, self.last_name)
     249        return full_name.strip()
     250
     251    def set_password(self, raw_password):
     252        if raw_password is None:
     253            self.set_unusable_password()
     254        else:
     255            import random
     256            algo = 'sha1'
     257            salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
     258            hsh = get_hexdigest(algo, salt, raw_password)
     259            self.password = '%s$%s$%s' % (algo, salt, hsh)
     260
     261    def check_password(self, raw_password):
     262        """
     263        Returns a boolean of whether the raw_password was correct. Handles
     264        encryption formats behind the scenes.
     265        """
     266        # Backwards-compatibility check. Older passwords won't include the
     267        # algorithm or salt.
     268        if '$' not in self.password:
     269            is_correct = (self.password == get_hexdigest('md5', '', raw_password))
     270            if is_correct:
     271                # Convert the password to the new, more secure format.
     272                self.set_password(raw_password)
     273                self.save()
     274            return is_correct
     275        return check_password(raw_password, self.password)
     276
     277    def set_unusable_password(self):
     278        # Sets a value that will never be a valid hash
     279        self.password = UNUSABLE_PASSWORD
     280
     281    def has_usable_password(self):
     282        if self.password is None \
     283            or self.password == UNUSABLE_PASSWORD:
     284            return False
     285        else:
     286            return True
     287
     288    def get_group_permissions(self, obj=None):
     289        """
     290        Returns a list of permission strings that this user has through
     291        his/her groups. This method queries all available auth backends.
     292        If an object is passed in, only permissions matching this object
     293        are returned.
     294        """
     295        permissions = set()
     296        for backend in auth.get_backends():
     297            if hasattr(backend, "get_group_permissions"):
     298                if obj is not None:
     299                    if backend.supports_object_permissions:
     300                        permissions.update(
     301                            backend.get_group_permissions(self, obj)
     302                        )
     303                else:
     304                    permissions.update(backend.get_group_permissions(self))
     305        return permissions
     306
     307    def get_all_permissions(self, obj=None):
     308        return _user_get_all_permissions(self, obj)
     309
     310    def has_perm(self, perm, obj=None):
     311        """
     312        Returns True if the user has the specified permission. This method
     313        queries all available auth backends, but returns immediately if any
     314        backend returns True. Thus, a user who has permission from a single
     315        auth backend is assumed to have permission in general. If an object
     316        is provided, permissions for this specific object are checked.
     317        """
     318
     319        # Active superusers have all permissions.
     320        if self.is_active and self.is_superuser:
     321            return True
     322
     323        # Otherwise we need to check the backends.
     324        return _user_has_perm(self, perm, obj)
     325
     326    def has_perms(self, perm_list, obj=None):
     327        """
     328        Returns True if the user has each of the specified permissions.
     329        If object is passed, it checks if the user has all required perms
     330        for this object.
     331        """
     332        for perm in perm_list:
     333            if not self.has_perm(perm, obj):
     334                return False
     335        return True
     336
     337    def has_module_perms(self, app_label):
     338        """
     339        Returns True if the user has any permissions in the given app
     340        label. Uses pretty much the same logic as has_perm, above.
     341        """
     342        # Active superusers have all permissions.
     343        if self.is_active and self.is_superuser:
     344            return True
     345
     346        return _user_has_module_perms(self, app_label)
     347
     348    def get_and_delete_messages(self):
     349        messages = []
     350        for m in self.message_set.all():
     351            messages.append(m.message)
     352            m.delete()
     353        return messages
     354
     355    def email_user(self, subject, message, from_email=None):
     356        "Sends an e-mail to this User."
     357        from django.core.mail import send_mail
     358        send_mail(subject, message, from_email, [self.email])
     359
     360    def get_profile(self):
     361        """
     362        Returns site-specific profile for this user. Raises
     363        SiteProfileNotAvailable if this site does not allow profiles.
     364        """
     365        if not hasattr(self, '_profile_cache'):
     366            from django.conf import settings
     367            if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
     368                raise SiteProfileNotAvailable('You need to set AUTH_PROFILE_MO'
     369                                              'DULE in your project settings')
     370            try:
     371                app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
     372            except ValueError:
     373                raise SiteProfileNotAvailable('app_label and model_name should'
     374                        ' be separated by a dot in the AUTH_PROFILE_MODULE set'
     375                        'ting')
     376
     377            try:
     378                model = models.get_model(app_label, model_name)
     379                if model is None:
     380                    raise SiteProfileNotAvailable('Unable to load the profile '
     381                        'model, check AUTH_PROFILE_MODULE in your project sett'
     382                        'ings')
     383                self._profile_cache = model._default_manager.using(self._state.db).get(user__id__exact=self.id)
     384                self._profile_cache.user = self
     385            except (ImportError, ImproperlyConfigured):
     386                raise SiteProfileNotAvailable
     387        return self._profile_cache
     388
     389    def _get_message_set(self):
     390        import warnings
     391        warnings.warn('The user messaging API is deprecated. Please update'
     392                      ' your code to use the new messages framework.',
     393                      category=DeprecationWarning)
     394        return self._message_set
     395    message_set = property(_get_message_set)
     396
     397class Message(models.Model):
     398    """
     399    The message system is a lightweight way to queue messages for given
     400    users. A message is associated with a User instance (so it is only
     401    applicable for registered users). There's no concept of expiration or
     402    timestamps. Messages are created by the Django admin after successful
     403    actions. For example, "The poll Foo was created successfully." is a
     404    message.
     405    """
     406    user = models.ForeignKey(getattr(settings, 'AUTH_USER_MODULE', 'auth.User'), related_name='_message_set')
     407    message = models.TextField(_('message'))
     408
     409    def __unicode__(self):
     410        return self.message
     411
     412class AnonymousUser(object):
     413    id = None
     414    username = ''
     415    is_staff = False
     416    is_active = False
     417    is_superuser = False
     418    _groups = EmptyManager()
     419    _user_permissions = EmptyManager()
     420
     421    def __init__(self):
     422        pass
     423
     424    def __unicode__(self):
     425        return 'AnonymousUser'
     426
     427    def __str__(self):
     428        return unicode(self).encode('utf-8')
     429
     430    def __eq__(self, other):
     431        return isinstance(other, self.__class__)
     432
     433    def __ne__(self, other):
     434        return not self.__eq__(other)
     435
     436    def __hash__(self):
     437        return 1 # instances always return the same hash value
     438
     439    def save(self):
     440        raise NotImplementedError
     441
     442    def delete(self):
     443        raise NotImplementedError
     444
     445    def set_password(self, raw_password):
     446        raise NotImplementedError
     447
     448    def check_password(self, raw_password):
     449        raise NotImplementedError
     450
     451    def _get_groups(self):
     452        return self._groups
     453    groups = property(_get_groups)
     454
     455    def _get_user_permissions(self):
     456        return self._user_permissions
     457    user_permissions = property(_get_user_permissions)
     458
     459    def get_group_permissions(self, obj=None):
     460        return set()
     461
     462    def get_all_permissions(self, obj=None):
     463        return _user_get_all_permissions(self, obj=obj)
     464
     465    def has_perm(self, perm, obj=None):
     466        return _user_has_perm(self, perm, obj=obj)
     467
     468    def has_perms(self, perm_list, obj=None):
     469        for perm in perm_list:
     470            if not self.has_perm(perm, obj):
     471                return False
     472        return True
     473
     474    def has_module_perms(self, module):
     475        return _user_has_module_perms(self, module)
     476
     477    def get_and_delete_messages(self):
     478        return []
     479
     480    def is_anonymous(self):
     481        return True
     482
     483    def is_authenticated(self):
     484        return False
  • django/contrib/auth/models.py

    diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
    index 24195c8..6291350 100644
     
    1 import datetime
    2 import urllib
    3 
    4 from django.contrib import auth
    5 from django.contrib.auth.signals import user_logged_in
    6 from django.core.exceptions import ImproperlyConfigured
    7 from django.db import models
    8 from django.db.models.manager import EmptyManager
    9 from django.contrib.contenttypes.models import ContentType
    10 from django.utils.encoding import smart_str
    11 from django.utils.hashcompat import md5_constructor, sha_constructor
     1from django.conf import settings
    122from django.utils.translation import ugettext_lazy as _
    13 from django.utils.crypto import constant_time_compare
    14 
    15 
    16 UNUSABLE_PASSWORD = '!' # This will never be a valid hash
    17 
    18 def get_hexdigest(algorithm, salt, raw_password):
    19     """
    20     Returns a string of the hexdigest of the given plaintext password and salt
    21     using the given algorithm ('md5', 'sha1' or 'crypt').
    22     """
    23     raw_password, salt = smart_str(raw_password), smart_str(salt)
    24     if algorithm == 'crypt':
    25         try:
    26             import crypt
    27         except ImportError:
    28             raise ValueError('"crypt" password algorithm not supported in this environment')
    29         return crypt.crypt(raw_password, salt)
    30 
    31     if algorithm == 'md5':
    32         return md5_constructor(salt + raw_password).hexdigest()
    33     elif algorithm == 'sha1':
    34         return sha_constructor(salt + raw_password).hexdigest()
    35     raise ValueError("Got unknown password algorithm type in password.")
     3from django.core.exceptions import ImproperlyConfigured
    364
    37 def check_password(raw_password, enc_password):
    38     """
    39     Returns a boolean of whether the raw_password was correct. Handles
    40     encryption formats behind the scenes.
    41     """
    42     algo, salt, hsh = enc_password.split('$')
    43     return constant_time_compare(hsh, get_hexdigest(algo, salt, raw_password))
     5from django.contrib.auth.base import *
    446
    45 def update_last_login(sender, user, **kwargs):
    46     """
    47     A signal receiver which updates the last_login date for
    48     the user logging in.
    49     """
    50     user.last_login = datetime.datetime.now()
    51     user.save()
    52 user_logged_in.connect(update_last_login)
    537
    54 class SiteProfileNotAvailable(Exception):
     8class AuthNotAvailable(Exception):
    559    pass
    5610
    57 class PermissionManager(models.Manager):
    58     def get_by_natural_key(self, codename, app_label, model):
    59         return self.get(
    60             codename=codename,
    61             content_type=ContentType.objects.get_by_natural_key(app_label, model)
    62         )
    63 
    64 class Permission(models.Model):
    65     """The permissions system provides a way to assign permissions to specific users and groups of users.
    66 
    67     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:
    68 
    69         - The "add" permission limits the user's ability to view the "add" form and add an object.
    70         - The "change" permission limits a user's ability to view the change list, view the "change" form and change an object.
    71         - The "delete" permission limits the ability to delete an object.
    72 
    73     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."
    74 
    75     Three basic permissions -- add, change and delete -- are automatically created for each Django model.
    76     """
    77     name = models.CharField(_('name'), max_length=50)
    78     content_type = models.ForeignKey(ContentType)
    79     codename = models.CharField(_('codename'), max_length=100)
    80     objects = PermissionManager()
    81 
    82     class Meta:
    83         verbose_name = _('permission')
    84         verbose_name_plural = _('permissions')
    85         unique_together = (('content_type', 'codename'),)
    86         ordering = ('content_type__app_label', 'content_type__model', 'codename')
    87 
    88     def __unicode__(self):
    89         return u"%s | %s | %s" % (
    90             unicode(self.content_type.app_label),
    91             unicode(self.content_type),
    92             unicode(self.name))
    93 
    94     def natural_key(self):
    95         return (self.codename,) + self.content_type.natural_key()
    96     natural_key.dependencies = ['contenttypes.contenttype']
    97 
    98 class Group(models.Model):
    99     """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.
    100 
    101     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.
    102 
    103     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 e-mail messages.
    104     """
    105     name = models.CharField(_('name'), max_length=80, unique=True)
    106     permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True)
    107 
    108     class Meta:
    109         verbose_name = _('group')
    110         verbose_name_plural = _('groups')
    111 
    112     def __unicode__(self):
    113         return self.name
    114 
    115 class UserManager(models.Manager):
    116     def create_user(self, username, email, password=None):
    117         """
    118         Creates and saves a User with the given username, e-mail and password.
    119         """
    120         now = datetime.datetime.now()
    121 
    122         # Normalize the address by lowercasing the domain part of the email
    123         # address.
    124         try:
    125             email_name, domain_part = email.strip().split('@', 1)
    126         except ValueError:
    127             pass
    128         else:
    129             email = '@'.join([email_name, domain_part.lower()])
    130 
    131         user = self.model(username=username, email=email, is_staff=False,
    132                          is_active=True, is_superuser=False, last_login=now,
    133                          date_joined=now)
    134 
    135         user.set_password(password)
    136         user.save(using=self._db)
    137         return user
    138 
    139     def create_superuser(self, username, email, password):
    140         u = self.create_user(username, email, password)
    141         u.is_staff = True
    142         u.is_active = True
    143         u.is_superuser = True
    144         u.save(using=self._db)
    145         return u
    146 
    147     def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
    148         "Generates a random password with the given length and given allowed_chars"
    149         # Note that default value of allowed_chars does not have "I" or letters
    150         # that look like it -- just to avoid confusion.
    151         from random import choice
    152         return ''.join([choice(allowed_chars) for i in range(length)])
    153 
    154 
    155 # A few helper functions for common logic between User and AnonymousUser.
    156 def _user_get_all_permissions(user, obj):
    157     permissions = set()
    158     anon = user.is_anonymous()
    159     for backend in auth.get_backends():
    160         if not anon or backend.supports_anonymous_user:
    161             if hasattr(backend, "get_all_permissions"):
    162                 if obj is not None:
    163                     if backend.supports_object_permissions:
    164                         permissions.update(
    165                             backend.get_all_permissions(user, obj)
    166                         )
    167                 else:
    168                     permissions.update(backend.get_all_permissions(user))
    169     return permissions
    170 
    171 
    172 def _user_has_perm(user, perm, obj):
    173     anon = user.is_anonymous()
    174     active = user.is_active
    175     for backend in auth.get_backends():
    176         if (not active and not anon and backend.supports_inactive_user) or \
    177                     (not anon or backend.supports_anonymous_user):
    178             if hasattr(backend, "has_perm"):
    179                 if obj is not None:
    180                     if (backend.supports_object_permissions and
    181                         backend.has_perm(user, perm, obj)):
    182                             return True
    183                 else:
    184                     if backend.has_perm(user, perm):
    185                         return True
    186     return False
    187 
    188 
    189 def _user_has_module_perms(user, app_label):
    190     anon = user.is_anonymous()
    191     active = user.is_active
    192     for backend in auth.get_backends():
    193         if (not active and not anon and backend.supports_inactive_user) or \
    194                     (not anon or backend.supports_anonymous_user):
    195             if hasattr(backend, "has_module_perms"):
    196                 if backend.has_module_perms(user, app_label):
    197                     return True
    198     return False
    199 
    200 
    201 class User(models.Model):
    202     """
    203     Users within the Django authentication system are represented by this model.
    204 
    205     Username and password are required. Other fields are optional.
    206     """
    207     username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))
    208     first_name = models.CharField(_('first name'), max_length=60, blank=True)
    209     last_name = models.CharField(_('last name'), max_length=60, blank=True)
    210     email = models.EmailField(_('e-mail address'), max_length=255, blank=True)
    211     password = models.CharField(_('password'), max_length=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
    212     is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
    213     is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts."))
    214     is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
    215     last_login = models.DateTimeField(_('last login'), default=datetime.datetime.now)
    216     date_joined = models.DateTimeField(_('date joined'), default=datetime.datetime.now)
    217     groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True,
    218         help_text=_("In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."))
    219     user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True)
    220     objects = UserManager()
    221 
    222     class Meta:
    223         verbose_name = _('user')
    224         verbose_name_plural = _('users')
    225 
    226     def __unicode__(self):
    227         return self.username
    228 
    229     def get_absolute_url(self):
    230         return "/users/%s/" % urllib.quote(smart_str(self.username))
    231 
    232     def is_anonymous(self):
    233         """
    234         Always returns False. This is a way of comparing User objects to
    235         anonymous users.
    236         """
    237         return False
    238 
    239     def is_authenticated(self):
    240         """
    241         Always return True. This is a way to tell if the user has been
    242         authenticated in templates.
    243         """
    244         return True
    245 
    246     def get_full_name(self):
    247         "Returns the first_name plus the last_name, with a space in between."
    248         full_name = u'%s %s' % (self.first_name, self.last_name)
    249         return full_name.strip()
    250 
    251     def set_password(self, raw_password):
    252         if raw_password is None:
    253             self.set_unusable_password()
    254         else:
    255             import random
    256             algo = 'sha1'
    257             salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
    258             hsh = get_hexdigest(algo, salt, raw_password)
    259             self.password = '%s$%s$%s' % (algo, salt, hsh)
    260 
    261     def check_password(self, raw_password):
    262         """
    263         Returns a boolean of whether the raw_password was correct. Handles
    264         encryption formats behind the scenes.
    265         """
    266         # Backwards-compatibility check. Older passwords won't include the
    267         # algorithm or salt.
    268         if '$' not in self.password:
    269             is_correct = (self.password == get_hexdigest('md5', '', raw_password))
    270             if is_correct:
    271                 # Convert the password to the new, more secure format.
    272                 self.set_password(raw_password)
    273                 self.save()
    274             return is_correct
    275         return check_password(raw_password, self.password)
    276 
    277     def set_unusable_password(self):
    278         # Sets a value that will never be a valid hash
    279         self.password = UNUSABLE_PASSWORD
    280 
    281     def has_usable_password(self):
    282         if self.password is None \
    283             or self.password == UNUSABLE_PASSWORD:
    284             return False
    285         else:
    286             return True
    287 
    288     def get_group_permissions(self, obj=None):
    289         """
    290         Returns a list of permission strings that this user has through
    291         his/her groups. This method queries all available auth backends.
    292         If an object is passed in, only permissions matching this object
    293         are returned.
    294         """
    295         permissions = set()
    296         for backend in auth.get_backends():
    297             if hasattr(backend, "get_group_permissions"):
    298                 if obj is not None:
    299                     if backend.supports_object_permissions:
    300                         permissions.update(
    301                             backend.get_group_permissions(self, obj)
    302                         )
    303                 else:
    304                     permissions.update(backend.get_group_permissions(self))
    305         return permissions
    306 
    307     def get_all_permissions(self, obj=None):
    308         return _user_get_all_permissions(self, obj)
    309 
    310     def has_perm(self, perm, obj=None):
    311         """
    312         Returns True if the user has the specified permission. This method
    313         queries all available auth backends, but returns immediately if any
    314         backend returns True. Thus, a user who has permission from a single
    315         auth backend is assumed to have permission in general. If an object
    316         is provided, permissions for this specific object are checked.
    317         """
    318 
    319         # Active superusers have all permissions.
    320         if self.is_active and self.is_superuser:
    321             return True
    322 
    323         # Otherwise we need to check the backends.
    324         return _user_has_perm(self, perm, obj)
    325 
    326     def has_perms(self, perm_list, obj=None):
    327         """
    328         Returns True if the user has each of the specified permissions.
    329         If object is passed, it checks if the user has all required perms
    330         for this object.
    331         """
    332         for perm in perm_list:
    333             if not self.has_perm(perm, obj):
    334                 return False
    335         return True
    336 
    337     def has_module_perms(self, app_label):
    338         """
    339         Returns True if the user has any permissions in the given app
    340         label. Uses pretty much the same logic as has_perm, above.
    341         """
    342         # Active superusers have all permissions.
    343         if self.is_active and self.is_superuser:
    344             return True
    345 
    346         return _user_has_module_perms(self, app_label)
    347 
    348     def get_and_delete_messages(self):
    349         messages = []
    350         for m in self.message_set.all():
    351             messages.append(m.message)
    352             m.delete()
    353         return messages
    354 
    355     def email_user(self, subject, message, from_email=None):
    356         "Sends an e-mail to this User."
    357         from django.core.mail import send_mail
    358         send_mail(subject, message, from_email, [self.email])
    359 
    360     def get_profile(self):
    361         """
    362         Returns site-specific profile for this user. Raises
    363         SiteProfileNotAvailable if this site does not allow profiles.
    364         """
    365         if not hasattr(self, '_profile_cache'):
    366             from django.conf import settings
    367             if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
    368                 raise SiteProfileNotAvailable('You need to set AUTH_PROFILE_MO'
    369                                               'DULE in your project settings')
    370             try:
    371                 app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
    372             except ValueError:
    373                 raise SiteProfileNotAvailable('app_label and model_name should'
    374                         ' be separated by a dot in the AUTH_PROFILE_MODULE set'
    375                         'ting')
    376 
    377             try:
    378                 model = models.get_model(app_label, model_name)
    379                 if model is None:
    380                     raise SiteProfileNotAvailable('Unable to load the profile '
    381                         'model, check AUTH_PROFILE_MODULE in your project sett'
    382                         'ings')
    383                 self._profile_cache = model._default_manager.using(self._state.db).get(user__id__exact=self.id)
    384                 self._profile_cache.user = self
    385             except (ImportError, ImproperlyConfigured):
    386                 raise SiteProfileNotAvailable
    387         return self._profile_cache
    388 
    389     def _get_message_set(self):
    390         import warnings
    391         warnings.warn('The user messaging API is deprecated. Please update'
    392                       ' your code to use the new messages framework.',
    393                       category=DeprecationWarning)
    394         return self._message_set
    395     message_set = property(_get_message_set)
    396 
    397 class Message(models.Model):
    398     """
    399     The message system is a lightweight way to queue messages for given
    400     users. A message is associated with a User instance (so it is only
    401     applicable for registered users). There's no concept of expiration or
    402     timestamps. Messages are created by the Django admin after successful
    403     actions. For example, "The poll Foo was created successfully." is a
    404     message.
    405     """
    406     user = models.ForeignKey(User, related_name='_message_set')
    407     message = models.TextField(_('message'))
    408 
    409     def __unicode__(self):
    410         return self.message
    411 
    412 class AnonymousUser(object):
    413     id = None
    414     username = ''
    415     is_staff = False
    416     is_active = False
    417     is_superuser = False
    418     _groups = EmptyManager()
    419     _user_permissions = EmptyManager()
    420 
    421     def __init__(self):
    422         pass
    423 
    424     def __unicode__(self):
    425         return 'AnonymousUser'
    426 
    427     def __str__(self):
    428         return unicode(self).encode('utf-8')
    429 
    430     def __eq__(self, other):
    431         return isinstance(other, self.__class__)
    432 
    433     def __ne__(self, other):
    434         return not self.__eq__(other)
    435 
    436     def __hash__(self):
    437         return 1 # instances always return the same hash value
    438 
    439     def save(self):
    440         raise NotImplementedError
    441 
    442     def delete(self):
    443         raise NotImplementedError
    444 
    445     def set_password(self, raw_password):
    446         raise NotImplementedError
    447 
    448     def check_password(self, raw_password):
    449         raise NotImplementedError
    450 
    451     def _get_groups(self):
    452         return self._groups
    453     groups = property(_get_groups)
    454 
    455     def _get_user_permissions(self):
    456         return self._user_permissions
    457     user_permissions = property(_get_user_permissions)
    458 
    459     def get_group_permissions(self, obj=None):
    460         return set()
    461 
    462     def get_all_permissions(self, obj=None):
    463         return _user_get_all_permissions(self, obj=obj)
    464 
    465     def has_perm(self, perm, obj=None):
    466         return _user_has_perm(self, perm, obj=obj)
    467 
    468     def has_perms(self, perm_list, obj=None):
    469         for perm in perm_list:
    470             if not self.has_perm(perm, obj):
    471                 return False
    472         return True
    473 
    474     def has_module_perms(self, module):
    475         return _user_has_module_perms(self, module)
    476 
    477     def get_and_delete_messages(self):
    478         return []
    479 
    480     def is_anonymous(self):
    481         return True
    48211
    483     def is_authenticated(self):
    484         return False
     12if hasattr(settings, 'AUTH_USER_MODULE'):
     13    try:
     14        app_label, model_name = settings.AUTH_USER_MODULE.split('.')
     15    except ValueError:
     16        raise AuthNotAvailable('app_label and model_name should'
     17                ' be separated by a dot in the AUTH_USER_MODULE set'
     18                'ting')
     19
     20    try:
     21        # Grab the AUTH_USER_MODULE path and classname from the settings.
     22        module = __import__(app_label + '.models', {}, {}, [''])
     23        # Store the user model so it is accessible with the standard
     24        # 'from django.contrib.auth.models import User'
     25        User = getattr(module, model_name, None)
     26
     27        if User is None:
     28            raise AuthNotAvailable('Unable to load the user '
     29                'model, check AUTH_USER_MODULE in your project sett'
     30                'ings')
     31    except (ImportError, ImproperlyConfigured):
     32        raise AuthNotAvailable
     33
     34    # Add te User model to the django models cache
     35    # These two lines allow the custom auth_user model to play nicely with syncdb
     36    # and other systems that rely on functions like
     37    # django.db.models.loading.get_model(...)
     38    from django.db.models.loading import cache
     39    cache.register_models('auth', User)
     40
     41    # We need to remove whatever we used as the AUTH_USER_MODUlE from the
     42    # db cache so apps like contenttypes don't think that it's part
     43    # of contrib.auth
     44    del cache.app_models['auth'][User.__name__.lower()]
     45else:
     46    class User(UserTemplate):
     47        class Meta:
     48            verbose_name = _('user')
     49            verbose_name_plural = _('users')
Back to Top