Versions Compared

Key

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

...

Finally, for non-browser use, it's also possible to supply the code in a request header, "X-Shibboleth-TOTP" by default, also controllable with a property. Because of this, the flow is installed by default as supporting non-browser use, though if the header is missing there is no user interface to ask for one.

Source of Token Seeds

Localtabgroup
tabStyleflat
Localtab
activetrue
Expand
titleUsing the Attribute Resolver

The default behavior of the flow is to perform a special attribute resolution step to resolve an attribute named by the idp.authn.TOTP.tokenSeedAttribute property, defaulting to "tokenSeeds". Since the attribute name really shouldn't matter much, leaving it defaulted is usually the best choice but if you want to set the property you can put it in any of the existing property files, advisedly the conf/authn/authn.properties file added in V4.1.

The attribute itself must supply one or more string values containing the Base32-encoded token seed(s) to try and validate the supplied code against. Note these seeds cannot be encrypted at this stage. If you wish to store them in an encrypted form, it's possible to do so using the IdP using its "DataSealer" component that manages a list of keys shared amongst all the nodes of a cluster. Assuming this is done (details below), the DecryptedAttributeDefinition can be used to decrypt them on the fly to produce the resulting attribute.

DataSealer Definition and Use

While most IdPs include a DataSealer configured internally, this is typically not a good choice for this use case because the original use cases tend to assume the keys are being rotated frequently. To use a longer-term key, a dedicated component will typically be required. In order to facilitate using it to encrypt data using the command line, it's a good idea to define it in a separate Spring resource and load that into the Attribute Resolver's set of configuration resources in conf/services.xml.

Note that you will need to use the seckeygen utility yourself out of band to initialize the keystore and a key to use:

Code Block
languagebash
titleInitializing keystore
collapsetrue
$ cd /opt/shibboleth-idp
$ bin/seckeygen.sh --alias totp --count 1 \
	--storefile credentials/totpsealer.jks \
    --storepass password \
    --versionfile credentials/totpsealer.kver


Code Block
languagexml
titleDedicated DataSealer configuration
collapsetrue
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"

       default-init-method="initialize"
       default-destroy-method="destroy">

    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
        p:placeholderPrefix="%{" p:placeholderSuffix="}" />

    <bean id="totp.DataSealerKeyStrategy" lazy-init="true"
            class="net.shibboleth.utilities.java.support.security.impl.BasicKeystoreKeyStrategy"
        p:keystoreType="JCEKS"
        p:keystoreResource="%{idp.home}/credentials/totpsealer.jks"
        p:keyVersionResource="%{idp.home}/credentials/totpsealer.kver"
        p:keyAlias="totp"
        p:keystorePassword="password"
        p:keyPassword="password"
        p:updateInterval="PT1H" />

    <bean id="totp.DataSealer" lazy-init="true"
        class="net.shibboleth.utilities.java.support.security.DataSealer"
        p:keyStrategy-ref="totp.DataSealerKeyStrategy" />

 </beans>

With this example, a DecryptedAttributeDefinition's dataSealerRef property would be set to "totp.DataSealer".

To use this from the command line to encrypt (and for example purposes, decrypt) data, assuming the file were named conf/totpsealer.xml:

Code Block
languagebash
titleDataSealer Command Example
$ cd /opt/shibboleth-idp
$ bin/sealer.sh --quiet conf/totpsealer.xml dec `bin/sealer.sh --quiet conf/totpsealer.xml enc data`
data


localtab
Tip

Note that the data produced by encryption is generally (though not absolutely required to be) Base64-encoded. This is not the same as how the token seed itself may be encoded, as the seed is in cleartext. The typical encoding for an encrypted seed would be a Base32-encoded seed, encrypted and encoded with Base64.


Expand
titleStatic Seeds

Primarily for testing, it's possible to supply a Spring bean containing a map of statically defined token seeds for users. The bean MUST be named shibboleth.authn.TOTP.SeedSource and will inherit from a parent bean named shibboleth.authn.TOTP.StaticSeedSource.

As an example, something like this in conf/global.xml will work:

Code Block
languagexml
titleStatic token seeds
<bean id="shibboleth.authn.TOTP.SeedSource" parent="shibboleth.authn.TOTP.StaticSeedSource">
	<property name="seeds">
		<map>
			<entry key="jdoe">
				<list>
					<value>K44GQWBAI54IQELEGYPDZG5LAJ6EJX73</value>
				</list>
			</entry>
			<entry key="jsmith">
				<list>
					<value>MLDE4YVTA7YKD5NZTDQX65ZPZ2A2OMW2</value>
				</list>
			</entry>
		</map>
	</property>
</bean>



Reference

true
Localtabgroup
Localtab
active
Expand
titleProperties

The TOTP-specific properties defined are:

NameDefaultDescription
idp.authn.TOTP.headerNameX-Shibboleth-TOTPName of request header to use for extracting non-browser submitted token codes
idp.authn.TOTP.fieldNametokencodeName of HTML form field to use for locating browser-submitted token codes
idp.authn.TOTP.tokenSeedAttributetokenSeedsName of IdPAttribute to resolve to obtain token seeds for users

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

