/
AttributeSourcedPostLoginC14NConfiguration

AttributeSourcedPostLoginC14NConfiguration

Current Files(s): conf/c14n/subject-c14n.properties, conf/c14n/subject-c14n.xml, conf/attribute-resolver.xml
Format: Properties, Native Spring

Overview

In V5.2, the name of this method was altered to allow for the enhanced c14n features introduced in that version to be added without breakage. The implications of this are minimal but are discussed below where relevant.

The “attribute-sourced” (legacy name, “attribute”) post-login subject c14n method extracts a username from an IdPAttribute resolved (primarily) using the attribute resolution function within the IdP. A common use for this flow is to perform a directory or database lookup to map information derived from the authentication process (e.g., a value input by a person) into a different value for use within the IdP.

A secondary feature allows for a Java Subject that contains one or more IdPAttributePrincipal objects to be processed directly for an IdPAttribute to pull the value from. This is primarily of use with various "external" authentication options such as SAML proxying, allowing a SAML Attribute decoded from another IdP to be directly consumed and used as a canonical name without the hassle of the attribute resolution process (and configuration). This feature can be leveraged by adjusting various properties (see below) to disable use of the Attribute Resolver and reference the Java Subject directly (note this is not referring to the SAML <Subject> element but to the Java object created as a result of all successful authentication flows in the IdP).

Configuration

Method Settings

Use conf/c14n/subject-c14n.properties to configure this method, along with the AttributeResolverConfiguration.

If your system is upgraded, you may continue to use conf/c14n/attribute-sourced-subject-c14n-config.xml as before, or you may remove it, while ensuring the new properties are being loaded.

There are two ways this method can locate a suitable IdPAttribute to use:

  • By running the "full" Attribute Resolver service (which has some special considerations noted below).

  • By pulling an IdPAttribute directly from an IdPAttributePrincipal in the input Subject (as mentioned above, this is normally useful when proxying authentication to another IdP). The “Subject” in this case does not refer directly to the Subject of a SAML assertion (e.g., during proxying), but to the Java “object” that represents the result of all authentications internally.

These methods can be combined, in the sense that the list of attributes to search for may be found in either way, so it's possible to run the resolver conditionally and/or check both the Subject and the resolution results. In most cases this is an either/or situation and the resolver isn't meant to be used if you expect the data to be in the Subject already.

When pulling directly, you will typically just supply a list of attributes to check for (first value wins), and set the idp.c14n.attribute.resolutionCondition property to "shibboleth.Conditions.FALSE", to turn off the full attribute resolution step, and set the idp.c14n.attribute.resolveFromSubject property to true.

When using the resolver, typically you will supply a list of attributes to resolve and a list of attributes to search for in the results. The first such attribute with a suitable value will supply the username to return.

By default, the only transform applied to the result is a trim of leading or trailing whitespace. Case-folding and regular expression replacements can be added, per the reference section below. The regular expression replacement feature is the only one remaining that still requires XML and you may define that bean, if needed, in conf/c14n/subject-c14n.xml

Using the Attribute Resolver

When relying on the Attribute Resolver with this feature, there are some additional considerations of which to be aware.

The IdP will internally set the “resolution label” used by the resolver to a value equal to the c14n method’s bean ID (typically “c14n/attribute-sourced” or “c14n/attribute” depending on IdP version). This is the value testable with the resolutionPhases setting supported by AttributeDefinitions and DataConnectors for conditional use.

Usually, the attribute resolver relies on the canonical principal name to do its work (the value of the $resolutionContext.principal variable in scripts or search templates). By definition that isn't possible here (this is the process that provides that value later). However, the value of that variable in the resolver can be set by means of a function bean (e.g., using a script) named shibboleth.c14n.attribute.PrincipalNameLookupStrategy. In most cases this function would peek inside the Java Subject being canonicalized and pull out custom bits of information.

The Java Subject this flow is operating on can be accessed via an expression of the form:

