Skip to content

Commit be659ca

Browse files
whytheplatypusjleclanche
authored andcommitted
Return state with authorization denied error
Conforms to RFC6749 section 4.1.2.1: https://tools.ietf.org/html/rfc6749#section-4.1.2.1 REQUIRED if a "state" parameter was present in the client authorization request. The exact value received from the client.
1 parent 9e1f3cb commit be659ca

File tree

2 files changed

+28
-2
lines changed

2 files changed

+28
-2
lines changed

oauth2_provider/oauth2_backends.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ def create_authorization_response(self, request, scopes, credentials, allow):
108108
"""
109109
try:
110110
if not allow:
111-
raise oauth2.AccessDeniedError()
111+
raise oauth2.AccessDeniedError(
112+
state=credentials.get("state", None))
112113

113114
# add current user to credentials. this will be used by OAUTH2_VALIDATOR_CLASS
114115
credentials["user"] = request.user

tests/test_authorization_code.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,26 @@ def test_code_post_auth_deny(self):
333333
response = self.client.post(reverse("oauth2_provider:authorize"), data=form_data)
334334
self.assertEqual(response.status_code, 302)
335335
self.assertIn("error=access_denied", response["Location"])
336+
self.assertIn("state=random_state_string", response["Location"])
337+
338+
def test_code_post_auth_deny_no_state(self):
339+
"""
340+
Test optional state when resource owner deny access
341+
"""
342+
self.client.login(username="test_user", password="123456")
343+
344+
form_data = {
345+
"client_id": self.application.client_id,
346+
"scope": "read write",
347+
"redirect_uri": "http://example.org",
348+
"response_type": "code",
349+
"allow": False,
350+
}
351+
352+
response = self.client.post(reverse("oauth2_provider:authorize"), data=form_data)
353+
self.assertEqual(response.status_code, 302)
354+
self.assertIn("error=access_denied", response["Location"])
355+
self.assertNotIn("state", response["Location"])
336356

337357
def test_code_post_auth_bad_responsetype(self):
338358
"""
@@ -431,6 +451,7 @@ def test_code_post_auth_deny_custom_redirect_uri_scheme(self):
431451
self.assertEqual(response.status_code, 302)
432452
self.assertIn("custom-scheme://example.com?", response["Location"])
433453
self.assertIn("error=access_denied", response["Location"])
454+
self.assertIn("state=random_state_string", response["Location"])
434455

435456
def test_code_post_auth_redirection_uri_with_querystring(self):
436457
"""
@@ -453,6 +474,7 @@ def test_code_post_auth_redirection_uri_with_querystring(self):
453474
self.assertEqual(response.status_code, 302)
454475
self.assertIn("http://example.com?foo=bar", response["Location"])
455476
self.assertIn("code=", response["Location"])
477+
self.assertIn("state=random_state_string", response["Location"])
456478

457479
def test_code_post_auth_failing_redirection_uri_with_querystring(self):
458480
"""
@@ -473,7 +495,10 @@ def test_code_post_auth_failing_redirection_uri_with_querystring(self):
473495

474496
response = self.client.post(reverse("oauth2_provider:authorize"), data=form_data)
475497
self.assertEqual(response.status_code, 302)
476-
self.assertEqual("http://example.com?foo=bar&error=access_denied", response["Location"])
498+
self.assertIn("http://example.com?", response["Location"])
499+
self.assertIn("error=access_denied", response["Location"])
500+
self.assertIn("state=random_state_string", response["Location"])
501+
self.assertIn("foo=bar", response["Location"])
477502

478503
def test_code_post_auth_fails_when_redirect_uri_path_is_invalid(self):
479504
"""

0 commit comments

Comments
 (0)