11import pytest
22from django .contrib .auth import get_user
3- from django .test import TestCase
3+ from django .contrib .auth .models import AnonymousUser
4+ from django .test import RequestFactory , TestCase
45from django .urls import reverse
56
67from oauth2_provider .exceptions import ClientIdMissmatch , InvalidOIDCClientError , InvalidOIDCRedirectURIError
8+ from oauth2_provider .models import get_id_token_model
79from oauth2_provider .oauth2_validators import OAuth2Validator
810from oauth2_provider .settings import oauth2_settings
9- from oauth2_provider .views .oidc import validate_logout_request
11+ from oauth2_provider .views .oidc import _load_id_token , validate_logout_request
1012
1113from . import presets
1214
@@ -165,6 +167,22 @@ def test_get_jwks_info_multiple_rsa_keys(self):
165167 assert response .json () == expected_response
166168
167169
170+ def mock_request ():
171+ """
172+ Dummy request with an AnonymousUser attached.
173+ """
174+ return mock_request_for (AnonymousUser ())
175+
176+
177+ def mock_request_for (user ):
178+ """
179+ Dummy request with the `user` attached.
180+ """
181+ request = RequestFactory ().get ("" )
182+ request .user = user
183+ return request
184+
185+
168186@pytest .mark .django_db
169187@pytest .mark .parametrize ("ALWAYS_PROMPT" , [True , False ])
170188def test_validate_logout_request (oidc_tokens , public_application , other_user , rp_settings , ALWAYS_PROMPT ):
@@ -174,66 +192,72 @@ def test_validate_logout_request(oidc_tokens, public_application, other_user, rp
174192 client_id = application .client_id
175193 id_token = oidc_tokens .id_token
176194 assert validate_logout_request (
177- user = oidc_tokens .user , id_token_hint = None , client_id = None , post_logout_redirect_uri = None
195+ request = mock_request_for (oidc_tokens .user ),
196+ id_token_hint = None ,
197+ client_id = None ,
198+ post_logout_redirect_uri = None ,
178199 ) == (True , (None , None ))
179200 assert validate_logout_request (
180- user = oidc_tokens .user , id_token_hint = None , client_id = client_id , post_logout_redirect_uri = None
201+ request = mock_request_for (oidc_tokens .user ),
202+ id_token_hint = None ,
203+ client_id = client_id ,
204+ post_logout_redirect_uri = None ,
181205 ) == (True , (None , application ))
182206 assert validate_logout_request (
183- user = oidc_tokens .user ,
207+ request = mock_request_for ( oidc_tokens .user ) ,
184208 id_token_hint = None ,
185209 client_id = client_id ,
186210 post_logout_redirect_uri = "http://example.org" ,
187211 ) == (True , ("http://example.org" , application ))
188212 assert validate_logout_request (
189- user = oidc_tokens .user ,
213+ request = mock_request_for ( oidc_tokens .user ) ,
190214 id_token_hint = id_token ,
191215 client_id = None ,
192216 post_logout_redirect_uri = "http://example.org" ,
193217 ) == (ALWAYS_PROMPT , ("http://example.org" , application ))
194218 assert validate_logout_request (
195- user = other_user ,
219+ request = mock_request_for ( other_user ) ,
196220 id_token_hint = id_token ,
197221 client_id = None ,
198222 post_logout_redirect_uri = "http://example.org" ,
199223 ) == (True , ("http://example.org" , application ))
200224 assert validate_logout_request (
201- user = oidc_tokens .user ,
225+ request = mock_request_for ( oidc_tokens .user ) ,
202226 id_token_hint = id_token ,
203227 client_id = client_id ,
204228 post_logout_redirect_uri = "http://example.org" ,
205229 ) == (ALWAYS_PROMPT , ("http://example.org" , application ))
206230 with pytest .raises (ClientIdMissmatch ):
207231 validate_logout_request (
208- user = oidc_tokens .user ,
232+ request = mock_request_for ( oidc_tokens .user ) ,
209233 id_token_hint = id_token ,
210234 client_id = public_application .client_id ,
211235 post_logout_redirect_uri = "http://other.org" ,
212236 )
213237 with pytest .raises (InvalidOIDCClientError ):
214238 validate_logout_request (
215- user = oidc_tokens .user ,
239+ request = mock_request_for ( oidc_tokens .user ) ,
216240 id_token_hint = None ,
217241 client_id = None ,
218242 post_logout_redirect_uri = "http://example.org" ,
219243 )
220244 with pytest .raises (InvalidOIDCRedirectURIError ):
221245 validate_logout_request (
222- user = oidc_tokens .user ,
246+ request = mock_request_for ( oidc_tokens .user ) ,
223247 id_token_hint = None ,
224248 client_id = client_id ,
225249 post_logout_redirect_uri = "example.org" ,
226250 )
227251 with pytest .raises (InvalidOIDCRedirectURIError ):
228252 validate_logout_request (
229- user = oidc_tokens .user ,
253+ request = mock_request_for ( oidc_tokens .user ) ,
230254 id_token_hint = None ,
231255 client_id = client_id ,
232256 post_logout_redirect_uri = "imap://example.org" ,
233257 )
234258 with pytest .raises (InvalidOIDCRedirectURIError ):
235259 validate_logout_request (
236- user = oidc_tokens .user ,
260+ request = mock_request_for ( oidc_tokens .user ) ,
237261 id_token_hint = None ,
238262 client_id = client_id ,
239263 post_logout_redirect_uri = "http://other.org" ,
@@ -354,6 +378,60 @@ def test_rp_initiated_logout_post_allowed(loggend_in_client, oidc_tokens, rp_set
354378 assert not is_logged_in (loggend_in_client )
355379
356380
381+ @pytest .mark .django_db
382+ @pytest .mark .oauth2_settings (presets .OIDC_SETTINGS_RP_LOGOUT )
383+ def test_rp_initiated_logout_expired_tokens_accept (loggend_in_client , application , expired_id_token ):
384+ # Accepting expired (but otherwise valid and signed by us) tokens is enabled. Logout should go through.
385+ rsp = loggend_in_client .get (
386+ reverse ("oauth2_provider:rp-initiated-logout" ),
387+ data = {
388+ "id_token_hint" : expired_id_token ,
389+ "client_id" : application .client_id ,
390+ },
391+ )
392+ assert rsp .status_code == 302
393+ assert not is_logged_in (loggend_in_client )
394+
395+
396+ @pytest .mark .django_db
397+ @pytest .mark .oauth2_settings (presets .OIDC_SETTINGS_RP_LOGOUT_DENY_EXPIRED )
398+ def test_rp_initiated_logout_expired_tokens_deny (loggend_in_client , application , expired_id_token ):
399+ # Expired tokens should not be accepted by default.
400+ rsp = loggend_in_client .get (
401+ reverse ("oauth2_provider:rp-initiated-logout" ),
402+ data = {
403+ "id_token_hint" : expired_id_token ,
404+ "client_id" : application .client_id ,
405+ },
406+ )
407+ assert rsp .status_code == 400
408+ assert is_logged_in (loggend_in_client )
409+
410+
411+ @pytest .mark .django_db
412+ @pytest .mark .oauth2_settings (presets .OIDC_SETTINGS_RP_LOGOUT )
413+ def test_load_id_token_accept_expired (expired_id_token ):
414+ assert isinstance (_load_id_token (mock_request (), expired_id_token ), get_id_token_model ())
415+
416+
417+ @pytest .mark .django_db
418+ @pytest .mark .oauth2_settings (presets .OIDC_SETTINGS_RP_LOGOUT )
419+ def test_load_id_token_wrong_aud (id_token_wrong_aud ):
420+ assert _load_id_token (mock_request (), id_token_wrong_aud ) is None
421+
422+
423+ @pytest .mark .django_db
424+ @pytest .mark .oauth2_settings (presets .OIDC_SETTINGS_RP_LOGOUT )
425+ def test_load_id_token_wrong_iss (id_token_wrong_iss ):
426+ assert _load_id_token (mock_request (), id_token_wrong_iss ) is None
427+
428+
429+ @pytest .mark .django_db
430+ @pytest .mark .oauth2_settings (presets .OIDC_SETTINGS_RP_LOGOUT_DENY_EXPIRED )
431+ def test_load_id_token_deny_expired (expired_id_token ):
432+ assert _load_id_token (mock_request (), expired_id_token ) is None
433+
434+
357435@pytest .mark .django_db
358436@pytest .mark .parametrize ("method" , ["get" , "post" ])
359437def test_userinfo_endpoint (oidc_tokens , client , method ):
0 commit comments