Skip to content

Commit 453eda3

Browse files
committed
Add test for session state on authorization view
1 parent f587442 commit 453eda3

File tree

5 files changed

+87
-39
lines changed

5 files changed

+87
-39
lines changed

oauth2_provider/settings.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,7 @@ def import_from_string(val, setting_name):
173173
try:
174174
return import_string(val)
175175
except ImportError as e:
176-
msg = "Could not import %r for setting %r. %s: %s." % (
177-
val,
178-
setting_name,
179-
e.__class__.__name__,
180-
e,
181-
)
176+
msg = "Could not import %r for setting %r. %s: %s." % (val, setting_name, e.__class__.__name__, e)
182177
raise ImportError(msg)
183178

184179

oauth2_provider/urls.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@
1717
management_urlpatterns = [
1818
# Application management views
1919
path("applications/", views.ApplicationList.as_view(), name="list"),
20-
path(
21-
"applications/register/",
22-
views.ApplicationRegistration.as_view(),
23-
name="register",
24-
),
20+
path("applications/register/", views.ApplicationRegistration.as_view(), name="register"),
2521
path("applications/<slug:pk>/", views.ApplicationDetail.as_view(), name="detail"),
2622
path("applications/<slug:pk>/delete/", views.ApplicationDelete.as_view(), name="delete"),
2723
path("applications/<slug:pk>/update/", views.ApplicationUpdate.as_view(), name="update"),

oauth2_provider/views/base.py

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,7 @@ def form_valid(self, form):
137137

138138
try:
139139
uri, headers, body, status = self.create_authorization_response(
140-
request=self.request,
141-
scopes=scopes,
142-
credentials=credentials,
143-
allow=allow,
140+
request=self.request, scopes=scopes, credentials=credentials, allow=allow
144141
)
145142
except OAuthToolkitError as error:
146143
return self.error_response(error, application)
@@ -160,7 +157,7 @@ def form_valid(self, form):
160157
salt = secrets.token_urlsafe(16)
161158
encoded = " ".join(
162159
[
163-
self.client.client_id,
160+
credentials["client_id"],
164161
client_origin,
165162
session_management_state_key(self.request),
166163
salt,
@@ -231,20 +228,15 @@ def get(self, request, *args, **kwargs):
231228
# are already approved.
232229
if application.skip_authorization:
233230
uri, headers, body, status = self.create_authorization_response(
234-
request=self.request,
235-
scopes=" ".join(scopes),
236-
credentials=credentials,
237-
allow=True,
231+
request=self.request, scopes=" ".join(scopes), credentials=credentials, allow=True
238232
)
239233
return self.redirect(uri, application)
240234

241235
elif require_approval == "auto":
242236
tokens = (
243237
get_access_token_model()
244238
.objects.filter(
245-
user=request.user,
246-
application=kwargs["application"],
247-
expires__gt=timezone.now(),
239+
user=request.user, application=kwargs["application"], expires__gt=timezone.now()
248240
)
249241
.all()
250242
)
@@ -253,10 +245,7 @@ def get(self, request, *args, **kwargs):
253245
for token in tokens:
254246
if token.allow_scopes(scopes):
255247
uri, headers, body, status = self.create_authorization_response(
256-
request=self.request,
257-
scopes=" ".join(scopes),
258-
credentials=credentials,
259-
allow=True,
248+
request=self.request, scopes=" ".join(scopes), credentials=credentials, allow=True
260249
)
261250
return self.redirect(uri, application)
262251

tests/presets.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
OIDC_SETTINGS_RP_LOGOUT_DENY_EXPIRED["OIDC_RP_INITIATED_LOGOUT_ACCEPT_EXPIRED_TOKENS"] = False
3838
OIDC_SETTINGS_RP_LOGOUT_KEEP_TOKENS = deepcopy(OIDC_SETTINGS_RP_LOGOUT)
3939
OIDC_SETTINGS_RP_LOGOUT_KEEP_TOKENS["OIDC_RP_INITIATED_LOGOUT_DELETE_TOKENS"] = False
40+
OIDC_SETTINGS_SESSION_MANAGEMENT = deepcopy(OIDC_SETTINGS_RW)
41+
OIDC_SETTINGS_SESSION_MANAGEMENT["OIDC_SESSION_MANAGEMENT_ENABLED"] = True
4042
REST_FRAMEWORK_SCOPES = {
4143
"SCOPES": {
4244
"read": "Read scope",

tests/test_oidc_views.py

Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import pytest
2-
from django.contrib.auth import get_user
2+
from django.contrib.auth import get_user, get_user_model
33
from django.contrib.auth.models import AnonymousUser
44
from django.test import RequestFactory
55
from django.urls import reverse
@@ -12,10 +12,19 @@
1212
InvalidOIDCClientError,
1313
InvalidOIDCRedirectURIError,
1414
)
15-
from oauth2_provider.models import get_access_token_model, get_id_token_model, get_refresh_token_model
15+
from oauth2_provider.models import (
16+
get_access_token_model,
17+
get_application_model,
18+
get_id_token_model,
19+
get_refresh_token_model,
20+
)
1621
from oauth2_provider.oauth2_validators import OAuth2Validator
1722
from oauth2_provider.settings import oauth2_settings
18-
from oauth2_provider.views.oidc import RPInitiatedLogoutView, _load_id_token, _validate_claims
23+
from oauth2_provider.views.oidc import (
24+
RPInitiatedLogoutView,
25+
_load_id_token,
26+
_validate_claims,
27+
)
1928

2029
from . import presets
2130
from .common_testing import OAuth2ProviderTestCase as TestCase
@@ -44,7 +53,10 @@ def test_get_connect_discovery_info(self):
4453
],
4554
"subject_types_supported": ["public"],
4655
"id_token_signing_alg_values_supported": ["RS256", "HS256"],
47-
"token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic"],
56+
"token_endpoint_auth_methods_supported": [
57+
"client_secret_post",
58+
"client_secret_basic",
59+
],
4860
"code_challenge_methods_supported": ["plain", "S256"],
4961
"claims_supported": ["sub"],
5062
}
@@ -71,7 +83,10 @@ def test_get_connect_discovery_info_deprecated(self):
7183
],
7284
"subject_types_supported": ["public"],
7385
"id_token_signing_alg_values_supported": ["RS256", "HS256"],
74-
"token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic"],
86+
"token_endpoint_auth_methods_supported": [
87+
"client_secret_post",
88+
"client_secret_basic",
89+
],
7590
"code_challenge_methods_supported": ["plain", "S256"],
7691
"claims_supported": ["sub"],
7792
}
@@ -98,7 +113,10 @@ def expect_json_response_with_rp_logout(self, base):
98113
],
99114
"subject_types_supported": ["public"],
100115
"id_token_signing_alg_values_supported": ["RS256", "HS256"],
101-
"token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic"],
116+
"token_endpoint_auth_methods_supported": [
117+
"client_secret_post",
118+
"client_secret_basic",
119+
],
102120
"code_challenge_methods_supported": ["plain", "S256"],
103121
"claims_supported": ["sub"],
104122
"end_session_endpoint": f"{base}/logout/",
@@ -132,7 +150,10 @@ def test_get_connect_discovery_info_without_issuer_url(self):
132150
],
133151
"subject_types_supported": ["public"],
134152
"id_token_signing_alg_values_supported": ["RS256", "HS256"],
135-
"token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic"],
153+
"token_endpoint_auth_methods_supported": [
154+
"client_secret_post",
155+
"client_secret_basic",
156+
],
136157
"code_challenge_methods_supported": ["plain", "S256"],
137158
"claims_supported": ["sub"],
138159
}
@@ -206,6 +227,42 @@ def test_get_jwks_info_multiple_rsa_keys(self):
206227
assert response.json() == expected_response
207228