profileContext.ensureSubcontext("net.shibboleth.idp.authn.context.SubjectCanonicalizationContext").getSubject()

While it would not be a typical case to need to access a value entered by a user except in one specific case noted below, that value will be present inside the Subject as a principal object of type net.shibboleth.idp.authn.principal.UsernamePrincipal. In most other cases, it's simpler to just leave such a value as the canonical principal name and adjust your resolver configuration to accomodate whatever that might be than to try and use the resolver ahead of time to turn it into some other value.

Enabling this Method

In V5.2+, this method is enabled by setting a per-login-flow property in conf/authn/authn.properties that references it. The default bean ID of this method is “c14n/attribute-sourced”, so enabling it for a login flow looks like:

idp.authn.SAML.c14n.flows = c14n/attribute-sourced

A quick comment about the naming. Because of how the original method was configured in most systems, the enhancements in this version necessitated “forking” things and picking a new name for the built-in copy of the new implementation to avoid stomping on the older name. As such, “c14n/attribute” as defined in the older IdP’s default configuration will continue to work as it did before.

The actual implementation difference between them is that the older version runs a Spring Web Flow, and can only be used with a single configuration. The newer version is faster and can be duplicated with alternative settings (as shown next).

It is possible to configure two instances of this method at the same time with different settings. The default instance is configured with a set of global properties, so defining a second instance of it with different settings requires adding a bean to conf/c14n/subject-c14n.xml. This bean can be defined at the top level of the file and needs a unique ID to reference in the login flow property example above. It does not have to carry the “c14n/” prefix but this is useful for clarity.

As an example, consider a case where the “standard” use of the method relies on the resolver to talk to a directory, but a secondary use of it is desired for the SAML proxy login method. While it is possible to do this as a single c14n setup, it can be safer and clearer to just separate them and add a second:

<bean id="c14n/proxy-attribute" parent="c14n/attribute-sourced" p:attributesToResolve="proxyUsername" p:attributeSourceIds="proxyUsername" p:resolveFromSubject="true" p:resolutionCondition="false" />

That then allows you to reference “c14n/proxy-attribute” in a login flow’s property as above.

In older versions, this method is not enabled by default and is in the shipped file inside a comment:

<util:listid="shibboleth.PostLoginSubjectCanonicalizationFlows"> <!-- <bean id="c14n/attribute" parent="shibboleth.PostLoginCanonicalizationFlow" /> --> </util:list>

Enabling it thus requires uncommenting this bean and then setting the properties required as appropriate.

Examples

MFA Example

One situation where this feature is frequently useful:

  • you need to use a Duo or other 2FA authentication plugin that would rely on the username entered by the user to send to the 2FA service

  • you want to allow the user to enter their username as one of several different identifiers when they do the initial password authentication

In that case, the same user could end up having multiple different identifiers with the 2FA service, because whichever one they choose to enter at login would be the one sent. This can be addressed by using this c14n method so that you ensure the same user identifier is sent to the 2FA service every time.

The following example illustrates how one could do this, where one has chosen to allow the user to enter either the value of their uid or their e-mail address as the username. Changes need to be made to all of the following, and sample config highlights the changes to each that would enable such. (One would also need to configure your authn handler to allow for either input, such as changing idp.authn.LDAP.userFilter to '(|(uid={user})(mail={user}))'.)

  • conf/attribute-resolver.xml

  • conf/c14n/subject-c14n.xml

  • conf/c14n/subject-c14n.properties

The example takes the user's input name and supplies it to the attribute resolver to do a search of LDAP against the two possible candidate attributes and returns the uid attribute from the directory so that either input maps to a fixed output. There are other ways to configure the resolver that might be more aligned to other searches you need to perform, cache results, etc. but this illustrates the idea.

