support federation file loading (#19396)

This commit is contained in:
Paul Marillonnet 2017-11-14 10:36:44 +01:00
parent 6d8e1ca517
commit 63993e360c
14 changed files with 1509 additions and 80 deletions

13
README
View File

@ -82,6 +82,19 @@ metadata file of the identity provider or if it starts with a slash
the absolute path toward a metadata file. All other keys are override
of generic settings.
MELLON_FEDERATIONS
------------------
A list of dictionaries, only one key 'FEDERATION' is mandatory in those
dictionaries. It should contain the local path or the remote URL for the
metadata file describing the SAML-based federation to be loaded in mellon. Both
relative and absolute paths are supported.
Additional parameters can be given as key/value pairs in the dictionaries, on
a similar basis as the aforementioned MELLON_IDENTITY_PROVIDERS config.
For each dictionary describing a federation, these parameters will apply to
any successfully-loaded provider belonging to that federation.
These parameters also override the global settings.
MELLON_PUBLIC_KEYS
------------------

View File

@ -9,8 +9,12 @@ import requests.exceptions
from django.core.exceptions import PermissionDenied
from django.contrib import auth
from django.contrib.auth.models import Group
from django.utils.text import slugify
from . import utils, app_settings, models
from mellon.federation_utils import idp_metadata_store, url2filename, \
idp_metadata_extract_entity_id, idp_metadata_is_cached, \
idp_metadata_load, idp_settings_store, idp_settings_load
class UserCreationError(Exception):
@ -23,15 +27,60 @@ class DefaultAdapter(object):
def get_idp(self, entity_id):
'''Find the first IdP definition matching entity_id'''
for idp in self.get_idps():
if entity_id == idp['ENTITY_ID']:
return idp
idp = None
if idp_metadata_is_cached(entity_id):
metadata_content = idp_metadata_load(entity_id)
entity_id = idp_metadata_extract_entity_id(metadata_content)
idp = {'METADATA': metadata_content,
'ENTITY_ID': entity_id}
else:
for extra_idp in self.get_identity_providers_setting():
if extra_idp.get('ENTITY_ID') == entity_id or \
idp_metadata_extract_entity_id(extra_idp) == entity_id:
idp = extra_idp.copy()
extra_idp_settings = idp_settings_load(entity_id)
if extra_idp_settings and idp:
idp.update(extra_idp_settings)
return idp
def get_identity_providers_setting(self):
return app_settings.IDENTITY_PROVIDERS
for federation_data in self.get_federations():
if not isinstance(federation_data, dict) or \
'FEDERATION' not in federation_data:
continue
fed_extra_attrs = federation_data.copy()
fed_content = fed_extra_attrs.pop('FEDERATION')
fed_filepath, _ = utils.get_federation_metadata(fed_content)
try:
tree = ET.parse(fed_filepath)
root = tree.getroot()
for child in root:
provider = {}
entity_id = idp_metadata_extract_entity_id(ET.tostring(child))
if not entity_id:
continue
provider['METADATA'] = idp_metadata_store(ET.tostring(child))
provider.update({'ENTITY_ID': entity_id})
provider.update(fed_extra_attrs)
idp_settings_store(provider)
yield provider
except:
self.logger.error('Couldn\'t load federation metadata file %r',
fed_filepath)
continue
for extra_provider in app_settings.IDENTITY_PROVIDERS:
yield extra_provider
def get_federations(self):
for federation in getattr(app_settings, 'FEDERATIONS', []):
yield federation
def get_idps(self):
for i, idp in enumerate(self.get_identity_providers_setting()):
entity_id = idp.get('ENTITY_ID')
if 'METADATA_URL' in idp and 'METADATA' not in idp:
verify_ssl_certificate = utils.get_setting(
idp, 'VERIFY_SSL_CERTIFICATE')
@ -43,28 +92,17 @@ class DefaultAdapter(object):
u'retrieval of metadata URL %r failed with error %s for %d-th idp',
idp['METADATA_URL'], e, i)
continue
idp['METADATA'] = response.content
elif 'METADATA' in idp:
if idp['METADATA'].startswith('/'):
idp['METADATA'] = file(idp['METADATA']).read()
else:
md_content = response.content
if not entity_id:
entity_id = idp_metadata_extract_entity_id(md_content)
idp['METADATA'] = idp_metadata_store(md_content)
elif not idp.get('METADATA'):
self.logger.error(u'missing METADATA or METADATA_URL in %d-th idp', i)
continue
if 'ENTITY_ID' not in idp:
try:
doc = ET.fromstring(idp['METADATA'])
except (TypeError, ET.ParseError):
self.logger.error(u'METADATA of %d-th idp is invalid', i)
continue
if doc.tag != '{%s}EntityDescriptor' % lasso.SAML2_METADATA_HREF:
self.logger.error(u'METADATA of %d-th idp has no EntityDescriptor root tag', i)
continue
if not 'entityID' in doc.attrib:
self.logger.error(
u'METADATA of %d-th idp has no entityID attribute on its root tag', i)
continue
idp['ENTITY_ID'] = doc.attrib['entityID']
# load federation-specific configuration
extra_idp_settings = idp_settings_load(entity_id)
if extra_idp_settings:
idp.update(idp_settings_load(entity_id))
yield idp
def authorize(self, idp, saml_attributes):

View File

@ -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

221
mellon/federation_utils.py Normal file
View File

@ -0,0 +1,221 @@
import fcntl
import json
import lasso
import logging
import tempfile
from datetime import timedelta
from django.utils.text import slugify
from datetime import datetime
import requests
from xml.etree import ElementTree as ET
import os
import hashlib
import os.path
from django.core.files.storage import default_storage
def truncate_unique(s, length=250):
if len(s) < length:
return s
md5 = hashlib.md5(s.encode('ascii')).hexdigest()
# we should be the first and last characters from the URL
l = (length - len(md5)) / 2 - 2 # four additional characters
assert l > 20
return s[:l] + '...' + s[-l:] + '_' + md5
def url2filename(url):
return truncate_unique(slugify(url), 230)
def load_federation_cache(url):
logger = logging.getLogger(__name__)
try:
filename = url2filename(url)
path = os.path.join('metadata-cache', filename)
unix_path = default_storage.path(path)
if not os.path.exists('metadata-cache'):
os.makedirs('metadata-cache')
f = open(unix_path, 'w')
try:
fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
return
else:
with tempfile.NamedTemporaryFile(dir=os.path.dirname(unix_path), delete=False) as temp:
try:
# increase modified time by one hour to prevent too many updates
st = os.stat(unix_path)
os.utime(unix_path, (st.st_atime, st.st_mtime + 3600))
response = requests.get(url)
response.raise_for_status()
temp.write(response.content)
temp.flush()
os.rename(temp.name, unix_path)
except:
logger.error('Could\'nt fetch %r', url)
os.unlink(temp.name)
finally:
fcntl.lockf(f, fcntl.LOCK_UN)
finally:
f.close()
except OSError:
logger.exception(u"could create the intermediary 'metadata-cache' "
"folder")
return
except:
logger.exception(u'failed to load federation from %s', url)
def get_federation_from_url(url, update_cache=False):
logger = logging.getLogger(__name__)
filename = url2filename(url)
path = os.path.join('metadata-cache', filename)
if not default_storage.exists(path) or update_cache or \
default_storage.created_time(path) < datetime.now() - timedelta(days=1):
load_federation_cache(url)
else:
logger.warning('federation %s has not been loaded', url)
return path
def idp_metadata_filepath(entity_id):
filename = url2filename(entity_id)
return os.path.join('./metadata-cache', filename)
def idp_settings_filepath(entity_id):
filename = url2filename(entity_id) + "_settings.json"
return os.path.join('./metadata-cache', filename)
def idp_metadata_is_cached(entity_id):
filepath = idp_metadata_filepath(entity_id)
if not default_storage.exists(filepath):
return False
return True
def idp_metadata_is_file(metadata):
# XXX too restrictive (e.g. 'metadata/http-somemetadataserver-com-md00.xml'
# could be a file too...)
# On the opposite, `if "http://" in metadata or "https://" in metadata:" is
# equally restrictive.
# Using a URLValidator doesn't seem adequate either.
if metadata.startswith('/') or metadata.startswith('./'):
return True
def idp_metadata_needs_refresh(entity_id, update_cache=False):
filepath = idp_metadata_filepath(entity_id)
if not default_storage.exists(filepath) or update_cache or \
default_storage.created_time(filepath) < datetime.now() - timedelta(days=1):
return True
return False
def idp_settings_needs_refresh(entity_id, update_cache=False):
filepath = idp_settings_filepath(entity_id)
if not default_storage.exists(filepath) or update_cache or \
default_storage.created_time(filepath) < datetime.now() - timedelta(days=1):
return True
return False
def idp_metadata_store(metadata_content):
entity_id = idp_metadata_extract_entity_id(metadata_content)
if not entity_id:
return
logger = logging.getLogger(__name__)
filepath = idp_metadata_filepath(entity_id)
if idp_metadata_needs_refresh(entity_id):
with open(filepath, 'w') as f:
try:
fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
f.write(metadata_content)
fcntl.lockf(f, fcntl.LOCK_UN)
except:
logger.error('Couldn\'t store metadata for EntityID %r',
entity_id)
return
return filepath
def idp_metadata_load(entity_id):
logger = logging.getLogger(__name__)
filepath = idp_metadata_filepath(entity_id)
if default_storage.exists(filepath):
logger.info('Loading metadata for EntityID %r', entity_id)
with open(filepath, 'r') as f:
return f.read()
else:
logger.warning('No metadata file for EntityID %r', entity_id)
def idp_settings_store(idp):
"""
Stores an IDP settings when loaded from a federation.
"""
logger = logging.getLogger(__name__)
entity_id = idp.get('ENTITY_ID')
filepath = idp_settings_filepath(entity_id)
idp_settings = {}
if not entity_id:
return
for key, value in idp.items():
if key not in ('METADATA', 'ENTITY_ID'):
idp_settings.update({key: value})
if idp_settings_needs_refresh(entity_id) and idp_settings:
with open(filepath, 'w') as f:
try:
fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
f.write(json.dumps(idp_settings))
fcntl.lockf(f, fcntl.LOCK_UN)
except:
logger.error('Couldn\'t store settings for EntityID %r',
entity_id)
return
return filepath
def idp_settings_load(entity_id):
logger = logging.getLogger(__name__)
filepath = idp_settings_filepath(entity_id)
if default_storage.exists(filepath):
logger.info('Loading JSON settings for EntityID %r', entity_id)
with open(filepath, 'r') as f:
try:
idp_settings = json.loads(f.read())
except:
logger.warning('Couldn\'t load JSON settings for EntityID %r',
entity_id)
else:
return idp_settings
else:
logger.warning('No JSON settings file for EntityID %r', entity_id)
def idp_metadata_extract_entity_id(metadata_content):
logger = logging.getLogger(__name__)
try:
doc = ET.fromstring(metadata_content)
except (TypeError, ET.ParseError):
logger.error(u'METADATA of idp %r is invalid', metadata_content)
return
if doc.tag != '{%s}EntityDescriptor' % lasso.SAML2_METADATA_HREF:
logger.error(u'METADATA of idp %r has no EntityDescriptor root tag',
metadata_content)
return
if not 'entityID' in doc.attrib:
logger.error(
u'METADATA of idp %r has no entityID attribute on its root tag',
metadata_content)
return
return doc.attrib['entityID']

View File

