0001-Modify-federation-storage-so-that-we-can-store-feder.patch
src/authentic2/idp/saml/saml2_endpoints.py | ||
---|---|---|
61 | 61 |
AUTHENTIC_STATUS_CODE_MISSING_NAMEID, \ |
62 | 62 |
AUTHENTIC_STATUS_CODE_MISSING_SESSION_INDEX, \ |
63 | 63 |
AUTHENTIC_STATUS_CODE_UNKNOWN_SESSION, \ |
64 | 64 |
AUTHENTIC_STATUS_CODE_INTERNAL_SERVER_ERROR, \ |
65 | 65 |
AUTHENTIC_STATUS_CODE_UNAUTHORIZED, \ |
66 | 66 |
send_soap_request, get_saml2_query_request, \ |
67 | 67 |
get_saml2_request_message_async_binding, create_saml2_server, \ |
68 | 68 |
get_saml2_metadata, get_sp_options_policy, \ |
69 |
get_entity_id |
|
69 |
get_entity_id, AUTHENTIC_SAME_ID_SENTINEL
|
|
70 | 70 |
import authentic2.saml.saml2utils as saml2utils |
71 | 71 |
from common import kill_django_sessions |
72 | 72 |
from authentic2.constants import NONCE_FIELD_NAME |
73 | 73 | |
74 | 74 |
from authentic2.idp import signals as idp_signals |
75 | 75 |
# from authentic2.idp.models import * |
76 | 76 | |
77 | 77 |
from authentic2.utils import (make_url, get_backends as get_idp_backends, |
... | ... | |
277 | 277 |
logger.debug("assertion after processing " |
278 | 278 |
"%s" % assertion.dump()) |
279 | 279 | |
280 | 280 | |
281 | 281 |
def build_assertion(request, login, nid_format='transient', attributes=None): |
282 | 282 |
"""After a successfully validated authentication request, build an |
283 | 283 |
authentication assertion |
284 | 284 |
""" |
285 |
entity_id = get_entity_id(request, reverse(metadata)) |
|
285 | 286 |
now = datetime.datetime.utcnow() |
286 | 287 |
logger.info("building assertion at %s" % str(now)) |
287 | 288 |
logger.debug('named Id format is %s' % nid_format) |
288 | 289 |
# 1 minute ago |
289 | 290 |
notBefore = now - datetime.timedelta(0, app_settings.SECONDS_TOLERANCE) |
290 | 291 |
# 1 minute in the future |
291 | 292 |
notOnOrAfter = now + datetime.timedelta(0, app_settings.SECONDS_TOLERANCE) |
292 | 293 |
ssl = 'HTTPS' in request.environ |
... | ... | |
339 | 340 |
logger.debug("fill assertion") |
340 | 341 |
fill_assertion(request, login.request, assertion, login.remoteProviderId, |
341 | 342 |
nid_format) |
342 | 343 |
# Save federation and new session |
343 | 344 |
if nid_format == 'persistent': |
344 | 345 |
logger.debug("nameID persistent, get or create " |
345 | 346 |
"federation") |
346 | 347 |
kwargs = nameid2kwargs(login.assertion.subject.nameID) |
348 |
# if qualifiers can be inferred from providers entityID replace them by |
|
349 |
# placeholders |
|
350 |
if kwargs.get('name_id_qualifier') == entity_id: |
|
351 |
kwargs['name_id_qualifier'] = AUTHENTIC_SAME_ID_SENTINEL |
|
352 |
if kwargs.get('name_id_sp_name_qualifier') == login.remoteProviderId: |
|
353 |
kwargs['name_id_sp_name_qualifier'] = AUTHENTIC_SAME_ID_SENTINEL |
|
347 | 354 |
service_provider = LibertyServiceProvider.objects \ |
348 | 355 |
.get(liberty_provider__entity_id=login.remoteProviderId) |
349 | 356 |
federation, new = LibertyFederation.objects.get_or_create( |
350 | 357 |
sp=service_provider, |
351 | 358 |
user=request.user, **kwargs) |
352 | 359 |
if new: |
353 | 360 |
logger.info("nameID persistent, new federation") |
354 | 361 |
federation.save() |
src/authentic2/saml/common.py | ||
---|---|---|
25 | 25 |
LIBERTY_SESSION_DUMP_KIND_IDP |
26 | 26 |
from authentic2.saml import models |
27 | 27 |
from authentic2.saml import saml2utils |
28 | 28 | |
29 | 29 |
from authentic2.http_utils import get_url |
30 | 30 |
from .. import nonce |
31 | 31 | |
32 | 32 |
AUTHENTIC_STATUS_CODE_NS = "http://authentic.entrouvert.org/status_code/" |
33 |
AUTHENTIC_SAME_ID_SENTINEL = 'urn:authentic.entrouvert.org:same-as-provider-entity-id' |
|
33 | 34 |
AUTHENTIC_STATUS_CODE_UNKNOWN_PROVIDER = AUTHENTIC_STATUS_CODE_NS + \ |
34 | 35 |
"UnknownProvider" |
35 | 36 |
AUTHENTIC_STATUS_CODE_MISSING_NAMEID= AUTHENTIC_STATUS_CODE_NS + \ |
36 | 37 |
"MissingNameID" |
37 | 38 |
AUTHENTIC_STATUS_CODE_MISSING_SESSION_INDEX = AUTHENTIC_STATUS_CODE_NS + \ |
38 | 39 |
"MissingSessionIndex" |
39 | 40 |
AUTHENTIC_STATUS_CODE_UNKNOWN_SESSION = AUTHENTIC_STATUS_CODE_NS + \ |
40 | 41 |
"UnknownSession" |
... | ... | |
229 | 230 |
</lasso:Federation> |
230 | 231 |
''' |
231 | 232 |
END_IDENTITY_DUMP = '''</Identity>''' |
232 | 233 | |
233 | 234 | |
234 | 235 |
def federations_to_identity_dump(self_entity_id, federations): |
235 | 236 |
l = [ START_IDENTITY_DUMP ] |
236 | 237 |
for federation in federations: |
238 |
name_id_qualifier = federation.name_id_qualifier |
|
239 |
name_id_sp_name_qualifier = federation.name_id_sp_name_qualifier |
|
240 |
# ease migration of federations by making qualifiers relative to the linked idp or sp |
|
237 | 241 |
if federation.sp: |
238 | 242 |
sp_id = federation.sp.liberty_provider.entity_id |
243 |
if name_id_sp_name_qualifier == AUTHENTIC_SAME_ID_SENTINEL: |
|
244 |
name_id_sp_name_qualifier = sp_id |
|
245 |
if name_id_qualifier == AUTHENTIC_SAME_ID_SENTINEL: |
|
246 |
name_id_qualifier = self_entity_id |
|
239 | 247 |
elif federation.idp: |
240 | 248 |
sp_id = self_entity_id |
249 |
if name_id_sp_name_qualifier == AUTHENTIC_SAME_ID_SENTINEL: |
|
250 |
name_id_sp_name_qualifier = self_entity_id |
|
251 |
if name_id_qualifier == AUTHENTIC_SAME_ID_SENTINEL: |
|
252 |
name_id_qualifier = federation.idp.liberty_provider.entity_id |
|
241 | 253 |
qualifiers = [] |
242 | 254 |
if federation.name_id_qualifier: |
243 |
qualifiers.append('NameQualifier="%s"' % federation.name_id_qualifier)
|
|
255 |
qualifiers.append('NameQualifier="%s"' % name_id_qualifier) |
|
244 | 256 |
if federation.name_id_sp_name_qualifier: |
245 |
qualifiers.append('SPNameQualifier="%s"' % federation.name_id_sp_name_qualifier)
|
|
257 |
qualifiers.append('SPNameQualifier="%s"' % name_id_sp_name_qualifier) |
|
246 | 258 |
l.append(MIDDLE_IDENTITY_DUMP.format( |
247 | 259 |
content=federation.name_id_content, |
248 | 260 |
format=federation.name_id_format, |
249 | 261 |
sp_id=sp_id, |
250 | 262 |
qualifiers=' '.join(qualifiers))) |
251 | 263 |
l.append(END_IDENTITY_DUMP) |
252 | 264 |
return ''.join(l) |
253 | 265 |
src/authentic2/saml/migrations/0002_ease_federation_migration.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 |
from django.db import migrations, models |
|
5 | ||
6 |
from authentic2.saml.common import AUTHENTIC_SAME_ID_SENTINEL |
|
7 | ||
8 |
def use_id_sentinel(apps, schema_editor): |
|
9 |
LibertyFederation = apps.get_model('saml', 'LibertyFederation') |
|
10 |
# idp federations |
|
11 |
LibertyFederation.objects.filter(idp__isnull=True, |
|
12 |
name_id_sp_name_qualifier=models.F('sp__liberty_provider__entity_id')) \ |
|
13 |
.update(name_id_sp_name_qualifier=AUTHENTIC_SAME_ID_SENTINEL) |
|
14 |
# If there is NameIDQualifier it must be ours |
|
15 |
LibertyFederation.objects.filter(idp__isnull=True, name_id_qualifier__isnull=False) \ |
|
16 |
.update(name_id_qualifier=AUTHENTIC_SAME_ID_SENTINEL) |
|
17 | ||
18 |
class Migration(migrations.Migration): |
|
19 |
dependencies = [ |
|
20 |
('saml', '0001_initial'), |
|
21 |
] |
|
22 |
operations = [ |
|
23 |
migrations.RunPython(use_id_sentinel), |
|
24 |
] |
|
0 |
- |