208229

230+
@pytest.mark.usefixtures("oauth2_settings")
231+
@pytest.mark.oauth2_settings(presets.OIDC_SETTINGS_SESSION_MANAGEMENT)
232+
class TestAuthorizationView(TestCase):
233+
def test_session_state_is_present_in_url(self):
234+
User = get_user_model()
235+
Application = get_application_model()
236+
237+
User.objects.create_user("test_user", "[email protected]", "123456")
238+
dev_user = User.objects.create_user("dev_user", "[email protected]", "123456")
239+
240+
application = Application.objects.create(
241+
name="Test Application",
242+
redirect_uris=(
243+
"http://localhost http://example.com http://example.org custom-scheme://example.com"
244+
),
245+
user=dev_user,
246+
client_type=Application.CLIENT_CONFIDENTIAL,
247+
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
248+
client_secret="1234567890qwertyuiop",
249+
)
250+
self.client.login(username="test_user", password="123456")
251+
response = self.client.post(
252+
reverse("oauth2_provider:authorize"),
253+
{
254+
"client_id": application.client_id,
255+
"response_type": "code",
256+
"state": "random_state_string",
257+
"scope": "read write",
258+
"redirect_uri": "http://example.org",
259+
"allow": True,
260+
},
261+
)
262+
self.assertEqual(response.status_code, 302)
263+
self.assertTrue("session_state" in response["Location"])
264+
265+
209266
def mock_request():
210267
"""
211268
Dummy request with an AnonymousUser attached.
@@ -335,7 +392,8 @@ def test_rp_initiated_logout_get(logged_in_client, rp_settings):
335392
@pytest.mark.django_db(databases=retrieve_current_databases())
336393
def test_rp_initiated_logout_get_id_token(logged_in_client, oidc_tokens, rp_settings):
337394
rsp = logged_in_client.get(
338-
reverse("oauth2_provider:rp-initiated-logout"), data={"id_token_hint": oidc_tokens.id_token}
395+
reverse("oauth2_provider:rp-initiated-logout"),
396+
data={"id_token_hint": oidc_tokens.id_token},
339397
)
340398
assert rsp.status_code == 302
341399
assert rsp["Location"] == "http://testserver/"
@@ -347,7 +405,8 @@ def test_rp_initiated_logout_get_revoked_id_token(logged_in_client, oidc_tokens,
347405
validator = oauth2_settings.OAUTH2_VALIDATOR_CLASS()
348406
validator._load_id_token(oidc_tokens.id_token).revoke()
349407
rsp = logged_in_client.get(
350-
reverse("oauth2_provider:rp-initiated-logout"), data={"id_token_hint": oidc_tokens.id_token}
408+
reverse("oauth2_provider:rp-initiated-logout"),
409+
data={"id_token_hint": oidc_tokens.id_token},
351410
)
352411
assert rsp.status_code == 400
353412
assert is_logged_in(logged_in_client)
@@ -357,7 +416,10 @@ def test_rp_initiated_logout_get_revoked_id_token(logged_in_client, oidc_tokens,
357416
def test_rp_initiated_logout_get_id_token_redirect(logged_in_client, oidc_tokens, rp_settings):
358417
rsp = logged_in_client.get(
359418
reverse("oauth2_provider:rp-initiated-logout"),
360-
data={"id_token_hint": oidc_tokens.id_token, "post_logout_redirect_uri": "http://example.org"},
419+
data={
420+
"id_token_hint": oidc_tokens.id_token,
421+
"post_logout_redirect_uri": "http://example.org",
422+
},
361423
)
362424
assert rsp.status_code == 302
363425
assert rsp["Location"] == "http://example.org"
@@ -385,7 +447,10 @@ def test_rp_initiated_logout_get_id_token_missmatch_client_id(
385447
):
386448
rsp = logged_in_client.get(
387449
reverse("oauth2_provider:rp-initiated-logout"),
388-
data={"id_token_hint": oidc_tokens.id_token, "client_id": public_application.client_id},
450+
data={
451+
"id_token_hint": oidc_tokens.id_token,
452+
"client_id": public_application.client_id,
453+
},
389454
)
390455
assert rsp.status_code == 400
391456
assert is_logged_in(logged_in_client)
@@ -427,7 +492,8 @@ def test_rp_initiated_logout_public_client_strict_redirect_client_id(
427492
@pytest.mark.django_db(databases=retrieve_current_databases())
428493
def test_rp_initiated_logout_get_client_id(logged_in_client, oidc_tokens, rp_settings):
429494
rsp = logged_in_client.get(
430-
reverse("oauth2_provider:rp-initiated-logout"), data={"client_id": oidc_tokens.application.client_id}
495+
reverse("oauth2_provider:rp-initiated-logout"),
496+
data={"client_id": oidc_tokens.application.client_id},
431497
)
432498
assert rsp.status_code == 200
433499
assert is_logged_in(logged_in_client)

0 commit comments

Comments
 (0)