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