Skip to content

Commit 5f4bd2d

Browse files
committed
handle oauthlib errors on create token and revoke token requests
1 parent da459a1 commit 5f4bd2d

File tree

4 files changed

+141
-11
lines changed

4 files changed

+141
-11
lines changed

‎AUTHORS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Aleksander Vaskevich
1616
Alessandro De Angelis
1717
Alex Szabó
1818
Allisson Azevedo
19+
Andrej Zbín
1920
Andrew Chen Wang
2021
Anvesh Agarwal
2122
Aristóbulo Meneses

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2727

2828
### Fixed
2929
* Remove upper version bound on Django, to allow upgrading to Django 4.1.1 bugfix release.
30+
* Handle oauthlib errors on create token and revoke token requests
3031

3132
## [2.1.0] 2022-06-19
3233

‎oauth2_provider/oauth2_backends.py‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,14 @@ def create_token_response(self, request):
152152
uri, http_method, body, headers=self._extract_params(request)
153153
extra_credentials=self._get_extra_credentials(request)
154154

155-
headers, body, status=self.server.create_token_response(
156-
uri, http_method, body, headers, extra_credentials
157-
)
158-
uri=headers.get("Location", None)
159-
160-
returnuri, headers, body, status
155+
try:
156+
headers, body, status=self.server.create_token_response(
157+
uri, http_method, body, headers, extra_credentials
158+
)
159+
uri=headers.get("Location", None)
160+
returnuri, headers, body, status
161+
exceptOAuth2Errorasexc:
162+
returnNone, exc.headers, exc.json, exc.status_code
161163

162164
defcreate_revocation_response(self, request):
163165
"""
@@ -168,10 +170,12 @@ def create_revocation_response(self, request):
168170
"""
169171
uri, http_method, body, headers=self._extract_params(request)
170172

171-
headers, body, status=self.server.create_revocation_response(uri, http_method, body, headers)
172-
uri=headers.get("Location", None)
173-
174-
returnuri, headers, body, status
173+
try:
174+
headers, body, status=self.server.create_revocation_response(uri, http_method, body, headers)
175+
uri=headers.get("Location", None)
176+
returnuri, headers, body, status
177+
exceptOAuth2Errorasexc:
178+
returnNone, exc.headers, exc.json, exc.status_code
175179

