From 2e6738fae8d6e78009e96127992b6804a7370f37 Mon Sep 17 00:00:00 2001 From: Paul Marillonnet Date: Mon, 16 Oct 2017 17:43:34 +0200 Subject: [PATCH] WIP support federation file loading (#19396) --- mellon/adapters.py | 4 ++++ mellon/app_settings.py | 20 ++++++++++++++++++-- mellon/utils.py | 17 +++++++++++++++++ tests/test_utils.py | 24 ++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/mellon/adapters.py b/mellon/adapters.py index 060a54c..5f24879 100644 --- a/mellon/adapters.py +++ b/mellon/adapters.py @@ -30,6 +30,10 @@ class DefaultAdapter(object): def get_identity_providers_setting(self): return app_settings.IDENTITY_PROVIDERS + def get_federations(self): # XXX only local files supported at the moment + for federation in getattr(app_settings, 'FEDERATIONS', []): + yield federation + def get_idps(self): for i, idp in enumerate(self.get_identity_providers_setting()): if 'METADATA_URL' in idp and 'METADATA' not in idp: diff --git a/mellon/app_settings.py b/mellon/app_settings.py index aeeab73..3558d14 100644 --- a/mellon/app_settings.py +++ b/mellon/app_settings.py @@ -36,16 +36,32 @@ class AppSettings(object): 'LOGIN_URL': 'mellon_login', 'LOGOUT_URL': 'mellon_logout', 'ARTIFACT_RESOLVE_TIMEOUT': 10.0, + 'FEDERATIONS': [], } @property + def FEDERATIONS(self): + from django.conf import settings + if settings.hasattr('MELLON_FEDERATIONS'): + federations = settings.MELLON_FEDERATIONS + if isinstance(federations, dict): + federations = [federations] + return federations + + @property def IDENTITY_PROVIDERS(self): from django.conf import settings + idps = [] try: - idps = settings.MELLON_IDENTITY_PROVIDERS + if hasattr(settings, 'MELLON_IDENTITY_PROVIDERS'): + idps = settings.MELLON_IDENTITY_PROVIDERS + elif not hasattr(settings, 'MELLON_FEDERATIONS'): + raise AttributeError except AttributeError: from django.core.exceptions import ImproperlyConfigured - raise ImproperlyConfigured('The MELLON_IDENTITY_PROVIDERS setting is mandatory') + raise ImproperlyConfigured('Either the MELLON_IDENTITY_PROVIDERS ' + 'or the MELLON_FEDERATIONS settings ' + 'are mandatory') if isinstance(idps, dict): idps = [idps] return idps diff --git a/mellon/utils.py b/mellon/utils.py index ab092a7..6571cb2 100644 --- a/mellon/utils.py +++ b/mellon/utils.py @@ -83,6 +83,16 @@ def create_server(request): logger.error(u'bad metadata in idp %r', idp['ENTITY_ID']) logger.debug(u'lasso error: %s', e) continue + for federation in get_federations(): + try: + server.loadMetadata(lasso.PROVIDER_ROLE_IDP, + federation, None, None, + lasso.SERVER_LOAD_METADATA_FLAG_DEFAULT) + + except lasso.Error, e: + logger.error(u'bad metadata for federation %r', federation) + logger.debug(u'lasso error: %s', e) + continue cache[root] = server settings._MELLON_SERVER_CACHE = cache return settings._MELLON_SERVER_CACHE.get(root) @@ -112,6 +122,13 @@ def get_idps(): yield idp +def get_federations(): + for adapter in get_adapters(): + if hasattr(adapter, 'get_federations'): + for federations in adapter.get_federations(): + yield federations + + def flatten_datetime(d): d = d.copy() for key, value in d.iteritems(): diff --git a/tests/test_utils.py b/tests/test_utils.py index ca73ba6..54e6f2b 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -9,6 +9,9 @@ from httmock import HTTMock from mellon.utils import create_server, create_metadata, iso8601_to_datetime, flatten_datetime import mellon.utils from xml_utils import assert_xml_constraints +from tempfile import mkstemp +from os import remove +from requests import get as rget from utils import error_500, metadata_response @@ -39,6 +42,27 @@ def test_create_server_internal_server_error(mocker, rf, private_settings, caplo assert 'failed with error' in caplog.text +def test_load_federation(mocker, rf, private_settings, caplog): + response = rget('https://metadata.federation.renater.fr/renater/main/main-idps-renater-metadata.xml') + _, tmpname = mkstemp('', 'mellontmp', '/tmp/', False) + tmpfile = open(tmpname, 'wb') + tmpcontent = response.content + tmpfile.write(tmpcontent) + tmpfile.close() + response.close() + + private_settings.MELLON_FEDERATIONS = [tmpname] + + request = rf.get('/') + assert 'failed with error' not in caplog.text + with HTTMock(error_500): + server = create_server(request) + assert server.providers > 100 + + # Cleanup + remove(tmpname) + + def test_create_server_invalid_metadata(mocker, rf, private_settings, caplog): private_settings.MELLON_IDENTITY_PROVIDERS = [ { -- 2.11.0