NameDefaultDescription
idp.authn.TOTP.order1000Flow priority relative to other enabled login flows (lower is "higher" in priority)
idp.authn.TOTP.nonBrowserSupportedtrueWhether the flow should handle non-browser request profiles (e.g., ECP)
idp.authn.TOTP.passiveAuthenticationSupportedtrueWhether the flow allows for passive authentication
idp.authn.TOTP.forcedAuthenticationSupportedtrueWhether the flow supports forced authentication
idp.authn.TOTP.proxyRestrictionsEnforced%{idp.authn.enforceProxyRestrictions:true}Whether the flow enforces upstream IdP-imposed restrictions on proxying
idp.authn.TOTP.proxyScopingEnforcedfalseWhether the flow considers itself to be proxying, and therefore enforces SP-signaled restrictions on proxying
idp.authn.TOTP.discoveryRequiredfalseWhether to invoke IdP-discovery prior to running flow
idp.authn.TOTP.lifetime%{idp.authn.defaultLifetime:PT1H}Lifetime of results produced by this flow
idp.authn.TOTP.inactivityTimeout%{idp.authn.defaultTimeout:PT30M}Inactivity timeout of results produced by this flow
idp.authn.TOTP.reuseConditionshibboleth.Conditions.TRUEBean ID of Predicate<ProfileRequestContext> controlling result reuse for SSO
idp.authn.TOTP.activationConditionshibboleth.Conditions.TRUEBean ID of Predicate<ProfileRequestContext> determining whether flow is usable for request
idp.authn.TOTP.subjectDecorator
Bean ID of BiConsumer<ProfileRequestContext,Subject> for subject customization
idp.authn.TOTP.supportedPrincipals(see below)Comma-delimited list of protocol-specific Principal strings associated with flow
idp.authn.TOTP.addDefaultPrincipalstrueWhether to auto-attach the preceding set of Principal objects to each Subject produced by this flow

As a non-password based flow, the supportedPrincipals property defaults to the following XML:

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

In property form, this is expressed as:

localtab
Code Block
idp.authn.TOTP.supportedPrincipals = \
    saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken, \
	saml1/urn:oasis:names:tc:SAML:1.0:am:HardwareToken



FDXML


Expand
titleBeans

The following beans exist or may be defined to customize the flow. They may be placed in conf/global.xml or another imported location.

Name / TypeDefaultDescription

shibboleth.authn.TOTP.SeedSource

Consumer<ProfileRequestContext>

Use of Attribute ResolverOverrides the component that populates seeds for a user into the context tree for validation of codes

shibboleth.authn.TOTP.Authenticator

net.shibboleth.idp.plugin.authn.totp.impl.TOTPAuthenticator

Google library-based implementationOverrides the component that does validation of token codes

shibboleth.authn.TOTP.AccountLockoutManager

AccountLockoutManager


A lockout manager that, if defined, will enable account lockout feature

shibboleth.authn.TOTP.ClassifiedMessageMap

Map<String,List<String>>

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

shibboleth.authn.TOTP.Validator

CredentialValidator

Built-in componentOverride of the core component that validates token codes

shibboleth.authn.Duo.UsernameLookupStrategy

Function<ProfileRequestContext,String>

CanonicalUsernameLookupStrategyOptional bean to supply username

shibboleth.authn.TOTP.resultCachingPredicate

Predicate<ProfileRequestContext>


An optional bean that can be defined to control whether to preserve the authentication result in an IdP session
Localtab
id


Expand
titleFlow Descriptor XML

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/TOTP" parent="shibboleth.AuthenticationFlow"
            p:order="%{idp.authn.TOTP.order:1000}"
            p:nonBrowserSupported="%{idp.authn.TOTP.nonBrowserSupported:true}"
            p:passiveAuthenticationSupported="%{idp.authn.TOTP.passiveAuthenticationSupported:true}"
            p:forcedAuthenticationSupported="%{idp.authn.TOTP.forcedAuthenticationSupported:true}"
            p:proxyRestrictionsEnforced="%{idp.authn.TOTP.proxyRestrictionsEnforced:%{idp.authn.enforceProxyRestrictions:true}}"
            p:proxyScopingEnforced="%{idp.authn.TOTP.proxyScopingEnforced:false}"
            p:discoveryRequired="%{idp.authn.TOTP.discoveryRequired:false}"
            p:lifetime="%{idp.authn.TOTP.lifetime:%{idp.authn.defaultLifetime:PT1H}}"
            p:inactivityTimeout="%{idp.authn.TOTP.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
            p:reuseCondition-ref="#{'%{idp.authn.TOTP.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
            p:activationCondition-ref="#{'%{idp.authn.TOTP.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
            p:subjectDecorator-ref="#{getObject('%{idp.authn.TOTP.subjectDecorator}'.trim())}">
        <property name="supportedPrincipalsByString">
            <bean parent="shibboleth.CommaDelimStringArray"
                c:_0="#{'%{idp.authn.TOTP.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+, no default version of the list is provided and it may simply be placed in conf/global.xml if needed.