[java-identity-provider] branch master updated: IDP-1239 - Non-browser support for Duo authentication
Scott Cantor
cantor.2 at osu.edu
Mon Aug 13 15:02:33 EDT 2018
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch master
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=e9c2303108ddabbacf3813b06c35022bc33ff3eb
The following commit(s) were added to refs/heads/master by this push:
new e9c2303 IDP-1239 - Non-browser support for Duo authentication
e9c2303 is described below
commit e9c2303108ddabbacf3813b06c35022bc33ff3eb
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Aug 13 15:02:29 2018 -0400
IDP-1239 - Non-browser support for Duo authentication
https://issues.shibboleth.net/jira/browse/IDP-1239
Integrated into existing Duo flow.
---
.../impl/ExtractDuoAuthenticationFromHeaders.java | 5 ++-
.../idp/authn/duo/impl/ValidateDuoAuthAPI.java | 13 ++++--
.../main/resources/conf/authn/duo-authn-config.xml | 2 +
.../src/main/resources/conf/authn/duo.properties | 30 ++++++++++++--
.../system/flows/authn/duo-authn-beans.xml | 46 +++++++++++++++++++++-
.../system/flows/authn/duo-authn-flow.xml | 19 +++++++++
6 files changed, 106 insertions(+), 9 deletions(-)
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ExtractDuoAuthenticationFromHeaders.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ExtractDuoAuthenticationFromHeaders.java
index 5ad90dd..fc9fea3 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ExtractDuoAuthenticationFromHeaders.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ExtractDuoAuthenticationFromHeaders.java
@@ -44,7 +44,6 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport;
* @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
* @event {@link AuthnEventIds#NO_CREDENTIALS}
- * @event {@link AuthnEventIds#INVALID_CREDENTIALS}
* @pre
* <pre>
* ProfileRequestContext.getSubcontext(AuthenticationContext.class) != null
@@ -190,6 +189,10 @@ public class ExtractDuoAuthenticationFromHeaders<InboundMessageType,OutboundMess
ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_CREDENTIALS);
return;
}
+ } else if (DuoAuthAPI.DUO_FACTOR_SMS.equals(duoCtx.getFactor())) {
+ log.warn("{} Request for SMS codes unsupported", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_CREDENTIALS);
+ return;
}
// Check for missing passcode.
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoAuthAPI.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoAuthAPI.java
index ba47950..ea79c55 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoAuthAPI.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ValidateDuoAuthAPI.java
@@ -263,11 +263,17 @@ public class ValidateDuoAuthAPI extends AbstractValidationAction {
if (duoContext.getDeviceID().equals(device.getDevice())) {
found = true;
break;
+ } else if (duoContext.getDeviceID().equals(device.getName())) {
+ log.debug("{} Remapped device ID based on device name ({}) for '{}'", getLogPrefix(),
+ device.getName(), username);
+ duoContext.setDeviceID(device.getDevice());
+ found = true;
+ break;
}
}
if (!found) {
- log.info("{} Request specified non-existent device ID ({}) for '{}': {}", getLogPrefix(),
- duoContext.getDeviceID(), username, preAuthResponse.getStatusMessage());
+ log.info("{} Duo authentication failed for '{}': non-existent device ID ({})", getLogPrefix(),
+ username, duoContext.getDeviceID());
handleError(profileRequestContext, authenticationContext, AuthnEventIds.INVALID_CREDENTIALS,
AuthnEventIds.INVALID_CREDENTIALS);
recordFailure();
@@ -284,7 +290,8 @@ public class ValidateDuoAuthAPI extends AbstractValidationAction {
final String authResult = authenticationResponse.getResult();
if (DuoAuthAPI.DUO_AUTH_RESULT_ALLOW.equals(authResult)) {
- log.info("{} Duo authentication succeeded for '{}'", getLogPrefix(), username);
+ log.info("{} Duo authentication succeeded for '{}', (Factor: {}, Device: {})", getLogPrefix(), username,
+ duoContext.getFactor(), duoContext.getDeviceID());
recordSuccess();
buildAuthenticationResult(profileRequestContext, authenticationContext);
} else if (DuoAuthAPI.DUO_AUTH_RESULT_DENY.equals(authResult)) {
diff --git a/idp-conf/src/main/resources/conf/authn/duo-authn-config.xml b/idp-conf/src/main/resources/conf/authn/duo-authn-config.xml
index 0a48152..3bf82e3 100644
--- a/idp-conf/src/main/resources/conf/authn/duo-authn-config.xml
+++ b/idp-conf/src/main/resources/conf/authn/duo-authn-config.xml
@@ -13,6 +13,8 @@
duo.properties file. If you need more flexibility, you can define a function bean
called "shibboleth.authn.Duo.DuoIntegrationStrategy" to return an instance of
net.shibboleth.idp.authn.duo.DuoIntegration based on the state of the request.
+ A second bean, "shibboleth.authn.Duo.NonBrowser.DuoIntegrationStrategy", can be
+ supplied to use the AuthAPI for non-browser profiles.
The Duo flow is designed to operate in conjunction with some other login flow,
usually orchestrated by the MFA login flow. It obtains the username to send to
diff --git a/idp-conf/src/main/resources/conf/authn/duo.properties b/idp-conf/src/main/resources/conf/authn/duo.properties
index 2ca71ee5..5e2af2c 100644
--- a/idp-conf/src/main/resources/conf/authn/duo.properties
+++ b/idp-conf/src/main/resources/conf/authn/duo.properties
@@ -1,9 +1,33 @@
-# Duo integration settings
+## Duo integration settings
-# Note: If upgrading from pre-3.3 IdP versions, you will need to manually add a pointer
-# to this property file to idp.properties.
+## Note: If upgrading from pre-3.3 IdP versions, you will need to manually add a pointer
+## to this property file to idp.properties.
+
+## The first set of properties support DuoWeb "iframe" integration.
idp.duo.apiHost = hostname
idp.duo.applicationKey = key
idp.duo.integrationKey = key
idp.duo.secretKey = key
+
+## The second set are used for direct AuthAPI usage for ECP support.
+## A seperate integration has to be created for this to work.
+
+#idp.duo.nonbrowser.apiHost = %{idp.duo.apiHost}
+#idp.duo.nonbrowser.applicationKey = key
+#idp.duo.nonbrowser.integrationKey = key
+#idp.duo.nonbrowser.secretKey = key
+
+## Request header names for Duo non-browser credentials.
+# idp.duo.nonbrowser.header.factor = X-Shibboleth-Duo-Factor
+# idp.duo.nonbrowser.header.device = X-Shibboleth-Duo-Device
+# idp.duo.nonbrowser.header.factor = X-Shibboleth-Duo-Passcode
+
+## Enables auto selection of factor/device if not specified by client.
+# idp.duo.nonbrowser.auto = true
+
+## Enables transmission of client address to Duo during authentication.
+# idp.duo.nonbrowser.clientAddressTrusted = true
+
+## Name of HttpClient bean to use.
+# idp.duo.nonbrowser.httpClient = shibboleth.NonCachingHttpClient
diff --git a/idp-conf/src/main/resources/system/flows/authn/duo-authn-beans.xml b/idp-conf/src/main/resources/system/flows/authn/duo-authn-beans.xml
index 6218c7e..536b2dd 100644
--- a/idp-conf/src/main/resources/system/flows/authn/duo-authn-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/authn/duo-authn-beans.xml
@@ -14,7 +14,8 @@
<bean class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />
<bean class="net.shibboleth.idp.profile.impl.ProfileActionBeanPostProcessor" />
- <!-- Default static integration. -->
+ <!-- Default static integrations. -->
+
<bean id="shibboleth.authn.Duo.DuoIntegration" class="net.shibboleth.idp.authn.duo.BasicDuoIntegration"
p:APIHost="%{idp.duo.apiHost:none}"
p:applicationKey="%{idp.duo.applicationKey:none}"
@@ -23,6 +24,15 @@
<bean id="shibboleth.authn.Duo.DuoIntegrationStrategy" class="com.google.common.base.Functions"
factory-method="constant" c:_0-ref="shibboleth.authn.Duo.DuoIntegration" />
+ <bean id="shibboleth.authn.Duo.NonBrowser.DuoIntegration" class="net.shibboleth.idp.authn.duo.BasicDuoIntegration"
+ p:APIHost="%{idp.duo.nonbrowser.apiHost:%{idp.duo.apiHost:none}}"
+ p:applicationKey="%{idp.duo.nonbrowser.applicationKey:none}"
+ p:integrationKey="%{idp.duo.nonbrowser.integrationKey:none}"
+ p:secretKey="%{idp.duo.nonbrowser.secretKey:none}" />
+ <bean id="shibboleth.authn.Duo.NonBrowser.DuoIntegrationStrategy" class="com.google.common.base.Functions"
+ factory-method="constant" c:_0-ref="shibboleth.authn.Duo.NonBrowser.DuoIntegration" />
+
+
<!-- Default username comes from previous c14n or session. -->
<bean id="shibboleth.authn.Duo.UsernameLookupStrategy"
class="net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy" />
@@ -37,6 +47,38 @@
p:httpServletRequest-ref="shibboleth.HttpServletRequest"
p:usernameLookupStrategy-ref="shibboleth.authn.Duo.UsernameLookupStrategy"
p:duoIntegrationLookupStrategy-ref="shibboleth.authn.Duo.DuoIntegrationStrategy"
- p:addDefaultPrincipals="#{getObject('shibboleth.authn.Duo.addDefaultPrincipals') ?: true}" />
+ p:addDefaultPrincipals="#{getObject('shibboleth.authn.Duo.addDefaultPrincipals') ?: true}"
+ p:resultCachingPredicate="#{getObject('shibboleth.authn.duo.resultCachingPredicate')}" />
+
+ <bean id="ExtractDuoAuthenticationFromHeaders" scope="prototype"
+ class="net.shibboleth.idp.authn.duo.impl.ExtractDuoAuthenticationFromHeaders"
+ p:httpServletRequest-ref="shibboleth.HttpServletRequest"
+ p:autoAuthenticationSupported="%{idp.duo.nonbrowser.auto:true}"
+ p:clientAdddressTrusted="%{idp.duo.nonbrowser.clientAddressTrusted:true}"
+ p:factorHeader="%{idp.duo.nonbrowser.header.factor:X-Shibboleth-Duo-Factor}"
+ p:deviceHeader="%{idp.duo.nonbrowser.header.device:X-Shibboleth-Duo-Device}"
+ p:passcodeHeader="%{idp.duo.nonbrowser.header.passcode:X-Shibboleth-Duo-Passcode}" />
+
+ <bean id="DuoPreauthAuthenticator" lazy-init="true"
+ class="net.shibboleth.idp.authn.duo.impl.DuoPreauthAuthenticator"
+ p:objectMapper-ref="shibboleth.JSONObjectMapper"
+ p:httpClient-ref="%{idp.duo.nonbrowser.httpClient:shibboleth.NonCachingHttpClient}" />
+
+ <bean id="DuoAuthAuthenticator" lazy-init="true"
+ class="net.shibboleth.idp.authn.duo.impl.DuoAuthAuthenticator"
+ p:objectMapper-ref="shibboleth.JSONObjectMapper"
+ p:httpClient-ref="%{idp.duo.nonbrowser.httpClient:shibboleth.NonCachingHttpClient}" />
+
+ <util:map id="shibboleth.authn.duo.DefaultClassifiedMessageMap" />
+
+ <bean id="ValidateDuoAuthAPI" scope="prototype"
+ class="net.shibboleth.idp.authn.duo.impl.ValidateDuoAuthAPI"
+ p:usernameLookupStrategy-ref="shibboleth.authn.Duo.UsernameLookupStrategy"
+ p:duoIntegrationLookupStrategy-ref="shibboleth.authn.Duo.NonBrowser.DuoIntegrationStrategy"
+ p:addDefaultPrincipals="#{getObject('shibboleth.authn.Duo.addDefaultPrincipals') ?: true}"
+ p:preauthAuthenticator-ref="DuoPreauthAuthenticator"
+ p:authAuthenticator-ref="DuoAuthAuthenticator"
+ p:classifiedMessages="#{getObject('shibboleth.authn.duo.ClassifiedMessageMap') ?: getObject('shibboleth.authn.duo.DefaultClassifiedMessageMap')}"
+ p:resultCachingPredicate="#{getObject('shibboleth.authn.duo.resultCachingPredicate')}" />
</beans>
diff --git a/idp-conf/src/main/resources/system/flows/authn/duo-authn-flow.xml b/idp-conf/src/main/resources/system/flows/authn/duo-authn-flow.xml
index 3b02daf..e58bec0 100644
--- a/idp-conf/src/main/resources/system/flows/authn/duo-authn-flow.xml
+++ b/idp-conf/src/main/resources/system/flows/authn/duo-authn-flow.xml
@@ -4,6 +4,25 @@
<!-- This is a simple login flow for Duo authentication. -->
+ <action-state id="ExtractDuoAuthenticationFromHeaders">
+ <evaluate expression="ExtractDuoAuthenticationFromHeaders" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="ValidateDuoAuthAPI" />
+
+ <!-- Fall through to a different flow if header 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="DisplayDuoWebView" />
+ </action-state>
+
+ <action-state id="ValidateDuoAuthAPI">
+ <evaluate expression="ValidateDuoAuthAPI" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="proceed" />
+ </action-state>
+
<view-state id="DisplayDuoWebView" view="duo">
<on-render>
<evaluate expression="environment" result="viewScope.environment" />
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list