Ticket #3011: 3011.6.diff

File 3011.6.diff, 15.7 KB (added by Michael Richardson <michael@…>, 7 years ago)

Patch against [7832] and added a quick fix so that apps like contenttypes wouldn't think that the imported module was part of contrib.auth.

  • django/conf/global_settings.py

     
    363363
    364364LOGIN_REDIRECT_URL = '/accounts/profile/'
    365365
     366# The class to use as the default AUTH_USER for the authentication system.
     367AUTH_USER_MODULE = 'django.contrib.auth.default_user.DefaultUser'
     368
    366369###########
    367370# TESTING #
    368371###########
  • django/contrib/auth/default_user.py

     
     1from django.db import models
     2from django.core import validators
     3from django.utils.translation import gettext_lazy as _
     4
     5from django.contrib.auth.models import Group, Permission, UserTemplate
     6
     7import datetime
     8
     9
     10class DefaultUserManager(models.Manager):
     11    def create_user(self, username, email, password=None):
     12        "Creates and saves a User with the given username, e-mail and password."
     13        now = datetime.datetime.now()
     14        user = self.model(None, username, '', '', email.strip().lower(), 'placeholder', False, True, False, now, now)
     15        if password:
     16            user.set_password(password)
     17        else:
     18            user.set_unusable_password()
     19        user.save()
     20        return user
     21
     22    def create_superuser(self, username, email, password):
     23        u = self.create_user(username, email, password)
     24        u.is_staff = True
     25        u.is_active = True
     26        u.is_superuser = True
     27        u.save()
     28
     29    def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
     30        "Generates a random password with the given length and given allowed_chars"
     31        # Note that default value of allowed_chars does not have "I" or letters
     32        # that look like it -- just to avoid confusion.
     33        from random import choice
     34        return ''.join([choice(allowed_chars) for i in range(length)])
     35
     36
     37class DefaultUser(UserTemplate):
     38    """Users within the Django authentication system are represented by this model.
     39
     40    Username and password are required. Other fields are optional.
     41    """
     42    username = models.CharField(_('username'), max_length=30, unique=True, validator_list=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."))
     43    first_name = models.CharField(_('first name'), max_length=30, blank=True)
     44    last_name = models.CharField(_('last name'), max_length=30, blank=True)
     45    email = models.EmailField(_('e-mail address'), blank=True)
     46    password = models.CharField(_('password'), max_length=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
     47    is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
     48    is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts."))
     49    is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
     50    last_login = models.DateTimeField(_('last login'), default=datetime.datetime.now)
     51    date_joined = models.DateTimeField(_('date joined'), default=datetime.datetime.now)
     52    groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True,
     53        help_text=_("In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."))
     54    user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True, filter_interface=models.HORIZONTAL)
     55    objects = DefaultUserManager()
     56
     57    class Admin:
     58        fields = (
     59            (None, {'fields': ('username', 'password')}),
     60            (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
     61            (_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
     62            (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
     63            (_('Groups'), {'fields': ('groups',)}),
     64        )
     65        list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
     66        list_filter = ('is_staff', 'is_superuser')
     67        search_fields = ('username', 'first_name', 'last_name', 'email')
     68        ordering = ('username',)
     69
     70    def __unicode__(self):
     71        return self.username
     72
     73    def get_absolute_url(self):
     74        return "/users/%s/" % urllib.quote(smart_str(self.username))
     75
     76    def get_full_name(self):
     77        "Returns the first_name plus the last_name, with a space in between."
     78        full_name = u'%s %s' % (self.first_name, self.last_name)
     79        return full_name.strip()
     80
     81    def set_password(self, raw_password):
     82        import random
     83        algo = 'sha1'
     84        salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
     85        hsh = get_hexdigest(algo, salt, raw_password)
     86        self.password = '%s$%s$%s' % (algo, salt, hsh)
     87
     88    def check_password(self, raw_password):
     89        """
     90        Returns a boolean of whether the raw_password was correct. Handles
     91        encryption formats behind the scenes.
     92        """
     93        # Backwards-compatibility check. Older passwords won't include the
     94        # algorithm or salt.
     95        if '$' not in self.password:
     96            is_correct = (self.password == get_hexdigest('md5', '', raw_password))
     97            if is_correct:
     98                # Convert the password to the new, more secure format.
     99                self.set_password(raw_password)
     100                self.save()
     101            return is_correct
     102        return check_password(raw_password, self.password)
     103
     104    def set_unusable_password(self):
     105        # Sets a value that will never be a valid hash
     106        self.password = UNUSABLE_PASSWORD
     107
     108    def has_usable_password(self):
     109        return self.password != UNUSABLE_PASSWORD
     110
     111    def email_user(self, subject, message, from_email=None):
     112        "Sends an e-mail to this User."
     113        from django.core.mail import send_mail
     114        send_mail(subject, message, from_email, [self.email])
     115 No newline at end of file
  • django/contrib/auth/models.py

     
    66from django.contrib.contenttypes.models import ContentType
    77from django.utils.encoding import smart_str
    88from django.utils.translation import ugettext_lazy as _
     9from django.conf import settings
    910import datetime
    1011import urllib
    1112
     
    104105    def __unicode__(self):
    105106        return self.name
    106107
    107 class UserManager(models.Manager):
    108     def create_user(self, username, email, password=None):
    109         "Creates and saves a User with the given username, e-mail and password."
    110         now = datetime.datetime.now()
    111         user = self.model(None, username, '', '', email.strip().lower(), 'placeholder', False, True, False, now, now)
    112         if password:
    113             user.set_password(password)
    114         else:
    115             user.set_unusable_password()
    116         user.save()
    117         return user
     108class UserTemplate(models.Model):
     109    """ Base class from which all User models inherit.  """
    118110
    119     def create_superuser(self, username, email, password):
    120         u = self.create_user(username, email, password)
    121         u.is_staff = True
    122         u.is_active = True
    123         u.is_superuser = True
    124         u.save()
    125 
    126     def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
    127         "Generates a random password with the given length and given allowed_chars"
    128         # Note that default value of allowed_chars does not have "I" or letters
    129         # that look like it -- just to avoid confusion.
    130         from random import choice
    131         return ''.join([choice(allowed_chars) for i in range(length)])
    132 
    133 class User(models.Model):
    134     """Users within the Django authentication system are represented by this model.
    135 
    136     Username and password are required. Other fields are optional.
    137     """
    138     username = models.CharField(_('username'), max_length=30, unique=True, validator_list=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."))
    139     first_name = models.CharField(_('first name'), max_length=30, blank=True)
    140     last_name = models.CharField(_('last name'), max_length=30, blank=True)
    141     email = models.EmailField(_('e-mail address'), blank=True)
    142     password = models.CharField(_('password'), max_length=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
    143     is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
    144     is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts."))
    145     is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
    146     last_login = models.DateTimeField(_('last login'), default=datetime.datetime.now)
    147     date_joined = models.DateTimeField(_('date joined'), default=datetime.datetime.now)
    148     groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True,
    149         help_text=_("In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."))
    150     user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True, filter_interface=models.HORIZONTAL)
    151     objects = UserManager()
    152 
    153111    class Meta:
    154112        verbose_name = _('user')
    155113        verbose_name_plural = _('users')
    156114
    157     class Admin:
    158         fields = (
    159             (None, {'fields': ('username', 'password')}),
    160             (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
    161             (_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
    162             (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    163             (_('Groups'), {'fields': ('groups',)}),
    164         )
    165         list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
    166         list_filter = ('is_staff', 'is_superuser')
    167         search_fields = ('username', 'first_name', 'last_name', 'email')
    168         ordering = ('username',)
    169 
    170     def __unicode__(self):
    171         return self.username
    172 
    173     def get_absolute_url(self):
    174         return "/users/%s/" % urllib.quote(smart_str(self.username))
    175 
    176115    def is_anonymous(self):
    177116        "Always returns False. This is a way of comparing User objects to anonymous users."
    178117        return False
     
    181120        """Always return True. This is a way to tell if the user has been authenticated in templates.
    182121        """
    183122        return True
    184 
    185     def get_full_name(self):
    186         "Returns the first_name plus the last_name, with a space in between."
    187         full_name = u'%s %s' % (self.first_name, self.last_name)
    188         return full_name.strip()
    189 
    190     def set_password(self, raw_password):
    191         import random
    192         algo = 'sha1'
    193         salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
    194         hsh = get_hexdigest(algo, salt, raw_password)
    195         self.password = '%s$%s$%s' % (algo, salt, hsh)
    196 
    197     def check_password(self, raw_password):
    198         """
    199         Returns a boolean of whether the raw_password was correct. Handles
    200         encryption formats behind the scenes.
    201         """
    202         # Backwards-compatibility check. Older passwords won't include the
    203         # algorithm or salt.
    204         if '$' not in self.password:
    205             is_correct = (self.password == get_hexdigest('md5', '', raw_password))
    206             if is_correct:
    207                 # Convert the password to the new, more secure format.
    208                 self.set_password(raw_password)
    209                 self.save()
    210             return is_correct
    211         return check_password(raw_password, self.password)
    212 
    213     def set_unusable_password(self):
    214         # Sets a value that will never be a valid hash
    215         self.password = UNUSABLE_PASSWORD
    216 
    217     def has_usable_password(self):
    218         return self.password != UNUSABLE_PASSWORD
    219 
     123   
    220124    def get_group_permissions(self):
    221125        """
    222126        Returns a list of permission strings that this user has through
     
    288192            m.delete()
    289193        return messages
    290194
    291     def email_user(self, subject, message, from_email=None):
    292         "Sends an e-mail to this User."
    293         from django.core.mail import send_mail
    294         send_mail(subject, message, from_email, [self.email])
    295 
    296195    def get_profile(self):
    297196        """
    298197        Returns site-specific profile for this user. Raises
     
    310209                raise SiteProfileNotAvailable
    311210        return self._profile_cache
    312211
     212
     213# Grab the AUTH_USER_MODULE path and classname from the settings.
     214# auth_user_module_parts[0] = module path
     215# auth_user_module_parts[1] = class name
     216auth_user_module_parts = settings.AUTH_USER_MODULE.rsplit('.', 1)
     217auth_user_module = __import__(auth_user_module_parts[0], {}, {}, [auth_user_module_parts[0]])
     218# Store the auth_user model so it is accessible with the standard
     219# 'from django.contrib.auth.models import User'
     220User = getattr(auth_user_module, auth_user_module_parts[1])
     221
     222# Add the User model to the django models cache
     223# These two lines allow the custom auth_user model to play nicely with syncdb
     224# and other systems that rely on functions like
     225# django.db.models.loading.get_model(...)
     226from django.db.models.loading import cache
     227cache.register_models('auth', User)
     228
     229# We need to remove whatever we used as the AUTH_USER_MODUlE from the
     230# db cache so apps like contenttypes don't think that it's part
     231# of contrib.auth
     232del cache.app_models['auth'][auth_user_module_parts[1].lower()]
     233
    313234class Message(models.Model):
    314235    """
    315236    The message system is a lightweight way to queue messages for given
  • docs/authentication.txt

     
    11641164the ``auth_permission`` table most of the time.
    11651165
    11661166.. _django/contrib/auth/backends.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py
     1167
     1168Overriding the Default Auth User Module
     1169=======================================
     1170
     1171If the default User model doesn't work for you, you can specify your own through
     1172the AUTH_USER_MODULE variable in settings.py.
     1173
     1174Simply import ``django.contrib.auth.UserTemplate`` and have your user model inherit
     1175from that.  You'll also have to specify your own authentication backend and any
     1176specific manager methods you'll need, such as create_user.
  • docs/settings.txt

     
    249249
    250250.. _documentation on user profile models: ../authentication/#storing-additional-information-about-users
    251251
     252AUTH_USER_MODULE
     253----------------
     254
     255Default: ``'django.contrib.auth.default_user.User'``
     256
     257The user model used by this site.  See the `documentation on user models`_ for details.
     258
     259.. _documentation on user models: ../authentication/#overriding-default-user-model
     260
    252261CACHE_BACKEND
    253262-------------
    254263
Back to Top