0005-utils-add-method-to-build-a-session-dump-from-models.patch
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 |
- |