-
Notifications
You must be signed in to change notification settings - Fork 0
Home
This functionality is now built into 3.4+. Please use that. https://wiki.shibboleth.net/confluence/display/IDP30/DuoAuthnConfiguration#DuoAuthnConfiguration-AuthAPIandNon-Browser/ECPUse
As with all things Shibboleth, it is not simple but is rather flexible. As with the Duo web authentication flow, it is presumed that you have done the first factor authentication and canonicalized the user name.
The credentials extractor can pull the Duo factor/device/passcode from the the HTTP headers or HTTP parameters. By default, the headers take precedence over the parameters; if nothing is found the defualt behavior is to use "auto" factor and "auto" device (see section 5 below for details on all of the settings). If successful, it will add an instance of edu.umd.idm.shibboleth.idp.authn.context.DuoAuthenticationContext
to the authentication context.
The validator calls both the /preauth and /auth Duo AuthAPI endpoints. If successful, it will add an instance of edu.umd.idm.shibboleth.idp.authn.context.DuoResponseContext
to the authentication context containing the details. See the Duo documentation for further information on the AuthAPI.
If you are using a proxy in front of your IdP, please see Keith Wessel's note on timeouts.
There are a number of configuration files that you will need to update/create.
Go to your duo admin console and create a new AuthAPI integration; then copy the host, iKey, and sKey into a new set of properties:
idp.duo.auth.apiHost = api-xxxxxxxxx.duosecurity.com
idp.duo.auth.integrationKey = yyyyyyyyyyyyyyyyyyyy
idp.duo.auth.secretKey = zzzzzzzzzzzzzzzzzzzzzzzzzzzz
Add a new authentication flow bean changing the supportedPrincipals
to whatever value you are using:
<bean id="authn/DuoAuthAPI" parent="shibboleth.AuthenticationFlow"
p:forcedAuthenticationSupported="true"
p:nonBrowserSupported="true">
<!--
The list below should be changed to reflect whatever locally- or
community-defined values are appropriate to represent MFA. It is
strongly advised that the value not be specific to Duo or any
particular technology.
-->
<property name="supportedPrincipals">
<list>
<bean parent="shibboleth.SAML2AuthnContextClassRef"
c:classRef="http://example.org/ac/classes/mfa" />
<bean parent="shibboleth.SAML1AuthenticationMethod"
c:method="http://example.org/ac/classes/mfa" />
</list>
</property>
</bean>
Presumably, this is where you are triggering the Duo web flow. To trigger the new flow, set the next flow to authn/DuoAuthAPI
. Exactly how to do this will be dependent on your configuration and is left as an exercise for the reader.
The ExtractDuoApiContext
bean can take a number of parameters which will affect its behavior:
parameter | default | description |
---|---|---|
autoAuthentiationSupoorted | true | use "auto" factor/device if no applicable header/parameter found |
useHeaders | true | examine the HTTP headers for Duo factor/device/passcode |
useParameters | true | examine the HTTP parameters for Duo factor/device/passcode |
factorHeaderName | X-Shiboleth-Duo-Factor | the HTTP header name for the Duo factor |
deviceHeaderName | X-Shiboleth-Duo-Device | the HTTP header name for the Duo device |
passcodeHeaderName | X-Shiboleth-Duo-Passcode | the HTTP header name for the Duo passcode |
factorParameterName | duoFactor | the HTTP parameter name for the Duo factor |
deviceParameterName | duoDevice | the HTTP parameter name for the Duo device |
passcodeParameterName | duoPasscode | the HTTP parameter name for the Duo passcode |
<?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 class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />
<bean class="net.shibboleth.idp.profile.impl.ProfileActionBeanPostProcessor" />
<bean id="shibboleth.authn.DuoAuthAPI.DuoIntegration" class="net.shibboleth.idp.authn.duo.BasicDuoIntegration"
p:APIHost="%{idp.duo.auth.apiHost:none}"
p:applicationKey="%{idp.duo.auth.applicationKey:none}"
p:integrationKey="%{idp.duo.auth.integrationKey:none}"
p:secretKey="%{idp.duo.auth.secretKey:none}" />
<bean id="shibboleth.authn.DuoAuthAPI.DuoIntegrationStrategy" class="com.google.common.base.Functions"
factory-method="constant" c:_0-ref="shibboleth.authn.DuoAuthAPI.DuoIntegration" />
<bean id="ExtractDuoApiContext" scope="prototype"
class="edu.umd.idm.shibboleth.idp.authn.duo.impl.ExtractDuoAuthticationContext"
p:httpServletRequest-ref="shibboleth.HttpServletRequest" />
<bean id="DuoAuthAuthenticator" scope="prototype"
class="edu.umd.idm.shibboleth.idp.authn.duo.impl.DuoAuthAuthenticator"
p:httpClient-ref="shibboleth.NonCachingHttpClient"
p:objectMapper-ref="shibboleth.JSONObjectMapper" />
<bean id="DuoPreauthAuthenticator" scope="prototype"
class="edu.umd.idm.shibboleth.idp.authn.duo.impl.DuoPreauthAuthenticator"
p:httpClient-ref="shibboleth.NonCachingHttpClient"
p:objectMapper-ref="shibboleth.JSONObjectMapper" />
<bean id="ValidateDuoAuthApi" scope="prototype"
class="edu.umd.idm.shibboleth.idp.authn.duo.impl.ValidateUsernameAgainstDuoAuthApi"
p:usernameLookupStrategy-ref="shibboleth.authn.Duo.UsernameLookupStrategy"
p:duoIntegrationLookupStrategy-ref="shibboleth.authn.DuoAuthAPI.DuoIntegrationStrategy"
p:authAuthenticator-ref="DuoAuthAuthenticator"
p:preauthAuthenticator-ref="DuoPreauthAuthenticator"
p:addDefaultPrincipals="#{getObject('shibboleth.authn.Duo.addDefaultPrincipals') ?: true}"
/>
<import resource="../../../system/flows/authn/duo-authn-beans.xml" />
</beans>
This is a rudimentary example flow
<flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
parent="authn.abstract">
<!-- This is a simple login flow for Duo authentication. -->
<var name="thisFlow" class="net.shibboleth.idp.authn.AuthenticationFlowDescriptor" />
<action-state id="ExtractDuoApiContext">
<evaluate expression="ExtractDuoApiContext" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="ValidateDuoAuthApi" />
<!-- Fall through to a different flow if basic-auth extract fails on a passive or non-browser request. -->
<transition on="#{ opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).isPassive() || !opensamlProfileRequestContext.isBrowserProfile() }" to="ReselectFlow" />
<transition on="NoCredentials" to="LogDuoException" />
<transition on="InvalidCredentials" to="LogDuoException" />
<on-exit>
<set name="thisFlow" value="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).getAttemptedFlow()" />
</on-exit>
</action-state>
<action-state id="ValidateDuoAuthApi">
<evaluate expression="ValidateDuoAuthApi" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="proceed" />
</action-state>
<action-state id="LogDuoException">
<on-entry>
<evaluate expression="T(org.slf4j.LoggerFactory).getLogger('net.shibboleth.idp.authn.duo').error('DuoWebException', flowExecutionException.getCause())" />
</on-entry>
<evaluate expression="'AuthenticationException'" />
</action-state>
<bean-import resource="DuoAuthAPI-beans.xml" />
</flow>
If you are not using the default Java keystore for rootCA certificates, you'll need to verify that the rootCA for the DuoAPI url's is included in your keystore. (thanks to Keith W.)