Skip to content

Commit fd2b99b

Browse files
author
Simon Willison
committed
After discussing with Malcolm, added set_unusable_password() and has_usable_password() methods to the User object, plus tests and updated documentation
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5771 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 5b898f3 commit fd2b99b

File tree

3 files changed

+51
-6
lines changed

3 files changed

+51
-6
lines changed

django/contrib/auth/models.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import datetime
88
import urllib
99

10+
UNUSABLE_PASSWORD = '!' # This will never be a valid hash
11+
1012
try:
1113
set
1214
except NameError:
@@ -83,11 +85,14 @@ def __unicode__(self):
8385
return self.name
8486

8587
class UserManager(models.Manager):
86-
def create_user(self, username, email, password):
88+
def create_user(self, username, email, password=None):
8789
"Creates and saves a User with the given username, e-mail and password."
8890
now = datetime.datetime.now()
8991
user = self.model(None, username, '', '', email.strip().lower(), 'placeholder', False, True, False, now, now)
90-
user.set_password(password)
92+
if password:
93+
user.set_password(password)
94+
else:
95+
user.set_unusable_password()
9196
user.save()
9297
return user
9398

@@ -179,6 +184,13 @@ def check_password(self, raw_password):
179184
return is_correct
180185
return check_password(raw_password, self.password)
181186

187+
def set_unusable_password(self):
188+
# Sets a value that will never be a valid hash
189+
self.password = UNUSABLE_PASSWORD
190+
191+
def has_usable_password(self):
192+
return self.password != UNUSABLE_PASSWORD
193+
182194
def get_group_permissions(self):
183195
"Returns a list of permission strings that this user has through his/her groups."
184196
if not hasattr(self, '_group_perm_cache'):
@@ -268,7 +280,8 @@ def get_profile(self):
268280
return self._profile_cache
269281

270282
class Message(models.Model):
271-
"""The message system is a lightweight way to queue messages for given users. A message is associated with a User instance (so it is only applicable for registered users). There's no concept of expiration or timestamps. Messages are created by the Django admin after successful actions. For example, "The poll Foo was created successfully." is a message.
283+
"""
284+
The message system is a lightweight way to queue messages for given users. A message is associated with a User instance (so it is only applicable for registered users). There's no concept of expiration or timestamps. Messages are created by the Django admin after successful actions. For example, "The poll Foo was created successfully." is a message.
272285
"""
273286
user = models.ForeignKey(User)
274287
message = models.TextField(_('message'))

django/contrib/auth/tests.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""
2+
>>> from models import User
3+
>>> u = User.objects.create_user('testuser', 'test@example.com', 'testpw')
4+
>>> u.has_usable_password()
5+
True
6+
>>> u.check_password('bad')
7+
False
8+
>>> u.check_password('testpw')
9+
True
10+
>>> u.set_unusable_password()
11+
>>> u.save()
12+
>>> u.check_password('testpw')
13+
False
14+
>>> u.has_usable_password()
15+
False
16+
>>> u2 = User.objects.create_user('testuser2', 'test2@example.com')
17+
>>> u2.has_usable_password()
18+
False
19+
"""

docs/authentication.txt

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,17 @@ custom methods:
114114
string is the correct password for the user. (This takes care of the
115115
password hashing in making the comparison.)
116116

117+
* ``set_unusable_password()`` -- Marks the user as having no password set.
118+
This isn't the same as having a blank string for a password.
119+
``check_password()`` for this user will never return ``True``. Doesn't
120+
save the ``User`` object.
121+
122+
You may need this if authentication for your application takes place
123+
against an existing external source such as an LDAP directory.
124+
125+
* ``has_usable_password()`` -- Returns ``False`` if
126+
``set_unusable_password()`` has been called for this user.
127+
117128
* ``get_group_permissions()`` -- Returns a list of permission strings that
118129
the user has, through his/her groups.
119130

@@ -152,9 +163,11 @@ Manager functions
152163

153164
The ``User`` model has a custom manager that has the following helper functions:
154165

155-
* ``create_user(username, email, password)`` -- Creates, saves and returns
156-
a ``User``. The ``username``, ``email`` and ``password`` are set as
157-
given, and the ``User`` gets ``is_active=True``.
166+
* ``create_user(username, email, password=None)`` -- Creates, saves and
167+
returns a ``User``. The ``username``, ``email`` and ``password`` are set
168+
as given, and the ``User`` gets ``is_active=True``.
169+
170+
If no password is provided, ``set_unusable_password()`` will be called.
158171

159172
See _`Creating users` for example usage.
160173

0 commit comments

Comments
 (0)