Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django
Commits
f5e9d679
Kaydet (Commit)
f5e9d679
authored
Tem 06, 2015
tarafından
Tim Graham
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Refs #16860 -- Moved password_changed() logic to AbstractBaseUser.
Thanks Carl Meyer for review.
üst
d7848c11
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
98 additions
and
10 deletions
+98
-10
base_user.py
django/contrib/auth/base_user.py
+16
-0
forms.py
django/contrib/auth/forms.py
+0
-2
passwords.txt
docs/topics/auth/passwords.txt
+5
-0
test_forms.py
tests/auth_tests/test_forms.py
+39
-7
test_models.py
tests/auth_tests/test_models.py
+38
-1
No files found.
django/contrib/auth/base_user.py
Dosyayı görüntüle @
f5e9d679
...
@@ -4,6 +4,7 @@ not in INSTALLED_APPS.
...
@@ -4,6 +4,7 @@ not in INSTALLED_APPS.
"""
"""
from
__future__
import
unicode_literals
from
__future__
import
unicode_literals
from
django.contrib.auth
import
password_validation
from
django.contrib.auth.hashers
import
(
from
django.contrib.auth.hashers
import
(
check_password
,
is_password_usable
,
make_password
,
check_password
,
is_password_usable
,
make_password
,
)
)
...
@@ -60,9 +61,21 @@ class AbstractBaseUser(models.Model):
...
@@ -60,9 +61,21 @@ class AbstractBaseUser(models.Model):
"Return the identifying username for this User"
"Return the identifying username for this User"
return
getattr
(
self
,
self
.
USERNAME_FIELD
)
return
getattr
(
self
,
self
.
USERNAME_FIELD
)
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
AbstractBaseUser
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
# Stores the raw password if set_password() is called so that it can
# be passed to password_changed() after the model is saved.
self
.
_password
=
None
def
__str__
(
self
):
def
__str__
(
self
):
return
self
.
get_username
()
return
self
.
get_username
()
def
save
(
self
,
*
args
,
**
kwargs
):
super
(
AbstractBaseUser
,
self
)
.
save
(
*
args
,
**
kwargs
)
if
self
.
_password
is
not
None
:
password_validation
.
password_changed
(
self
.
_password
,
self
)
self
.
_password
=
None
def
natural_key
(
self
):
def
natural_key
(
self
):
return
(
self
.
get_username
(),)
return
(
self
.
get_username
(),)
...
@@ -82,6 +95,7 @@ class AbstractBaseUser(models.Model):
...
@@ -82,6 +95,7 @@ class AbstractBaseUser(models.Model):
def
set_password
(
self
,
raw_password
):
def
set_password
(
self
,
raw_password
):
self
.
password
=
make_password
(
raw_password
)
self
.
password
=
make_password
(
raw_password
)
self
.
_password
=
raw_password
def
check_password
(
self
,
raw_password
):
def
check_password
(
self
,
raw_password
):
"""
"""
...
@@ -90,6 +104,8 @@ class AbstractBaseUser(models.Model):
...
@@ -90,6 +104,8 @@ class AbstractBaseUser(models.Model):
"""
"""
def
setter
(
raw_password
):
def
setter
(
raw_password
):
self
.
set_password
(
raw_password
)
self
.
set_password
(
raw_password
)
# Password hash upgrades shouldn't be considered password changes.
self
.
_password
=
None
self
.
save
(
update_fields
=
[
"password"
])
self
.
save
(
update_fields
=
[
"password"
])
return
check_password
(
raw_password
,
self
.
password
,
setter
)
return
check_password
(
raw_password
,
self
.
password
,
setter
)
...
...
django/contrib/auth/forms.py
Dosyayı görüntüle @
f5e9d679
...
@@ -289,7 +289,6 @@ class SetPasswordForm(forms.Form):
...
@@ -289,7 +289,6 @@ class SetPasswordForm(forms.Form):
def
save
(
self
,
commit
=
True
):
def
save
(
self
,
commit
=
True
):
password
=
self
.
cleaned_data
[
"new_password1"
]
password
=
self
.
cleaned_data
[
"new_password1"
]
self
.
user
.
set_password
(
password
)
self
.
user
.
set_password
(
password
)
password_validation
.
password_changed
(
password
,
self
.
user
)
if
commit
:
if
commit
:
self
.
user
.
save
()
self
.
user
.
save
()
return
self
.
user
return
self
.
user
...
@@ -363,7 +362,6 @@ class AdminPasswordChangeForm(forms.Form):
...
@@ -363,7 +362,6 @@ class AdminPasswordChangeForm(forms.Form):
"""
"""
password
=
self
.
cleaned_data
[
"password1"
]
password
=
self
.
cleaned_data
[
"password1"
]
self
.
user
.
set_password
(
password
)
self
.
user
.
set_password
(
password
)
password_validation
.
password_changed
(
password
,
self
.
user
)
if
commit
:
if
commit
:
self
.
user
.
save
()
self
.
user
.
save
()
return
self
.
user
return
self
.
user
...
...
docs/topics/auth/passwords.txt
Dosyayı görüntüle @
f5e9d679
...
@@ -379,6 +379,11 @@ or if you have API calls that allow passwords to be set, for example.
...
@@ -379,6 +379,11 @@ or if you have API calls that allow passwords to be set, for example.
by validators such as one that prevents password reuse. This should be
by validators such as one that prevents password reuse. This should be
called once the password has been successfully changed.
called once the password has been successfully changed.
For subclasses of :class:`~django.contrib.auth.models.AbstractBaseUser`,
the password field will be marked as "dirty" when calling
:meth:`~django.contrib.auth.models.AbstractBaseUser.set_password` which
triggers a call to ``password_changed()`` after the user is saved.
.. function:: password_validators_help_texts(password_validators=None)
.. function:: password_validators_help_texts(password_validators=None)
Returns a list of the help texts of all validators. These explain the
Returns a list of the help texts of all validators. These explain the
...
...
tests/auth_tests/test_forms.py
Dosyayı görüntüle @
f5e9d679
...
@@ -5,16 +5,16 @@ import re
...
@@ -5,16 +5,16 @@ import re
from
django
import
forms
from
django
import
forms
from
django.contrib.auth.forms
import
(
from
django.contrib.auth.forms
import
(
A
uthenticationForm
,
PasswordChangeForm
,
PasswordReset
Form
,
A
dminPasswordChangeForm
,
AuthenticationForm
,
PasswordChange
Form
,
ReadOnlyPasswordHashField
,
ReadOnlyPasswordHashWidget
,
SetPasswordForm
,
PasswordResetForm
,
ReadOnlyPasswordHashField
,
ReadOnlyPasswordHashWidget
,
UserChangeForm
,
UserCreationForm
,
SetPasswordForm
,
UserChangeForm
,
UserCreationForm
,
)
)
from
django.contrib.auth.models
import
User
from
django.contrib.auth.models
import
User
from
django.contrib.sites.models
import
Site
from
django.contrib.sites.models
import
Site
from
django.core
import
mail
from
django.core
import
mail
from
django.core.mail
import
EmailMultiAlternatives
from
django.core.mail
import
EmailMultiAlternatives
from
django.forms.fields
import
CharField
,
Field
from
django.forms.fields
import
CharField
,
Field
from
django.test
import
SimpleTestCase
,
TestCase
,
override_settings
from
django.test
import
SimpleTestCase
,
TestCase
,
mock
,
override_settings
from
django.utils
import
translation
from
django.utils
import
translation
from
django.utils.encoding
import
force_text
from
django.utils.encoding
import
force_text
from
django.utils.text
import
capfirst
from
django.utils.text
import
capfirst
...
@@ -116,7 +116,8 @@ class UserCreationFormTest(TestDataMixin, TestCase):
...
@@ -116,7 +116,8 @@ class UserCreationFormTest(TestDataMixin, TestCase):
self
.
assertEqual
(
form
[
'password1'
]
.
errors
,
required_error
)
self
.
assertEqual
(
form
[
'password1'
]
.
errors
,
required_error
)
self
.
assertEqual
(
form
[
'password2'
]
.
errors
,
[])
self
.
assertEqual
(
form
[
'password2'
]
.
errors
,
[])
def
test_success
(
self
):
@mock.patch
(
'django.contrib.auth.password_validation.password_changed'
)
def
test_success
(
self
,
password_changed
):
# The success case.
# The success case.
data
=
{
data
=
{
'username'
:
'jsmith@example.com'
,
'username'
:
'jsmith@example.com'
,
...
@@ -125,7 +126,10 @@ class UserCreationFormTest(TestDataMixin, TestCase):
...
@@ -125,7 +126,10 @@ class UserCreationFormTest(TestDataMixin, TestCase):
}
}
form
=
UserCreationForm
(
data
)
form
=
UserCreationForm
(
data
)
self
.
assertTrue
(
form
.
is_valid
())
self
.
assertTrue
(
form
.
is_valid
())
form
.
save
(
commit
=
False
)
self
.
assertEqual
(
password_changed
.
call_count
,
0
)
u
=
form
.
save
()
u
=
form
.
save
()
self
.
assertEqual
(
password_changed
.
call_count
,
1
)
self
.
assertEqual
(
repr
(
u
),
'<User: jsmith@example.com>'
)
self
.
assertEqual
(
repr
(
u
),
'<User: jsmith@example.com>'
)
...
@@ -254,7 +258,8 @@ class SetPasswordFormTest(TestDataMixin, TestCase):
...
@@ -254,7 +258,8 @@ class SetPasswordFormTest(TestDataMixin, TestCase):
self
.
assertEqual
(
form
[
"new_password2"
]
.
errors
,
self
.
assertEqual
(
form
[
"new_password2"
]
.
errors
,
[
force_text
(
form
.
error_messages
[
'password_mismatch'
])])
[
force_text
(
form
.
error_messages
[
'password_mismatch'
])])
def
test_success
(
self
):
@mock.patch
(
'django.contrib.auth.password_validation.password_changed'
)
def
test_success
(
self
,
password_changed
):
user
=
User
.
objects
.
get
(
username
=
'testclient'
)
user
=
User
.
objects
.
get
(
username
=
'testclient'
)
data
=
{
data
=
{
'new_password1'
:
'abc123'
,
'new_password1'
:
'abc123'
,
...
@@ -262,6 +267,10 @@ class SetPasswordFormTest(TestDataMixin, TestCase):
...
@@ -262,6 +267,10 @@ class SetPasswordFormTest(TestDataMixin, TestCase):
}
}
form
=
SetPasswordForm
(
user
,
data
)
form
=
SetPasswordForm
(
user
,
data
)
self
.
assertTrue
(
form
.
is_valid
())
self
.
assertTrue
(
form
.
is_valid
())
form
.
save
(
commit
=
False
)
self
.
assertEqual
(
password_changed
.
call_count
,
0
)
form
.
save
()
self
.
assertEqual
(
password_changed
.
call_count
,
1
)
@override_settings
(
AUTH_PASSWORD_VALIDATORS
=
[
@override_settings
(
AUTH_PASSWORD_VALIDATORS
=
[
{
'NAME'
:
'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'
},
{
'NAME'
:
'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'
},
...
@@ -313,7 +322,8 @@ class PasswordChangeFormTest(TestDataMixin, TestCase):
...
@@ -313,7 +322,8 @@ class PasswordChangeFormTest(TestDataMixin, TestCase):
self
.
assertEqual
(
form
[
"new_password2"
]
.
errors
,
self
.
assertEqual
(
form
[
"new_password2"
]
.
errors
,
[
force_text
(
form
.
error_messages
[
'password_mismatch'
])])
[
force_text
(
form
.
error_messages
[
'password_mismatch'
])])
def
test_success
(
self
):
@mock.patch
(
'django.contrib.auth.password_validation.password_changed'
)
def
test_success
(
self
,
password_changed
):
# The success case.
# The success case.
user
=
User
.
objects
.
get
(
username
=
'testclient'
)
user
=
User
.
objects
.
get
(
username
=
'testclient'
)
data
=
{
data
=
{
...
@@ -323,6 +333,10 @@ class PasswordChangeFormTest(TestDataMixin, TestCase):
...
@@ -323,6 +333,10 @@ class PasswordChangeFormTest(TestDataMixin, TestCase):
}
}
form
=
PasswordChangeForm
(
user
,
data
)
form
=
PasswordChangeForm
(
user
,
data
)
self
.
assertTrue
(
form
.
is_valid
())
self
.
assertTrue
(
form
.
is_valid
())
form
.
save
(
commit
=
False
)
self
.
assertEqual
(
password_changed
.
call_count
,
0
)
form
.
save
()
self
.
assertEqual
(
password_changed
.
call_count
,
1
)
def
test_field_order
(
self
):
def
test_field_order
(
self
):
# Regression test - check the order of fields:
# Regression test - check the order of fields:
...
@@ -586,3 +600,21 @@ class ReadOnlyPasswordHashTest(SimpleTestCase):
...
@@ -586,3 +600,21 @@ class ReadOnlyPasswordHashTest(SimpleTestCase):
def
test_readonly_field_has_changed
(
self
):
def
test_readonly_field_has_changed
(
self
):
field
=
ReadOnlyPasswordHashField
()
field
=
ReadOnlyPasswordHashField
()
self
.
assertFalse
(
field
.
has_changed
(
'aaa'
,
'bbb'
))
self
.
assertFalse
(
field
.
has_changed
(
'aaa'
,
'bbb'
))
@override_settings
(
USE_TZ
=
False
,
PASSWORD_HASHERS
=
[
'django.contrib.auth.hashers.SHA1PasswordHasher'
])
class
AdminPasswordChangeFormTest
(
TestDataMixin
,
TestCase
):
@mock.patch
(
'django.contrib.auth.password_validation.password_changed'
)
def
test_success
(
self
,
password_changed
):
user
=
User
.
objects
.
get
(
username
=
'testclient'
)
data
=
{
'password1'
:
'test123'
,
'password2'
:
'test123'
,
}
form
=
AdminPasswordChangeForm
(
user
,
data
)
self
.
assertTrue
(
form
.
is_valid
())
form
.
save
(
commit
=
False
)
self
.
assertEqual
(
password_changed
.
call_count
,
0
)
form
.
save
()
self
.
assertEqual
(
password_changed
.
call_count
,
1
)
tests/auth_tests/test_models.py
Dosyayı görüntüle @
f5e9d679
import
datetime
import
datetime
from
django.conf.global_settings
import
PASSWORD_HASHERS
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth.hashers
import
get_hasher
from
django.contrib.auth.models
import
(
from
django.contrib.auth.models
import
(
AbstractUser
,
Group
,
Permission
,
User
,
UserManager
,
AbstractUser
,
Group
,
Permission
,
User
,
UserManager
,
)
)
from
django.contrib.contenttypes.models
import
ContentType
from
django.contrib.contenttypes.models
import
ContentType
from
django.core
import
mail
from
django.core
import
mail
from
django.db.models.signals
import
post_save
from
django.db.models.signals
import
post_save
from
django.test
import
TestCase
,
override_settings
from
django.test
import
TestCase
,
mock
,
override_settings
@override_settings
(
USE_TZ
=
False
)
@override_settings
(
USE_TZ
=
False
)
...
@@ -216,6 +218,41 @@ class AbstractUserTestCase(TestCase):
...
@@ -216,6 +218,41 @@ class AbstractUserTestCase(TestCase):
user2
=
User
.
objects
.
create_user
(
username
=
'user2'
)
user2
=
User
.
objects
.
create_user
(
username
=
'user2'
)
self
.
assertIsNone
(
user2
.
last_login
)
self
.
assertIsNone
(
user2
.
last_login
)
def
test_user_double_save
(
self
):
"""
Calling user.save() twice should trigger password_changed() once.
"""
user
=
User
.
objects
.
create_user
(
username
=
'user'
,
password
=
'foo'
)
user
.
set_password
(
'bar'
)
with
mock
.
patch
(
'django.contrib.auth.password_validation.password_changed'
)
as
pw_changed
:
user
.
save
()
self
.
assertEqual
(
pw_changed
.
call_count
,
1
)
user
.
save
()
self
.
assertEqual
(
pw_changed
.
call_count
,
1
)
@override_settings
(
PASSWORD_HASHERS
=
PASSWORD_HASHERS
)
def
test_check_password_upgrade
(
self
):
"""
password_changed() shouldn't be called if User.check_password()
triggers a hash iteration upgrade.
"""
user
=
User
.
objects
.
create_user
(
username
=
'user'
,
password
=
'foo'
)
initial_password
=
user
.
password
self
.
assertTrue
(
user
.
check_password
(
'foo'
))
hasher
=
get_hasher
(
'default'
)
self
.
assertEqual
(
'pbkdf2_sha256'
,
hasher
.
algorithm
)
old_iterations
=
hasher
.
iterations
try
:
# Upgrade the password iterations
hasher
.
iterations
=
old_iterations
+
1
with
mock
.
patch
(
'django.contrib.auth.password_validation.password_changed'
)
as
pw_changed
:
user
.
check_password
(
'foo'
)
self
.
assertEqual
(
pw_changed
.
call_count
,
0
)
self
.
assertNotEqual
(
initial_password
,
user
.
password
)
finally
:
hasher
.
iterations
=
old_iterations
class
IsActiveTestCase
(
TestCase
):
class
IsActiveTestCase
(
TestCase
):
"""
"""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment