Projet

Général

Profil

0005-utils-add-method-to-build-a-session-dump-from-models.patch

Benjamin Dauvergne, 05 octobre 2022 12:43

Télécharger (9,4 ko)

Voir les différences:

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(-)
mellon/templates/mellon/session_dump.xml
1
<ns0:Session xmlns:ns0="http://www.entrouvert.org/namespaces/lasso/0.0" xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion" Version="2">
2
    {% for session_info in session_infos %}
3
    <ns0:NidAndSessionIndex AssertionID="" 
4
                            ProviderID="{{ session_info.entity_id }}"
5
                            SessionIndex="{{ session_info.session_index }}">
6
            <ns1:NameID Format="{{ session_info.name_id_format }}"
7
                    {% if session_info.name_id_name_qualifier %}NameQualifier="{{ session_info.name_id_name_qualifier }}"{% endif %}
8
                    {% if session_info.name_id_sp_name_qualifier %}SPNameQualifier="{{ session_info.name_id_sp_name_qualifier }}"{% endif %}
9
                    >{{ session_info.name_id_content }}</ns1:NameID>
10
    </ns0:NidAndSessionIndex>
11
    {% endfor %}
1
<ns0:Session xmlns:ns0="http://www.entrouvert.org/namespaces/lasso/0.0" xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion" Version="2">{% for session_index in session_indexes %}{% with nameid=session_index.saml_identifier %}
2
<ns0:NidAndSessionIndex AssertionID="" ProviderID="{{ nameid.issuer.entity_id }}" SessionIndex="{{ session_index.session_index }}">
3
<ns1:NameID Format="{{ nameid.nid_format }}"{% if nameid.nid_name_qualifier %} NameQualifier="{{ nameid.nid_name_qualifier }}"{% endif %}{% if nameid.nid_sp_name_qualifier %} SPNameQualifier="{{ nameid.nid_sp_name_qualifier }}"{% endif %}{% if nameid.nid_sp_provided_id %} SPProvidedId="{{ nameid.nid_sp_provided_id}}"{% endif %}>{{ nameid.name_id }}</ns1:NameID>
4
</ns0:NidAndSessionIndex>{% endwith %}{% endfor %}
12 5
</ns0:Session>
mellon/utils.py
211 211
    return idp.get(name) or getattr(app_settings, name, default)
212 212

  
213 213

  
214
def make_session_dump(lasso_name_id, indexes):
215
    session_infos = []
216
    name_id = force_str(lasso_name_id.content)
217
    name_id_format = force_str(lasso_name_id.format)
218
    name_qualifier = lasso_name_id.nameQualifier and force_str(lasso_name_id.nameQualifier)
219
    sp_name_qualifier = lasso_name_id.spNameQualifier and force_str(lasso_name_id.spNameQualifier)
220
    for index in indexes:
221
        issuer = index.saml_identifier.issuer.entity_id
222
        session_infos.append(
223
            {
224
                'entity_id': issuer,
225
                'session_index': index.session_index,
226
                'name_id_content': name_id,
227
                'name_id_format': name_id_format,
228
                'name_id_name_qualifier': name_qualifier,
229
                'name_id_sp_name_qualifier': sp_name_qualifier,
230
            }
231
        )
232
    session_dump = render_to_string('mellon/session_dump.xml', {'session_infos': session_infos})
233
    return session_dump
214
def make_session_dump(session_indexes):
215
    return render_to_string('mellon/session_dump.xml', {'session_indexes': session_indexes})
234 216

  
235 217

  
236 218
def create_logout(request):
mellon/views.py
318 318
        else:
319 319
            self.log.warning('no user found for NameID %r', attributes['name_id_content'])
320 320
            return self.render(request, 'mellon/user_not_found.html', {'saml_attributes': attributes})
321
        request.session['lasso_session_dump'] = login.session.dump()
322

  
323 321
        return HttpResponseRedirect(next_url)