@ -5,14 +5,18 @@ from functools import wraps
import isodate
from django.contrib import auth
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
from django.core.validators import URLValidator
from django.template.loader import render_to_string
from django.utils.text import slugify
from django.utils.timezone import make_aware, now, make_naive, is_aware, get_default_timezone
from django.conf import settings
from django.utils.six.moves.urllib.parse import urlparse
import lasso
from . import app_settings
from federation_utils import get_federation_from_url, idp_metadata_is_file
def create_metadata(request):
@ -48,44 +52,71 @@ SERVERS = {}
def create_server(request):
logger = logging.getLogger(__name__)
root = request.build_absolute_uri('/')
cache = getattr(settings, '_MELLON_SERVER_CACHE', {})
if root not in cache:
metadata = create_metadata(request)
if app_settings.PRIVATE_KEY:
private_key = app_settings.PRIVATE_KEY
private_key_password = app_settings.PRIVATE_KEY_PASSWORD
elif app_settings.PRIVATE_KEYS:
private_key = app_settings.PRIVATE_KEYS[0]
private_key_password = None
if isinstance(private_key, (tuple, list)):
private_key_password = private_key[1]
private_key = private_key[0]
else: # no signature
private_key = None
private_key_password = None
server = lasso.Server.newFromBuffers(metadata, private_key_content=private_key,
private_key_password=private_key_password)
server.setEncryptionPrivateKeyWithPassword(private_key, private_key_password)
private_keys = app_settings.PRIVATE_KEYS
# skip first key if it is already loaded
if not app_settings.PRIVATE_KEY:
private_keys = app_settings.PRIVATE_KEYS[1:]
for key in private_keys:
password = None
if isinstance(key, (tuple, list)):
password = key[1]
key = key[0]
server.setEncryptionPrivateKeyWithPassword(key, password)
for idp in get_idps():
try:
server.addProviderFromBuffer(lasso.PROVIDER_ROLE_IDP, idp['METADATA'])
except lasso.Error as e:
logger.error(u'bad metadata in idp %r', idp['ENTITY_ID'])
logger.debug(u'lasso error: %s', e)
continue
cache[root] = server
settings._MELLON_SERVER_CACHE = cache
return settings._MELLON_SERVER_CACHE.get(root)
metadata = create_metadata(request)
if app_settings.PRIVATE_KEY:
private_key = app_settings.PRIVATE_KEY
private_key_password = app_settings.PRIVATE_KEY_PASSWORD
elif app_settings.PRIVATE_KEYS:
private_key = app_settings.PRIVATE_KEYS[0]
private_key_password = None
if isinstance(private_key, (tuple, list)):
private_key_password = private_key[1]
private_key = private_key[0]
else: # no signature
private_key = None
private_key_password = None
server = lasso.Server.newFromBuffers(metadata, private_key_content=private_key,
private_key_password=private_key_password)
server.setEncryptionPrivateKeyWithPassword(private_key, private_key_password)
private_keys = app_settings.PRIVATE_KEYS
# skip first key if it is already loaded
if not app_settings.PRIVATE_KEY:
private_keys = app_settings.PRIVATE_KEYS[1:]
for key in private_keys:
password = None
if isinstance(key, (tuple, list)):
password = key[1]
key = key[0]
server.setEncryptionPrivateKeyWithPassword(key, password)
for idp in get_idps():
try:
metadata = idp.get('METADATA')
if idp_metadata_is_file(metadata):
with open(metadata, 'r') as f:
metadata = f.read()
server.addProviderFromBuffer(lasso.PROVIDER_ROLE_IDP, metadata)
except lasso.Error, e:
logger.error(u'bad metadata in idp %r', idp)
logger.debug(u'lasso error: %s', e)
except IOError, e:
logger.warning('No such metadata file: %r', metadata)
continue
return server
def get_federation_metadata(federation):
logger = logging.getLogger(__name__)
fedmd = None
pemcert = None
if (isinstance(federation, tuple) and len(federation) == 2):
logger.info('Loading local cert-based federation %r',
federation)
if federation[1].endswith('.pem'):
fedmd = federation[0]
pemcert = federation[1]
else:
urlval = URLValidator()
try:
urlval(federation)
except ValidationError as e:
logger.info('Loading file-based federation %s',
federation)
fedmd = federation
else:
logger.info('Fetching and loading url-based federation %s',
federation)
fedmd = get_federation_from_url(federation)
return (fedmd, pemcert)
def create_login(request):
@ -112,6 +143,13 @@ def get_idps():
yield idp
def get_federations():
for adapter in get_adapters():
if hasattr(adapter, 'get_federations'):
for federation in adapter.get_federations():
yield federation
def flatten_datetime(d):
d = d.copy()
for key, value in d.iteritems():

View File

@ -342,9 +342,9 @@ class LoginView(ProfileMixin, LogMixin, View):
if idp is None:
return HttpResponseBadRequest('no idp found')
self.profile = login = utils.create_login(request)
self.log.debug('authenticating to %r', idp['ENTITY_ID'])
self.log.debug('authenticating to %r', idp.get('ENTITY_ID') or idp['METADATA'])
try:
login.initAuthnRequest(idp['ENTITY_ID'], lasso.HTTP_METHOD_REDIRECT)
login.initAuthnRequest(idp.get('ENTITY_ID'), lasso.HTTP_METHOD_REDIRECT)
authn_request = login.request
# configure NameID policy
policy = authn_request.nameIdPolicy

View File

