[java-idp-plugin-duo] branch main updated: JDUO-33 - Add non-browser support to the new flow
Scott Cantor
cantor.2 at osu.edu
Fri Feb 12 19:21:17 UTC 2021
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-idp-plugin-duo.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-duo.git;a=commit;h=ab638ef5111364f072a2c5075bd9327ef649dca6
The following commit(s) were added to refs/heads/main by this push:
new ab638ef JDUO-33 - Add non-browser support to the new flow
ab638ef is described below
commit ab638ef5111364f072a2c5075bd9327ef649dca6
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Feb 12 14:21:14 2021 -0500
JDUO-33 - Add non-browser support to the new flow
https://issues.shibboleth.net/jira/browse/JDUO-33
---
idp-duo-impl/pom.xml | 10 ++++
.../META-INF/net.shibboleth.idp/postconfig.xml | 2 +-
.../flows/authn/DuoOIDC/duo-oidc-authn-beans.xml | 53 ++++++++++++++++++++--
.../flows/authn/DuoOIDC/duo-oidc-authn-flow.xml | 20 +++++++-
.../impl/AbstractAuthnXmlFlowExecutionTests.java | 1 +
.../plugin/authn/duo/impl/DuoAuthnFlowTest.java | 3 +-
.../duo/nimbus/conf/authn/duo-oidc.properties | 20 +++++++-
.../authn/duo/sdk/conf/authn/duo-oidc.properties | 20 +++++++-
8 files changed, 118 insertions(+), 11 deletions(-)
diff --git a/idp-duo-impl/pom.xml b/idp-duo-impl/pom.xml
index 20df8d4..89d64a7 100644
--- a/idp-duo-impl/pom.xml
+++ b/idp-duo-impl/pom.xml
@@ -53,6 +53,16 @@
<artifactId>idp-authn-api</artifactId>
<scope>provided</scope>
</dependency>
+ <!--
+ Needed to reuse Duo AuthAPI code from original flow.
+ Can be removed if/when original flow is discontinued.
+ -->
+ <dependency>
+ <groupId>${idp.groupId}</groupId>
+ <artifactId>idp-authn-impl</artifactId>
+ <version>${idp.version}</version>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>${opensaml.groupId}</groupId>
<artifactId>opensaml-messaging-api</artifactId>
diff --git a/idp-duo-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-duo-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index e353312..285d8e0 100644
--- a/idp-duo-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-duo-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -27,7 +27,7 @@
p:subjectDecorator="#{getObject('%{idp.authn.DuoOIDC.subjectDecorator:}'.trim())}">
<property name="supportedPrincipalsByString">
<bean parent="shibboleth.CommaDelimStringArray"
- c:_0="#{'%{idp.authn.DuoOIDC.supportedPrincipals:%{idp.authn.Duo.supportedPrincipals}}'.trim()}" />
+ c:_0="#{'%{idp.authn.DuoOIDC.supportedPrincipals:%{idp.authn.Duo.supportedPrincipals:}}'.trim()}" />
</property>
</bean>
diff --git a/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-beans.xml b/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-beans.xml
index e26a3fe..b2efad2 100644
--- a/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-beans.xml
+++ b/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-beans.xml
@@ -24,16 +24,25 @@
<!-- Default Duo Integration -->
<bean id="shibboleth.authn.DuoOIDC.DuoIntegration"
- class="net.shibboleth.idp.plugin.authn.duo.DefaultDuoOIDCIntegration" p:APIHost="%{idp.duo.oidc.apiHost:none}"
- p:clientId="%{idp.duo.oidc.clientId:none}" p:secretKey="%{idp.duo.oidc.secretKey:none}"
+ class="net.shibboleth.idp.plugin.authn.duo.DefaultDuoOIDCIntegration"
+ p:APIHost="%{idp.duo.oidc.apiHost:none}"
+ p:clientId="%{idp.duo.oidc.clientId:none}"
+ p:secretKey="%{idp.duo.oidc.secretKey:none}"
p:redirectURI="%{idp.duo.oidc.redirectURL:none}"
p:healthCheckEndpoint="%{idp.duo.oidc.endpoint.health:/oauth/v1/health_check}"
p:tokenEndpoint="%{idp.duo.oidc.endpoint.token:/oauth/v1/token}"
- p:authorizeEndpoint="%{idp.duo.oidc.endpoint.authorize:/oauth/v1/authorize}"
- />
+ p:authorizeEndpoint="%{idp.duo.oidc.endpoint.authorize:/oauth/v1/authorize}" />
<bean id="shibboleth.authn.DuoOIDC.DuoIntegrationStrategy" parent="shibboleth.Functions.Constant"
c:target-ref="shibboleth.authn.DuoOIDC.DuoIntegration" />
+ <!-- Default "optional" non-browser integration. -->
+ <bean id="shibboleth.authn.DuoOIDC.NonBrowser.DuoIntegration" class="net.shibboleth.idp.authn.duo.BasicDuoIntegration"
+ p:APIHost="%{idp.duo.oidc.nonbrowser.apiHost:%{idp.duo.oidc.apiHost:none}}"
+ p:integrationKey="%{idp.duo.oidc.nonbrowser.integrationKey:none}"
+ p:secretKey="%{idp.duo.oidc.nonbrowser.secretKey:none}" />
+ <bean id="shibboleth.authn.DuoOIDC.NonBrowser.DuoIntegrationStrategy" parent="shibboleth.Functions.Constant"
+ c:target-ref="shibboleth.authn.DuoOIDC.NonBrowser.DuoIntegration" />
+
<!-- Default username comes from previous c14n or session. -->
<bean id="shibboleth.authn.DuoOIDC.UsernameLookupStrategy"
class="net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy" />
@@ -51,13 +60,47 @@
to change the location of the user config file. -->
<import resource="conditional:%{idp.home}/conf/authn/%{idp.duo.oidc.user.config:duo-oidc-authn-config.xml}" />
+ <!--
+ Non-Browser actions and beans. Code lives in idp-authn-impl for now, may migrate here later.
+ -->
+ <bean id="ExtractDuoAuthenticationFromHeaders" scope="prototype"
+ class="net.shibboleth.idp.authn.duo.impl.ExtractDuoAuthenticationFromHeaders"
+ p:httpServletRequest-ref="shibboleth.HttpServletRequest"
+ p:autoAuthenticationSupported="%{idp.duo.oidc.nonbrowser.auto:true}"
+ p:clientAdddressTrusted="%{idp.duo.oidc.nonbrowser.clientAddressTrusted:true}"
+ p:factorHeader="%{idp.duo.oidc.nonbrowser.header.factor:X-Shibboleth-Duo-Factor}"
+ p:deviceHeader="%{idp.duo.oidc.nonbrowser.header.device:X-Shibboleth-Duo-Device}"
+ p:passcodeHeader="%{idp.duo.oidc.nonbrowser.header.passcode:X-Shibboleth-Duo-Passcode}"
+ p:pushInfoLookupStrategy="#{getObject('shibboleth.authn.DuoOIDC.PushInfoLookupStrategy')}" />
+
+ <bean id="DuoPreauthAuthenticator" lazy-init="true"
+ class="net.shibboleth.idp.authn.duo.impl.DuoPreauthAuthenticator"
+ p:objectMapper-ref="shibboleth.JSONObjectMapper"
+ p:httpClient="#{getObject('shibboleth.authn.DuoOIDC.NonBrowser.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
+ p:httpClientSecurityParameters="#{getObject('shibboleth.authn.DuoOIDC.NonBrowser.HttpClientSecurityParameters')}" />
+
+ <bean id="DuoAuthAuthenticator" lazy-init="true"
+ class="net.shibboleth.idp.authn.duo.impl.DuoAuthAuthenticator"
+ p:objectMapper-ref="shibboleth.JSONObjectMapper"
+ p:httpClient="#{getObject('shibboleth.authn.DuoOIDC.NonBrowser.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
+ p:httpClientSecurityParameters="#{getObject('shibboleth.authn.DuoOIDC.NonBrowser.HttpClientSecurityParameters')}" />
+
+ <bean id="ValidateDuoAuthAPI" scope="prototype"
+ class="net.shibboleth.idp.authn.duo.impl.ValidateDuoAuthAPI"
+ p:usernameLookupStrategy-ref="shibboleth.authn.DuoOIDC.UsernameLookupStrategy"
+ p:duoIntegrationLookupStrategy-ref="shibboleth.authn.DuoOIDC.NonBrowser.DuoIntegrationStrategy"
+ p:addDefaultPrincipals="%{idp.authn.DuoOIDC.addDefaultPrincipals:true}"
+ p:preauthAuthenticator-ref="DuoPreauthAuthenticator"
+ p:authAuthenticator-ref="DuoAuthAuthenticator"
+ p:classifiedMessages="#{getObject('shibboleth.authn.DuoOIDC.ClassifiedMessageMap')}"
+ p:resultCachingPredicate="#{getObject('shibboleth.authn.DuoOIDC.resultCachingPredicate')}" />
+
<!-- Prototype per conversation beans -->
<bean id="PopulateDuoAuthenticationContext" scope="prototype"
class="net.shibboleth.idp.plugin.authn.duo.impl.PopulateDuoAuthenticationContext"
p:duoIntegrationLookupStrategy-ref="shibboleth.authn.DuoOIDC.DuoIntegrationStrategy"
p:usernameLookupStrategy-ref="shibboleth.authn.DuoOIDC.UsernameLookupStrategy"
p:clientRegistry-ref="shibboleth.authn.DuoOIDC.clientRegistry" />
-
<bean id="HealthCheckDuoOIDCAuthAPI" scope="prototype"
class="net.shibboleth.idp.plugin.authn.duo.impl.HealthCheckDuoOIDCAuthAPI" />
diff --git a/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-flow.xml b/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-flow.xml
index 5d4805f..9b95f96 100644
--- a/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-flow.xml
+++ b/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-flow.xml
@@ -4,6 +4,25 @@
<!-- This is a login flow for the Duo OIDC authentication flow -->
+ <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="CheckDuoOIDCAuthAPI" />
+ </action-state>
+
+ <action-state id="ValidateDuoAuthAPI">
+ <evaluate expression="ValidateDuoAuthAPI" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="proceed" />
+ </action-state>
+
<!-- TODO: throws an AuthnException if the endpoint is not healthy, no backoff etc. -->
<action-state id="CheckDuoOIDCAuthAPI">
<evaluate expression="PopulateDuoAuthenticationContext" />
@@ -12,7 +31,6 @@
<transition on="proceed" to="Duo2FAAuthorizationRequest" />
</action-state>
-
<view-state id="Duo2FAAuthorizationRequest"
view="externalRedirect:#{T(net.shibboleth.idp.authn.ExternalAuthentication).getExternalRedirect(flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.authn.DuoOIDC.externalAuthnPathStrategy').apply(opensamlProfileRequestContext) + '/authorize', flowExecutionContext.getKey().toString())}">
<attribute name="csrf_excluded" value="true" type="boolean" />
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/AbstractAuthnXmlFlowExecutionTests.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/AbstractAuthnXmlFlowExecutionTests.java
index 0de0f8e..531c37b 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/AbstractAuthnXmlFlowExecutionTests.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/AbstractAuthnXmlFlowExecutionTests.java
@@ -414,6 +414,7 @@ public abstract class AbstractAuthnXmlFlowExecutionTests extends CustomAbstractX
sc.setIdPSession(session);
prc.addSubcontext(sc);
+ prc.setBrowserProfile(true);
return prc;
}
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/DuoAuthnFlowTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/DuoAuthnFlowTest.java
index 47823f6..30d7035 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/DuoAuthnFlowTest.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/DuoAuthnFlowTest.java
@@ -125,10 +125,9 @@ public class DuoAuthnFlowTest extends AbstractAuthnXmlFlowExecutionTests {
flowExecution.getConversationScope().put("opensamlProfileRequestContext", buildProfileRequestContext(false,true));
updateFlowExecution(flowExecution);
flowExecution.start(inputMap, externalContext);
- //TODO: only check it has ended, should check correct state - but it does now allow this
+ //TODO: only check it has ended, should check correct state - but it does not allow this
//find a way to check last state of an ended flow.
assertFlowExecutionEnded();
-
}
/** Test the Duo flow up to the external authorization request.*/
diff --git a/idp-duo-nimbus-client-impl/src/main/resources/net/shibboleth/idp/plugin/authn/duo/nimbus/conf/authn/duo-oidc.properties b/idp-duo-nimbus-client-impl/src/main/resources/net/shibboleth/idp/plugin/authn/duo/nimbus/conf/authn/duo-oidc.properties
index e3bae0a..ced668f 100644
--- a/idp-duo-nimbus-client-impl/src/main/resources/net/shibboleth/idp/plugin/authn/duo/nimbus/conf/authn/duo-oidc.properties
+++ b/idp-duo-nimbus-client-impl/src/main/resources/net/shibboleth/idp/plugin/authn/duo/nimbus/conf/authn/duo-oidc.properties
@@ -1,13 +1,31 @@
## DuoOIDC default integration settings
+# Generic flow properties to adjust behavior
+#idp.authn.DuoOIDC.order = 1000
+#idp.authn.DuoOIDC.nonBrowserSupported = false
+#idp.authn.DuoOIDC.forcedAuthenticationSupported = true
+# The list below should be changed to reflect whatever locally- or
+# community-defined values are appropriate to represent Duo. It is
+# strongly advised that the value not be specific to Duo or any
+# particular technology to avoid lock-in.
+idp.authn.DuoOIDC.supportedPrincipals = \
+ saml2/http://example.org/ac/classes/mfa, \
+ saml1/http://example.org/ac/classes/mfa
+
+
# Configure for your particular integration settings
idp.duo.oidc.apiHost = hostname
idp.duo.oidc.clientId = clientid
idp.duo.oidc.redirectURL = https://<hostname>:<port>/idp/profile/Authn/Duo/2FA/duo-callback
-
# We suggest defining this in credentials/secrets.properties
#idp.duo.oidc.secretKey = key
+# Non-Browser AuthAPI integration if desired
+#idp.duo.oidc.nonbrowser.apiHost = %{idp.duo.oidc.apiHost}
+#idp.duo.oidc.nonbrowser.integrationKey = ikey
+# Suggest defining this in credentials/secrets.properties
+#idp.duo.oidc nonbrowser.secretKey = key
+
# Shouldn't need changing
#idp.duo.oidc.endpoint.health = /oauth/v1/health_check
#idp.duo.oidc.endpoint.token = /oauth/v1/token
diff --git a/idp-duo-sdk-client-impl/src/main/resources/net/shibboleth/idp/plugin/authn/duo/sdk/conf/authn/duo-oidc.properties b/idp-duo-sdk-client-impl/src/main/resources/net/shibboleth/idp/plugin/authn/duo/sdk/conf/authn/duo-oidc.properties
index 04a6e41..2f85ccd 100644
--- a/idp-duo-sdk-client-impl/src/main/resources/net/shibboleth/idp/plugin/authn/duo/sdk/conf/authn/duo-oidc.properties
+++ b/idp-duo-sdk-client-impl/src/main/resources/net/shibboleth/idp/plugin/authn/duo/sdk/conf/authn/duo-oidc.properties
@@ -1,13 +1,31 @@
## DuoOIDC default integration settings
+# Generic flow properties to adjust behavior
+#idp.authn.DuoOIDC.order = 1000
+#idp.authn.DuoOIDC.nonBrowserSupported = false
+#idp.authn.DuoOIDC.forcedAuthenticationSupported = true
+# The list below should be changed to reflect whatever locally- or
+# community-defined values are appropriate to represent Duo. It is
+# strongly advised that the value not be specific to Duo or any
+# particular technology to avoid lock-in.
+idp.authn.DuoOIDC.supportedPrincipals = \
+ saml2/http://example.org/ac/classes/mfa, \
+ saml1/http://example.org/ac/classes/mfa
+
+
# Configure for your particular integration settings
idp.duo.oidc.apiHost = hostname
idp.duo.oidc.clientId = clientid
idp.duo.oidc.redirectURL = https://<hostname>:<port>/idp/profile/Authn/Duo/2FA/duo-callback
-
# We suggest defining this in credentials/secrets.properties
#idp.duo.oidc.secretKey = key
+# Non-Browser AuthAPI integration if desired
+#idp.duo.oidc.nonbrowser.apiHost = %{idp.duo.oidc.apiHost}
+#idp.duo.oidc.nonbrowser.integrationKey = ikey
+# Suggest defining this in credentials/secrets.properties
+#idp.duo.oidc nonbrowser.secretKey = key
+
# Shouldn't need changing
#idp.duo.oidc.endpoint.health = /oauth/v1/health_check
#idp.duo.oidc.endpoint.token = /oauth/v1/token
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list