From 500a20ad690c52a599ffc3013fe9525dad772cc0 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Mon, 3 Oct 2022 11:17:37 +0200 Subject: [PATCH 3/8] views: allow overriding the default return url after logout (#69740) --- mellon/views.py | 14 +++++++------- tests/test_sso_slo.py | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/mellon/views.py b/mellon/views.py index 04244cd..3388ded 100644 --- a/mellon/views.py +++ b/mellon/views.py @@ -612,13 +612,13 @@ login = transaction.non_atomic_requests(csrf_exempt(LoginView.as_view())) class LogoutView(ProfileMixin, LogMixin, View): - def get(self, request, *args, **kwargs): + def get(self, request, *args, logout_next_url='/', **kwargs): if 'SAMLRequest' in request.GET: return self.idp_logout(request, request.META['QUERY_STRING'], 'redirect') elif 'SAMLResponse' in request.GET: - return self.sp_logout_response(request) + return self.sp_logout_response(request, logout_next_url=logout_next_url) else: - return self.sp_logout_request(request) + return self.sp_logout_request(request, logout_next_url=logout_next_url) def post(self, request, *args, **kwargs): return self.idp_logout(request, force_str(request.body), 'soap') @@ -721,14 +721,14 @@ class LogoutView(ProfileMixin, LogMixin, View): else: return HttpResponseRedirect(logout.msgUrl) - def sp_logout_request(self, request): + def sp_logout_request(self, request, logout_next_url=None): '''Launch a logout request to the identity provider''' referer = request.headers.get('Referer') field_next_url = request.GET.get(REDIRECT_FIELD_NAME) next_url = None if field_next_url and utils.same_origin(request.build_absolute_uri(), field_next_url): next_url = field_next_url - next_url = next_url or '/' + next_url = next_url or logout_next_url if not referer or utils.same_origin(request.build_absolute_uri(), referer): if hasattr(request, 'user') and request.user.is_authenticated: logout = None @@ -763,7 +763,7 @@ class LogoutView(ProfileMixin, LogMixin, View): self.log.warning('logout refused referer %r is not of the same origin', referer) return HttpResponseRedirect(next_url) - def sp_logout_response(self, request, next_url='/'): + def sp_logout_response(self, request, logout_next_url='/'): '''Launch a logout request to the identity provider''' self.profile = logout = utils.create_logout(request) logout.msgRelayState = request.GET.get('RelayState') @@ -778,7 +778,7 @@ class LogoutView(ProfileMixin, LogMixin, View): self.log.warning('partial logout') except lasso.Error as e: self.log.warning('unable to process a logout response: %s', e) - return HttpResponseRedirect(self.get_next_url() or next_url) + return HttpResponseRedirect(self.get_next_url() or logout_next_url) logout = csrf_exempt(LogoutView.as_view()) diff --git a/tests/test_sso_slo.py b/tests/test_sso_slo.py index 62fd99f..e324057 100644 --- a/tests/test_sso_slo.py +++ b/tests/test_sso_slo.py @@ -270,6 +270,32 @@ def test_sso_slo_next(db, app, idp, caplog, sp_settings): assert response.location == '/some/path/' +def test_sso_slo_default_next_url(db, app, idp, caplog, sp_settings, rf): + from mellon.views import logout + + 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}) + + request = rf.get('/logout/') + request.session = app.session + request.user = mock.Mock() + request.user.is_authenticated = True + response = logout(request, logout_next_url='/other/path/') + assert list(request.session.values()) == ['/other/path/'] + + 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}) + + request = rf.get('/logout/?next=/some/path/') + request.session = app.session + request.user = mock.Mock() + request.user.is_authenticated = True + response = logout(request, logout_next_url='/other/path/') + assert list(request.session.values()) == ['/some/path/'] + + def test_sso_idp_slo(db, app, idp, caplog, sp_settings): assert Session.objects.count() == 0 assert User.objects.count() == 0 -- 2.37.2