Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Current File(s): conf/authn/external-authn-config.xml, conf/authn/authn.properties(V4.1+)
Format: Properties, Native Spring, Properties (V4.1+)

Table of Contents

Overview

...

Warning

Once control is transferred to the external path, the IdP has no control over what happens, and it will implicitly trust any information passed back through the defined interface. If that information can be manipulated, security holes may result. The deployer takes full responsibility for the security of the overall exchange.

Enabling Module (V4.1+)

For V4.1+, configuring and using this feature requires that you first enable the "idp.authn.External" module if it isn't already enabled. Systems upgraded from older releases generally come pre-enabled due to the prior state of the configuration tree.

Code Block
(Windows)
C:\opt\shibboleth-idp> bin\module.bat -t idp.authn.External || bin\module.bat -e idp.authn.External
 
(Other)
$ bin/module.sh -t idp.authn.External || bin/module.sh -e idp.authn.External

General Configuration

Expand
titleV4.0

Use conf/authn/external-authn-config.xml to configure this flow.

The shibboleth.authn.External.externalAuthnPath bean defines the flow redirection path to the resource that's used to perform the external login, by default a context-relative location. It can be modified if needed, but must be a resource with access to the container session. Modify as needed to match the location of your external interface (see the documentation on flow redirects).

Expand
titleV4.1+

Most of the usual options are available via authn/authn.properties, and some more advanced cases will require defining/adjusting bean definitions in authn/external-authn-config.xml.

The idp.authn.External.externalAuthnPath property defines the flow redirection path to the resource that's used to perform the external login, by default a context-relative location. It can be modified if needed, but must be a resource with access to the container session. Modify as needed to match the location of your external interface (see the documentation on flow redirects).

You may also dynamically derive the path to use, typically so that it can vary based on aspects of the request, by defining a bean named shibboleth.authn.External.externalAuthnPathStrategy of type Function<ProfileRequestContext,String>.

The shibboleth.authn.External.ClassifiedMessageMap is a map of exception/error messages to classified error conditions. You can make use of this map either by modifying it to understand the error or exception messages returned by your external code, or by using the map as is and passing back the literal tokens in the map from your external code via the exception or error message interface.

API

The ExternalAuthentication class makes up the interface between the external code and the IdP. The general flow is:

  1. Call ExternalAuthentication.startExternalAuthentication(HttpServletRequest), saving off the result as a key.

  2. Do work as necessary (reading request details from the attributes below). Any redirects must preserve the key value returned in step 1 because it must be used to complete the login later.

  3. Set request attributes to communicate the result of the login back.

  4. Call ExternalAuthentication.finishExternalAuthentication(String, HttpServletRequest, HttpServletResponse). The first parameter is the key returned in step 1.

Example JSP implementations are below.

...

titleExternal interface example in JSP

General Configuration

Most of the usual options are available via authn/authn.properties, and some more advanced cases will require creating new bean definitions in conf/global.xml.

Note for Upgraded Systems

The old file conf/authn/external-authn-config.xml is now supported only for compatibility and generally not installed or needed going forward. Any beans placed there can be defined in global.xml instead.

The idp.authn.External.externalAuthnPath property defines the flow redirection path to the resource that's used to perform the external login, by default a context-relative location. It can be modified if needed, but must be a resource with access to the container session. Modify as needed to match the location of your external interface (see the documentation on flow redirects).

You may also dynamically derive the path to use, typically so that it can vary based on aspects of the request, by defining a bean named shibboleth.authn.External.externalAuthnPathStrategy of type Function<ProfileRequestContext,String>.

The shibboleth.authn.External.ClassifiedMessageMap is a map of exception/error messages to classified error conditions. You can make use of this map either by modifying it to understand the error or exception messages returned by your external code.

API

The ExternalAuthentication class makes up the interface between the external code and the IdP. The general flow is:

  1. Call ExternalAuthentication.startExternalAuthentication(HttpServletRequest), saving off the result as a key.

  2. Do work as necessary (reading request details from the attributes below). Any redirects must preserve the key value returned in step 1 because it must be used to complete the login later.

  3. Set request attributes to communicate the result of the login back.

  4. Call ExternalAuthentication.finishExternalAuthentication(String, HttpServletRequest, HttpServletResponse). The first parameter is the key returned in step 1.

Example JSP implementations are below.

