Skip to content

Commit be34163

Browse files
authored
handle oauthlib errors on create token requests (#1210)
Co-authored-by: andrej <[email protected]>
1 parent da459a1 commit be34163

File tree

4 files changed

+104
-7
lines changed

4 files changed

+104
-7
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 requests
3031

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

oauth2_provider/oauth2_backends.py

Lines changed: 8 additions & 6 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-
return uri, 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+
return uri, headers, body, status
161+
except OAuth2Error as exc:
162+
return None, exc.headers, exc.json, exc.status_code
161163

162164
def create_revocation_response(self, request):
163165
"""

tests/test_oauth2_backends.py

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import base64
12
import json
23

34
import pytest
5+
from django.contrib.auth import get_user_model
46
from django.test import RequestFactory, TestCase
7+
from django.utils.timezone import now, timedelta
58

69
from oauth2_provider.backends import get_oauthlib_core
7-
from oauth2_provider.models import redirect_to_uri_allowed
10+
from oauth2_provider.models import get_access_token_model, get_application_model, redirect_to_uri_allowed
811
from oauth2_provider.oauth2_backends import JSONOAuthLibCore, OAuthLibCore
912

1013

@@ -50,6 +53,96 @@ def test_application_json_extract_params(self):
5053
self.assertNotIn("password=123456", body)
5154

5255

56+
UserModel = get_user_model()
57+
ApplicationModel = get_application_model()
58+
AccessTokenModel = get_access_token_model()
59+
60+
61+
@pytest.mark.usefixtures("oauth2_settings")
62+
class TestOAuthLibCoreBackendErrorHandling(TestCase):
63+
def setUp(self):
64+
self.factory = RequestFactory()
65+
self.oauthlib_core = OAuthLibCore()
66+
self.user = UserModel.objects.create_user("john", "[email protected]", "123456")
67+
self.app = ApplicationModel.objects.create(
68+
name="app",
69+
client_id="app_id",
70+
client_secret="app_secret",
71+
client_type=ApplicationModel.CLIENT_CONFIDENTIAL,
72+
authorization_grant_type=ApplicationModel.GRANT_PASSWORD,
73+
user=self.user,
74+
)
75+
76+
def tearDown(self):
77+
self.user.delete()
78+
self.app.delete()
79+
80+
def test_create_token_response_valid(self):
81+
payload = (
82+
"grant_type=password&username=john&password=123456&client_id=app_id&client_secret=app_secret"
83+
)
84+
request = self.factory.post(
85+
"/o/token/",
86+
payload,
87+
content_type="application/x-www-form-urlencoded",
88+
HTTP_AUTHORIZATION="Basic %s" % base64.b64encode(b"john:123456").decode(),
89+
)
90+
91+
uri, headers, body, status = self.oauthlib_core.create_token_response(request)
92+
self.assertEqual(status, 200)
93+
94+
def test_create_token_response_query_params(self):
95+
payload = (
96+
"grant_type=password&username=john&password=123456&client_id=app_id&client_secret=app_secret"
97+
)
98+
request = self.factory.post(
99+
"/o/token/?test=foo",
100+
payload,
101+
content_type="application/x-www-form-urlencoded",
102+
HTTP_AUTHORIZATION="Basic %s" % base64.b64encode(b"john:123456").decode(),
103+
)
104+
uri, headers, body, status = self.oauthlib_core.create_token_response(request)
105+
106+
self.assertEqual(status, 400)
107+
self.assertDictEqual(
108+
json.loads(body),
109+
{"error": "invalid_request", "error_description": "URL query parameters are not allowed"},
110+
)
111+
112+
def test_create_revocation_response_valid(self):
113+
AccessTokenModel.objects.create(
114+
user=self.user, token="tokstr", application=self.app, expires=now() + timedelta(days=365)
115+
)
116+
payload = "client_id=app_id&client_secret=app_secret&token=tokstr"
117+
request = self.factory.post(
118+
"/o/revoke_token/",
119+
payload,
120+
content_type="application/x-www-form-urlencoded",
121+
HTTP_AUTHORIZATION="Basic %s" % base64.b64encode(b"john:123456").decode(),
122+
)
123+
uri, headers, body, status = self.oauthlib_core.create_revocation_response(request)
124+
self.assertEqual(status, 200)
125+
126+
def test_create_revocation_response_query_params(self):
127+
token = AccessTokenModel.objects.create(
128+
user=self.user, token="tokstr", application=self.app, expires=now() + timedelta(days=365)
129+
)
130+
payload = "client_id=app_id&client_secret=app_secret&token=tokstr"
131+
request = self.factory.post(
132+
"/o/revoke_token/?test=foo",
133+
payload,
134+
content_type="application/x-www-form-urlencoded",
135+
HTTP_AUTHORIZATION="Basic %s" % base64.b64encode(b"john:123456").decode(),
136+
)
137+
uri, headers, body, status = self.oauthlib_core.create_revocation_response(request)
138+
self.assertEqual(status, 400)
139+
self.assertDictEqual(
140+
json.loads(body),
141+
{"error": "invalid_request", "error_description": "URL query parameters are not allowed"},
142+
)
143+
token.delete()
144+
145+
53146
class TestCustomOAuthLibCoreBackend(TestCase):
54147
"""
55148
Tests that the public API behaves as expected when we override

0 commit comments

Comments
 (0)