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 <jdennis@redhat.com>
Reviewed-by: Patrick Uiterwijk <puiterwijk@redhat.com>
url_sp = url + args['saml_sp']
url_logout = url + args['saml_sp_logout']
url_post = url + args['saml_sp_post']
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')
# Generate metadata
m = Metadata('sp')
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['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)
m.add_allowed_name_format(SAML2_NAMEID_MAP[args['saml_nameid']])
sp_metafile = os.path.join(path, 'metadata.xml')
m.output(sp_metafile)
help="Single Logout URL")
parser.add_argument('--saml-sp-post', default=None,
help="Post response URL")
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")
parser.add_argument('--no-saml-soap-logout', action='store_true',
default=False,
help="Disable Single Logout over SOAP")
# Validate that all path options begin with '/'
path_args = ['saml_base', 'saml_auth', 'saml_sp', 'saml_sp_logout',
# Validate that all path options begin with '/'
path_args = ['saml_base', 'saml_auth', 'saml_sp', 'saml_sp_logout',
+ '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.' %
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.' %
if not args['saml_sp'].startswith(args['saml_base']):
raise ValueError('--saml-sp must be a subpath of --saml-base.')
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',
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('/'),
for path_arg, default_path in path_args.items():
if args[path_arg] is None:
args[path_arg] = '%s/%s' % (args['saml_sp'].rstrip('/'),
'slo-soap': ('SingleLogoutService',
lasso.SAML2_METADATA_BINDING_SOAP),
'response-post': ('AssertionConsumerService',
'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
}
EDESC = '{%s}EntityDescriptor' % lasso.SAML2_METADATA_HREF