Projet

Général

Profil

0002-views-improve-handling-of-next_url-for-sp-initiated-.patch

Benjamin Dauvergne, 30 septembre 2022 01:09

Télécharger (4,58 ko)

Voir les différences:

Subject: [PATCH 2/2] views: improve handling of next_url for sp initiated
 logout (#69740)

 mellon/views.py       | 14 +++++++++-----
 tests/test_sso_slo.py | 21 +++++++++++++++++++--
 2 files changed, 28 insertions(+), 7 deletions(-)
mellon/views.py
612 612

  
613 613

  
614 614
class LogoutView(ProfileMixin, LogMixin, View):
615
    def get(self, request, *args, **kwargs):
615
    def get(self, request, *args, next_url=None, **kwargs):
616 616
        if 'SAMLRequest' in request.GET:
617 617
            return self.idp_logout(request, request.META['QUERY_STRING'], 'redirect')
618 618
        elif 'SAMLResponse' in request.GET:
619 619
            return self.sp_logout_response(request)
620 620
        else:
621
            return self.sp_logout_request(request)
621
            return self.sp_logout_request(request, next_url=next_url)
622 622

  
623 623
    def post(self, request, *args, **kwargs):
624 624
        return self.idp_logout(request, force_str(request.body), 'soap')
......
721 721
        else:
722 722
            return HttpResponseRedirect(logout.msgUrl)
723 723

  
724
    def sp_logout_request(self, request):
724
    def sp_logout_request(self, request, next_url=None):
725 725
        '''Launch a logout request to the identity provider'''
726
        next_url = request.GET.get(REDIRECT_FIELD_NAME)
727 726
        referer = request.headers.get('Referer')
727
        if not next_url:
728
            field_next_url = request.GET.get(REDIRECT_FIELD_NAME)
729
            if field_next_url and utils.same_origin(request.build_absolute_uri(), field_next_url):
730
                next_url = field_next_url
731
        next_url = next_url or '/'
728 732
        if not referer or utils.same_origin(request.build_absolute_uri(), referer):
729 733
            if hasattr(request, 'user') and request.user.is_authenticated:
730 734
                logout = None
......
754 758
                    self.log.info('user logged out, SLO request sent to IdP')
755 759
            else:
756 760
                # anonymous user: if next_url is None redirect to referer
757
                return HttpResponseRedirect(next_url or referer)
761
                return HttpResponseRedirect(next_url)
758 762
        else:
759 763
            self.log.warning('logout refused referer %r is not of the same origin', referer)
760 764
        return HttpResponseRedirect(next_url)
tests/test_sso_slo.py
254 254

  
255 255
    # again, user is already logged out
256 256
    response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': '/some/path'})
257
    assert urlparse.urlparse(response['Location']).path == '/some/path'
257
    assert urlparse.urlparse(response['Location']).path == '/'
258 258

  
259 259

  
260 260
def test_sso_slo_next(db, app, idp, caplog, sp_settings):
261 261
    response = app.get(reverse('mellon_login'))
262 262
    url, body, relay_state = idp.process_authn_request_redirect(response['Location'])
263 263
    response = app.post(reverse('mellon_login'), params={'SAMLResponse': body, 'RelayState': relay_state})
264
    response = app.get(reverse('mellon_logout') + '?next=/some/path/')
264
    response = app.get(
265
        reverse('mellon_logout') + '?next=/some/path/', extra_environ={'HTTP_REFERER': '/other/path'}
266
    )
265 267
    assert urlparse.urlparse(response['Location']).path == '/singleLogout'
266 268
    url = idp.process_logout_request_redirect(response.location)
267 269
    response = app.get(url)
268 270
    assert response.location == '/some/path/'
269 271

  
270 272

  
273
def test_sso_slo_forced_next(db, app, idp, caplog, sp_settings, rf):
274
    from mellon.views import logout
275

  
276
    response = app.get(reverse('mellon_login'))
277
    url, body, relay_state = idp.process_authn_request_redirect(response['Location'])
278
    response = app.post(reverse('mellon_login'), params={'SAMLResponse': body, 'RelayState': relay_state})
279

  
280
    request = rf.get('/logout/?next=/some/path/')
281
    request.session = app.session
282
    request.user = mock.Mock()
283
    request.user.is_authenticated = True
284
    response = logout(request, next_url='/other/path/')
285
    assert list(request.session.values()) == ['/other/path/']
286

  
287

  
271 288
def test_sso_idp_slo(db, app, idp, caplog, sp_settings):
272 289
    assert Session.objects.count() == 0
273 290
    assert User.objects.count() == 0
274
-