Expand
titleExternal interface example in JSP
Code Block
languagejava
<%@ page pageEncoding="UTF-8" %>
<%@ page import="net.shibboleth.idp.authn.ExternalAuthentication" %>
<%@ page import="net.shibboleth.idp.authn.ExternalAuthenticationException" %>

<%
try {
    final String key = ExternalAuthentication.startExternalAuthentication(request);
    final String username = request.getRemoteUser();
    if (username != null) {
        request.setAttribute(ExternalAuthentication.PRINCIPAL_NAME_KEY, username);
    }
    ExternalAuthentication.finishExternalAuthentication(key, request, response);
     
} catch (final ExternalAuthenticationException e) {
    throw new ServletException("Error processing external authentication request", e);
}
%>
Expand
titleExternal interface with attributes in JSP
Code Block
languagejava
<%@ page pageEncoding="UTF-8" %>
<%@ page import="net.shibboleth.idp.authn.ExternalAuthentication*" %>
<%@ page import="net.shibboleth.idp.authnattribute.ExternalAuthenticationException*" %>
<%@ <%
try {
    final String key = ExternalAuthentication.startExternalAuthentication(request);page import="net.shibboleth.idp.authn.principal.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.security.*"%>
<%@ page import="javax.security.auth.*"%>

<%
try {
    final String usernamekey = requestExternalAuthentication.getRemoteUserstartExternalAuthentication(request);

   if (usernameHashSet<Principal> !principals=new nullHashSet<Principal>() {;

       request.setAttribute(ExternalAuthentication.PRINCIPAL_NAME_KEY, usernameprincipals.add(new UsernamePrincipal("bbarker"));

   } //<DataConnector xsi:type="Subject" exportAttributes="mail  ExternalAuthentication.finishExternalAuthentication(key, request, response);eduPersonNickname" id="myId" />
    //<AttributeDefinition ... <InputDataConnector } catch (final ExternalAuthenticationException e) {
    throw new ServletException("Error processing external authentication request", e);
}
%>
Expand
titleExternal interface with attributes in JSP
Code Block
languagejava
<%@ page pageEncoding="UTF-8" %>
<%@ page import="net.shibboleth.idp.authn.*" %>
<%@ page import="net.shibboleth.idp.attribute.*"%>
<%@ page import="net.shibboleth.idp.authn.principal.*"%>
<%@ page import="java.util.*"%>

<%
try {
    final String key = ExternalAuthentication.startExternalAuthentication(request);

    HashSet<Principal> principals=new HashSet<Principal>();

    principals.add(new UsernamePrincipal("bbarker"));

    //<DataConnector xsi:type="Subject" exportAttributes="mail eduPersonNickname" id="myId" />
    //<AttributeDefinition ... <InputDataConnector ref="myId" ...
    IdPAttribute attr=new IdPAttribute("eduPersonNickname");
    attr.setValues(Collections.singleton(new StringAttributeValue("Bob Barker")));
    principals.add(new IdPAttributePrincipal(attr));

    attr=new IdPAttribute("mail");
    attr.setValues(Collections.singleton(new StringAttributeValue("bbarker@example.org")));
    principals.add(new IdPAttributePrincipal(attr));

    request.setAttribute(ExternalAuthentication.SUBJECT_KEY,new Subject(false, principals, Collections.EMPTY_SET, Collections.EMPTY_SET));

    ExternalAuthentication.finishExternalAuthentication(key, request, response);

} catch (final ExternalAuthenticationException e) {
    throw new ServletException("Error processing external authentication request", e);
}
%>

Inputs

On first access to the external resource, the request attributes below will be set.

...

Name

...

Type

...

Function

...

opensamlProfileRequestContext

...

ProfileRequestContext

...

Access to full request context tree

...

forceAuthn

...

Boolean

...

Whether the requester asked for re-authentication

...

isPassive

...

Boolean

...

Whether the requested asked for passive authentication

...

relyingParty

...

String

...

Name of the relying party requesting authentication

...

extended

...

Boolean

...

Whether this login flow has been invoked as an extension of another login flow

Outputs

...

Name

...

Type

...

Function

...

principalName          

...

String

...

Name of authenticated subject to use as the login result

...

principal

...

Principal

...

Java Principal object to use as the login result

...

subject

...

Subject

...

Java Subject object to use as the login result

...

authnError

...

String

...

Error message to return in place of a successful login

...

authnException

...

Exception

...

Explicit exception object to return in place of a successful login

...

authnInstant

...

Instant

...

Exact time of authentication to report back

...

authnAuthorities

...

Collection<String>

...

Ordered collection of URIs identifying upstream/proxied authenticating "authorities" used to authenticate the subject

...

attributes

...

Collection<IdPAttribute>

...

Collection of IdPAttribute objects to associate with the authenticated subject

...

doNotCache

...

Boolean

...

If true, prevents the result from being saved for future use for SSO

...

previousResult

...

Boolean

...

If true, the "new" AuthenticationResult is created with the "previousResult" flag set to true (mainly impacts auditing)

Only one "result" or error attribute should be set by the external code. Setting more than one has unspecified behavior. In most cases, the simple principalName should be returned on success, but you can return the more complex objects to pass back additional information such as public or private credentials or custom principal data.

Any IdPAttribute objects supplied will be processed by the AttributeFilter service as "inbound" data. If at least one value in the "authnAuthorities" attribute is supplied, it is set as the "issuer" of the attributes for the purposes of the filter evaluation.

Note that returning a Subject is often paired with setting the shibboleth.authn.External.addDefaultPrincipals bean (V4.0) or idp.authn.External.addDefaultPrincipals property (V4.1+) to false, to dynamically establish Principal(s) representing the authentication method used without having them overwritten.

For example, your External flow's supportedPrincipals property might be defined to include both password and multi-factor authentication Principals (meaning it supports both methods), but you can return the specific method used at runtime in the Subject. For SAML 2.0, this is typically done (programmatically) by using the net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal class with the appropriate value from the standard or a deployment. Other classes in that package address SAML 1.1 and unusual SAML 2.0 use cases. For the built-in constants defined by the standard, there are Java constants available via org.opensaml.saml.saml2.core.AuthnContext.

Reference

The beans defined, or expected to be defined, in authn/external-authn-config.xml follow:

Expand
titleBeans (V4.0)

Bean ID / Type

Default

Description

shibboleth.authn.External.externalAuthnPath

String

contextRelative:external.jsp

Spring Web Flow redirection expression for the protected resource

shibboleth.authn.External.externalAuthnPathStrategy

Function<ProfileRequestContext,String>

Optional function that returns the redirection expression to use for the protected resource

shibboleth.authn.External.ClassifiedMessageMap

Map<String,List<String>>

(see file)

A map between defined error/warning conditions and events and implementation-specific message fragments to map to them.

shibboleth.authn.External.resultCachingPredicate

Predicate<ProfileRequestContext>

Optional bean that can be defined to control whether to preserve the authentication result in an IdP session

shibboleth.authn.External.addDefaultPrincipals

Boolean

true

Whether to add the content of the supportedPrincipals property of the underlying flow descriptor to the resulting Subject

shibboleth.authn.External.matchExpression

Pattern

Regular expression to match username against

Expand
titleBeans (V4.1+)
The beans defined, or expected to be defined, in authn/external-authn-config
ref="myId" ...
    IdPAttribute attr=new IdPAttribute("eduPersonNickname");
    attr.setValues(Collections.singletonList(new StringAttributeValue("Bob Barker")));
    principals.add(new IdPAttributePrincipal(attr));

    attr=new IdPAttribute("mail");
    attr.setValues(Collections.singletonList(new StringAttributeValue("bbarker@example.org")));
    principals.add(new IdPAttributePrincipal(attr));

    request.setAttribute(ExternalAuthentication.SUBJECT_KEY,new Subject(false, principals, Collections.EMPTY_SET, Collections.EMPTY_SET));

    ExternalAuthentication.finishExternalAuthentication(key, request, response);

} catch (final ExternalAuthenticationException e) {
    throw new ServletException("Error processing external authentication request", e);
}
%>

Inputs

On first access to the external resource, the request attributes below will be set.

Name

Type

Function

opensamlProfileRequestContext

ProfileRequestContext

Access to full request context tree

forceAuthn

Boolean

Whether the requester asked for re-authentication

isPassive

Boolean

Whether the requested asked for passive authentication

relyingParty

String

Name of the relying party requesting authentication

Outputs

Name

Type

Function

principalName          

String

Name of authenticated subject to use as the login result

principal

Principal

Java Principal object to use as the login result

subject

Subject

Java Subject object to use as the login result

authnError

String

Error message to return in place of a successful login

authnException

Exception

Explicit exception object to return in place of a successful login

authnInstant

Instant

Exact time of authentication to report back

authnAuthorities

Collection<String>

Ordered collection of URIs identifying upstream/proxied authenticating "authorities" used to authenticate the subject

attributes

Collection<IdPAttribute>

Collection of IdPAttribute objects to associate with the authenticated subject

doNotCache

Boolean

If true, prevents the result from being saved for future use for SSO

previousResult

Boolean

If true, the "new" AuthenticationResult is created with the "previousResult" flag set to true (mainly impacts auditing)

Only one "result" or error attribute should be set by the external code. Setting more than one has unspecified behavior. In most cases, a simple principalName should be returned on success, but you can return the more complex objects to pass back additional information such as public or private credentials or custom principal data.

Any IdPAttribute objects supplied will be processed by the AttributeFilter service as "inbound" data. If at least one value in the "authnAuthorities" attribute is supplied, it is set as the "issuer" of the attributes for the purposes of the filter evaluation.

Note that returning a Subject is often paired with setting the idp.authn.External.addDefaultPrincipals property to false, to dynamically establish Principal(s) representing the authentication method used without having them overwritten.

For example, your External flow's supportedPrincipals property might be defined to include both password and multi-factor authentication Principals (meaning it supports both methods), but you can return the specific method used at runtime in the Subject. For SAML 2.0, this is typically done (programmatically) by using the net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal class with the appropriate value from the standard or a deployment. Other classes in that package address SAML 1.1 and unusual SAML 2.0 use cases. For the built-in constants defined by the standard, there are Java constants available via org.opensaml.saml.saml2.core.AuthnContext.

Advanced Topics

Custom Events

The API supports the signaling of custom errors and exceptions. The main purpose of this feature is to support the signalling of custom events from the login flow by mapping these errors into custom Web Flow events that become the result of the login flow, and can be handled either via MFA scripting or used to control eventual error handling within the IdP.

The actual handling of custom events is discussed in the AuthenticationConfigurationtopic. To actually signal such an event, you need to utilize the so-called “classified message map” feature that is common to a number of login flows.

The input to the mapping process comes from the output attributes defined in the API above, either “authnError” or “authnException”. The value of the former, or the exception message contained in the latter, is the input string. The output of the mapping process is the event you want to signal. If you completely control the input value because you are creating it yourself in your code, then the simplest thing to do is simply use the desired event as the “authnError” value. However, you still need to create the mapping bean because the IdP doesn’t know this is the event you want to signal.

The mapping process is controlled by a map bean you must create, named shibboleth.authn.External.ClassifiedMessageMap, typically in global.xml. The map keys are the event(s) you want to signal, and the map values are a list of strings to test the input values against to produce that event. In the simplest case, these can be the same thing. The matching is by substring so if any part of the map’s values are found in the input string, it will map to that entry’s key.

For example, if you want to use an “authnError” value of “MyCustomEvent” or trap an exception message containing the string “Error message you don’t control”, your map would look like this:

Code Block
languagexml
<util:map id="shibboleth.authn.External.ClassifiedMessageMap">
  <entry key="MyCustomEvent">
    <list>
      <value>MyCustomEvent</value>
      <value>Error message you don't control</value>
    </list>
  </entry>
</util:map>

Reference

Expand
titleBeans

Beans that may be defined in global.xml follow:

Bean ID / Type

Default

Description

shibboleth.authn.External.externalAuthnPathStrategy

Function<ProfileRequestContext,String>

Optional function that returns the redirection expression to use for the protected resource

shibboleth.authn.External.ClassifiedMessageMap

Map<String,List<String>>(see file)

A map between defined error/warning conditions and events and implementation-specific message fragments to map to them. See section above on Custom Events.

shibboleth.authn.External.resultCachingPredicate

Predicate<ProfileRequestContext>

Optional bean that can be defined to control whether to preserve the authentication result in an IdP session

Expand
titleProperties (V4.1+)

The flow-specific properties usable via authn/authn.properties are:

Name

Default

Description

idp.authn.External.externalAuthnPath

contextRelative:external.jsp

Spring Web Flow redirection expression for the protected resource

idp.authn.External.matchExpression

Regular expression to match username against

The general properties configuring this flow via authn/authn.properties are:

Name

Default

Description

idp.authn.External.order

1000

Flow priority relative to other enabled login flows (lower is "higher" in priority)

idp.authn.External.nonBrowserSupported

false

Whether the flow should handle non-browser request profiles (e.g., ECP)

idp.authn.External.passiveAuthenticationSupported

false

Whether the flow allows for passive authentication

idp.authn.External.forcedAuthenticationSupported

false

Whether the flow supports forced authentication

idp.authn.External.proxyRestrictionsEnforced

%{idp.authn.enforceProxyRestrictions:true}

Whether the flow enforces upstream IdP-imposed restrictions on proxying

idp.authn.External.proxyScopingEnforced

false

Whether the flow considers itself to be proxying, and therefore enforces SP-signaled restrictions on proxying

idp.authn.External.discoveryRequired

false

Whether to invoke IdP-discovery prior to running flow

idp.authn.External.lifetime

%{idp.authn.defaultLifetime:PT1H}

Lifetime of results produced by this flow

idp.authn.External.inactivityTimeout

%{idp.authn.defaultTimeout:PT30M}

Inactivity timeout of results produced by this flow

idp.authn.External.reuseCondition

shibboleth.Conditions.TRUE

Bean ID of Predicate<ProfileRequestContext> controlling result reuse for SSO

idp.authn.External.activationCondition

shibboleth.Conditions.TRUE

Bean ID of Predicate<ProfileRequestContext> determining whether flow is usable for request

idp.authn.External.subjectDecorator


Bean ID of BiConsumer<ProfileRequestContext,Subject> for subject customization

idp.authn.External.supportedPrincipals

(see below)

Comma-delimited list of protocol-specific Principal strings associated with flow

idp.authn.External.addDefaultPrincipals

true

Whether to auto-attach the preceding set of Principal objects to each Subject produced by this flow

Most of the flows, including this one, default to describing themselves in terms of "password"-based authentication, so the supportedPrincipals property defaults to the following XML:

Code Block
languagexml
<list>
    <bean parent="shibboleth.SAML2AuthnContextClassRef"
        c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" />
    <bean parent="shibboleth.SAML2AuthnContextClassRef"
        c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:Password" />
    <bean parent="shibboleth.SAML1AuthenticationMethod"
        c:method="urn:oasis:names:tc:SAML:1.0:am:password" />
</list>

In property form, this is expressed as (note especially the trailing commas, which MUST be there):

Code Block
idp.authn.External.supportedPrincipals = \
    saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport, \
    saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:Password, \
    saml1/urn:oasis:names:tc:SAML:1.0:am:password
Expand
titleFlow Descriptor XML (V4.1+)

To replace the internally defined flow descriptor bean, the following XML is required:

Code Block
languagexml
<util:list id="shibboleth.AvailableAuthenticationFlows">
 
    <bean p:id="authn/External" parent="shibboleth.AuthenticationFlow"
            p:order="%{idp.authn.External.order:1000}"
            p:nonBrowserSupported="%{idp.authn.External.nonBrowserSupported:false}"
            p:passiveAuthenticationSupported="%{idp.authn.External.passiveAuthenticationSupported:false}"
            p:forcedAuthenticationSupported="%{idp.authn.External.forcedAuthenticationSupported:false}"
            p:proxyRestrictionsEnforced="%{idp.authn.External.proxyRestrictionsEnforced:%{idp.authn.enforceProxyRestrictions:true}}"
            p:proxyScopingEnforced="%{idp.authn.External.proxyScopingEnforced:false}"
            p:discoveryRequired="%{idp.authn.External.discoveryRequired:false}"
            p:lifetime="%{idp.authn.External.lifetime:%{idp.authn.defaultLifetime:PT1H}}"
            p:inactivityTimeout="%{idp.authn.External.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
            p:reuseCondition-ref="#{'%{idp.authn.External.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
            p:activationCondition-ref="#{'%{idp.authn.External.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
            p:subjectDecorator-ref="#{getObject('%{idp.authn.External.subjectDecorator:}'.trim())}">
        <property name="supportedPrincipalsByString">
            <bean parent="shibboleth.CommaDelimStringArray"
                c:_0="#{'%{idp.authn.External.supportedPrincipals:}'.trim()}" />
        </property>
    </bean>
 
</util:list>

In older versions and upgraded systems, this list is defined in conf/authn/general-authn.xml. In V4.1+V5, no default version of the list is provided and it may simply be placed in conf/global.xml if needed.

Notes

Note that upgraded systems will have alternate, legacy approaches to configuring this feature, as noted above.