Using SAML Proxying to another IdP
This how-to applies to Shibboleth Identity Provider v4.0 and can be used to integrate the authentication flows with other SAML2 compliant identity providers such as SimpleSAMLphp or Microsoft Azure. There is a far more detailed guide to integrating with Azure at Using SAML Proxying in the V4 Shibboleth IdP to connect with Azure AD.
Please read and follow the documentation first, before or along with using this example. This documentation is not maintained by the development team and may not be entirely accurate or consistent with the software at any given time. It is a complement to the documentation, not a replacement for it. It is currently out of date with respect to some improvements made in V4.1.
Delegating Authentication to another IdP
This process will absolve your Identity Provider (IdP) of the process of authenticating the user, instead relying on another SAML2 IdP to do that job. The resulting Assertion is used to generate the user's local username which is then used in the standard Attribute Resolution process.
In essence, your IdP well become a Service Provider (SP) to a second IdP.
This method describes extracting the username from an Attribute in the Assertion. It's also possible to use the Subject.
In this example, the following entities and attributes are in use:
- Original IdP EntityID:
https://idp.example.ac.uk/entity
- Upstream IdP EntityID:
https://upstream.idp/entity
- Joining attribute (common to both services):
uid
(unscoped username)
Basic workflow
- Authentication request hits IdP
- IdP issues a redirect to Upstream IdP
- User authenticates (or reuses session?) against Upstream IdP and generates an Assertion
- Assertion consumed from upstream IdP
- Assertion filtered before use
- Attribute extracted from upstream Assertion for use as real username:
- Configure attribute-based subject c14n.
- Look through list of
AttributesToResolve
in the resolver and resolve each one. - Look through list of resulting attributes in
AttributeSourceIds
and pick first valid one to be the principal's name to then be used later
- Resulting trusted real username used as
$resolutionContext.principal
(eg. existing LDAP data connector, etc.) during "standard" attribute resolution process
Pre-requisites
- A working Identity Provider at V4 or above
- A SAML2 compliant Identity Provider to delegate to
- A suitable attribute available to both IdPs to use as a "joining" attribute (so the other IdP can provide a value which can be looked up in the main IdP's connected data source)
Preparation
Update your IdP's metadata
As your IdP will need act as an SP, you'll need extra blocks in your entity's metadata. Create a new sp-metadata.xml
(or update your existing idp-metadata.xml
but consider whether this should be included in multi-lateral federation agreements) file to include a <SPSSODescriptor>
block. You'll need to copy the signing and encryption certificates from the IdP part of the metadata and replace the base URI (https://idp.example.ac.uk/idp
) with the base of your IdP.
Register your IdP with the upstream IdP
Use your updated metadata to register the IdP/SP with the IdP you'd like to delegate to and configure it to send a value to use an username (eg. eduPersonPrincipalName
, uid
or sAMAccountName
).
You may just need to supply the EntityID and Assertion Consumer Service URL:
- EntityID: same as for your IdP
- Assertion Consumer Service:
https://idp.example.ac.uk/idp/profile/Authn/SAML2/POST/SSO
Register the upstream IdP's metadata locally
If your upstream IdP is not already known by some other means, then register the upstream IdP, too. This is handled just like any other metadata and can be included in your metadata-providers.xml
as a new <MetadataProvider>
block. For example:
<MetadataProvider id="upstream-idp-metadata" xsi:type="FilesystemMetadataProvider" metadataFile="/opt/idp/metadata/upstream-idp.xml" />
IdP configuration
The following changes need to be made to the IdP to support this workflow:
- Enable the SAML authentication flow
- Configure to which Entity to delegate
- Update attribute filter to allow incoming attributes to be ingested
- Set up attribute extraction through Subject Canonicalisation (c14n and resolver)
Enable the SAML authentication flow
Edit authn/saml-authn-config.xml
to set the EntityID of the upsteam IdP. Uncomment the shibboleth.authn.SAML.discoveryFunction
bean and edit the target
:
<bean id="shibboleth.authn.SAML.discoveryFunction" parent="shibboleth.Functions.Constant" c:target="https://upstream.idp/entity" />
Enable the flow by updating idp.authn.flows
in idp.properties
:
idp.authn.flows=SAML
Update Attribute Filter
The IdP will not ingest attributes from the Upstream IdP unless they're allowed in by a filter. Add a new <AttributeFilterPolicy>
to permit trusted attributes to be handled:
<AttributeFilterPolicy id="saml-proxy-pass-through"> <PolicyRequirementRule xsi:type="Issuer" value="https://upstream.idp/entity" /> <AttributeRule attributeID="uid" permitAny="true" /> </AttributeFilterPolicy>
Subject Canonicalisation
This workflow takes the incoming assertion and extracts some data from it to work out the canonical (authoritative) username of the authenticated user. In this very simple case we're using uid
(unscoped username).
Add a new <AttributeDefinition>
to the attribute-resolver.xml
which will transform the uid
attribute from the Subject (the filtered data from the incoming assertion) into a proxied-uid
attribute for use elsewhere:
<AttributeDefinition xsi:type="SubjectDerivedAttribute" forCanonicalization="true" principalAttributeName="uid" id="proxied-uid" />
With the Subject, configure which attributes to fire in the resolver to work out what's going on. Set AttributesToResolve
in c14n/attribute-sourced-subject-c14n-config.xml
to the id of the new <AttributeDefinition>
:
<util:list id="shibboleth.c14n.attribute.AttributesToResolve"> <value>proxied-uid</value> </util:list>
This may need to include more attributes depending on how much work you need to do to turn the incoming attribute into the real username that you need later.
Set the AttributeSourceIds
value to which newly resolved attributes you would treat as the real username. This is probably the same or a subset of AttributesToResolve
.
Review c14n/subject-c14n.xml
and ensure the PostLoginSubjectCanonicalizationFlow
bean has been uncommented.
At this point you should have a valid locally understood username to pass into the "normal" resolver that already works, which is now available from places like:
$resolutionContext.principal
Test
Restart your IdP and test!
Your existing resolver should still work using aacli
.