attribute-resolver.xml
    <!-- Example LDAP Connector -->     <resolver:DataConnector id="myLDAP" xsi:type="dc:LDAPDirectory" exportAttributes="uid"        ldapURL="ldap://localhost:10389"        baseDN="ou=People,dc=example,dc=edu"        principal="cn=admin,dc=example,dc=edu"        principalCredential="password">        <dc:FilterTemplate>            <![CDATA[                (|(uid=$resolutionContext.principal)(mail=$resolutionContext.principal))            ]]>        </dc:FilterTemplate>        <dc:ReturnAttributes>uid</dc:ReturnAttributes>     </resolver:DataConnector>
subject-c14n.properties
idp.c14n.attribute.attributesToResolve = uid idp.c14n.attribute.attributeSourceIds = uid
subject-c14n.xml
<!-- at the bottom... --> <bean id="shibboleth.c14n.attribute.PrincipalNameLookupStrategy" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript"> <constructor-arg> <value> <![CDATA[ var principalName = null; var subject = profileContext.getSubcontext("net.shibboleth.idp.authn.context.SubjectCanonicalizationContext").getSubject(); var princs = subject.getPrincipals(Java.type("net.shibboleth.idp.authn.principal.UsernamePrincipal").class); if (princs.size() == 1) { principalName = princs.iterator().next().getName(); } principalName; ]]> </value> </constructor-arg> </bean>
... <!-- Remove comment tags to enable Attribute-based c14n --> <bean id="c14n/attribute" parent="shibboleth.PostLoginSubjectCanonicalizationFlow" /> ... <!-- at the bottom... --> <bean id="shibboleth.c14n.attribute.PrincipalNameLookupStrategy" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript"> <constructor-arg> <value> <![CDATA[ var principalName = null; var subject = profileContext.getSubcontext("net.shibboleth.idp.authn.context.SubjectCanonicalizationContext").getSubject(); var princs = subject.getPrincipals(Java.type("net.shibboleth.idp.authn.principal.UsernamePrincipal").class); if (princs.size() == 1) { principalName = princs.iterator().next().getName(); } principalName; ]]> </value> </constructor-arg> </bean>

Reference

Bean ID

Type

Description

Bean ID

Type

Description

c14n/attribute-sourced 5.2

AttributeSourcedSubjectCanonicalization

Built-in instance of this method, auto-configured by properties and other beans as described. V5.2+ allows reuse of this bean as a parent to define additional instances of this method with different settings.

c14n/attribute

SubjectCanonicalizationFlowDescriptor

Legacy definition of the original webflow-based version of this method, it was used “by example” as a commented bean in the original shipping default file

shibboleth.c14n.attribute.PrincipalNameLookupStrategy

Function<ProfileRequestContext,String>

Provides a principal name value for the AttributeResolutionContext during attribute resolution (i.e., $resolutionContext.principal will be set)

shibboleth.c14n.attribute.Transforms

Pair<String,String>

Pairs of regular expressions and replacement expressions to apply to the attribute-sourced username

The following properties are commented out in conf/c14n/subject-c14n.properties:

Name / Type / Default

Default

Description

Name / Type / Default

Default

Description

idp.c14n.attribute.attributesToResolve

 

Comma-delimited list of attributes to resolve (an empty list directs the resolver to resolve everything it can)

idp.c14n.attribute.attributeSourceIds

 

Comma-delimited list of attributes to search for in the results, looking for a StringAttributeValue or ScopedStringAttributeValue

idp.c14n.attribute.resolveFromSubject

false

Whether to examine the input Subject for IdPAttributePrincipal objects to pull from directly, instead of from the output of the Attribute Resolver service

idp.c14n.attribute.resolutionCondition

shibboleth.Conditions.TRUE

Bean ID of a Predicate<ProfileRequestContext> to evaluate to determine whether to run the Attribute Resolver or go directly to the Subject alone

idp.c14n.attribute.lowercase

false

Whether to lowercase the username

idp.c14n.attribute.uppercase

false

Whether to uppercase the username

idp.c14n.attribute.trim

true

Whether to trim leading and trailing whitespace from the username

 

Related content