176180
defcreate_userinfo_response(self, request):
177181
"""

‎tests/test_oauth2_backends.py‎

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
importbase64
12
importjson
23

34
importpytest
5+
fromdjango.contrib.authimportget_user_model
46
fromdjango.testimportRequestFactory, TestCase
7+
fromdjango.utils.timezoneimportnow, timedelta
8+
fromoauthlib.oauth2importOAuth2Error
59

610
fromoauth2_provider.backendsimportget_oauthlib_core
7-
fromoauth2_provider.modelsimportredirect_to_uri_allowed
11+
fromoauth2_provider.modelsimportget_access_token_model, get_application_model, redirect_to_uri_allowed
812
fromoauth2_provider.oauth2_backendsimportJSONOAuthLibCore, OAuthLibCore
913

1014

@@ -50,6 +54,126 @@ def test_application_json_extract_params(self):
5054
self.assertNotIn("password=123456", body)
5155

5256

57+
UserModel=get_user_model()
58+
ApplicationModel=get_application_model()
59+
AccessTokenModel=get_access_token_model()
60+
61+
62+
@pytest.mark.usefixtures("oauth2_settings")
63+
classTestOAuthLibCoreBackendErrorHandling(TestCase):
64+
defsetUp(self):
65+
self.factory=RequestFactory()
66+
self.oauthlib_core=OAuthLibCore()
67+
self.user=UserModel.objects.create_user("john", "[email protected]", "123456")
68+
self.app=ApplicationModel.objects.create(
69+
name="app",
70+
client_id="app_id",
71+
client_secret="app_secret",
72+
client_type=ApplicationModel.CLIENT_CONFIDENTIAL,
73+
authorization_grant_type=ApplicationModel.GRANT_PASSWORD,
74+
user=self.user,
75+
)
76+
77+
deftearDown(self):
78+
self.user.delete()
79+
self.app.delete()
80+
81+
deftest_create_token_response_valid(self):
82+
payload= (
83+
"grant_type=password&username=john&password=123456&client_id=app_id&client_secret=app_secret"
84+
)
85+
request=self.factory.post(
86+
"/o/token/",
87+
payload,
88+
content_type="application/x-www-form-urlencoded",
89+
HTTP_AUTHORIZATION="Basic %s"%base64.b64encode(b"john:123456").decode(),
90+
)
91+
92+
uri, headers, body, status=self.oauthlib_core.create_token_response(request)
93+
self.assertEqual(status, 200)
94+
95+
deftest_create_token_response_raise_exception(self):
96+
payload= (
97+
"grant_type=password&username=john&password=123456&client_id=app_id&client_secret=app_secret"
98+
)
99+
request=self.factory.post(
100+
"/o/token/",
101+
payload,
102+
content_type="application/x-www-form-urlencoded",
103+
HTTP_AUTHORIZATION="Basic %s"%base64.b64encode(b"john:123456").decode(),
104+
)
105+
withmock.patch("oauthlib.oauth2.Server.create_token_response") ascreate_token_response:
106+
create_token_response.side_effect=OAuth2Error("test error description")
107+
uri, headers, body, status=self.oauthlib_core.create_token_response(request)
108+
109+
self.assertEqual(json.loads(body)['error_description'], "test error description")
110+
111+
deftest_create_token_response_query_params(self):
112+
payload= (
113+
"grant_type=password&username=john&password=123456&client_id=app_id&client_secret=app_secret"
114+
)
115+
request=self.factory.post(
116+
"/o/token/?test=foo",
117+
payload,
118+
content_type="application/x-www-form-urlencoded",
119+
HTTP_AUTHORIZATION="Basic %s"%base64.b64encode(b"john:123456").decode(),
120+
)
121+
uri, headers, body, status=self.oauthlib_core.create_token_response(request)
122+
123+
self.assertEqual(status, 400)
124+
self.assertDictEqual(
125+
json.loads(body),
126+
{"error": "invalid_request", "error_description": "URL query parameters are not allowed"},
127+
)
128+
129+
deftest_create_revocation_response_valid(self):
130+
AccessTokenModel.objects.create(
131+
user=self.user, token="tokstr", application=self.app, expires=now() +timedelta(days=365)
132+
)
133+
payload="client_id=app_id&client_secret=app_secret&token=tokstr"
134+
request=self.factory.post(
135+
"/o/revoke_token/",
136+
payload,
137+
content_type="application/x-www-form-urlencoded",
138+
HTTP_AUTHORIZATION="Basic %s"%base64.b64encode(b"john:123456").decode(),
139+
)
140+
uri, headers, body, status=self.oauthlib_core.create_revocation_response(request)
141+
self.assertEqual(status, 200)
142+
143+
deftest_create_revocation_response_raise_exception(self):
144+
payload="client_id=app_id&client_secret=app_secret&token=tokstr"
145+
request=self.factory.post(
146+
"/o/revoke_token/",
147+
payload,
148+
content_type="application/x-www-form-urlencoded",
149+
HTTP_AUTHORIZATION="Basic %s"%base64.b64encode(b"john:123456").decode(),
150+
)
151+
withmock.patch("oauthlib.oauth2.Server.create_revocation_response") ascreate_revocation_response:
152+
create_revocation_response.side_effect=OAuth2Error("test error description")
153+
uri, headers, body, status=self.oauthlib_core.create_revocation_response(request)
154+
155+
self.assertEqual(json.loads(body)['error_description'], "test error description")
156+
157+
deftest_create_revocation_response_query_params(self):
158+
token=AccessTokenModel.objects.create(
159+
user=self.user, token="tokstr", application=self.app, expires=now() +timedelta(days=365)
160+
)
161+
payload="client_id=app_id&client_secret=app_secret&token=tokstr"
162+
request=self.factory.post(
163+
"/o/revoke_token/?test=foo",
164+
payload,
165+
content_type="application/x-www-form-urlencoded",
166+
HTTP_AUTHORIZATION="Basic %s"%base64.b64encode(b"john:123456").decode(),
167+
)
168+
uri, headers, body, status=self.oauthlib_core.create_revocation_response(request)
169+
self.assertEqual(status, 400)
170+
self.assertDictEqual(
171+
json.loads(body),
172+
{"error": "invalid_request", "error_description": "URL query parameters are not allowed"},
173+
)
174+
token.delete()
175+
176+
53177
classTestCustomOAuthLibCoreBackend(TestCase):
54178
"""
55179
Tests that the public API behaves as expected when we override

0 commit comments

Comments
(0)