Ticket #3011: #3011-extendable_auth_user.diff

File #3011-extendable_auth_user.diff, 40.0 KB (added by German M. Bravo, 13 years ago)
  • 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..30131e0
    - +  
     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
     14
     15
     16UNUSABLE_PASSWORD = '!' # This will never be a valid hash
     17
     18def 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.")
     36
     37def 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))
     44
     45def 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()
     52user_logged_in.connect(update_last_login)
     53
     54class SiteProfileNotAvailable(Exception):
     55    pass
     56
     57class 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
     64class 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
     98class 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
     115class 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.
     156def _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
     172def _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
     189def _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
     201class UserTemplate(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        abstract = True
     224
     225    def __unicode__(self):
     226        return self.username
     227
     228    def get_absolute_url(self):
     229        return "/users/%s/" % urllib.quote(smart_str(self.username))
     230
     231    def is_anonymous(self):
     232        """
     233        Always returns False. This is a way of comparing User objects to
     234        anonymous users.
     235        """
     236        return False
     237
     238    def is_authenticated(self):
     239        """
     240        Always return True. This is a way to tell if the user has been
     241        authenticated in templates.
     242        """
     243        return True
     244
     245    def get_full_name(self):
     246        "Returns the first_name plus the last_name, with a space in between."
     247        full_name = u'%s %s' % (self.first_name, self.last_name)
     248        return full_name.strip()
     249
     250    def set_password(self, raw_password):
     251        if raw_password is None:
     252            self.set_unusable_password()
     253        else:
     254            import random
     255            algo = 'sha1'
     256            salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
     257            hsh = get_hexdigest(algo, salt, raw_password)
     258            self.password = '%s$%s$%s' % (algo, salt, hsh)
     259
     260    def check_password(self, raw_password):
     261        """
     262        Returns a boolean of whether the raw_password was correct. Handles
     263        encryption formats behind the scenes.
     264        """
     265        # Backwards-compatibility check. Older passwords won't include the
     266        # algorithm or salt.
     267        if '$' not in self.password:
     268            is_correct = (self.password == get_hexdigest('md5', '', raw_password))
     269            if is_correct:
     270                # Convert the password to the new, more secure format.
     271                self.set_password(raw_password)
     272                self.save()
     273            return is_correct
     274        return check_password(raw_password, self.password)
     275
     276    def set_unusable_password(self):
     277        # Sets a value that will never be a valid hash
     278        self.password = UNUSABLE_PASSWORD
     279
     280    def has_usable_password(self):
     281        if self.password is None \
     282            or self.password == UNUSABLE_PASSWORD:
     283            return False
     284        else:
     285            return True
     286
     287    def get_group_permissions(self, obj=None):
     288        """
     289        Returns a list of permission strings that this user has through
     290        his/her groups. This method queries all available auth backends.
     291        If an object is passed in, only permissions matching this object
     292        are returned.
     293        """
     294        permissions = set()
     295        for backend in auth.get_backends():
     296            if hasattr(backend, "get_group_permissions"):
     297                if obj is not None:
     298                    if backend.supports_object_permissions:
     299                        permissions.update(
     300                            backend.get_group_permissions(self, obj)
     301                        )
     302                else:
     303                    permissions.update(backend.get_group_permissions(self))
     304        return permissions
     305
     306    def get_all_permissions(self, obj=None):
     307        return _user_get_all_permissions(self, obj)
     308
     309    def has_perm(self, perm, obj=None):
     310        """
     311        Returns True if the user has the specified permission. This method
     312        queries all available auth backends, but returns immediately if any
     313        backend returns True. Thus, a user who has permission from a single
     314        auth backend is assumed to have permission in general. If an object
     315        is provided, permissions for this specific object are checked.
     316        """
     317
     318        # Active superusers have all permissions.
     319        if self.is_active and self.is_superuser:
     320            return True
     321
     322        # Otherwise we need to check the backends.
     323        return _user_has_perm(self, perm, obj)
     324
     325    def has_perms(self, perm_list, obj=None):
     326        """
     327        Returns True if the user has each of the specified permissions.
     328        If object is passed, it checks if the user has all required perms
     329        for this object.
     330        """
     331        for perm in perm_list:
     332            if not self.has_perm(perm, obj):
     333                return False
     334        return True
     335
     336    def has_module_perms(self, app_label):
     337        """
     338        Returns True if the user has any permissions in the given app
     339        label. Uses pretty much the same logic as has_perm, above.
     340        """
     341        # Active superusers have all permissions.
     342        if self.is_active and self.is_superuser:
     343            return True
     344
     345        return _user_has_module_perms(self, app_label)
     346
     347    def get_and_delete_messages(self):
     348        messages = []
     349        for m in self.message_set.all():
     350            messages.append(m.message)
     351            m.delete()
     352        return messages
     353
     354    def email_user(self, subject, message, from_email=None):
     355        "Sends an e-mail to this User."
     356        from django.core.mail import send_mail
     357        send_mail(subject, message, from_email, [self.email])
     358
     359    def get_profile(self):
     360        """
     361        Returns site-specific profile for this user. Raises
     362        SiteProfileNotAvailable if this site does not allow profiles.
     363        """
     364        if not hasattr(self, '_profile_cache'):
     365            from django.conf import settings
     366            if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
     367                raise SiteProfileNotAvailable('You need to set AUTH_PROFILE_MO'
     368                                              'DULE in your project settings')
     369            try:
     370                app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
     371            except ValueError:
     372                raise SiteProfileNotAvailable('app_label and model_name should'
     373                        ' be separated by a dot in the AUTH_PROFILE_MODULE set'
     374                        'ting')
     375
     376            try:
     377                model = models.get_model(app_label, model_name)
     378                if model is None:
     379                    raise SiteProfileNotAvailable('Unable to load the profile '
     380                        'model, check AUTH_PROFILE_MODULE in your project sett'
     381                        'ings')
     382                self._profile_cache = model._default_manager.using(self._state.db).get(user__id__exact=self.id)
     383                self._profile_cache.user = self
     384            except (ImportError, ImproperlyConfigured):
     385                raise SiteProfileNotAvailable
     386        return self._profile_cache
     387
     388    def _get_message_set(self):
     389        import warnings
     390        warnings.warn('The user messaging API is deprecated. Please update'
     391                      ' your code to use the new messages framework.',
     392                      category=DeprecationWarning)
     393        return self._message_set
     394    message_set = property(_get_message_set)
     395
     396
     397class AnonymousUser(object):
     398    id = None
     399    username = ''
     400    is_staff = False
     401    is_active = False
     402    is_superuser = False
     403    _groups = EmptyManager()
     404    _user_permissions = EmptyManager()
     405
     406    def __init__(self):
     407        pass
     408
     409    def __unicode__(self):
     410        return 'AnonymousUser'
     411
     412    def __str__(self):
     413        return unicode(self).encode('utf-8')
     414
     415    def __eq__(self, other):
     416        return isinstance(other, self.__class__)
     417
     418    def __ne__(self, other):
     419        return not self.__eq__(other)
     420
     421    def __hash__(self):
     422        return 1 # instances always return the same hash value
     423
     424    def save(self):
     425        raise NotImplementedError
     426
     427    def delete(self):
     428        raise NotImplementedError
     429
     430    def set_password(self, raw_password):
     431        raise NotImplementedError
     432
     433    def check_password(self, raw_password):
     434        raise NotImplementedError
     435
     436    def _get_groups(self):
     437        return self._groups
     438    groups = property(_get_groups)
     439
     440    def _get_user_permissions(self):
     441        return self._user_permissions
     442    user_permissions = property(_get_user_permissions)
     443
     444    def get_group_permissions(self, obj=None):
     445        return set()
     446
     447    def get_all_permissions(self, obj=None):
     448        return _user_get_all_permissions(self, obj=obj)
     449
     450    def has_perm(self, perm, obj=None):
     451        return _user_has_perm(self, perm, obj=obj)
     452
     453    def has_perms(self, perm_list, obj=None):
     454        for perm in perm_list:
     455            if not self.has_perm(perm, obj):
     456                return False
     457        return True
     458
     459    def has_module_perms(self, module):
     460        return _user_has_module_perms(self, module)
     461
     462    def get_and_delete_messages(self):
     463        return []
     464
     465    def is_anonymous(self):
     466        return True
     467
     468    def is_authenticated(self):
     469        return False
     470 No newline at end of file
  • django/contrib/auth/models.py

    diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
    index 24195c8..b96ed76 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
     1from django.conf import settings
    72from 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
    123from 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.")
    36 
    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))
    44 
    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)
    53 
    54 class SiteProfileNotAvailable(Exception):
    55     pass
    56 
    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))
    934
    94     def natural_key(self):
    95         return (self.codename,) + self.content_type.natural_key()
    96     natural_key.dependencies = ['contenttypes.contenttype']
     5from django.contrib.auth.base import *
     6
     7if hasattr(settings, 'AUTH_USER_MODULE'):
     8    # Grab the AUTH_USER_MODULE path and classname from the settings.
     9    # auth_user_module_parts[0] = module path
     10    # auth_user_module_parts[1] = class name
     11    auth_user_module_parts = settings.AUTH_USER_MODULE.rsplit('.', 1)
     12    auth_user_module = __import__(auth_user_module_parts[0], {}, {}, [auth_user_module_parts[0]])
     13    # Store the auth_user model so it is accessible with the standard
     14    # 'from django.contrib.auth.models import User'
     15    User = getattr(auth_user_module, auth_user_module_parts[1])
     16
     17    # Add te User model to the django models cache
     18    # These two lines allow the custom auth_user model to play nicely with syncdb
     19    # and other systems that rely on functions like
     20    # django.db.models.loading.get_model(...)
     21    from django.db.models.loading import cache
     22    cache.register_models('auth', User)
     23
     24    # We need to remove whatever we used as the AUTH_USER_MODUlE from the
     25    # db cache so apps like contenttypes don't think that it's part
     26    # of contrib.auth
     27    del cache.app_models['auth'][User.__name__.lower()]
     28else:
     29    class User(UserTemplate):
     30        class Meta:
     31            verbose_name = _('user')
     32            verbose_name_plural = _('users')
    9733
    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)
    39634
    39735class Message(models.Model):
    39836    """
    class Message(models.Model):  
    40846
    40947    def __unicode__(self):
    41048        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
    482 
    483     def is_authenticated(self):
    484         return False
Back to Top