From ef5d5d48a90b4d19ec9a5d6f600c9f5b26797d30 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Mon, 3 Oct 2022 16:06:03 +0200 Subject: [PATCH 5/8] utils: add method to build a session dump from models (#69740) Storing the LassoSession dump in the Django session is no longer needed, we can rebuild it from the information in the models. --- mellon/templates/mellon/session_dump.xml | 15 ++++-------- mellon/utils.py | 22 ++---------------- mellon/views.py | 14 +++++++----- tests/test_sso_slo.py | 8 +++---- tests/test_utils.py | 29 +++++++++++++++++++++++- 5 files changed, 45 insertions(+), 43 deletions(-) diff --git a/mellon/templates/mellon/session_dump.xml b/mellon/templates/mellon/session_dump.xml index cbb83b4..a7305e9 100644 --- a/mellon/templates/mellon/session_dump.xml +++ b/mellon/templates/mellon/session_dump.xml @@ -1,12 +1,5 @@ - - {% for session_info in session_infos %} - - {{ session_info.name_id_content }} - - {% endfor %} +{% for session_index in session_indexes %}{% with nameid=session_index.saml_identifier %} + +{{ nameid.name_id }} +{% endwith %}{% endfor %} diff --git a/mellon/utils.py b/mellon/utils.py index 1fd6a3f..04c2caa 100644 --- a/mellon/utils.py +++ b/mellon/utils.py @@ -211,26 +211,8 @@ def get_setting(idp, name, default=None): return idp.get(name) or getattr(app_settings, name, default) -def make_session_dump(lasso_name_id, indexes): - session_infos = [] - name_id = force_str(lasso_name_id.content) - name_id_format = force_str(lasso_name_id.format) - name_qualifier = lasso_name_id.nameQualifier and force_str(lasso_name_id.nameQualifier) - sp_name_qualifier = lasso_name_id.spNameQualifier and force_str(lasso_name_id.spNameQualifier) - for index in indexes: - issuer = index.saml_identifier.issuer.entity_id - session_infos.append( - { - 'entity_id': issuer, - 'session_index': index.session_index, - 'name_id_content': name_id, - 'name_id_format': name_id_format, - 'name_id_name_qualifier': name_qualifier, - 'name_id_sp_name_qualifier': sp_name_qualifier, - } - ) - session_dump = render_to_string('mellon/session_dump.xml', {'session_infos': session_infos}) - return session_dump +def make_session_dump(session_indexes): + return render_to_string('mellon/session_dump.xml', {'session_indexes': session_indexes}) def create_logout(request): diff --git a/mellon/views.py b/mellon/views.py index 7946b9f..550af8c 100644 --- a/mellon/views.py +++ b/mellon/views.py @@ -318,8 +318,6 @@ class LoginView(ProfileMixin, LogMixin, View): else: self.log.warning('no user found for NameID %r', attributes['name_id_content']) return self.render(request, 'mellon/user_not_found.html', {'saml_attributes': attributes}) - request.session['lasso_session_dump'] = login.session.dump() - return HttpResponseRedirect(next_url) def render_debug_template(self, request, login, attributes=None): @@ -698,7 +696,7 @@ class LogoutView(ProfileMixin, LogMixin, View): indexes = indexes.filter(session_index__in=session_indexes) # lasso has too much state :/ - logout.setSessionFromDump(utils.make_session_dump(logout.nameIdentifier, indexes)) + logout.setSessionFromDump(utils.make_session_dump(indexes)) try: logout.validateRequest() @@ -743,10 +741,14 @@ class LogoutView(ProfileMixin, LogMixin, View): 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']) - else: + session_indexes = models.SessionIndex.objects.filter( + saml_identifier__user=request.user, saml_identifier__issuer__entity_id=issuer + ).order_by('-id')[:1] + if not session_indexes: self.log.error('unable to find lasso session dump') + else: + session_dump = utils.make_session_dump(session_indexes) + logout.setSessionFromDump(session_dump) logout.initRequest(issuer, lasso.HTTP_METHOD_REDIRECT) logout.buildRequestMsg() except lasso.Error as e: diff --git a/tests/test_sso_slo.py b/tests/test_sso_slo.py index e324057..e8d947c 100644 --- a/tests/test_sso_slo.py +++ b/tests/test_sso_slo.py @@ -270,7 +270,7 @@ 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): +def test_sso_slo_default_next_url(db, app, idp, caplog, sp_settings, rf, django_user_model): from mellon.views import logout response = app.get(reverse('mellon_login')) @@ -279,8 +279,7 @@ def test_sso_slo_default_next_url(db, app, idp, caplog, sp_settings, rf): request = rf.get('/logout/') request.session = app.session - request.user = mock.Mock() - request.user.is_authenticated = True + request.user = django_user_model.objects.get() response = logout(request, logout_next_url='/other/path/') assert list(request.session.values()) == ['/other/path/'] @@ -290,8 +289,7 @@ def test_sso_slo_default_next_url(db, app, idp, caplog, sp_settings, rf): request = rf.get('/logout/?next=/some/path/') request.session = app.session - request.user = mock.Mock() - request.user.is_authenticated = True + request.user = django_user_model.objects.get() response = logout(request, logout_next_url='/other/path/') assert list(request.session.values()) == ['/some/path/'] diff --git a/tests/test_utils.py b/tests/test_utils.py index 2932d60..ff330da 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -22,7 +22,7 @@ from xml_utils import assert_xml_constraints from mellon.models import Issuer from mellon.models_utils import get_issuer -from mellon.utils import create_metadata, flatten_datetime, iso8601_to_datetime +from mellon.utils import create_metadata, flatten_datetime, iso8601_to_datetime, make_session_dump from mellon.views import check_next_url @@ -236,3 +236,30 @@ def test_get_issuer_entity_id_migration(db, settings, metadata): assert issuer3.id == issuer1.id assert issuer3.entity_id == entity_id2 assert issuer3.slug == 'idp' + + +def test_make_session_dump(db, django_user_model): + from mellon.models import SessionIndex, UserSAMLIdentifier + + user = django_user_model.objects.create(username='user') + issuer = Issuer.objects.create(entity_id='https://idp.example.com/metadata', slug='idp') + saml_identifier = UserSAMLIdentifier.objects.create( + user=user, name_id='1234', issuer=issuer, nid_format=lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT + ) + + for i in range(2): + SessionIndex.objects.create(session_index=str(i), saml_identifier=saml_identifier, session_key='abcd') + + assert ( + make_session_dump(saml_identifier.sessionindex_set.all()) + == '''\ + + +1234 + + +1234 + + +''' + ) -- 2.37.2