Projet

Général

Profil

0001-Modify-federation-storage-so-that-we-can-store-feder.patch

Benjamin Dauvergne, 18 mars 2015 15:46

Télécharger (8,02 ko)

Voir les différences:

Subject: [PATCH] Modify federation storage so that we can store federation
 relative to the provider model

If the content of name_id_qualifier or name_id_sp_name_qualifier is
equals to the issuer or service provider entity ID then we store a
sentinel value instead, meaning 'same as provider entity ID'. If we
change the provider entity, all federations are still correct.
 src/authentic2/idp/saml/saml2_endpoints.py         |  9 +++++++-
 src/authentic2/saml/common.py                      | 16 +++++++++++++--
 .../migrations/0002_ease_federation_migration.py   | 24 ++++++++++++++++++++++
 3 files changed, 46 insertions(+), 3 deletions(-)
 create mode 100644 src/authentic2/saml/migrations/0002_ease_federation_migration.py
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
-