From 085d5b1a893b59af797dc530a5abdac1df118647 Mon Sep 17 00:00:00 2001 From: John Dennis Date: Sep 02 2015 01:26:54 +0000 Subject: Define PAOS AssertionConsumerService in ipsilon-client-install A SAML SP will not be able to perform ECP unless a AssertionConsumerService for the PAOS binding has been defined in it's metadata. The PAOS AssertionConsumerService participates in the ECP protocol exchange, specifically it's where the ECP client sends the IdP Assertion. If lasso starts to engage in an ECP transaction by trying to generate a Samlp:AuthnRequest and no PAOS AssertionConsumerService is defined in the SP metadata it will fail with a unknown provider error. Note, AssertionConsumerService elements are indexed endpoints, there may be one per protocol binding. Now that there is more than 1 AssertionConsumerService we set the isDefault flag to True on the existing post response at index 0. This isn't strictly necessary because the spec says if the default flag isn't set on any AssertionConsumerService endpoint then the first one is selected, but it's good practice anyway. FWIW, if mod_auth_mellon is not configured with metadata then mod_auth_mellon will generate it's own metadata which includes the PAOS AssertionConsumerService. However in ipsilon-client we generate the SP metadata and were failing to add the PAOS AssertionConsumerService, something mellon would have done automatically for us. This is why this bug was only first seen using ipsilon-client-install. Ticket: 162 Signed-off-by: John Dennis Reviewed-by: Patrick Uiterwijk --- diff --git a/ipsilon/install/ipsilon-client-install b/ipsilon/install/ipsilon-client-install index 2c6df8e..1d65b5f 100755 --- a/ipsilon/install/ipsilon-client-install +++ b/ipsilon/install/ipsilon-client-install @@ -89,6 +89,7 @@ def saml2(): url_sp = url + args['saml_sp'] url_logout = url + args['saml_sp_logout'] url_post = url + args['saml_sp_post'] + url_paos = url + args['saml_sp_paos'] # Generate metadata m = Metadata('sp') @@ -99,7 +100,10 @@ def saml2(): m.add_service(SAML2_SERVICE_MAP['logout-redirect'], url_logout) if not args['no_saml_soap_logout']: m.add_service(SAML2_SERVICE_MAP['slo-soap'], url_logout) - m.add_service(SAML2_SERVICE_MAP['response-post'], url_post, index="0") + m.add_service(SAML2_SERVICE_MAP['response-post'], url_post, + index="0", isDefault="true") + m.add_service(SAML2_SERVICE_MAP['response-paos'], url_paos, + index="1") m.add_allowed_name_format(SAML2_NAMEID_MAP[args['saml_nameid']]) sp_metafile = os.path.join(path, 'metadata.xml') m.output(sp_metafile) @@ -336,6 +340,8 @@ def parse_args(): help="Single Logout URL") parser.add_argument('--saml-sp-post', default=None, help="Post response URL") + parser.add_argument('--saml-sp-paos', default=None, + help="PAOS response URL, used for ECP") parser.add_argument('--no-saml-soap-logout', action='store_true', default=False, help="Disable Single Logout over SOAP") @@ -366,7 +372,7 @@ def parse_args(): # Validate that all path options begin with '/' path_args = ['saml_base', 'saml_auth', 'saml_sp', 'saml_sp_logout', - 'saml_sp_post'] + 'saml_sp_post', 'saml_sp_paos'] for path_arg in path_args: if args[path_arg] is not None and not args[path_arg].startswith('/'): raise ValueError('--%s must begin with a / character.' % @@ -377,10 +383,11 @@ def parse_args(): if not args['saml_sp'].startswith(args['saml_base']): raise ValueError('--saml-sp must be a subpath of --saml-base.') - # The saml_sp_logout and saml_sp_post settings must be subpaths - # of saml_sp (the mellon endpoint). + # The saml_sp_logout, saml_sp_post and saml_sp_paos settings must + # be subpaths of saml_sp (the mellon endpoint). path_args = {'saml_sp_logout': 'logout', - 'saml_sp_post': 'postResponse'} + 'saml_sp_post': 'postResponse', + 'saml_sp_paos': 'paosResponse'} for path_arg, default_path in path_args.items(): if args[path_arg] is None: args[path_arg] = '%s/%s' % (args['saml_sp'].rstrip('/'), diff --git a/ipsilon/tools/saml2metadata.py b/ipsilon/tools/saml2metadata.py index 2138777..d1b8e46 100755 --- a/ipsilon/tools/saml2metadata.py +++ b/ipsilon/tools/saml2metadata.py @@ -32,7 +32,9 @@ SAML2_SERVICE_MAP = { 'slo-soap': ('SingleLogoutService', lasso.SAML2_METADATA_BINDING_SOAP), 'response-post': ('AssertionConsumerService', - lasso.SAML2_METADATA_BINDING_POST) + lasso.SAML2_METADATA_BINDING_POST), + 'response-paos': ('AssertionConsumerService', + lasso.SAML2_METADATA_BINDING_PAOS), } EDESC = '{%s}EntityDescriptor' % lasso.SAML2_METADATA_HREF