Fixed #273 -- BACKWARDS-INCOMPATIBLE CHANGE -- Changed auth.User.password field to add support for other password encryption algorithms. Renamed password_md5 to password and changed field length from 32 to 128. See http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges for upgrade information
git-svn-id: http://code.djangoproject.com/svn/django/trunk@1327 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
f1a8869339
commit
a49fa746cd
|
@ -34,7 +34,7 @@ class User(meta.Model):
|
||||||
first_name = meta.CharField(_('first name'), maxlength=30, blank=True)
|
first_name = meta.CharField(_('first name'), maxlength=30, blank=True)
|
||||||
last_name = meta.CharField(_('last name'), maxlength=30, blank=True)
|
last_name = meta.CharField(_('last name'), maxlength=30, blank=True)
|
||||||
email = meta.EmailField(_('e-mail address'), blank=True)
|
email = meta.EmailField(_('e-mail address'), blank=True)
|
||||||
password_md5 = meta.CharField(_('password'), maxlength=32, help_text=_("Use an MD5 hash -- not the raw password."))
|
password = meta.CharField(_('password'), maxlength=128, help_text=_("Use '[algo]$[salt]$[hexdigest]"))
|
||||||
is_staff = meta.BooleanField(_('staff status'), help_text=_("Designates whether the user can log into this admin site."))
|
is_staff = meta.BooleanField(_('staff status'), help_text=_("Designates whether the user can log into this admin site."))
|
||||||
is_active = meta.BooleanField(_('active'), default=True)
|
is_active = meta.BooleanField(_('active'), default=True)
|
||||||
is_superuser = meta.BooleanField(_('superuser status'))
|
is_superuser = meta.BooleanField(_('superuser status'))
|
||||||
|
@ -53,7 +53,7 @@ class User(meta.Model):
|
||||||
exceptions = ('SiteProfileNotAvailable',)
|
exceptions = ('SiteProfileNotAvailable',)
|
||||||
admin = meta.Admin(
|
admin = meta.Admin(
|
||||||
fields = (
|
fields = (
|
||||||
(None, {'fields': ('username', 'password_md5')}),
|
(None, {'fields': ('username', 'password')}),
|
||||||
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
|
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
|
||||||
(_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
|
(_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
|
||||||
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
||||||
|
@ -78,13 +78,35 @@ class User(meta.Model):
|
||||||
return full_name.strip()
|
return full_name.strip()
|
||||||
|
|
||||||
def set_password(self, raw_password):
|
def set_password(self, raw_password):
|
||||||
import md5
|
import sha, random
|
||||||
self.password_md5 = md5.new(raw_password).hexdigest()
|
algo = 'sha1'
|
||||||
|
salt = sha.new(str(random.random())).hexdigest()[:5]
|
||||||
|
hsh = sha.new(salt+raw_password).hexdigest()
|
||||||
|
self.password = '%s$%s$%s' % (algo, salt, hsh)
|
||||||
|
|
||||||
def check_password(self, raw_password):
|
def check_password(self, raw_password):
|
||||||
"Returns a boolean of whether the raw_password was correct."
|
"""
|
||||||
import md5
|
Returns a boolean of whether the raw_password was correct. Handles
|
||||||
return self.password_md5 == md5.new(raw_password).hexdigest()
|
encryption formats behind the scenes.
|
||||||
|
"""
|
||||||
|
# Backwards-compatibility check. Older passwords won't include the
|
||||||
|
# algorithm or salt.
|
||||||
|
if '$' not in self.password:
|
||||||
|
import md5
|
||||||
|
is_correct = (self.password == md5.new(raw_password).hexdigest())
|
||||||
|
if is_correct:
|
||||||
|
# Convert the password to the new, more secure format.
|
||||||
|
self.set_password(raw_password)
|
||||||
|
self.save()
|
||||||
|
return is_correct
|
||||||
|
algo, salt, hsh = self.password.split('$')
|
||||||
|
if algo == 'md5':
|
||||||
|
import md5
|
||||||
|
return hsh == md5.new(salt+raw_password).hexdigest()
|
||||||
|
elif algo == 'sha1':
|
||||||
|
import sha
|
||||||
|
return hsh == sha.new(salt+raw_password).hexdigest()
|
||||||
|
raise ValueError, "Got unknown password algorithm type in password."
|
||||||
|
|
||||||
def get_group_permissions(self):
|
def get_group_permissions(self):
|
||||||
"Returns a list of permission strings that this user has through his/her groups."
|
"Returns a list of permission strings that this user has through his/her groups."
|
||||||
|
@ -176,10 +198,9 @@ class User(meta.Model):
|
||||||
|
|
||||||
def _module_create_user(username, email, password):
|
def _module_create_user(username, email, password):
|
||||||
"Creates and saves a User with the given username, e-mail and password."
|
"Creates and saves a User with the given username, e-mail and password."
|
||||||
import md5
|
|
||||||
password_md5 = md5.new(password).hexdigest()
|
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
user = User(None, username, '', '', email.strip().lower(), password_md5, False, True, False, now, now)
|
user = User(None, username, '', '', email.strip().lower(), 'placeholder', False, True, False, now, now)
|
||||||
|
user.set_password(password)
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,9 @@ Fields
|
||||||
* ``first_name`` -- Optional. 30 characters or fewer.
|
* ``first_name`` -- Optional. 30 characters or fewer.
|
||||||
* ``last_name`` -- Optional. 30 characters or fewer.
|
* ``last_name`` -- Optional. 30 characters or fewer.
|
||||||
* ``email`` -- Optional. E-mail address.
|
* ``email`` -- Optional. E-mail address.
|
||||||
* ``password_md5`` -- Required. An MD5 hash of the password. (Django
|
* ``password`` -- Required. A hash of, and metadata about, the password.
|
||||||
doesn't store the raw password.) Raw passwords can be arbitrarily long
|
(Django doesn't store the raw password.) Raw passwords can be arbitrarily
|
||||||
and can contain any character.
|
long and can contain any character. See the "Passwords" section below.
|
||||||
* ``is_staff`` -- Boolean. Designates whether this user can access the
|
* ``is_staff`` -- Boolean. Designates whether this user can access the
|
||||||
admin site.
|
admin site.
|
||||||
* ``is_active`` -- Boolean. Designates whether this user can log into the
|
* ``is_active`` -- Boolean. Designates whether this user can log into the
|
||||||
|
@ -167,6 +167,28 @@ Change a password with ``set_password()``::
|
||||||
>>> u.set_password('new password')
|
>>> u.set_password('new password')
|
||||||
>>> u.save()
|
>>> u.save()
|
||||||
|
|
||||||
|
Passwords
|
||||||
|
---------
|
||||||
|
|
||||||
|
**This only applies to the Django development version.** Previous versions,
|
||||||
|
such as Django 0.90, used simple MD5 hashes without password salts.
|
||||||
|
|
||||||
|
The ``password`` field of a ``User`` object is a string in this format::
|
||||||
|
|
||||||
|
hashtype$salt$hash
|
||||||
|
|
||||||
|
That's hashtype, salt and hash, separated by the dollar-sign character.
|
||||||
|
|
||||||
|
Hashtype is either ``sha1`` (default) or ``md5``. Salt is a random string
|
||||||
|
used to salt the raw password to create the hash.
|
||||||
|
|
||||||
|
For example::
|
||||||
|
|
||||||
|
sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4
|
||||||
|
|
||||||
|
The ``User.set_password()`` and ``User.check_password()`` functions handle
|
||||||
|
the setting and checking of these values behind the scenes.
|
||||||
|
|
||||||
Anonymous users
|
Anonymous users
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue