diff --git a/mellon/views.py b/mellon/views.py index ce83a75..aa162a4 100644 --- a/mellon/views.py +++ b/mellon/views.py @@ -723,6 +723,7 @@ class LogoutView(ProfileMixin, LogMixin, View): issuer = request.session.get('mellon_session', {}).get('issuer') if issuer: self.profile = logout = utils.create_logout(request) + self.get_relay_state(create=True) try: if 'lasso_session_dump' in request.session: logout.setSessionFromDump(request.session['lasso_session_dump']) @@ -752,6 +753,7 @@ class LogoutView(ProfileMixin, LogMixin, View): def sp_logout_response(self, request): '''Launch a logout request to the identity provider''' self.profile = logout = utils.create_logout(request) + logout.msgRelayState = request.GET.get('RelayState') # the user shouldn't be logged anymore at this point but it may happen # that a concurrent SSO happened in the meantime, so we do another # logout to make sure. diff --git a/tests/test_sso_slo.py b/tests/test_sso_slo.py index 201cca8..196e33a 100644 --- a/tests/test_sso_slo.py +++ b/tests/test_sso_slo.py @@ -213,6 +213,15 @@ class MockIdp: else: logout.processResponseMsg(force_str(url.split('?', 1)[-1])) + def process_logout_request_redirect(self, url): + logout = lasso.Logout(self.server) + logout.setIdentityFromDump(self.identity_dump) + logout.setSessionFromDump(self.session_dump) + logout.processRequestMsg(url.split('?', 1)[1]) + logout.validateRequest() + logout.buildResponseMsg() + return logout.msgUrl + def mock_artifact_resolver(self): @all_requests def f(url, request): @@ -239,11 +248,26 @@ def test_sso_slo(db, app, idp, caplog, sp_settings): assert urlparse.urlparse(response['Location']).path == '/whatever/' response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': '/some/path'}) assert urlparse.urlparse(response['Location']).path == '/singleLogout' + url = idp.process_logout_request_redirect(response.location) + response = app.get(url) + assert response.location == '/' + # again, user is already logged out response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': '/some/path'}) assert urlparse.urlparse(response['Location']).path == '/some/path' +def test_sso_slo_next(db, app, idp, caplog, sp_settings): + response = app.get(reverse('mellon_login')) + url, body, relay_state = idp.process_authn_request_redirect(response['Location']) + response = app.post(reverse('mellon_login'), params={'SAMLResponse': body, 'RelayState': relay_state}) + response = app.get(reverse('mellon_logout') + '?next=/some/path/') + assert urlparse.urlparse(response['Location']).path == '/singleLogout' + url = idp.process_logout_request_redirect(response.location) + response = app.get(url) + assert response.location == '/some/path/' + + def test_sso_idp_slo(db, app, idp, caplog, sp_settings): assert Session.objects.count() == 0 assert User.objects.count() == 0