Skip to content

Commit a34be99

Browse files
Adds the ability to define how to store a user (#1328)
* Update oauth2_validators.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add docs & tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 2ef14c5 commit a34be99

File tree

5 files changed

+33
-3
lines changed

5 files changed

+33
-3
lines changed

‎AUTHORS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Hasan Ramezani
6060
Hiroki Kiyohara
6161
Hossein Shakiba
6262
Islam Kamel
63+
Ivan Lukyanets
6364
Jadiel Teófilo
6465
Jens Timmerman
6566
Jerome Leclanche

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3232
*#1337 Gracefully handle expired or deleted refresh tokens, in `validate_user`.
3333
*#1350 Support Python 3.12 and Django 5.0
3434
*#1249 Add code_challenge_methods_supported property to auto discovery information, per [RFC 8414 section 2](https://www.rfc-editor.org/rfc/rfc8414.html#page-7)
35+
*#1328 Adds the ability to define how to store a user profile
3536

3637

3738
### Fixed

‎docs/oidc.rst‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,17 @@ In the docs below, it assumes that you have mounted the
404404
the URLs accordingly.
405405

406406

407+
Define where to store the profile
408+
=================================
409+
410+
.. py:function:: OAuth2Validator.get_or_create_user_from_content(content)
411+
412+
An optional layer to define where to store the profile in ``UserModel`` or a separate model. For example ``UserOAuth``, where ``user = models.OneToOneField(UserModel)``.
413+
414+
The function is called after checking that the username is present in the content.
415+
416+
:return: An instance of the ``UserModel`` representing the user fetched or created.
417+
407418
ConnectDiscoveryInfoView
408419
~~~~~~~~~~~~~~~~~~~~~~~~
409420

‎oauth2_provider/oauth2_validators.py‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,17 @@ def validate_client_id(self, client_id, request, *args, **kwargs):
333333
defget_default_redirect_uri(self, client_id, request, *args, **kwargs):
334334
returnrequest.client.default_redirect_uri
335335

336+
defget_or_create_user_from_content(self, content):
337+
"""
338+
An optional layer to define where to store the profile in `UserModel` or a separate model. For example `UserOAuth`, where `user = models.OneToOneField(UserModel)` .
339+
340+
The function is called after checking that username is in the content.
341+
342+
Returns an UserModel instance;
343+
"""
344+
user, _=UserModel.objects.get_or_create(**{UserModel.USERNAME_FIELD: content["username"]})
345+
returnuser
346+
336347
def_get_token_from_authentication_server(
337348
self, token, introspection_url, introspection_token, introspection_credentials
338349
):
@@ -383,9 +394,7 @@ def _get_token_from_authentication_server(
383394

384395
if"active"incontentandcontent["active"] isTrue:
385396
if"username"incontent:
386-
user, _created=UserModel.objects.get_or_create(
387-
**{UserModel.USERNAME_FIELD: content["username"]}
388-
)
397+
user=self.get_or_create_user_from_content(content)
389398
else:
390399
user=None
391400

‎tests/test_oauth2_validators.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,14 @@ def test_save_bearer_token__with_new_token__calls_methods_to_create_access_and_r
335335
assertcreate_access_token_mock.call_count==1
336336
assertcreate_refresh_token_mock.call_count==1
337337

338+
deftest_get_or_create_user_from_content(self):
339+
content={"username": "test_user"}
340+
UserModel.objects.filter(username=content["username"]).delete()
341+
user=self.validator.get_or_create_user_from_content(content)
342+
343+
self.assertIsNotNone(user)
344+
self.assertEqual(content["username"], user.username)
345+
338346

339347
classTestOAuth2ValidatorProvidesErrorData(TransactionTestCase):
340348
"""These test cases check that the recommended error codes are returned

0 commit comments

Comments
(0)