Skip to content

Commit 937ae21

Browse files
matejspMatej Spiller Muys
and
Matej Spiller Muys
authored
Support for specifying client secret hasher (#1498)
Co-authored-by: Matej Spiller Muys <[email protected]>
1 parent e34819a commit 937ae21

File tree

8 files changed

+36
-1
lines changed

8 files changed

+36
-1
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ Ludwig Hähne
8686
Łukasz Skarżyński
8787
Madison Swain-Bowden
8888
Marcus Sonestedt
89+
Matej Spiller Muys
8990
Matias Seniquiel
9091
Michael Howitz
9192
Owen Gong

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
<!--
88
## [unreleased]
99
### Added
10+
* Support for specifying client secret hasher via CLIENT_SECRET_HASHER setting.
1011
### Changed
1112
### Deprecated
1213
### Removed

docs/settings.rst

+4
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ CLIENT_SECRET_GENERATOR_LENGTH
104104
The length of the generated secrets, in characters. If this value is too low,
105105
secrets may become subject to bruteforce guessing.
106106

107+
CLIENT_SECRET_HASHER
108+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109+
The hasher for storing generated secrets. By default library will use the first hasher in PASSWORD_HASHERS.
110+
107111
EXTRA_SERVER_KWARGS
108112
~~~~~~~~~~~~~~~~~~~
109113
A dictionary to be passed to oauthlib's Server class. Three options

oauth2_provider/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def pre_save(self, model_instance, add):
4040
logger.debug(f"{model_instance}: {self.attname} is already hashed with {hasher}.")
4141
except ValueError:
4242
logger.debug(f"{model_instance}: {self.attname} is not hashed; hashing it now.")
43-
hashed_secret = make_password(secret)
43+
hashed_secret = make_password(secret, hasher=oauth2_settings.CLIENT_SECRET_HASHER)
4444
setattr(model_instance, self.attname, hashed_secret)
4545
return hashed_secret
4646
return super().pre_save(model_instance, add)

oauth2_provider/settings.py

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"CLIENT_ID_GENERATOR_CLASS": "oauth2_provider.generators.ClientIdGenerator",
3838
"CLIENT_SECRET_GENERATOR_CLASS": "oauth2_provider.generators.ClientSecretGenerator",
3939
"CLIENT_SECRET_GENERATOR_LENGTH": 128,
40+
"CLIENT_SECRET_HASHER": "default",
4041
"ACCESS_TOKEN_GENERATOR": None,
4142
"REFRESH_TOKEN_GENERATOR": None,
4243
"EXTRA_SERVER_KWARGS": {},

tests/custom_hasher.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from django.contrib.auth.hashers import PBKDF2PasswordHasher
2+
3+
4+
class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher):
5+
"""
6+
A subclass of PBKDF2PasswordHasher that uses less iterations.
7+
"""
8+
9+
algorithm = "fast_pbkdf2"
10+
iterations = 10000

tests/settings.py

+2
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@
8989
"tests",
9090
)
9191

92+
PASSWORD_HASHERS = django.conf.settings.PASSWORD_HASHERS + ["tests.custom_hasher.MyPBKDF2PasswordHasher"]
93+
9294
LOGGING = {
9395
"version": 1,
9496
"disable_existing_loggers": False,

tests/test_models.py

+16
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ def test_hashed_secret(self):
7272
self.assertNotEqual(app.client_secret, CLEARTEXT_SECRET)
7373
self.assertTrue(check_password(CLEARTEXT_SECRET, app.client_secret))
7474

75+
@override_settings(OAUTH2_PROVIDER={"CLIENT_SECRET_HASHER": "fast_pbkdf2"})
76+
def test_hashed_from_settings(self):
77+
app = Application.objects.create(
78+
name="test_app",
79+
redirect_uris="http://localhost http://example.com http://example.org",
80+
user=self.user,
81+
client_type=Application.CLIENT_CONFIDENTIAL,
82+
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
83+
client_secret=CLEARTEXT_SECRET,
84+
hash_client_secret=True,
85+
)
86+
87+
self.assertNotEqual(app.client_secret, CLEARTEXT_SECRET)
88+
self.assertIn("fast_pbkdf2", app.client_secret)
89+
self.assertTrue(check_password(CLEARTEXT_SECRET, app.client_secret))
90+
7591
def test_unhashed_secret(self):
7692
app = Application.objects.create(
7793
name="test_app",

0 commit comments

Comments
 (0)