[java-idp-plugin-duo] branch master updated: Add Issuer validation for completeness
Phil Smart
philip.smart at jisc.ac.uk
Wed Aug 5 12:52:51 UTC 2020
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch master
in repository java-idp-plugin-duo.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-duo.git;a=commit;h=15579841e58ceb2e03726cd804c3fd5cf8abf72b
The following commit(s) were added to refs/heads/master by this push:
new 1557984 Add Issuer validation for completeness
1557984 is described below
commit 15579841e58ceb2e03726cd804c3fd5cf8abf72b
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Wed Aug 5 13:52:46 2020 +0100
Add Issuer validation for completeness
---
.../authn/duo/impl/ValidateDuoTokenIssuedAt.java | 3 +-
.../authn/duo/impl/ValidateDuoTokenIssuer.java | 48 ++++++++++++++--
.../flows/authn/DuoOIDC/duo-oidc-authn-beans.xml | 64 +++++++++++-----------
.../flows/authn/DuoOIDC/duo-oidc-authn-flow.xml | 1 +
.../impl/AbstractAuthnXmlFlowExecutionTests.java | 9 ++-
.../authn/duo/impl/AbstractDuoActionTest.java | 8 +--
.../plugin/authn/duo/impl/DuoAuthnFlowTest.java | 12 ++--
.../duo/impl/ValidateDuoTokenAudienceTest.java | 4 +-
.../ValidateDuoTokenAuthenticationResultTest.java | 6 +-
.../ValidateDuoTokenAuthenticationTimeTest.java | 10 ++--
.../impl/ValidateDuoTokenExpirationTimeTest.java | 8 +--
.../duo/impl/ValidateDuoTokenIssuedAtTest.java | 6 +-
...ctTest.java => ValidateDuoTokenIssuerTest.java} | 61 +++++++++++----------
.../duo/impl/ValidateDuoTokenSubjectTest.java | 4 +-
.../plugin/authn/mock/MockDuoOIDCClient_OK.java | 2 +-
15 files changed, 146 insertions(+), 100 deletions(-)
diff --git a/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuedAt.java b/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuedAt.java
index ed9906f..4ee87c0 100644
--- a/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuedAt.java
+++ b/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuedAt.java
@@ -57,7 +57,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
* @event {@link net.shibboleth.idp.authn.AuthnEventIds#AUTHN_EXCEPTION}
*/
public class ValidateDuoTokenIssuedAt extends AbstractDuoAuthenticationAction {
-
+
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(ValidateDuoTokenIssuedAt.class);
@@ -70,6 +70,7 @@ public class ValidateDuoTokenIssuedAt extends AbstractDuoAuthenticationAction {
/** The Duo authentication token. */
@Nullable private DuoAuthToken token;
+
/** Constructor. */
public ValidateDuoTokenIssuedAt() {
iatMaxClockSkew = Duration.ofMinutes(3);
diff --git a/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuer.java b/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuer.java
index 0e2de20..298a31a 100644
--- a/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuer.java
+++ b/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuer.java
@@ -30,12 +30,16 @@ import net.shbboleth.idp.plugin.authn.duo.context.DuoOIDCAuthenticationContext;
import net.shbboleth.idp.plugin.authn.duo.model.DuoAuthToken;
import net.shibboleth.idp.authn.AuthnEventIds;
import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
/**
- * An action that verifies the issuer (iss) of the id_token exactly matches that of the configured
- * Duo token provider. See section 3.1.3.7 of OpenID Connect core 1.0.
+ * <p>An action that verifies the issuer (iss) of the id_token exactly matches that of the configured
+ * Duo token provider. See section 3.1.3.7 of OpenID Connect core 1.0.</p>
*
- * * @pre
+ * <p>This is specific to the Duo implementation, and mimics the native Duo client issuer validation.</p>
+ *
+ * @pre
*
* <pre>
* ProfileRequestContext.getSubcontext(AuthenticationContext.class, false) != null
@@ -56,15 +60,35 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
* @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
* @event {@link net.shibboleth.idp.authn.AuthnEventIds#AUTHN_EXCEPTION}
*
- * TODO: Can we do this for Duo (The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery) MUST exactly match the value of the iss (issuer) Claim.)
*/
public class ValidateDuoTokenIssuer extends AbstractDuoAuthenticationAction {
+
+ /** HTTPS scheme protocol.*/
+ private static final String HTTPS = "https://";
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(ValidateDuoTokenIssuer.class);
/** The Duo authentication token. */
@Nullable private DuoAuthToken token;
+
+ /** The URL path component of the issuer.*/
+ @Nonnull private String issuerPath;
+
+ /** Constructor.*/
+ public ValidateDuoTokenIssuer() {
+ issuerPath = "/oauth/v1/token";
+ }
+
+ /**
+ * Sets the issuer URL path component.
+ *
+ * @param path the issuer path
+ */
+ public synchronized void setIssuerPath(@Nonnull final String path) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ issuerPath = Constraint.isNotNull(path, "Issuer URL path cannot be null");
+ }
@Override
protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
@@ -97,9 +121,21 @@ public class ValidateDuoTokenIssuer extends AbstractDuoAuthenticationAction {
ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.AUTHN_EXCEPTION);
return;
}
+ final String apiHost = duoContext.getIntegration().getAPIHost();
+ if (apiHost == null) {
+ log.error("{} No Duo integration API host found", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.AUTHN_EXCEPTION);
+ return;
+ }
- //TODO: NOT IMPLEMENTED.
- //audience is fine
+ final String issuerFromIntegration = HTTPS+apiHost+issuerPath;
+ if (!issuer.equals(issuerFromIntegration)) {
+ log.error("{} Token issuer differs from that expected, issuer is '{}', expected '{}'",getLogPrefix(),
+ issuer,issuerFromIntegration);
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.AUTHN_EXCEPTION);
+ return;
+ }
+ //isuer is fine.
}
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 139e68f..479ee38 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,26 +24,24 @@
<!-- Default Duo Integration -->
<bean id="shibboleth.authn.duo.OIDC.DuoIntegration"
- class="net.shbboleth.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.redirectUri:none}" />
+ class="net.shbboleth.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.redirectUri:none}" />
<bean id="shibboleth.authn.duo.OIDC.DuoIntegrationStrategy" parent="shibboleth.Functions.Constant"
c:target-ref="shibboleth.authn.duo.OIDC.DuoIntegration" />
-
- <!-- Default username comes from previous c14n or session. -->
+
+ <!-- Default username comes from previous c14n or session. -->
<bean id="shibboleth.authn.duo.OIDC.UsernameLookupStrategy"
class="net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy" />
-
- <!-- Duo Client factory and bean registry -->
+
+ <!-- Duo Client factory and bean registry -->
<bean id="shibboleth.authn.duo.OIDC.clientRegistry" scope="singleton"
class="net.shibboleth.idp.plugin.authn.duo.impl.DefaultDuoOIDCClientRegistry"
p:clientFactory="#{getObject('shibboleth.authn.duo.OIDC.clientFactory') ?: getObject('shibboleth.authn.duo.OIDC.internal.clientFactory')}" />
-
- <!-- FIXME: aim here is to allow this to be switched out, but as it stands you always need this dep as it is
- explicit here! -->
+
+ <!-- FIXME: aim here is to allow this to be switched out, but as it stands you always need this dep as it is explicit
+ here! -->
<bean id="shibboleth.authn.duo.OIDC.internal.clientFactory"
class="net.shibboleth.idp.plugin.authn.duo.sdk.impl.DuoSDKClientFactory" scope="singleton">
<!-- certficate pins. probably need managing external to the flow/plugin or overwritable -->
@@ -62,12 +60,12 @@
</list>
</property>
</bean>
-
-
+
+
<!-- Can override one or more of the beans above. -->
<import resource="${idp.duo.oidc.config.user:%{idp.home}/conf/authn/duo-authn-config.xml}" />
-
+
<!-- Prototype per conversation beans -->
<bean id="PopulateDuoAuthenticationContext" scope="prototype"
class="net.shibboleth.idp.plugin.authn.duo.impl.PopulateDuoAuthenticationContext"
@@ -76,35 +74,37 @@
p:clientRegistry-ref="shibboleth.authn.duo.OIDC.clientRegistry" />
<bean id="HealthCheckDuoOIDCAuthAPI" scope="prototype"
- class="net.shibboleth.idp.plugin.authn.duo.impl.HealthCheckDuoOIDCAuthAPI"/>
+ class="net.shibboleth.idp.plugin.authn.duo.impl.HealthCheckDuoOIDCAuthAPI" />
<bean id="ValidateDuoResponseState" scope="prototype"
class="net.shibboleth.idp.plugin.authn.duo.impl.ValidateDuoResponseState" />
-
- <bean id="ValidateDuoTokenAudience" scope="prototype"
+
+ <bean id="ValidateDuoTokenAudience" scope="prototype"
class="net.shibboleth.idp.plugin.authn.duo.impl.ValidateDuoTokenAudience" />
-
- <bean id="ValidateDuoTokenExpirationTime" scope="prototype"
+
+ <bean id="ValidateDuoTokenIssuer" scope="prototype"
+ class="net.shibboleth.idp.plugin.authn.duo.impl.ValidateDuoTokenIssuer" />
+
+ <bean id="ValidateDuoTokenExpirationTime" scope="prototype"
class="net.shibboleth.idp.plugin.authn.duo.impl.ValidateDuoTokenExpirationTime" />
-
- <bean id="ValidateDuoTokenAuthenticationTime" scope="prototype"
+
+ <bean id="ValidateDuoTokenAuthenticationTime" scope="prototype"
class="net.shibboleth.idp.plugin.authn.duo.impl.ValidateDuoTokenAuthenticationTime" />
-
- <bean id="ValidateDuoTokenIssuedAt" scope="prototype"
+
+ <bean id="ValidateDuoTokenIssuedAt" scope="prototype"
class="net.shibboleth.idp.plugin.authn.duo.impl.ValidateDuoTokenIssuedAt" />
<bean id="ExchangeCodeForDuoToken" scope="prototype"
- class="net.shibboleth.idp.plugin.authn.duo.impl.ExchangeCodeForDuoToken"/>
+ class="net.shibboleth.idp.plugin.authn.duo.impl.ExchangeCodeForDuoToken" />
- <bean id="ValidateDuoTokenAuthenticationResult" scope="prototype"
- class="net.shibboleth.idp.plugin.authn.duo.impl.ValidateDuoTokenAuthenticationResult"
+ <bean id="ValidateDuoTokenAuthenticationResult" scope="prototype"
+ class="net.shibboleth.idp.plugin.authn.duo.impl.ValidateDuoTokenAuthenticationResult"
p:addDefaultPrincipals="#{getObject('shibboleth.authn.duo.OIDC.addDefaultPrincipals') ?: true}"
p:classifiedMessages="#{getObject('shibboleth.authn.duo.OIDC.ClassifiedMessageMap') ?: getObject('shibboleth.authn.duo.OIDC.DefaultClassifiedMessageMap')}"
- p:resultCachingPredicate="#{getObject('shibboleth.authn.duo.OIDC.resultCachingPredicate')}"
- />
-
- <!-- TODO may not be the correct values for the new API -->
- <util:map id="shibboleth.authn.duo.OIDC.DefaultClassifiedMessageMap">
+ p:resultCachingPredicate="#{getObject('shibboleth.authn.duo.OIDC.resultCachingPredicate')}" />
+
+ <!-- TODO may not be the correct values for the new API -->
+ <util:map id="shibboleth.authn.duo.OIDC.DefaultClassifiedMessageMap">
<entry key="AccountLocked">
<list>
<value>locked_out</value>
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 4b68345..3015391 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
@@ -35,6 +35,7 @@
<evaluate expression="ExchangeCodeForDuoToken"/>
<!-- validate the token and set principal -->
<evaluate expression="ValidateDuoTokenAudience"/>
+ <evaluate expression="ValidateDuoTokenIssuer"/>
<evaluate expression="ValidateDuoTokenExpirationTime"/>
<evaluate expression="ValidateDuoTokenAuthenticationTime"/>
<evaluate expression="ValidateDuoTokenIssuedAt"/>
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 4c93c3c..db64e0f 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
@@ -328,7 +328,8 @@ public abstract class AbstractAuthnXmlFlowExecutionTests extends AbstractXmlFlow
* @param forceAuthn force authentication
* @return a profile request context.
*/
- @Nonnull protected ProfileRequestContext buildProfileRequestContext(@Nonnull final boolean forceAuthn) {
+ @Nonnull protected ProfileRequestContext buildProfileRequestContext(@Nonnull final boolean forceAuthn,
+ @Nonnull boolean addC14Context) {
final ProfileRequestContext prc = new ProfileRequestContext();
final AuthenticationContext ac = new AuthenticationContext();
@@ -338,9 +339,11 @@ public abstract class AbstractAuthnXmlFlowExecutionTests extends AbstractXmlFlow
ac.addSubcontext(new RelyingPartyUIContext());
ac.setForceAuthn(forceAuthn);
prc.addSubcontext(ac);
+ if (addC14Context) {
final SubjectCanonicalizationContext scc = new SubjectCanonicalizationContext();
- scc.setPrincipalName("jdoe");
- prc.addSubcontext(scc);
+ scc.setPrincipalName("jdoe");
+ prc.addSubcontext(scc);
+ }
final SessionContext sc = new SessionContext();
final IdPSession session = Mockito.mock(IdPSession.class);
Mockito.when(session.getPrincipalName()).thenReturn("jdoe");
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/AbstractDuoActionTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/AbstractDuoActionTest.java
index 6e706e8..f81d2d7 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/AbstractDuoActionTest.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/AbstractDuoActionTest.java
@@ -60,7 +60,7 @@ public abstract class AbstractDuoActionTest {
protected static final String REDIRECT_URI = "http://localhost/";
- protected static final String API_HOST = "host.com";
+ protected static final String API_HOST = "api.duosecurity.com";
protected static final String SECRET = "rFvDfPul27v3Wew2zb6xRPzAJewJ34MP2w8UitPh";
@@ -103,15 +103,15 @@ public abstract class AbstractDuoActionTest {
* @param exp expiration time.
* @param iat issued at.
* @param authTime the auth time.
- *
+ * @param apiHost TODO
* @return the duo auth token.
*/
protected DuoAuthToken createDummyToken(@Nonnull final String authResult,
@Nonnull final String authResultMessage, @Nonnull final String aud,
@Nonnull final Instant exp, @Nonnull final Instant iat,
- @Nonnull final Instant authTime) {
+ @Nonnull final Instant authTime, @Nonnull final String apiHost) {
return DuoAuthToken.builder()
- .withIss("https://api.duosecurity.com/oauth/v1/token")
+ .withIss("https://"+apiHost+"/oauth/v1/token")
.withSub("jdoe")
.withAud(aud)
.withExp(Math.toIntExact(exp.getEpochSecond()))
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 d8c6ee3..9dd7584 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
@@ -114,7 +114,7 @@ public class DuoAuthnFlowTest extends AbstractAuthnXmlFlowExecutionTests {
inputMap.put("calledAsSubflow", true);
final FlowExecution flowExecution = getFlowExecutionFactory().createFlowExecution(getFlowDefinition());
- flowExecution.getConversationScope().put("opensamlProfileRequestContext", buildProfileRequestContext(false));
+ flowExecution.getConversationScope().put("opensamlProfileRequestContext", buildProfileRequestContext(false,true));
updateFlowExecution(flowExecution);
flowExecution.start(inputMap, externalContext);
assertFlowExecutionEnded();
@@ -143,7 +143,7 @@ public class DuoAuthnFlowTest extends AbstractAuthnXmlFlowExecutionTests {
inputMap.put("calledAsSubflow", true);
final FlowExecution flowExecution = getFlowExecutionFactory().createFlowExecution(getFlowDefinition());
- flowExecution.getConversationScope().put("opensamlProfileRequestContext", buildProfileRequestContext(false));
+ flowExecution.getConversationScope().put("opensamlProfileRequestContext", buildProfileRequestContext(false,true));
updateFlowExecution(flowExecution);
flowExecution.start(inputMap, externalContext);
assertFlowExecutionActive();
@@ -174,7 +174,7 @@ public class DuoAuthnFlowTest extends AbstractAuthnXmlFlowExecutionTests {
inputMap.put("calledAsSubflow", true);
final FlowExecution flowExecution = getFlowExecutionFactory().createFlowExecution(getFlowDefinition());
- final ProfileRequestContext prcOne = buildProfileRequestContext(false);
+ final ProfileRequestContext prcOne = buildProfileRequestContext(false,true);
final RelyingPartyContext rpcOne = new RelyingPartyContext();
rpcOne.setRelyingPartyId(FIRST_INTEGRATION_SP);
prcOne.addSubcontext(rpcOne);
@@ -217,7 +217,7 @@ public class DuoAuthnFlowTest extends AbstractAuthnXmlFlowExecutionTests {
inputMap.put("calledAsSubflow", true);
final FlowExecution flowExecution = getFlowExecutionFactory().createFlowExecution(getFlowDefinition());
- final ProfileRequestContext prcOne = buildProfileRequestContext(false);
+ final ProfileRequestContext prcOne = buildProfileRequestContext(false,true);
final RelyingPartyContext rpcOne = new RelyingPartyContext();
rpcOne.setRelyingPartyId(SECOND_INTEGRATION_SP);
prcOne.addSubcontext(rpcOne);
@@ -261,7 +261,7 @@ public class DuoAuthnFlowTest extends AbstractAuthnXmlFlowExecutionTests {
inputMap.put("calledAsSubflow", true);
final FlowExecution flowExecution = getFlowExecutionFactory().createFlowExecution(getFlowDefinition());
- flowExecution.getConversationScope().put("opensamlProfileRequestContext", buildProfileRequestContext(false));
+ flowExecution.getConversationScope().put("opensamlProfileRequestContext", buildProfileRequestContext(false,true));
updateFlowExecution(flowExecution);
flowExecution.start(inputMap, externalContext);
assertFlowExecutionActive();
@@ -289,7 +289,7 @@ public class DuoAuthnFlowTest extends AbstractAuthnXmlFlowExecutionTests {
final FlowExecutionImpl flowExecution = (FlowExecutionImpl)getFlowExecutionFactory()
.createFlowExecution(getFlowDefinition());
- final ProfileRequestContext prc = buildProfileRequestContext(false);
+ final ProfileRequestContext prc = buildProfileRequestContext(false,false);
//add a DuoContext
final DuoOIDCAuthenticationContext duoContext = new DuoOIDCAuthenticationContext();
final String nonce = DuoSupport.generateNonce(32);
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAudienceTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAudienceTest.java
index 7e0949b..0815b9e 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAudienceTest.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAudienceTest.java
@@ -69,7 +69,7 @@ public class ValidateDuoTokenAudienceTest extends AbstractDuoActionTest {
addDuoIntegrationToContext();
addAttemptedFlow("authn/DuoOIDC");
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now()));
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
@@ -84,7 +84,7 @@ public class ValidateDuoTokenAudienceTest extends AbstractDuoActionTest {
addDuoIntegrationToContext();
addAttemptedFlow("authn/DuoOIDC");
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful","WRONG",
- Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now()));
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAuthenticationResultTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAuthenticationResultTest.java
index e725765..4f90ae6 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAuthenticationResultTest.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAuthenticationResultTest.java
@@ -61,7 +61,7 @@ public class ValidateDuoTokenAuthenticationResultTest extends AbstractDuoActionT
addDuoIntegrationToContext();
addAttemptedFlow("authn/DuoOIDC");
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now()));
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "api.duosecurity.com"));
dc.setUsername("jdoe");
action.initialize();
@@ -100,7 +100,7 @@ public class ValidateDuoTokenAuthenticationResultTest extends AbstractDuoActionT
action.setClassifiedMessages(classifiedMessages);
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_DENY,"Account locked",CLIENT_ID,
- Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now()));
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "api.duosecurity.com"));
dc.setUsername("jdoe");
action.initialize();
@@ -140,7 +140,7 @@ public class ValidateDuoTokenAuthenticationResultTest extends AbstractDuoActionT
addAttemptedFlow("authn/DuoOIDC");
//made up fail message, TODO: do they describe this anywhere.
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_DENY,"Login Failed",CLIENT_ID,
- Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now()));
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "api.duosecurity.com"));
dc.setUsername("jdoe");
action.initialize();
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAuthenticationTimeTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAuthenticationTimeTest.java
index 1a6e876..0af88ee 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAuthenticationTimeTest.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenAuthenticationTimeTest.java
@@ -68,7 +68,7 @@ public class ValidateDuoTokenAuthenticationTimeTest extends AbstractDuoActionTes
action.setClockSkew(Duration.of(1, ChronoUnit.MINUTES));
action.setAuthnLifetime(Duration.of(1, ChronoUnit.MINUTES));
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now(),Instant.now(), Instant.now()));
+ Instant.now(),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
@@ -90,7 +90,7 @@ public class ValidateDuoTokenAuthenticationTimeTest extends AbstractDuoActionTes
action.setClockSkew(Duration.of(1, ChronoUnit.MINUTES));
action.setAuthnLifetime(Duration.of(1, ChronoUnit.MINUTES));
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now(),Instant.now(), Instant.now()));
+ Instant.now(),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
@@ -112,7 +112,7 @@ public class ValidateDuoTokenAuthenticationTimeTest extends AbstractDuoActionTes
action.setClockSkew(Duration.of(1, ChronoUnit.MINUTES));
action.setAuthnLifetime(Duration.of(1, ChronoUnit.MINUTES));
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now(),Instant.now(), Instant.now().plus(Duration.of(10, ChronoUnit.MINUTES))));
+ Instant.now(),Instant.now(), Instant.now().plus(Duration.of(10, ChronoUnit.MINUTES)), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
@@ -134,7 +134,7 @@ public class ValidateDuoTokenAuthenticationTimeTest extends AbstractDuoActionTes
action.setClockSkew(Duration.of(1, ChronoUnit.MINUTES));
action.setAuthnLifetime(Duration.of(1, ChronoUnit.MINUTES));
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now(),Instant.now(), Instant.now().minus(Duration.of(10, ChronoUnit.MINUTES))));
+ Instant.now(),Instant.now(), Instant.now().minus(Duration.of(10, ChronoUnit.MINUTES)), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
assertEventId(event, AuthnEventIds.AUTHN_EXCEPTION);
@@ -155,7 +155,7 @@ public class ValidateDuoTokenAuthenticationTimeTest extends AbstractDuoActionTes
action.setClockSkew(Duration.of(1, ChronoUnit.MINUTES));
action.setAuthnLifetime(Duration.of(1, ChronoUnit.MINUTES));
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now(),Instant.now(), Instant.now().plus(Duration.of(10, ChronoUnit.MINUTES))));
+ Instant.now(),Instant.now(), Instant.now().plus(Duration.of(10, ChronoUnit.MINUTES)), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
assertEventId(event, AuthnEventIds.AUTHN_EXCEPTION);
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenExpirationTimeTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenExpirationTimeTest.java
index 4d54bcb..e186ce1 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenExpirationTimeTest.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenExpirationTimeTest.java
@@ -56,7 +56,7 @@ public class ValidateDuoTokenExpirationTimeTest extends AbstractDuoActionTest {
addDuoIntegrationToContext();
addAttemptedFlow("authn/DuoOIDC");
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now()));
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
@@ -76,7 +76,7 @@ public class ValidateDuoTokenExpirationTimeTest extends AbstractDuoActionTest {
addAttemptedFlow("authn/DuoOIDC");
//create token, set expiry 1 day in the past.
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now().minus(1,ChronoUnit.DAYS),Instant.now(), Instant.now()));
+ Instant.now().minus(1,ChronoUnit.DAYS),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
assertEventId(event, AuthnEventIds.AUTHN_EXCEPTION);
@@ -98,7 +98,7 @@ public class ValidateDuoTokenExpirationTimeTest extends AbstractDuoActionTest {
action.setClockSkew(Duration.of(1, ChronoUnit.MINUTES));
//create token, set expiry 50 second in the past.
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now().minus(50,ChronoUnit.SECONDS),Instant.now(), Instant.now()));
+ Instant.now().minus(50,ChronoUnit.SECONDS),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
@@ -120,7 +120,7 @@ public class ValidateDuoTokenExpirationTimeTest extends AbstractDuoActionTest {
action.setClockSkew(Duration.of(0, ChronoUnit.SECONDS));
//create token, set expiry 1 second in the past.
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now().minus(1,ChronoUnit.SECONDS),Instant.now(), Instant.now()));
+ Instant.now().minus(1,ChronoUnit.SECONDS),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
assertEventId(event, AuthnEventIds.AUTHN_EXCEPTION);
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuedAtTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuedAtTest.java
index 32d3d3a..1a971f0 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuedAtTest.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuedAtTest.java
@@ -59,7 +59,7 @@ public class ValidateDuoTokenIssuedAtTest extends AbstractDuoActionTest {
addDuoIntegrationToContext();
addAttemptedFlow("authn/DuoOIDC");
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now(),Instant.now(), Instant.now()));
+ Instant.now(),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
@@ -79,7 +79,7 @@ public class ValidateDuoTokenIssuedAtTest extends AbstractDuoActionTest {
addAttemptedFlow("authn/DuoOIDC");
action.setIatMaxClockSkew(Duration.of(1, ChronoUnit.MINUTES));
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now(),Instant.now().minus(3,ChronoUnit.MINUTES), Instant.now()));
+ Instant.now(),Instant.now().minus(3,ChronoUnit.MINUTES), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
@@ -99,7 +99,7 @@ public class ValidateDuoTokenIssuedAtTest extends AbstractDuoActionTest {
addAttemptedFlow("authn/DuoOIDC");
action.setIatMaxClockSkew(Duration.of(1, ChronoUnit.MINUTES));
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now(),Instant.now().plus(3,ChronoUnit.MINUTES), Instant.now()));
+ Instant.now(),Instant.now().plus(3,ChronoUnit.MINUTES), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenSubjectTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuerTest.java
similarity index 56%
copy from idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenSubjectTest.java
copy to idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuerTest.java
index 0ae9b1b..8048d76 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenSubjectTest.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenIssuerTest.java
@@ -1,20 +1,3 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
package net.shibboleth.idp.plugin.authn.duo.impl;
import static org.testng.Assert.assertNull;
@@ -30,20 +13,20 @@ import net.shbboleth.idp.plugin.authn.duo.DuoOIDCAuthAPI;
import net.shibboleth.idp.authn.AuthnEventIds;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
-class ValidateDuoTokenSubjectTest extends AbstractDuoActionTest {
+public class ValidateDuoTokenIssuerTest extends AbstractDuoActionTest {
/** The action to test. */
- private ValidateDuoTokenSubject action;
+ private ValidateDuoTokenIssuer action;
@BeforeMethod
public void setUp() throws Exception {
super.setup();
- action = new ValidateDuoTokenSubject();
+ action = new ValidateDuoTokenIssuer();
}
-
+
/**
- * Test Duo 2FA token subject validation, success.
+ * Test Duo 2FA token issuer validation, success.
*
* @throws ComponentInitializationException on error.
*/
@@ -53,8 +36,9 @@ class ValidateDuoTokenSubjectTest extends AbstractDuoActionTest {
addDuoIntegrationToContext();
addAttemptedFlow("authn/DuoOIDC");
dc.setUsername("jdoe");
+
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now()));
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
@@ -62,22 +46,43 @@ class ValidateDuoTokenSubjectTest extends AbstractDuoActionTest {
}
/**
- * Test Duo 2FA token subject validation, failure.
+ * Test Duo 2FA token issuer validation, different issuer.
*
* @throws ComponentInitializationException on error.
*/
@Test
- public final void testExecuteInvalidSubject() throws ComponentInitializationException {
+ public final void testExecuteDifferentIssuer() throws ComponentInitializationException {
addDuoContext();
addDuoIntegrationToContext();
addAttemptedFlow("authn/DuoOIDC");
- dc.setUsername("different-user");
+ dc.setUsername("jdoe");
+
+ dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "different.host.com"));
+ action.initialize();
+ final Event event = action.execute(src);
+ // null event is success.
+ assertEventId(event, AuthnEventIds.AUTHN_EXCEPTION);
+ }
+
+ /**
+ * Test Duo 2FA token issuer validation, no context.
+ *
+ * @throws ComponentInitializationException on error.
+ */
+ @Test
+ public final void testExecuteNoIntegration() throws ComponentInitializationException {
+ addDuoContext();
+
+ addAttemptedFlow("authn/DuoOIDC");
+ dc.setUsername("jdoe");
+
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now()));
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "different.host.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
- assertEventId(event, AuthnEventIds.INVALID_CREDENTIALS);
+ assertEventId(event, AuthnEventIds.AUTHN_EXCEPTION);
}
}
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenSubjectTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenSubjectTest.java
index 0ae9b1b..0dc31c0 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenSubjectTest.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/ValidateDuoTokenSubjectTest.java
@@ -54,7 +54,7 @@ class ValidateDuoTokenSubjectTest extends AbstractDuoActionTest {
addAttemptedFlow("authn/DuoOIDC");
dc.setUsername("jdoe");
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now()));
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
@@ -73,7 +73,7 @@ class ValidateDuoTokenSubjectTest extends AbstractDuoActionTest {
addAttemptedFlow("authn/DuoOIDC");
dc.setUsername("different-user");
dc.setAuthToken(createDummyToken(DuoOIDCAuthAPI.DUO_AUTH_RESULT_ALLOW,"Login Succesful",CLIENT_ID,
- Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now()));
+ Instant.now().plus(1,ChronoUnit.MINUTES),Instant.now(), Instant.now(), "api.duosecurity.com"));
action.initialize();
final Event event = action.execute(src);
// null event is success.
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/mock/MockDuoOIDCClient_OK.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/mock/MockDuoOIDCClient_OK.java
index ac65ddd..c78efc2 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/mock/MockDuoOIDCClient_OK.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/mock/MockDuoOIDCClient_OK.java
@@ -68,7 +68,7 @@ public class MockDuoOIDCClient_OK implements DuoOIDCClient{
public DuoAuthToken exchangeAuthorizationCodeFor2FAResult(final String code,
final String username) throws DuoClientException {
return DuoAuthToken.builder()
- .withIss("https://api.duosecurity.com/oauth/v1/token")
+ .withIss("https://"+integration.getAPIHost()+"/oauth/v1/token")
.withSub(SUB)
.withAud(integration.getClientId())
.withExp(Math.toIntExact(Instant.now().plus(10,ChronoUnit.MINUTES).getEpochSecond()))
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list