@ -94,6 +94,7 @@ setup(name="django-mellon",
'django>=1.5,<2.0',
'requests',
'isodate',
'pytz',
],
setup_requires=[
'django>=1.5,<2.0',

367
tests/dummy_md.xml Normal file
View File

@ -0,0 +1,367 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><md:EntitiesDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute" xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi" xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui" xmlns:pyff="http://pyff.io/NS" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:xrd="http://docs.oasis-open.org/ns/xri/xrd-1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="_20171018T113001Z" Name="https://federation.renater.fr/" cacheDuration="PT1H" validUntil="2017-10-27T11:30:01Z"><ds:Signature>
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>JKdLdd5yGvkFdb1fCAByMMnurIKYhZepRouZfOjIUrg=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
OTexfi8c63TsP1V9j5m6digA2NomUfqBtT8pPKhwdqEDQS5qLh6fxvT+wWkP6JaIhkP8nxwpbArl
7cUHkRv5ibZzcknIAjXYMhsSTtFQUq89OMcDHtZHG54jiKyHPhu2+XEbvv6DsAYanYC6SHEnGjNG
opnOEUB2XqeycsvvTQQIuWZEoABTVcKYyk2CW7Ij5EUmPOAPiidtbt8lzrtkV6dwLbkyoEbChAyj
emrL/oS01aJgT9sQoJxR8lyRMGiZ/BwQqYTareiKwOXLPdGThzsfZXD8de9T1xuysILaAM7sHPJV
QfrQJm80Zo2MM/GnhJTO9rc4m3kRnRhqmA6qMw==
</ds:SignatureValue>
<ds:KeyInfo>
<ds:KeyValue>
<ds:RSAKeyValue>
<ds:Modulus>
71+vTf66BPgYUF7sm4T++W69qMVyGQn9wNqpBLc6sp53eq/JRTOUD26Yehjsld5qN52Bv2r5QG7o
4VU123akXUYzupvq1f+tmF9NwYa7MPEPFzCzJHhNXjZNRxcsW1WLW34fhQCm0oak3oSPoNo5qeGi
jNsTSkgSt1mPH0P8d95af2VJnT6zbrclxvH4emqpT9oGLsWqKWLlIbZ7u1PUjuNVwLHuj909/apm
C13RBIpV52fey4qey34bnRHdCTknZeN/TJLTJ9hMWzz9TbdjfIFaiF7MeY+OYRXzUJeQuHHMu/2I
emkoR26mYi6irvmx8AdPcPCwcRKw2Ca4xLhbNw==
</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
<ds:X509Data>
<ds:X509Certificate>
MIIC9zCCAd+gAwIBAgIEfe6j3jANBgkqhkiG9w0BAQsFADAsMSowKAYDVQQDEyFTQU1MIE1ldGFk
YXRhIFNpZ25pbmcgQ2VydGlmaWNhdGUwHhcNMTYwNzI5MDczNjM4WhcNMjYwNjA3MDczNjM4WjAs
MSowKAYDVQQDEyFTQU1MIE1ldGFkYXRhIFNpZ25pbmcgQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDvX69N/roE+BhQXuybhP75br2oxXIZCf3A2qkEtzqynnd6r8lF
M5QPbph6GOyV3mo3nYG/avlAbujhVTXbdqRdRjO6m+rV/62YX03Bhrsw8Q8XMLMkeE1eNk1HFyxb
VYtbfh+FAKbShqTehI+g2jmp4aKM2xNKSBK3WY8fQ/x33lp/ZUmdPrNutyXG8fh6aqlP2gYuxaop
YuUhtnu7U9SO41XAse6P3T39qmYLXdEEilXnZ97Lip7LfhudEd0JOSdl439MktMn2ExbPP1Nt2N8
gVqIXsx5j45hFfNQl5C4ccy7/Yh6aShHbqZiLqKu+bHwB09w8LBxErDYJrjEuFs3AgMBAAGjITAf
MB0GA1UdDgQWBBTT88iZzWO+hN9SBUkpx871lmTuLTANBgkqhkiG9w0BAQsFAAOCAQEABoPpODry
XwiM5jjtqk6veR02FevCKHpZP6Od7Kqcfs6lg5LcQmGUOgpmW3Gg4UMjBYkgARsT2Nsnah1CJqa8
cjvv8p5KEIhY0hVS8iMJnrb3PDeiFSeP4xSfct/6z/ebV4+QFl22bsm2zpAC6BpFz8+IJ/jAmQzT
Vob4MAUeQPnwwzm3xz6yanLZx7BK5cfrTCa+hrarNQCboRjXPwiejF8WRCxpgRHH6yNs5QH/Z6o5
e3tUP7uEpn2Ob+kcLsEMGb9DghkoDAgkHCOZeTy+7hgxt+/T94cLTa58gVtvEOnd0GuL7Vfd+IVd
XgSard8RfR3OyZlf6M4aSGQA73sskQ==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature><md:EntityDescriptor entityID="https://aishib.agropolis.fr/idp/shibboleth">
<md:Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://federation.renater.fr/" registrationInstant="2013-06-06T11:49:20Z">
<mdrpi:RegistrationPolicy xml:lang="en">https://services.renater.fr/federation/en/metadata_registration_practice_statement</mdrpi:RegistrationPolicy>
</mdrpi:RegistrationInfo>
</md:Extensions>
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:2.0:protocol">
<md:Extensions>
<shibmd:Scope regexp="false">agropolis.fr</shibmd:Scope>
<mdui:UIInfo>
<mdui:DisplayName xml:lang="en">Agropolis International</mdui:DisplayName>
<mdui:Logo height="16" width="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAACPUlEQVQoz21SPW8TQRR8u7d3ju34Er6UCHACRqK4Bjk0oDSEjiYSBQVS8k9AkWgp+AuUASGEaCASkoPcgARVMF8iTnxJwMFJfL47397u3u6jsGVFwLzmFTN6ozdDEBEAAOD4kiRJsVgkhMA/YMfZzc3NVstnzGq1/KXlJfgf2Ii9XquVZ2YWbi5Io4MsbfPeZK4wRm0AOH6KICIivq2tV6/O5cYLHztbW9FvYTKuZaLk7PjpW+UrJXtspCHGmGazCQBnZ8svtj/0tbAINYhcy1DyThpRhHtztyedwkBDAWBnZ6dSqbzZ+7THu0IraTJplDSZ0JnQ2Y+482jj1cgSRUTHdrhW9fa3SKaxErFKIyUiKaIsjVQaKf5s631HxP1+X2vNwjB0J9zd+OgnD044Ra4lI5ZBw7XqyeRQREciaqe9xoE/K/OFfIENnqBM1uZBqlWBOYxQjYZnqieTThru8zCU3AASIAjIXNellGLePkjCUPICy1mEDAShSg7SqCsTBtQ7WfY3vlarVUYpdUsuAs5PXV7dfpe3HEYtjSbNZJwJoRUi3rl4fSrvfufctm0ySA0RD0V84+WDL1EbCCDCYIDApeKZ+uKK6faDIPA8jw7jIORUbry2eH+5Mu8ARTSAkCPW3QvX6osrE+B8bjQ8zxu2aACDaIwxxuzzsLbbePj88a8k0Mb4vr/2ei3LMoOIiGRU0iGGVuDp6pNz5fNSiKnpac/zgAABMuzSXwIggIjdbrdUKjHGYGQaAAD+AJBJecXxnEvWAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTA3LTIwVDEwOjQ4OjE1KzAyOjAwpWiGMQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0wNy0yMFQxMDo0ODoxNSswMjowMNQ1Po0AAAAASUVORK5CYII=</mdui:Logo>
<mdui:InformationURL xml:lang="fr">http://www.agropolis.fr</mdui:InformationURL>
<mdui:DisplayName xml:lang="fr">Agropolis International</mdui:DisplayName>
</mdui:UIInfo>
</md:Extensions>
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIDNzCCAh+gAwIBAgIUYY3sGXwChkj2CRy6QFDvkdj2zlAwDQYJKoZIhvcNAQEF
BQAwHjEcMBoGA1UEAxMTYWlzaGliLmFncm9wb2xpcy5mcjAeFw0xMzA1MTUxMzM3
MTJaFw0zMzA1MTUxMzM3MTJaMB4xHDAaBgNVBAMTE2Fpc2hpYi5hZ3JvcG9saXMu
ZnIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxrDy6lrhIBjcxv16n
4UJ2cEMYPO4wSmfDwhO6feoSIEuIblYRHE2nQKirMokwD6seF4rbDHyxLXg/ColL
VLv+0CJteIOZjSCgSN90WzQRrC1Ex5sJfPu6yPEXvW8H1906gEg6ok8rlCIHRGfE
15pHK5eqxQS5f2n8c2t/Uk33/FBj79/hb3Cd7vE4mdlvReD3AFswC0lV4bPmj3Ka
KUuMj9xwipwnfWCu6p2/ZJF4M3ADU5grXHJ2Vqmd8DWm5raaObKjYwJddbRBByI8
bJJLIwAQQmX4Dh4hf1QKlf2oqWPWVQxLQp0erL1U8IWmj1RG8TTH9xOJl6kkEhYq
Z2gfAgMBAAGjbTBrMEoGA1UdEQRDMEGCE2Fpc2hpYi5hZ3JvcG9saXMuZnKGKmh0
dHBzOi8vYWlzaGliLmFncm9wb2xpcy5mci9pZHAvc2hpYmJvbGV0aDAdBgNVHQ4E
FgQU9A7iQ8Qo+t2JCpKuOOV9YBoYs4MwDQYJKoZIhvcNAQEFBQADggEBAG0LOW6I
F+M8n2NpzyQjfVCJCA6QhWjbXrfemiPJFZGZZb2dVmHof4yCpCUYgHOBoZaXPOlB
nLYsUWvFZ6V2GELZpLHzHSSrYidieW07qQkh1DwcIYpvtZgLviOtT/tCEGsk925f
DUoGdeIqpqt54WZcW9+TbKicvjg3JT4BFOQ17bFNwPW+YjTbvsWYxen+e0mRp4vM
V0yMu2f3bccVhePASSZGL3yod3sJ1dPvlrJO9c35BekhtirolVjZqMQ0AYPVifua
yIU0dWXsZkAOcBL9kZFbJcYRUIxMgvp8U2Zdv1+ZlwOyXnnWDOOh9wjuT7FAyObU
ChvjHlgZHkvLwJI=
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://aishib.agropolis.fr/idp/profile/SAML2/POST/SSO"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://aishib.agropolis.fr/idp/profile/SAML2/Redirect/SSO"/>
<md:SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://aishib.agropolis.fr/idp/profile/Shibboleth/SSO"/>
</md:IDPSSODescriptor>
<md:Organization>
<md:OrganizationName xml:lang="en">Agropolis International</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en">Agropolis International</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en">http://www.agropolis.fr</md:OrganizationURL>
</md:Organization>
<md:ContactPerson contactType="technical">
<md:SurName>Jean Cerda</md:SurName>
<md:EmailAddress>cerda@agropolis.fr</md:EmailAddress>
</md:ContactPerson>
<md:ContactPerson contactType="technical">
<md:SurName>Jean-Pierre Allano</md:SurName>
<md:EmailAddress>allano@agropolis.fr</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor><md:EntityDescriptor entityID="https://ambre.vetagro-sup.fr/idp/shibboleth">
<md:Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://federation.renater.fr/" registrationInstant="2013-01-14T16:11:53Z">
<mdrpi:RegistrationPolicy xml:lang="en">https://services.renater.fr/federation/en/metadata_registration_practice_statement</mdrpi:RegistrationPolicy>
</mdrpi:RegistrationInfo>
</md:Extensions>
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:2.0:protocol">
<md:Extensions>
<shibmd:Scope regexp="false">vetagro-sup.fr</shibmd:Scope>
<mdui:UIInfo>
<mdui:DisplayName xml:lang="en">Vetagro Sup</mdui:DisplayName>
<mdui:Logo height="16" width="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAAB/klEQVQ4y2NkQAP///+X+/jxI/PO7dujP3/7kf7v778ffDzciw2MDFaqq6t/Y2RkfIysngndAEZGxkezZ8/25xEQqVDTs5eRVrNU4RQUL7x9+7YtumasBjAwMDBISIgbcvBKct998p7h1fvfDKyc4nz//jF6yjAwSBNlwM+fP3/9/PmT4dbl4wysrCwMf//9Z/r7959UcFISD1EGPH107xgfD9sbTg52hrcvHjDw87Aw/Pz+7tLEefNuEmWAm6ffxvu3Ll4zMjZleHz/KsO7lw+f3bh+czs2tVgNsLS0fPfs4b3VnKy//wrycW84e2L/uobmtg0MpIKurt6N////Z8jPzxcnWTMDAwPD79//tbq7+9bhU8OMTfD//8cMP79L1X/8tjxMQYHXT0Uh88aBgyuvEW3Aly+8ntw8jLU3bx20cnH/xPz2jTyvk9OGpTt3NhIOxP//GRgkJGR8tPVeyElIvWA4dfIqg57Bff0nD+eHExULIb5dqkYmYgYm5r8YPH3vMzx//omBk+edpI4+vxVRBnz5zPqbi4vt7a9fv//9+cvAYG79jIGZmZWBg4NJiCgDdh4sfHD/7u9j714Z/BYWiGBQVkxjePNK8+erV5+uYDOABTMM/nP09y9Z8+OHgNjli9ahf//++8vGwrlAS0tp/v///7kYGRm/IasHAIVTy8DG/VpJAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTA3LTIwVDEwOjUwOjA5KzAyOjAwfDtz7wAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0wNy0yMFQxMDo1MDowOSswMjowMA1my1MAAAAASUVORK5CYII=</mdui:Logo>
<mdui:InformationURL xml:lang="fr">http://www.vetagro-sup.fr</mdui:InformationURL>
<mdui:DisplayName xml:lang="fr">Vetagro Sup</mdui:DisplayName>
</mdui:UIInfo>
</md:Extensions>
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIDPDCCAiSgAwIBAgIVAL9PsuadPSIZcMHNxlK/oevezmzWMA0GCSqGSIb3DQEB
BQUAMB8xHTAbBgNVBAMTFGFtYnJlLnZldGFncm8tc3VwLmZyMB4XDTEyMTEwODEw
MTQwNFoXDTMyMTEwODEwMTQwNFowHzEdMBsGA1UEAxMUYW1icmUudmV0YWdyby1z
dXAuZnIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc/ptfpmkomwmT
4RsID+1Ce1dX0eUjcLgSOZN8hVpHWLag2ERWkpmvB5aK7BAFcI5i//Gk80tAiasu
JtlZhBnEw54aTJRGpyL2CVkHyl6SMRxprIi1Ji67IoGqEgUeGaheAxo+tG5e1WSc
bIbldcSKdwvjAV+7HSB4C6NqLsAzJH25++yaRH2uf2LTD0TDzNR9Q2hVj/VyYWR+
K3HWI1Snjn/i7aFfZZhYmBkwHuQOaPhwCM+khikg5XicMsxUhHCMi93UgHGIsdkr
IEGj4xydBTUKsLaykeuFS8EgXbWwCLGkeX76w8xDoFIpnppU/yFd9v7Zg3EBfn4p
kTW3GdIjAgMBAAGjbzBtMEwGA1UdEQRFMEOCFGFtYnJlLnZldGFncm8tc3VwLmZy
hitodHRwczovL2FtYnJlLnZldGFncm8tc3VwLmZyL2lkcC9zaGliYm9sZXRoMB0G
A1UdDgQWBBTPTqWkVHrHXFjmxMWkNt/sp2h5ozANBgkqhkiG9w0BAQUFAAOCAQEA
FvXMtfBUmRZCzz8CjanGzr1TBUPmnkrKci5AtkseKw9YlfUmBXTHB01y697nYq6m
RB6KhvfW212h9CF0IOEEjoadgDhXqGYhq8PnAOtT4Ty3XDy8SbRh8aQWfvnfSngv
FdpHRiSpj5UXXuT5zTtkf59h58XKtEfCkMbUzvdOgUobJzpD0WISmQHPQnx+Neg6
9j7oMRrDiZjS39Om8Imu9xvsnddDM3PlsDBIsvrr1o7K5iLkEdR1YYX0ZNDbiFuw
QXXl2dwQPB8KrScPUvCe57slU2gFQvvIBzjQysxC6V6TPSuM3A/ee56lACuB3jKj
oYkHQc5Gj/1rSMLmu9aLMg==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://ambre.vetagro-sup.fr/idp/profile/SAML2/POST/SSO"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://ambre.vetagro-sup.fr/idp/profile/SAML2/Redirect/SSO"/>
<md:SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://ambre.vetagro-sup.fr/idp/profile/Shibboleth/SSO"/>
</md:IDPSSODescriptor>
<md:Organization>
<md:OrganizationName xml:lang="en">Vetagro Sup</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en">Vetagro Sup</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en">http://www.vetagro-sup.fr</md:OrganizationURL>
</md:Organization>
<md:ContactPerson contactType="technical">
<md:SurName>Nicolas Aulas</md:SurName>
<md:EmailAddress>nicolas.aulas@vetagro-sup.fr</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor><md:EntityDescriptor entityID="https://antimoine.insa-strasbourg.fr/idp/shibboleth">
<md:Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://federation.renater.fr/" registrationInstant="2014-02-11T08:44:08Z">
<mdrpi:RegistrationPolicy xml:lang="en">https://services.renater.fr/federation/en/metadata_registration_practice_statement</mdrpi:RegistrationPolicy>
</mdrpi:RegistrationInfo>
</md:Extensions>
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:2.0:protocol">
<md:Extensions>
<shibmd:Scope regexp="false">insa-strasbourg.fr</shibmd:Scope>
<mdui:UIInfo>
<mdui:DisplayName xml:lang="en">INSA Strasbourg</mdui:DisplayName>
<mdui:Logo height="16" width="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAq1BMVEXeAACEhoTWz87nQTn3oqXnIBjvgnvWlpT/5+fnEAjvZWOltrXnNDH3mpT/9/fnCAD/4+fvioz3x8bnVVL3qq3nKCnvkpTnHBjvcXP3sq3vgoT/7+/nFBDnODH3mpz////nDAj3z87vlpTveXv3vr3nAACMmpznRUL3pqXnJCHnFAj/+//nDADvjoz3y87vXVr3rq3nLCnvdXP3srXvhoT/8/fvODH3npz3lpQaie6kAAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAAAe0lEQVQY053OwQqCQBhF4VM22VSMMWrFGP2kkIpUQ1nz/m8Ws20TeFeHb3WRnzEBBjO8xRjZrURi0TFiy+UITjTpjIKaOndZuDSGxF0j9G1+e7CuLN1nE2F7VI28tAoqMMezP1ieFOOp7RPueBXKSqdnMq8Wg66nPP0LX4uIG4jEwJ0sAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTA3LTIwVDEwOjQ5OjA0KzAyOjAwIHfmJQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0wNy0yMFQxMDo0OTowNCswMjowMFEqXpkAAAAASUVORK5CYII=</mdui:Logo>
<mdui:InformationURL xml:lang="fr">http://www.insa-strasbourg.fr</mdui:InformationURL>
<mdui:DisplayName xml:lang="fr">INSA Strasbourg</mdui:DisplayName>
</mdui:UIInfo>
</md:Extensions>
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIDUDCCAjigAwIBAgIVAIbX8U0uAqAhuXm1jWxiFpggtDTDMA0GCSqGSIb3DQEB
CwUAMCQxIjAgBgNVBAMMGXNvdWZyZS5pbnNhLXN0cmFzYm91cmcuZnIwHhcNMTYw
OTI3MTIzNjIxWhcNMzYwOTI3MTIzNjIxWjAkMSIwIAYDVQQDDBlzb3VmcmUuaW5z
YS1zdHJhc2JvdXJnLmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
sEE02sLRPAG5N81DMHEeGpI2MYF8yG/RiwH07cFIlLqgV80ewOmi0FWPYijxMb8A
bmx0RwUMvJBVI6WMxtT9fykhID20k8rWOuYOzvaynzVqCktqVgKoEAxP1PFE9b0n
iGKFprjjNl9ZD90GOUsxbAO7yXG9Q4WBa/eThl6XkUvNkSaZp5hcdWrgcAdsae3q
iD/uxFa38NXNNeRLGyfxjd2K5qYSzbwBza9s9TOq1+pfw7sxu3/4BnfQ0RLGO6co
4tH4Mufh0ome4cyYk4pvW5DOd1AznxDb8HpqvE0zwEsa69c/FDX0akgFZydmc77a
j6USn6JKjjbO49yGtG1gVQIDAQABo3kwdzAdBgNVHQ4EFgQUjzMsxZYiokPYxper
9zadM8J0F0kwVgYDVR0RBE8wTYIZc291ZnJlLmluc2Etc3RyYXNib3VyZy5mcoYw
aHR0cHM6Ly9zb3VmcmUuaW5zYS1zdHJhc2JvdXJnLmZyL2lkcC9zaGliYm9sZXRo
MA0GCSqGSIb3DQEBCwUAA4IBAQBFJKsiS3yfWuDB/E+iqQ0TuQJzL5+JIcloN0dw
BFxW3VZOju15zeQ7LwRBg9S4SGLMPJU+LM1lvr68cK9brut/FjF51SETIXEeCWo3
7+PIqgOCzraLNinmpU/OtN8ENalOPvpS6Jvbd23qB2t+IqOtZ+j15b0Yq4/on1E3
W2F9CVzKpe4EwmmtCPQbe7U1wvhgFylEx797pex8veWs79YSYwqvcKMh79dzl8Fo
/CgsO5pDrfKmc6SGMkByq75dZj+PqhZDzZ9EFTxbrXOTaS08VRN6a5Rh2iYRnGxq
yZl66tPcaIm5PHgOEmu5X4lPkUoY+Jt36Gj3SGCbYt8qH5S0
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIDXDCCAkSgAwIBAgIVAKI+qiqDCk9wTTqn7OVAoZrvj/CpMA0GCSqGSIb3DQEB
BQUAMCcxJTAjBgNVBAMTHGFudGltb2luZS5pbnNhLXN0cmFzYm91cmcuZnIwHhcN
MTQwMTEzMTAzOTU4WhcNMzQwMTEzMTAzOTU4WjAnMSUwIwYDVQQDExxhbnRpbW9p
bmUuaW5zYS1zdHJhc2JvdXJnLmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAtuM8lRjlVjjmrHq9VtguaOMQL+Wd99BiOs56kL3Mbctg1FwH69LYThCW
6dOz6WJg/jU/naF7jEikXKc71xGyu7Ph7Iqa9S5hoXXAT8u/0q2nZDeTOraJqKe1
FMF2RzXhEEMyQO3CiKNK9b+tbKoNZS7FQCixMZklWZPt4EcEKd6jyRq1WYX3dpnb
r9I/aCdhtK/PGvGe5gKTDoTR2HKyWKJTc/obf8x/vlYIEwiaGgdlqI2KiBE0x48n
zQdP6XVi3T8ZWbnkLmCfgJtP2C8PtEJuwDRAy0Z9N4DSwvxn5YCVYgBLSi0TLa10
B/lUqqBezZrTrA9p9Lt8JtGXW5YGHwIDAQABo38wfTBcBgNVHREEVTBTghxhbnRp
bW9pbmUuaW5zYS1zdHJhc2JvdXJnLmZyhjNodHRwczovL2FudGltb2luZS5pbnNh
LXN0cmFzYm91cmcuZnIvaWRwL3NoaWJib2xldGgwHQYDVR0OBBYEFLFkjPZUc9JY
qrWjldJ/iGGkKAt4MA0GCSqGSIb3DQEBBQUAA4IBAQBSk/wU1mRn4VF2ifmy261K
DK7uX+t1H1hh8S38fKSFU7HoNXJTV3vQnmBOpYIGC1gtvmb+qjqpNtikU2zO84Gq
Q0bXHxYF2d9RUP89mKaFxE5uNcXFmlOA3ChZY3pMT5zwAPI/T60tGrex7zci7OLn
JDAQj/q4Yk9ejx6JTFggQSCCVh+oV/SDIMd2p5AY6H3mto3b6XCk7Lssa8a/D30k
pEkZnhTKdN82eRyynuOR7UDU4tasV4d7Mi/j53f5ihnRcsvwh/pYodjoVYY8cEcZ
JLnAXYF8coSwh8UN4D/0NHsvTuSOFQc85hGrqacMsvxiQiw9mv01AX5+A5YLEbVQ
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://antimoine.insa-strasbourg.fr/idp/profile/SAML2/Redirect/SLO"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://antimoine.insa-strasbourg.fr/idp/profile/SAML2/POST/SLO"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://antimoine.insa-strasbourg.fr/idp/profile/SAML2/SOAP/SLO"/>
<md:NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://antimoine.insa-strasbourg.fr/idp/profile/SAML2/POST/SSO"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://antimoine.insa-strasbourg.fr/idp/profile/SAML2/Redirect/SSO"/>
<md:SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://antimoine.insa-strasbourg.fr/idp/profile/Shibboleth/SSO"/>
</md:IDPSSODescriptor>
<md:Organization>
<md:OrganizationName xml:lang="en">INSA Strasbourg</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en">INSA Strasbourg</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en">http://www.insa-strasbourg.fr</md:OrganizationURL>
</md:Organization>
<md:ContactPerson contactType="technical">
<md:SurName>Lahsen BOUZID</md:SurName>
<md:EmailAddress>lahsen.bouzid@insa-strasbourg.fr</md:EmailAddress>
</md:ContactPerson>
<md:ContactPerson contactType="technical">
<md:SurName>Simon SCHERRER</md:SurName>
<md:EmailAddress>simon.scherrer@insa-strasbourg.fr</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor></md:EntitiesDescriptor>

557
tests/federation-sample.xml Normal file
View File

@ -0,0 +1,557 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><md:EntitiesDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute" xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi" xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui" xmlns:pyff="http://pyff.io/NS" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:xrd="http://docs.oasis-open.org/ns/xri/xrd-1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="_20171018T113001Z" Name="https://federation.renater.fr/" cacheDuration="PT1H" validUntil="2017-10-27T11:30:01Z"><ds:Signature>
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>JKdLdd5yGvkFdb1fCAByMMnurIKYhZepRouZfOjIUrg=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
OTexfi8c63TsP1V9j5m6digA2NomUfqBtT8pPKhwdqEDQS5qLh6fxvT+wWkP6JaIhkP8nxwpbArl
7cUHkRv5ibZzcknIAjXYMhsSTtFQUq89OMcDHtZHG54jiKyHPhu2+XEbvv6DsAYanYC6SHEnGjNG
opnOEUB2XqeycsvvTQQIuWZEoABTVcKYyk2CW7Ij5EUmPOAPiidtbt8lzrtkV6dwLbkyoEbChAyj
emrL/oS01aJgT9sQoJxR8lyRMGiZ/BwQqYTareiKwOXLPdGThzsfZXD8de9T1xuysILaAM7sHPJV
QfrQJm80Zo2MM/GnhJTO9rc4m3kRnRhqmA6qMw==
</ds:SignatureValue>
<ds:KeyInfo>
<ds:KeyValue>
<ds:RSAKeyValue>
<ds:Modulus>
71+vTf66BPgYUF7sm4T++W69qMVyGQn9wNqpBLc6sp53eq/JRTOUD26Yehjsld5qN52Bv2r5QG7o
4VU123akXUYzupvq1f+tmF9NwYa7MPEPFzCzJHhNXjZNRxcsW1WLW34fhQCm0oak3oSPoNo5qeGi
jNsTSkgSt1mPH0P8d95af2VJnT6zbrclxvH4emqpT9oGLsWqKWLlIbZ7u1PUjuNVwLHuj909/apm
C13RBIpV52fey4qey34bnRHdCTknZeN/TJLTJ9hMWzz9TbdjfIFaiF7MeY+OYRXzUJeQuHHMu/2I
emkoR26mYi6irvmx8AdPcPCwcRKw2Ca4xLhbNw==
</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
<ds:X509Data>
<ds:X509Certificate>
MIIC9zCCAd+gAwIBAgIEfe6j3jANBgkqhkiG9w0BAQsFADAsMSowKAYDVQQDEyFTQU1MIE1ldGFk
YXRhIFNpZ25pbmcgQ2VydGlmaWNhdGUwHhcNMTYwNzI5MDczNjM4WhcNMjYwNjA3MDczNjM4WjAs
MSowKAYDVQQDEyFTQU1MIE1ldGFkYXRhIFNpZ25pbmcgQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDvX69N/roE+BhQXuybhP75br2oxXIZCf3A2qkEtzqynnd6r8lF
M5QPbph6GOyV3mo3nYG/avlAbujhVTXbdqRdRjO6m+rV/62YX03Bhrsw8Q8XMLMkeE1eNk1HFyxb
VYtbfh+FAKbShqTehI+g2jmp4aKM2xNKSBK3WY8fQ/x33lp/ZUmdPrNutyXG8fh6aqlP2gYuxaop
YuUhtnu7U9SO41XAse6P3T39qmYLXdEEilXnZ97Lip7LfhudEd0JOSdl439MktMn2ExbPP1Nt2N8
gVqIXsx5j45hFfNQl5C4ccy7/Yh6aShHbqZiLqKu+bHwB09w8LBxErDYJrjEuFs3AgMBAAGjITAf
MB0GA1UdDgQWBBTT88iZzWO+hN9SBUkpx871lmTuLTANBgkqhkiG9w0BAQsFAAOCAQEABoPpODry
XwiM5jjtqk6veR02FevCKHpZP6Od7Kqcfs6lg5LcQmGUOgpmW3Gg4UMjBYkgARsT2Nsnah1CJqa8
cjvv8p5KEIhY0hVS8iMJnrb3PDeiFSeP4xSfct/6z/ebV4+QFl22bsm2zpAC6BpFz8+IJ/jAmQzT
Vob4MAUeQPnwwzm3xz6yanLZx7BK5cfrTCa+hrarNQCboRjXPwiejF8WRCxpgRHH6yNs5QH/Z6o5
e3tUP7uEpn2Ob+kcLsEMGb9DghkoDAgkHCOZeTy+7hgxt+/T94cLTa58gVtvEOnd0GuL7Vfd+IVd
XgSard8RfR3OyZlf6M4aSGQA73sskQ==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature><md:EntityDescriptor entityID="https://access-check.edugain.org/simplesaml/saml2/idp/metadata.php">
<md:Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://federation.renater.fr/" registrationInstant="2015-01-30T15:32:58Z">
<mdrpi:RegistrationPolicy xml:lang="en">https://services.renater.fr/federation/en/metadata_registration_practice_statement</mdrpi:RegistrationPolicy>
</mdrpi:RegistrationInfo>
</md:Extensions>
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:Extensions>
<shibmd:Scope regexp="false">access-check.edugain.org</shibmd:Scope>
<mdui:UIInfo>
<mdui:DisplayName xml:lang="en">eduGAIN Access Check</mdui:DisplayName>
<mdui:Logo height="16" width="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAABbUlEQVQoz52RPW4UQRCFv6ru6fnZNSxCJuVKpFwAicR3IUI+AakvhQhI7JU8M/1T3QQzsg1sAhWV3qtPVaonfPrCX9W+fpTP3y7otzceGJKJxCiujpVUkCv0+m3K967hixUfWgWSHwAPxG6UqtIFbEFHGoCqR721BX+wirO8LVGg+a6amEXXjqxhM5ZxNFPvX1Odocn5ZwB7HCn4hWI42wxD6KWUBVfIZxXd9J2zNhHFmro2Gx3QPKSReGCiV40ESM/A1NcxTDnn7HvLFViXBRZ6MKJnmwaktca/lFzO4fZG7n5e0D9cK4DjFI69yrGbwvhqP7KWp7kR99QrQAn3cW5N5/SQ1rivDgdUCUegFfkDkKF26TG7FijzZoS0sM7kM7D6gncvgG5d7cEdu6wN+v3R/cRwQgaAdnA2vACQvn9Tk6NNqjtwjis1Iyp4JOpafwvu3ZAYa3TV2fBjBnjfe8uLKErOZLk6fU//lcMvhuSrh7MzMwcAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDctMjBUMTA6NTA6MTErMDI6MDCDfj0WAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA3LTIwVDEwOjUwOjExKzAyOjAw8iOFqgAAAABJRU5ErkJggg==</mdui:Logo>
<mdui:InformationURL xml:lang="fr">http://www.renater.fr</mdui:InformationURL>
<mdui:Description xml:lang="en">eduGAIN Access Check allows administrators of a Service Provider (SP) registered in eduGAIN to create test accounts with different profiles to validate the behaviour and test federated login. The test accounts can only be used to access own services.</mdui:Description>
<mdui:DisplayName xml:lang="fr">eduGAIN Access Check</mdui:DisplayName>
<mdui:Description xml:lang="fr">eduGAIN Access Check allows administrators of a Service Provider (SP) registered in eduGAIN to create test accounts with different profiles to validate the behaviour and test federated login. The test accounts can only be used to access own services.</mdui:Description>
</mdui:UIInfo>
</md:Extensions>
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIID2zCCAsOgAwIBAgIJAJpdV2MFitUqMA0GCSqGSIb3DQEBBQUAMIGDMQswCQYD
VQQGEwJGUjEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MQ4wDAYDVQQKDAVHRUFOVDEd
MBsGA1UEAwwUdGVzdC1pZHAuZWR1Z2Fpbi5vcmcxLjAsBgkqhkiG9w0BCQEWH3Rl
c3RpZHBhY2NvdW50bWFuYWdlckBnZWFudC5uZXQwHhcNMTQxMjE4MTAxODU5WhcN
MjQxMjE3MTAxODU5WjCBgzELMAkGA1UEBhMCRlIxFTATBgNVBAcMDERlZmF1bHQg
Q2l0eTEOMAwGA1UECgwFR0VBTlQxHTAbBgNVBAMMFHRlc3QtaWRwLmVkdWdhaW4u
b3JnMS4wLAYJKoZIhvcNAQkBFh90ZXN0aWRwYWNjb3VudG1hbmFnZXJAZ2VhbnQu
bmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo48FFP0P/81e3WHb
U91F/TYDZC/JypEqO2XQNH50baXpk2JrJFVFOWdgdK6qWHsLznuxngRsfOasAaVA
Ob1Bf3g2xgPUd2htSLxds+o/Y24DOM6ZairxbWJk2rOvLhJFchlrcNWCpMtUCkfJ
xmqGmeo93XAud5byj3wQ1NuH2o8rjTPAkMgQdr8D2b8EG1NYEH00AqRlXZTFCWGL
KDEuZwyta6vgMQYT4K6UF/F+HWF2wzbmVgRTHguJ0rzNqz6t+9CtLkhyZO+/57Ro
4U0ikshVWkUOENPKCnB1t+ebs/AsNozbIGA/HcdtwUwDgIowv/K0hdnLDC1vz6/S
F3rnGQIDAQABo1AwTjAdBgNVHQ4EFgQUgWN9jmJxOEHYU5m8D0atl895HxowHwYD
VR0jBBgwFoAUgWN9jmJxOEHYU5m8D0atl895HxowDAYDVR0TBAUwAwEB/zANBgkq
hkiG9w0BAQUFAAOCAQEAXvlBHMaBK6m0PQNanTqGBRdRAFt8Xkr5texD5mPTmS/7
nqnxlN0orqYWGCaARmQE+T77EB2a2n9g2s130pUXwJxcbUwIOdPKH6CMKEHT/512
bndJXQ3DyhkuVSLtRFOdfleIhi8qUkNC9FWxM4jDHDTTQtNEHnCjFxlhxw+ri5QJ
AVKpH9MkcuIkM6Jx+QhNwTDwCRIJffoDOH420yR5EWx/sQ4tjKQGiFOPv/WHFjXd
LqHU+X8ErzxeNmUHHST6pHePWRCMtoPTdCPhEroJhou6NMHh8ylQOIVHt6gggc7r
kUWMUybDUxPp49qMeNkdKqFPby2aW7ouKRoOXuxZhg==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://access-check.edugain.org/simplesaml/saml2/idp/SSOService.php"/>
</md:IDPSSODescriptor>
<md:Organization>
<md:OrganizationName xml:lang="en">eduGAIN Access Check</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en">eduGAIN Access Check</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en">http://www.renater.fr</md:OrganizationURL>
</md:Organization>
<md:ContactPerson contactType="technical">
<md:EmailAddress>edugain-integration@geant.net</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor><md:EntityDescriptor entityID="https://aishib.agropolis.fr/idp/shibboleth">
<md:Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://federation.renater.fr/" registrationInstant="2013-06-06T11:49:20Z">
<mdrpi:RegistrationPolicy xml:lang="en">https://services.renater.fr/federation/en/metadata_registration_practice_statement</mdrpi:RegistrationPolicy>
</mdrpi:RegistrationInfo>
</md:Extensions>
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:2.0:protocol">
<md:Extensions>
<shibmd:Scope regexp="false">agropolis.fr</shibmd:Scope>
<mdui:UIInfo>
<mdui:DisplayName xml:lang="en">Agropolis International</mdui:DisplayName>
<mdui:Logo height="16" width="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAACPUlEQVQoz21SPW8TQRR8u7d3ju34Er6UCHACRqK4Bjk0oDSEjiYSBQVS8k9AkWgp+AuUASGEaCASkoPcgARVMF8iTnxJwMFJfL47397u3u6jsGVFwLzmFTN6ozdDEBEAAOD4kiRJsVgkhMA/YMfZzc3NVstnzGq1/KXlJfgf2Ii9XquVZ2YWbi5Io4MsbfPeZK4wRm0AOH6KICIivq2tV6/O5cYLHztbW9FvYTKuZaLk7PjpW+UrJXtspCHGmGazCQBnZ8svtj/0tbAINYhcy1DyThpRhHtztyedwkBDAWBnZ6dSqbzZ+7THu0IraTJplDSZ0JnQ2Y+482jj1cgSRUTHdrhW9fa3SKaxErFKIyUiKaIsjVQaKf5s631HxP1+X2vNwjB0J9zd+OgnD044Ra4lI5ZBw7XqyeRQREciaqe9xoE/K/OFfIENnqBM1uZBqlWBOYxQjYZnqieTThru8zCU3AASIAjIXNellGLePkjCUPICy1mEDAShSg7SqCsTBtQ7WfY3vlarVUYpdUsuAs5PXV7dfpe3HEYtjSbNZJwJoRUi3rl4fSrvfufctm0ySA0RD0V84+WDL1EbCCDCYIDApeKZ+uKK6faDIPA8jw7jIORUbry2eH+5Mu8ARTSAkCPW3QvX6osrE+B8bjQ8zxu2aACDaIwxxuzzsLbbePj88a8k0Mb4vr/2ei3LMoOIiGRU0iGGVuDp6pNz5fNSiKnpac/zgAABMuzSXwIggIjdbrdUKjHGYGQaAAD+AJBJecXxnEvWAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTA3LTIwVDEwOjQ4OjE1KzAyOjAwpWiGMQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0wNy0yMFQxMDo0ODoxNSswMjowMNQ1Po0AAAAASUVORK5CYII=</mdui:Logo>
<mdui:InformationURL xml:lang="fr">http://www.agropolis.fr</mdui:InformationURL>
<mdui:DisplayName xml:lang="fr">Agropolis International</mdui:DisplayName>
</mdui:UIInfo>
</md:Extensions>
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIDNzCCAh+gAwIBAgIUYY3sGXwChkj2CRy6QFDvkdj2zlAwDQYJKoZIhvcNAQEF
BQAwHjEcMBoGA1UEAxMTYWlzaGliLmFncm9wb2xpcy5mcjAeFw0xMzA1MTUxMzM3
MTJaFw0zMzA1MTUxMzM3MTJaMB4xHDAaBgNVBAMTE2Fpc2hpYi5hZ3JvcG9saXMu
ZnIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxrDy6lrhIBjcxv16n
4UJ2cEMYPO4wSmfDwhO6feoSIEuIblYRHE2nQKirMokwD6seF4rbDHyxLXg/ColL
VLv+0CJteIOZjSCgSN90WzQRrC1Ex5sJfPu6yPEXvW8H1906gEg6ok8rlCIHRGfE
15pHK5eqxQS5f2n8c2t/Uk33/FBj79/hb3Cd7vE4mdlvReD3AFswC0lV4bPmj3Ka
KUuMj9xwipwnfWCu6p2/ZJF4M3ADU5grXHJ2Vqmd8DWm5raaObKjYwJddbRBByI8
bJJLIwAQQmX4Dh4hf1QKlf2oqWPWVQxLQp0erL1U8IWmj1RG8TTH9xOJl6kkEhYq
Z2gfAgMBAAGjbTBrMEoGA1UdEQRDMEGCE2Fpc2hpYi5hZ3JvcG9saXMuZnKGKmh0
dHBzOi8vYWlzaGliLmFncm9wb2xpcy5mci9pZHAvc2hpYmJvbGV0aDAdBgNVHQ4E
FgQU9A7iQ8Qo+t2JCpKuOOV9YBoYs4MwDQYJKoZIhvcNAQEFBQADggEBAG0LOW6I
F+M8n2NpzyQjfVCJCA6QhWjbXrfemiPJFZGZZb2dVmHof4yCpCUYgHOBoZaXPOlB
nLYsUWvFZ6V2GELZpLHzHSSrYidieW07qQkh1DwcIYpvtZgLviOtT/tCEGsk925f
DUoGdeIqpqt54WZcW9+TbKicvjg3JT4BFOQ17bFNwPW+YjTbvsWYxen+e0mRp4vM
V0yMu2f3bccVhePASSZGL3yod3sJ1dPvlrJO9c35BekhtirolVjZqMQ0AYPVifua
yIU0dWXsZkAOcBL9kZFbJcYRUIxMgvp8U2Zdv1+ZlwOyXnnWDOOh9wjuT7FAyObU
ChvjHlgZHkvLwJI=
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://aishib.agropolis.fr/idp/profile/SAML2/POST/SSO"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://aishib.agropolis.fr/idp/profile/SAML2/Redirect/SSO"/>
<md:SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://aishib.agropolis.fr/idp/profile/Shibboleth/SSO"/>
</md:IDPSSODescriptor>
<md:Organization>
<md:OrganizationName xml:lang="en">Agropolis International</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en">Agropolis International</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en">http://www.agropolis.fr</md:OrganizationURL>
</md:Organization>
<md:ContactPerson contactType="technical">
<md:SurName>Jean Cerda</md:SurName>
<md:EmailAddress>cerda@agropolis.fr</md:EmailAddress>
</md:ContactPerson>
<md:ContactPerson contactType="technical">
<md:SurName>Jean-Pierre Allano</md:SurName>
<md:EmailAddress>allano@agropolis.fr</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor><md:EntityDescriptor entityID="https://ambre.vetagro-sup.fr/idp/shibboleth">
<md:Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://federation.renater.fr/" registrationInstant="2013-01-14T16:11:53Z">
<mdrpi:RegistrationPolicy xml:lang="en">https://services.renater.fr/federation/en/metadata_registration_practice_statement</mdrpi:RegistrationPolicy>
</mdrpi:RegistrationInfo>
</md:Extensions>
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:2.0:protocol">
<md:Extensions>
<shibmd:Scope regexp="false">vetagro-sup.fr</shibmd:Scope>
<mdui:UIInfo>
<mdui:DisplayName xml:lang="en">Vetagro Sup</mdui:DisplayName>
<mdui:Logo height="16" width="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAAB/klEQVQ4y2NkQAP///+X+/jxI/PO7dujP3/7kf7v778ffDzciw2MDFaqq6t/Y2RkfIysngndAEZGxkezZ8/25xEQqVDTs5eRVrNU4RQUL7x9+7YtumasBjAwMDBISIgbcvBKct998p7h1fvfDKyc4nz//jF6yjAwSBNlwM+fP3/9/PmT4dbl4wysrCwMf//9Z/r7959UcFISD1EGPH107xgfD9sbTg52hrcvHjDw87Aw/Pz+7tLEefNuEmWAm6ffxvu3Ll4zMjZleHz/KsO7lw+f3bh+czs2tVgNsLS0fPfs4b3VnKy//wrycW84e2L/uobmtg0MpIKurt6N////Z8jPzxcnWTMDAwPD79//tbq7+9bhU8OMTfD//8cMP79L1X/8tjxMQYHXT0Uh88aBgyuvEW3Aly+8ntw8jLU3bx20cnH/xPz2jTyvk9OGpTt3NhIOxP//GRgkJGR8tPVeyElIvWA4dfIqg57Bff0nD+eHExULIb5dqkYmYgYm5r8YPH3vMzx//omBk+edpI4+vxVRBnz5zPqbi4vt7a9fv//9+cvAYG79jIGZmZWBg4NJiCgDdh4sfHD/7u9j714Z/BYWiGBQVkxjePNK8+erV5+uYDOABTMM/nP09y9Z8+OHgNjli9ahf//++8vGwrlAS0tp/v///7kYGRm/IasHAIVTy8DG/VpJAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTA3LTIwVDEwOjUwOjA5KzAyOjAwfDtz7wAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0wNy0yMFQxMDo1MDowOSswMjowMA1my1MAAAAASUVORK5CYII=</mdui:Logo>
<mdui:InformationURL xml:lang="fr">http://www.vetagro-sup.fr</mdui:InformationURL>
<mdui:DisplayName xml:lang="fr">Vetagro Sup</mdui:DisplayName>
</mdui:UIInfo>
</md:Extensions>
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIDPDCCAiSgAwIBAgIVAL9PsuadPSIZcMHNxlK/oevezmzWMA0GCSqGSIb3DQEB
BQUAMB8xHTAbBgNVBAMTFGFtYnJlLnZldGFncm8tc3VwLmZyMB4XDTEyMTEwODEw
MTQwNFoXDTMyMTEwODEwMTQwNFowHzEdMBsGA1UEAxMUYW1icmUudmV0YWdyby1z
dXAuZnIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc/ptfpmkomwmT
4RsID+1Ce1dX0eUjcLgSOZN8hVpHWLag2ERWkpmvB5aK7BAFcI5i//Gk80tAiasu
JtlZhBnEw54aTJRGpyL2CVkHyl6SMRxprIi1Ji67IoGqEgUeGaheAxo+tG5e1WSc
bIbldcSKdwvjAV+7HSB4C6NqLsAzJH25++yaRH2uf2LTD0TDzNR9Q2hVj/VyYWR+
K3HWI1Snjn/i7aFfZZhYmBkwHuQOaPhwCM+khikg5XicMsxUhHCMi93UgHGIsdkr
IEGj4xydBTUKsLaykeuFS8EgXbWwCLGkeX76w8xDoFIpnppU/yFd9v7Zg3EBfn4p
kTW3GdIjAgMBAAGjbzBtMEwGA1UdEQRFMEOCFGFtYnJlLnZldGFncm8tc3VwLmZy
hitodHRwczovL2FtYnJlLnZldGFncm8tc3VwLmZyL2lkcC9zaGliYm9sZXRoMB0G
A1UdDgQWBBTPTqWkVHrHXFjmxMWkNt/sp2h5ozANBgkqhkiG9w0BAQUFAAOCAQEA
FvXMtfBUmRZCzz8CjanGzr1TBUPmnkrKci5AtkseKw9YlfUmBXTHB01y697nYq6m
RB6KhvfW212h9CF0IOEEjoadgDhXqGYhq8PnAOtT4Ty3XDy8SbRh8aQWfvnfSngv
FdpHRiSpj5UXXuT5zTtkf59h58XKtEfCkMbUzvdOgUobJzpD0WISmQHPQnx+Neg6
9j7oMRrDiZjS39Om8Imu9xvsnddDM3PlsDBIsvrr1o7K5iLkEdR1YYX0ZNDbiFuw
QXXl2dwQPB8KrScPUvCe57slU2gFQvvIBzjQysxC6V6TPSuM3A/ee56lACuB3jKj
oYkHQc5Gj/1rSMLmu9aLMg==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://ambre.vetagro-sup.fr/idp/profile/SAML2/POST/SSO"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://ambre.vetagro-sup.fr/idp/profile/SAML2/Redirect/SSO"/>
<md:SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://ambre.vetagro-sup.fr/idp/profile/Shibboleth/SSO"/>
</md:IDPSSODescriptor>
<md:Organization>
<md:OrganizationName xml:lang="en">Vetagro Sup</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en">Vetagro Sup</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en">http://www.vetagro-sup.fr</md:OrganizationURL>
</md:Organization>
<md:ContactPerson contactType="technical">
<md:SurName>Nicolas Aulas</md:SurName>
<md:EmailAddress>nicolas.aulas@vetagro-sup.fr</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor><md:EntityDescriptor entityID="https://antimoine.insa-strasbourg.fr/idp/shibboleth">
<md:Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://federation.renater.fr/" registrationInstant="2014-02-11T08:44:08Z">
<mdrpi:RegistrationPolicy xml:lang="en">https://services.renater.fr/federation/en/metadata_registration_practice_statement</mdrpi:RegistrationPolicy>
</mdrpi:RegistrationInfo>
</md:Extensions>
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:2.0:protocol">
<md:Extensions>
<shibmd:Scope regexp="false">insa-strasbourg.fr</shibmd:Scope>
<mdui:UIInfo>
<mdui:DisplayName xml:lang="en">INSA Strasbourg</mdui:DisplayName>
<mdui:Logo height="16" width="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAq1BMVEXeAACEhoTWz87nQTn3oqXnIBjvgnvWlpT/5+fnEAjvZWOltrXnNDH3mpT/9/fnCAD/4+fvioz3x8bnVVL3qq3nKCnvkpTnHBjvcXP3sq3vgoT/7+/nFBDnODH3mpz////nDAj3z87vlpTveXv3vr3nAACMmpznRUL3pqXnJCHnFAj/+//nDADvjoz3y87vXVr3rq3nLCnvdXP3srXvhoT/8/fvODH3npz3lpQaie6kAAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAAAe0lEQVQY053OwQqCQBhF4VM22VSMMWrFGP2kkIpUQ1nz/m8Ws20TeFeHb3WRnzEBBjO8xRjZrURi0TFiy+UITjTpjIKaOndZuDSGxF0j9G1+e7CuLN1nE2F7VI28tAoqMMezP1ieFOOp7RPueBXKSqdnMq8Wg66nPP0LX4uIG4jEwJ0sAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTA3LTIwVDEwOjQ5OjA0KzAyOjAwIHfmJQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0wNy0yMFQxMDo0OTowNCswMjowMFEqXpkAAAAASUVORK5CYII=</mdui:Logo>
<mdui:InformationURL xml:lang="fr">http://www.insa-strasbourg.fr</mdui:InformationURL>
<mdui:DisplayName xml:lang="fr">INSA Strasbourg</mdui:DisplayName>
</mdui:UIInfo>
</md:Extensions>
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIDUDCCAjigAwIBAgIVAIbX8U0uAqAhuXm1jWxiFpggtDTDMA0GCSqGSIb3DQEB
CwUAMCQxIjAgBgNVBAMMGXNvdWZyZS5pbnNhLXN0cmFzYm91cmcuZnIwHhcNMTYw
OTI3MTIzNjIxWhcNMzYwOTI3MTIzNjIxWjAkMSIwIAYDVQQDDBlzb3VmcmUuaW5z
YS1zdHJhc2JvdXJnLmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
sEE02sLRPAG5N81DMHEeGpI2MYF8yG/RiwH07cFIlLqgV80ewOmi0FWPYijxMb8A
bmx0RwUMvJBVI6WMxtT9fykhID20k8rWOuYOzvaynzVqCktqVgKoEAxP1PFE9b0n
iGKFprjjNl9ZD90GOUsxbAO7yXG9Q4WBa/eThl6XkUvNkSaZp5hcdWrgcAdsae3q
iD/uxFa38NXNNeRLGyfxjd2K5qYSzbwBza9s9TOq1+pfw7sxu3/4BnfQ0RLGO6co
4tH4Mufh0ome4cyYk4pvW5DOd1AznxDb8HpqvE0zwEsa69c/FDX0akgFZydmc77a
j6USn6JKjjbO49yGtG1gVQIDAQABo3kwdzAdBgNVHQ4EFgQUjzMsxZYiokPYxper
9zadM8J0F0kwVgYDVR0RBE8wTYIZc291ZnJlLmluc2Etc3RyYXNib3VyZy5mcoYw
aHR0cHM6Ly9zb3VmcmUuaW5zYS1zdHJhc2JvdXJnLmZyL2lkcC9zaGliYm9sZXRo
MA0GCSqGSIb3DQEBCwUAA4IBAQBFJKsiS3yfWuDB/E+iqQ0TuQJzL5+JIcloN0dw
BFxW3VZOju15zeQ7LwRBg9S4SGLMPJU+LM1lvr68cK9brut/FjF51SETIXEeCWo3
7+PIqgOCzraLNinmpU/OtN8ENalOPvpS6Jvbd23qB2t+IqOtZ+j15b0Yq4/on1E3
W2F9CVzKpe4EwmmtCPQbe7U1wvhgFylEx797pex8veWs79YSYwqvcKMh79dzl8Fo
/CgsO5pDrfKmc6SGMkByq75dZj+PqhZDzZ9EFTxbrXOTaS08VRN6a5Rh2iYRnGxq
yZl66tPcaIm5PHgOEmu5X4lPkUoY+Jt36Gj3SGCbYt8qH5S0
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIDXDCCAkSgAwIBAgIVAKI+qiqDCk9wTTqn7OVAoZrvj/CpMA0GCSqGSIb3DQEB
BQUAMCcxJTAjBgNVBAMTHGFudGltb2luZS5pbnNhLXN0cmFzYm91cmcuZnIwHhcN
MTQwMTEzMTAzOTU4WhcNMzQwMTEzMTAzOTU4WjAnMSUwIwYDVQQDExxhbnRpbW9p
bmUuaW5zYS1zdHJhc2JvdXJnLmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAtuM8lRjlVjjmrHq9VtguaOMQL+Wd99BiOs56kL3Mbctg1FwH69LYThCW
6dOz6WJg/jU/naF7jEikXKc71xGyu7Ph7Iqa9S5hoXXAT8u/0q2nZDeTOraJqKe1
FMF2RzXhEEMyQO3CiKNK9b+tbKoNZS7FQCixMZklWZPt4EcEKd6jyRq1WYX3dpnb
r9I/aCdhtK/PGvGe5gKTDoTR2HKyWKJTc/obf8x/vlYIEwiaGgdlqI2KiBE0x48n
zQdP6XVi3T8ZWbnkLmCfgJtP2C8PtEJuwDRAy0Z9N4DSwvxn5YCVYgBLSi0TLa10
B/lUqqBezZrTrA9p9Lt8JtGXW5YGHwIDAQABo38wfTBcBgNVHREEVTBTghxhbnRp
bW9pbmUuaW5zYS1zdHJhc2JvdXJnLmZyhjNodHRwczovL2FudGltb2luZS5pbnNh
LXN0cmFzYm91cmcuZnIvaWRwL3NoaWJib2xldGgwHQYDVR0OBBYEFLFkjPZUc9JY
qrWjldJ/iGGkKAt4MA0GCSqGSIb3DQEBBQUAA4IBAQBSk/wU1mRn4VF2ifmy261K
DK7uX+t1H1hh8S38fKSFU7HoNXJTV3vQnmBOpYIGC1gtvmb+qjqpNtikU2zO84Gq
Q0bXHxYF2d9RUP89mKaFxE5uNcXFmlOA3ChZY3pMT5zwAPI/T60tGrex7zci7OLn
JDAQj/q4Yk9ejx6JTFggQSCCVh+oV/SDIMd2p5AY6H3mto3b6XCk7Lssa8a/D30k
pEkZnhTKdN82eRyynuOR7UDU4tasV4d7Mi/j53f5ihnRcsvwh/pYodjoVYY8cEcZ
JLnAXYF8coSwh8UN4D/0NHsvTuSOFQc85hGrqacMsvxiQiw9mv01AX5+A5YLEbVQ
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://antimoine.insa-strasbourg.fr/idp/profile/SAML2/Redirect/SLO"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://antimoine.insa-strasbourg.fr/idp/profile/SAML2/POST/SLO"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://antimoine.insa-strasbourg.fr/idp/profile/SAML2/SOAP/SLO"/>
<md:NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://antimoine.insa-strasbourg.fr/idp/profile/SAML2/POST/SSO"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://antimoine.insa-strasbourg.fr/idp/profile/SAML2/Redirect/SSO"/>
<md:SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://antimoine.insa-strasbourg.fr/idp/profile/Shibboleth/SSO"/>
</md:IDPSSODescriptor>
<md:Organization>
<md:OrganizationName xml:lang="en">INSA Strasbourg</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en">INSA Strasbourg</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en">http://www.insa-strasbourg.fr</md:OrganizationURL>
</md:Organization>
<md:ContactPerson contactType="technical">
<md:SurName>Lahsen BOUZID</md:SurName>
<md:EmailAddress>lahsen.bouzid@insa-strasbourg.fr</md:EmailAddress>
</md:ContactPerson>
<md:ContactPerson contactType="technical">
<md:SurName>Simon SCHERRER</md:SurName>
<md:EmailAddress>simon.scherrer@insa-strasbourg.fr</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor>
<md:EntityDescriptor entityID="http://idp5/metadata">
<md:IDPSSODescriptor
WantAuthnRequestsSigned="true"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data><ds:X509Certificate>
MIIDnjCCAoagAwIBAgIBATANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJGUjEP
MA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJpczETMBEGA1UEChMKRW50cm91
dmVydDEPMA0GA1UEAxMGRGFtaWVuMB4XDTA2MTAyNzA5MDc1NFoXDTExMTAyNjA5
MDc1NFowVDELMAkGA1UEBhMCRlIxDzANBgNVBAgTBkZyYW5jZTEOMAwGA1UEBxMF
UGFyaXMxEzARBgNVBAoTCkVudHJvdXZlcnQxDzANBgNVBAMTBkRhbWllbjCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM06Hx6VgHYR9wUf/tZVVTRkVWNq
h9x+PvHA2qH4OYMuqGs4Af6lU2YsZvnrmRdcFWv0+UkdAgXhReCWAZgtB1pd/W9m
6qDRldCCyysow6xPPKRz/pOTwRXm/fM0QGPeXzwzj34BXOIOuFu+n764vKn18d+u
uVAEzk1576pxTp4pQPzJfdNLrLeQ8vyCshoFU+MYJtp1UA+h2JoO0Y8oGvywbUxH
ioHN5PvnzObfAM4XaDQohmfxM9Uc7Wp4xKAc1nUq5hwBrHpjFMRSz6UCfMoJSGIi
+3xJMkNCjL0XEw5NKVc5jRKkzSkN5j8KTM/k1jPPsDHPRYzbWWhnNtd6JlkCAwEA
AaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0
ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFP2WWMDShux3iF74+SoO1xf6qhqaMB8G
A1UdIwQYMBaAFGjl6TRXbQDHzSlZu+e8VeBaZMB5MA0GCSqGSIb3DQEBBQUAA4IB
AQAZ/imK7UMognXbs5RfSB8cMW6iNAI+JZqe9XWjvtmLfIIPbHM96o953SiFvrvQ
BZjGmmPMK3UH29cjzDx1R/RQaYTyMrHyTePLh3BMd5mpJ/9eeJCSxPzE2ECqWRUa
pkjukecFXqmRItwgTxSIUE9QkpzvuQRb268PwmgroE0mwtiREADnvTFkLkdiEMew
fiYxZfJJLPBqwlkw/7f1SyzXoPXnz5QbNwDmrHelga6rKSprYKb3pueqaIe8j/AP
NC1/bzp8cGOcJ88BD5+Ny6qgPVCrMLE5twQumJ12V3SvjGNtzFBvg2c/9S5OmVqR
LlTxKnCrWAXftSm1rNtewTsF
</ds:X509Certificate></ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:KeyValue>
MIIDnjCCAoagAwIBAgIBATANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJGUjEP
MA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJpczETMBEGA1UEChMKRW50cm91
dmVydDEPMA0GA1UEAxMGRGFtaWVuMB4XDTA2MTAyNzA5MDc1NFoXDTExMTAyNjA5
MDc1NFowVDELMAkGA1UEBhMCRlIxDzANBgNVBAgTBkZyYW5jZTEOMAwGA1UEBxMF
UGFyaXMxEzARBgNVBAoTCkVudHJvdXZlcnQxDzANBgNVBAMTBkRhbWllbjCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM06Hx6VgHYR9wUf/tZVVTRkVWNq
h9x+PvHA2qH4OYMuqGs4Af6lU2YsZvnrmRdcFWv0+UkdAgXhReCWAZgtB1pd/W9m
6qDRldCCyysow6xPPKRz/pOTwRXm/fM0QGPeXzwzj34BXOIOuFu+n764vKn18d+u
uVAEzk1576pxTp4pQPzJfdNLrLeQ8vyCshoFU+MYJtp1UA+h2JoO0Y8oGvywbUxH
ioHN5PvnzObfAM4XaDQohmfxM9Uc7Wp4xKAc1nUq5hwBrHpjFMRSz6UCfMoJSGIi
+3xJMkNCjL0XEw5NKVc5jRKkzSkN5j8KTM/k1jPPsDHPRYzbWWhnNtd6JlkCAwEA
AaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0
ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFP2WWMDShux3iF74+SoO1xf6qhqaMB8G
A1UdIwQYMBaAFGjl6TRXbQDHzSlZu+e8VeBaZMB5MA0GCSqGSIb3DQEBBQUAA4IB
AQAZ/imK7UMognXbs5RfSB8cMW6iNAI+JZqe9XWjvtmLfIIPbHM96o953SiFvrvQ
BZjGmmPMK3UH29cjzDx1R/RQaYTyMrHyTePLh3BMd5mpJ/9eeJCSxPzE2ECqWRUa
pkjukecFXqmRItwgTxSIUE9QkpzvuQRb268PwmgroE0mwtiREADnvTFkLkdiEMew
fiYxZfJJLPBqwlkw/7f1SyzXoPXnz5QbNwDmrHelga6rKSprYKb3pueqaIe8j/AP
NC1/bzp8cGOcJ88BD5+Ny6qgPVCrMLE5twQumJ12V3SvjGNtzFBvg2c/9S5OmVqR
LlTxKnCrWAXftSm1rNtewTsF
</ds:KeyValue>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:ArtifactResolutionService isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://idp5/artifact" />
<md:SingleLogoutService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://idp5/singleLogoutSOAP" />
<md:SingleLogoutService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://idp5/singleLogout"
ResponseLocation="http://idp5/singleLogoutReturn" />
<md:ManageNameIDService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://idp5/manageNameIdSOAP" />
<md:ManageNameIDService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://idp5/manageNameId"
ResponseLocation="http://idp5/manageNameIdReturn" />
<md:SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://idp5/singleSignOn" />
<md:SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://idp5/singleSignOnSOAP" />
</md:IDPSSODescriptor>
<md:AuthnAuthorityDescriptor
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:AuthnQueryService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://idp6/authnQueryService"/>
<md:AssertionIDRequestService Binding="urn:oasis:names:tc:SAML:2.0:bindings:URI" Location="http://idp6/authnAuthAssertionIDRequestService"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
</md:AuthnAuthorityDescriptor>
<md:PDPDescriptor
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:AuthzService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://idp6/authzService"/>
<md:AssertionIDRequestService Binding="urn:oasis:names:tc:SAML:2.0:bindings:URI" Location="http://idp6/PDPAuthAssertionIDRequestService"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:kerberos</md:NameIDFormat>
</md:PDPDescriptor>
<md:AttributeAuthorityDescriptor
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:AttributeService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://idp6/attributeService"/>
<md:AssertionIDRequestService Binding="urn:oasis:names:tc:SAML:2.0:bindings:URI" Location="http://idp6/AttributeAuthAssertionIDRequestService"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</md:NameIDFormat>
</md:AttributeAuthorityDescriptor>
<md:Organization>
<md:OrganizationName xml:lang="en">Entr'ouvert</md:OrganizationName>
</md:Organization>
</md:EntityDescriptor>
</md:EntitiesDescriptor>

View File

@ -89,7 +89,7 @@ def test_provision_user_attributes(settings, django_user_model, caplog):
assert user.email == 'test@example.net'
assert user.is_superuser is False
assert user.is_staff is False
assert len(caplog.records) == 4
assert len(caplog.records) == 6
assert 'created new user' in caplog.text
assert 'set field first_name' in caplog.text
assert 'set field last_name' in caplog.text
@ -102,7 +102,7 @@ def test_provision_user_groups(settings, django_user_model, caplog):
user = SAMLBackend().authenticate(saml_attributes=saml_attributes)
assert user.groups.count() == 3
assert set(user.groups.values_list('name', flat=True)) == set(saml_attributes['group'])
assert len(caplog.records) == 4
assert len(caplog.records) == 6
assert 'created new user' in caplog.text
assert 'adding group GroupA' in caplog.text
assert 'adding group GroupB' in caplog.text
@ -112,7 +112,7 @@ def test_provision_user_groups(settings, django_user_model, caplog):
user = SAMLBackend().authenticate(saml_attributes=saml_attributes2)
assert user.groups.count() == 2
assert set(user.groups.values_list('name', flat=True)) == set(saml_attributes2['group'])
assert len(caplog.records) == 5
assert len(caplog.records) == 9
assert 'removing group GroupA' in caplog.records[-1].message
@ -142,7 +142,7 @@ def test_provision_absent_attribute(settings, django_user_model, caplog):
del local_saml_attributes['email']
user = SAMLBackend().authenticate(saml_attributes=local_saml_attributes)
assert not user.email
assert len(caplog.records) == 4
assert len(caplog.records) == 6
assert 'created new user' in caplog.text
assert re.search(r'invalid reference.*email', caplog.text)
assert 'set field first_name' in caplog.text
@ -160,7 +160,7 @@ def test_provision_long_attribute(settings, django_user_model, caplog):
local_saml_attributes['first_name'] = [('y' * 32)]
user = SAMLBackend().authenticate(saml_attributes=local_saml_attributes)
assert user.first_name == 'y' * 30
assert len(caplog.records) == 4
assert len(caplog.records) == 6
assert 'created new user' in caplog.text
assert 'set field first_name' in caplog.text
assert 'to value %r ' % (u'y' * 30) in caplog.text

View File

@ -0,0 +1,39 @@
import os
import time
from django.utils.text import slugify
from httmock import HTTMock
from mellon.federation_utils import get_federation_from_url, truncate_unique
from utils import sample_federation_response
def test_mock_fedmd_caching():
url = u'https://dummy.mdserver/metadata.xml'
filepath = os.path.join('metadata-cache/', truncate_unique(slugify(url)))
if os.path.isfile(filepath):
os.remove(filepath)
with HTTMock(sample_federation_response):
tmp = get_federation_from_url(url)
assert tmp == filepath
st = os.stat(filepath)
assert os.path.isfile(filepath)
assert st.st_mtime < time.time() + 3600
with HTTMock(sample_federation_response):
get_federation_from_url(url)
stnew = os.stat(filepath)
assert stnew.st_ctime == st.st_ctime
assert stnew.st_mtime == st.st_mtime
storig = os.stat(os.path.join('tests', 'federation-sample.xml'))
assert storig.st_size == st.st_size
os.remove(filepath)

View File

@ -4,7 +4,8 @@ from pytest import fixture
from django.core.urlresolvers import reverse
from mellon.utils import create_metadata
from mellon.utils import create_metadata, create_server
from django.utils.http import urlencode
from httmock import all_requests, HTTMock, response as mock_response
@ -16,6 +17,11 @@ def idp_metadata():
return open('tests/metadata.xml').read()
@fixture
def federation_metadata():
return './tests/federation-sample.xml'
@fixture
def idp_private_key():
return open('tests/idp-private-key.pem').read()
@ -43,12 +49,30 @@ def sp_settings(private_settings, idp_metadata, sp_private_key, public_key):
return private_settings
@fixture
def federated_sp_settings(private_settings, federation_metadata, sp_private_key, public_key):
private_settings.MELLON_FEDERATIONS = [{
'FEDERATION': federation_metadata,
}]
private_settings.MELLON_PUBLIC_KEYS = [public_key]
private_settings.MELLON_PRIVATE_KEYS = [sp_private_key]
private_settings.MELLON_NAME_ID_POLICY_FORMAT = lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT
private_settings.LOGIN_REDIRECT_URL = '/'
return private_settings
@fixture
def sp_metadata(sp_settings, rf):
request = rf.get('/')
return create_metadata(request)
@fixture
def federated_sp_metadata(federated_sp_settings, rf):
request = rf.get('/')
return create_metadata(request)
class MockIdp(object):
def __init__(self, idp_metadata, private_key, sp_metadata):
self.server = server = lasso.Server.newFromBuffers(idp_metadata, private_key)
@ -103,6 +127,11 @@ def idp(sp_settings, idp_metadata, idp_private_key, sp_metadata):
return MockIdp(idp_metadata, idp_private_key, sp_metadata)
@fixture
def federated_idp(federated_sp_settings, idp_metadata, idp_private_key, federated_sp_metadata):
return MockIdp(idp_metadata, idp_private_key, federated_sp_metadata)
def test_sso_slo(db, app, idp, caplog, sp_settings):
response = app.get(reverse('mellon_login'))
url, body = idp.process_authn_request_redirect(response['Location'])
@ -171,3 +200,60 @@ def test_sso_artifact(db, app, caplog, sp_settings, idp_metadata, idp_private_ke
assert 'created new user' in caplog.text
assert 'logged in using SAML' in caplog.text
assert response['Location'].endswith(sp_settings.LOGIN_REDIRECT_URL)
def test_login_federation(db, app, federated_idp, caplog, federated_sp_settings):
qs = urlencode({
'entityID': 'http://idp5/metadata',
})
response = app.get('/login/?' + qs)
url, body = federated_idp.process_authn_request_redirect(response['Location'])
assert url.endswith(reverse('mellon_login'))
response = app.post(reverse('mellon_login'), params={'SAMLResponse': body})
assert 'created new user' in caplog.text
assert 'logged in using SAML' in caplog.text
assert response['Location'].endswith(federated_sp_settings.LOGIN_REDIRECT_URL)
def test_sso_artifact_federation(db, app, caplog, federated_sp_settings, idp_metadata, idp_private_key, rf):
qs = urlencode({
'entityID': 'http://idp5/metadata',
})
federated_sp_settings.MELLON_DEFAULT_ASSERTION_CONSUMER_BINDING = 'artifact'
request = rf.get('/')
federated_sp_metadata = create_metadata(request)
idp = MockIdp(idp_metadata, idp_private_key, federated_sp_metadata)
response = app.get('/login/?' + qs)
url, body = idp.process_authn_request_redirect(response['Location'])
assert body is None
assert reverse('mellon_login') in url
assert 'SAMLart' in url
acs_artifact_url = url.split('testserver', 1)[1]
with HTTMock(idp.mock_artifact_resolver()):
response = app.get(acs_artifact_url)
assert 'created new user' in caplog.text
assert 'logged in using SAML' in caplog.text
assert response['Location'].endswith(federated_sp_settings.LOGIN_REDIRECT_URL)
# force delog
app.session.flush()
assert 'dead artifact' not in caplog.text
with HTTMock(idp.mock_artifact_resolver()):
response = app.get(acs_artifact_url)
# verify retry login was asked
assert 'dead artifact' in caplog.text
assert response.status_code == 302
assert reverse('mellon_login') in url
response = response.follow()
url, body = idp.process_authn_request_redirect(response['Location'])
reset_caplog(caplog)
# verify caplog has been cleaned
assert 'created new user' not in caplog.text
assert body is None
assert reverse('mellon_login') in url
assert 'SAMLart' in url
acs_artifact_url = url.split('testserver', 1)[1]
with HTTMock(idp.mock_artifact_resolver()):
response = app.get(acs_artifact_url)
assert 'created new user' in caplog.text
assert 'logged in using SAML' in caplog.text
assert response['Location'].endswith(federated_sp_settings.LOGIN_REDIRECT_URL)

View File

@ -1,3 +1,4 @@
import os
import re
import datetime
@ -6,11 +7,13 @@ import lasso
import requests.exceptions
from httmock import HTTMock
from mellon.utils import create_server, create_metadata, iso8601_to_datetime, flatten_datetime
from mellon.utils import create_server, create_metadata, iso8601_to_datetime, \
flatten_datetime, get_idp
import mellon.utils
from xml_utils import assert_xml_constraints
from utils import error_500, metadata_response
from utils import error_500, metadata_response, sample_federation_response, \
html_response, dummy_md_response
def test_create_server_connection_error(mocker, rf, private_settings, caplog):
@ -39,6 +42,48 @@ def test_create_server_internal_server_error(mocker, rf, private_settings, caplo
assert 'failed with error' in caplog.text
def test_load_federation_file(mocker, rf, private_settings, caplog, tmpdir):
private_settings.MELLON_FEDERATIONS = [
{'FEDERATION': 'tests/federation-sample.xml'},
]
request = rf.get('/')
assert 'failed with error' not in caplog.text
with HTTMock(html_response):
server = create_server(request)
assert len(server.providers) == 5
def test_load_federation_url(mocker, rf, private_settings, caplog, tmpdir):
private_settings.MELLON_FEDERATIONS = [
{'FEDERATION': 'https://dummy.server/metadata.xml'},
]
request = rf.get('/')
assert 'failed with error' not in caplog.text
with HTTMock(dummy_md_response):
server = create_server(request)
assert len(server.providers) == 3
def test_federation_parameters(mocker, rf, private_settings, caplog, tmpdir):
private_settings.MELLON_FEDERATIONS = [{
'FEDERATION': 'tests/federation-sample.xml',
'VERIFY_SSL_CERTIFICATE': False,
'ERROR_REDIRECT_AFTER_TIMEOUT': 150,
'PROVISION': True
}]
request = rf.get('/')
assert 'failed with error' not in caplog.text
with HTTMock(html_response):
server = create_server(request)
assert len(server.providers) == 5
for entity_id in server.providers.keys():
idp = get_idp(entity_id)
assert idp
assert idp['VERIFY_SSL_CERTIFICATE'] is False
assert idp['ERROR_REDIRECT_AFTER_TIMEOUT'] == 150
assert idp['PROVISION'] is True
def test_create_server_invalid_metadata(mocker, rf, private_settings, caplog):
private_settings.MELLON_IDENTITY_PROVIDERS = [
{
@ -49,8 +94,8 @@ def test_create_server_invalid_metadata(mocker, rf, private_settings, caplog):
assert not 'failed with error' in caplog.text
with HTTMock(error_500):
create_server(request)
assert len(caplog.records) == 1
assert re.search('METADATA.*is invalid', caplog.text)
assert len(caplog.records) == 5
assert re.search('METADATA.*is invalid|bad metadata in idp', caplog.text)
def test_create_server_invalid_metadata_file(mocker, rf, private_settings, caplog):
@ -70,13 +115,11 @@ def test_create_server_invalid_metadata_file(mocker, rf, private_settings, caplo
def test_create_server_good_metadata_file(mocker, rf, private_settings, caplog):
private_settings.MELLON_IDENTITY_PROVIDERS = [
{
'METADATA': '/xxx',
'METADATA': './tests/metadata.xml',
}
]
request = rf.get('/')
with mock.patch(
'mellon.adapters.file', mock.mock_open(read_data=file('tests/metadata.xml').read()),
create=True):
with HTTMock(html_response):
server = create_server(request)
assert 'ERROR' not in caplog.text
assert len(server.providers) == 1

View File

@ -16,6 +16,16 @@ def metadata_response(url, request):
return response(200, content=file('tests/metadata.xml').read())
@all_requests
def dummy_md_response(url, request):
return response(200, content=file('tests/dummy_md.xml').read())
@all_requests
def sample_federation_response(url, request):
return response(200, content=file('tests/federation-sample.xml').read())
def reset_caplog(cap):
cap.handler.stream.truncate(0)
cap.handler.records = []