324 322

  
325 323
    def render_debug_template(self, request, login, attributes=None):
......
698 696
                indexes = indexes.filter(session_index__in=session_indexes)
699 697

  
700 698
            # lasso has too much state :/
701
            logout.setSessionFromDump(utils.make_session_dump(logout.nameIdentifier, indexes))
699
            logout.setSessionFromDump(utils.make_session_dump(indexes))
702 700

  
703 701
            try:
704 702
                logout.validateRequest()
......
743 741
                        self.profile = logout = utils.create_logout(request)
744 742
                        self.get_relay_state(create=True)
745 743
                        try:
746
                            if 'lasso_session_dump' in request.session:
747
                                logout.setSessionFromDump(request.session['lasso_session_dump'])
748
                            else:
744
                            session_indexes = models.SessionIndex.objects.filter(
745
                                saml_identifier__user=request.user, saml_identifier__issuer__entity_id=issuer
746
                            ).order_by('-id')[:1]
747
                            if not session_indexes:
749 748
                                self.log.error('unable to find lasso session dump')
749
                            else:
750
                                session_dump = utils.make_session_dump(session_indexes)
751
                                logout.setSessionFromDump(session_dump)
750 752
                            logout.initRequest(issuer, lasso.HTTP_METHOD_REDIRECT)
751 753
                            logout.buildRequestMsg()
752 754
                        except lasso.Error as e:
tests/test_sso_slo.py
270 270
    assert response.location == '/some/path/'
271 271

  
272 272

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

  
276 276
    response = app.get(reverse('mellon_login'))
......
279 279

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

  
......
290 289

  
291 290
    request = rf.get('/logout/?next=/some/path/')
292 291
    request.session = app.session
293
    request.user = mock.Mock()
294
    request.user.is_authenticated = True
292
    request.user = django_user_model.objects.get()
295 293
    response = logout(request, logout_next_url='/other/path/')
296 294
    assert list(request.session.values()) == ['/some/path/']
297 295

  
tests/test_utils.py
22 22

  
23 23
from mellon.models import Issuer
24 24
from mellon.models_utils import get_issuer
25
from mellon.utils import create_metadata, flatten_datetime, iso8601_to_datetime
25
from mellon.utils import create_metadata, flatten_datetime, iso8601_to_datetime, make_session_dump
26 26
from mellon.views import check_next_url
27 27

  
28 28

  
......
236 236
    assert issuer3.id == issuer1.id
237 237
    assert issuer3.entity_id == entity_id2
238 238
    assert issuer3.slug == 'idp'
239

  
240

  
241
def test_make_session_dump(db, django_user_model):
242
    from mellon.models import SessionIndex, UserSAMLIdentifier
243

  
244
    user = django_user_model.objects.create(username='user')
245
    issuer = Issuer.objects.create(entity_id='https://idp.example.com/metadata', slug='idp')
246
    saml_identifier = UserSAMLIdentifier.objects.create(
247
        user=user, name_id='1234', issuer=issuer, nid_format=lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT
248
    )
249

  
250
    for i in range(2):
251
        SessionIndex.objects.create(session_index=str(i), saml_identifier=saml_identifier, session_key='abcd')
252

  
253
    assert (
254
        make_session_dump(saml_identifier.sessionindex_set.all())
255
        == '''\
256
<ns0:Session xmlns:ns0="http://www.entrouvert.org/namespaces/lasso/0.0" xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion" Version="2">
257
<ns0:NidAndSessionIndex AssertionID="" ProviderID="https://idp.example.com/metadata" SessionIndex="0">
258
<ns1:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">1234</ns1:NameID>
259
</ns0:NidAndSessionIndex>
260
<ns0:NidAndSessionIndex AssertionID="" ProviderID="https://idp.example.com/metadata" SessionIndex="1">
261
<ns1:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">1234</ns1:NameID>
262
</ns0:NidAndSessionIndex>
263
</ns0:Session>
264
'''
265
    )
239
-