[java-idp-plugin-duo] branch dev/JDUO-80 updated: Add passwordless to deprecated class for tests and add more tests.
Scott Cantor
cantor.2 at osu.edu
Thu Dec 28 15:36:37 UTC 2023
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch dev/JDUO-80
in repository java-idp-plugin-duo.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-duo.git;a=commit;h=0c18d20e0f686f1777a48d953dccaf6898cb4290
The following commit(s) were added to refs/heads/dev/JDUO-80 by this push:
new 0c18d20e Add passwordless to deprecated class for tests and add more tests.
0c18d20e is described below
commit 0c18d20e0f686f1777a48d953dccaf6898cb4290
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Dec 28 10:36:34 2023 -0500
Add passwordless to deprecated class for tests and add more tests.
---
.../plugin/authn/duo/SimpleDuoOIDCIntegration.java | 32 +++++-
.../authn/duo/impl/AbstractDuoActionTest.java | 2 +
.../impl/PopulateDuoAuthenticationContextTest.java | 113 ++++++++++++++++++++-
3 files changed, 137 insertions(+), 10 deletions(-)
diff --git a/idp-duo-api/src/main/java/net/shibboleth/idp/plugin/authn/duo/SimpleDuoOIDCIntegration.java b/idp-duo-api/src/main/java/net/shibboleth/idp/plugin/authn/duo/SimpleDuoOIDCIntegration.java
index 29add449..c6d80a8a 100644
--- a/idp-duo-api/src/main/java/net/shibboleth/idp/plugin/authn/duo/SimpleDuoOIDCIntegration.java
+++ b/idp-duo-api/src/main/java/net/shibboleth/idp/plugin/authn/duo/SimpleDuoOIDCIntegration.java
@@ -44,9 +44,11 @@ import net.shibboleth.shared.primitive.StringSupport;
*/
@ThreadSafe
@Deprecated(forRemoval=true, since="2.1.0")
-public final class SimpleDuoOIDCIntegration
- extends AbstractInitializableComponent implements DuoOIDCIntegration {
+public final class SimpleDuoOIDCIntegration extends AbstractInitializableComponent implements DuoOIDCIntegration {
+ /** Passwordless indicator. */
+ @GuardedBy("this") private boolean passwordless;
+
/** API host. */
@GuardedBy("this") @NonnullAfterInit @NotEmpty private String apiHost;
@@ -76,6 +78,26 @@ public final class SimpleDuoOIDCIntegration
supportedPrincipals = new Subject();
}
+ /**
+ * Sets whether this integration is suitable for use as a single factor.
+ *
+ * <p>Defaults to false.</p>
+ *
+ * @param flag flag to set
+ *
+ * @since 2.1.0
+ */
+ public synchronized void setPasswordless(final boolean flag) {
+ checkSetterPreconditions();
+ passwordless = flag;
+ }
+
+ /** {@inheritDoc} */
+ public synchronized boolean isPasswordless() {
+ checkComponentActive();
+ return passwordless;
+ }
+
/** {@inheritDoc} */
@Nonnull @NotEmpty public synchronized String getAPIHost() {
checkComponentActive();
@@ -235,9 +257,9 @@ public final class SimpleDuoOIDCIntegration
/** {@inheritDoc} */
@Override
protected void doInitialize() throws ComponentInitializationException {
- if (getAPIHost() == null || getClientId() == null || getSecretKey() == null
- || getHealthCheckEndpoint() == null || getAuthorizeEndpoint() == null
- || getTokenEndpoint() == null || getRedirectURI() == null) {
+ if (apiHost == null || clientId == null || secretKey == null
+ || healthEndpoint == null || authorizeEndpoint == null
+ || tokenEndpoint == null || redirectURI == null) {
throw new ComponentInitializationException("API host, clientId, secret key,"
+ "token endpoint, health check endpoint, authorization endpoint, and "
+ "redirectURI must be set");
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 40f82746..4adf1333 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
@@ -49,6 +49,7 @@ import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileR
import net.shibboleth.idp.profile.testing.RequestContextBuilder;
import net.shibboleth.shared.codec.Base64Support;
import net.shibboleth.shared.codec.EncodingException;
+import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.component.ComponentInitializationException;
@@ -896,6 +897,7 @@ public abstract class AbstractDuoActionTest {
integ.setAuthorizeEndpoint(AUTHORIZE_URI);
integ.setTokenEndpoint(TOKEN_URI);
integ.setHealthCheckEndpoint(HEALTH_URI);
+ integ.setAllowedOrigins(CollectionSupport.singletonList("https://example.com"));
//do not initialize so the tests can mutate and initialize if required
//integ.initialize();
return integ;
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/PopulateDuoAuthenticationContextTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/PopulateDuoAuthenticationContextTest.java
index c91c3a06..6b37df43 100644
--- a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/PopulateDuoAuthenticationContextTest.java
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/PopulateDuoAuthenticationContextTest.java
@@ -27,6 +27,7 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
import net.shibboleth.idp.plugin.authn.duo.DefaultDuoOIDCIntegration;
import net.shibboleth.idp.plugin.authn.duo.DuoClientException;
import net.shibboleth.idp.plugin.authn.duo.DuoOIDCClient;
@@ -35,13 +36,14 @@ import net.shibboleth.idp.plugin.authn.duo.DuoOIDCIntegration;
import net.shibboleth.idp.plugin.authn.duo.DuoRegistryException;
import net.shibboleth.idp.plugin.authn.duo.SimpleDuoOIDCIntegration;
import net.shibboleth.idp.plugin.authn.duo.context.DuoOIDCAuthenticationContext;
+import net.shibboleth.idp.plugin.authn.duo.context.DuoPasswordlessContext;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.testing.ConstantSupplier;
/**
* Tests for the {@link PopulateDuoAuthenticationContext} strategy.
*/
-public class PopulateDuoAuthenticationContextTest extends AbstractDuoActionTest{
+public class PopulateDuoAuthenticationContextTest extends AbstractDuoActionTest {
/** The action to test. */
private PopulateDuoAuthenticationContext action;
@@ -80,7 +82,7 @@ public class PopulateDuoAuthenticationContextTest extends AbstractDuoActionTest{
integ.setAuthorizeEndpoint(AUTHORIZE_URI);
integ.setTokenEndpoint(TOKEN_URI);
integ.setHealthCheckEndpoint(HEALTH_URI);
-
+ integ.initialize();
//set the duo integration strategy to lookup
action.setStandardDuoIntegrationLookupStrategy(prc -> integ);
@@ -105,6 +107,53 @@ public class PopulateDuoAuthenticationContextTest extends AbstractDuoActionTest{
assertEquals(duoContext.getRedirectURIOverride(), null);
}
+ /**
+ * Test successful passwordless execution assuming a client that does not support dynamic redirect URIs.
+ *
+ * @throws ComponentInitializationException on error.
+ * @throws DuoClientException on error.
+ * @throws DuoRegistryException one error.
+ */
+ @Test
+ public void testPasswordlessExecuteSuccessWithStaticClient()
+ throws ComponentInitializationException, DuoRegistryException, DuoClientException {
+
+ final SimpleDuoOIDCIntegration integ = new SimpleDuoOIDCIntegration();
+ integ.setPasswordless(true);
+ integ.setAPIHost(API_HOST);
+ integ.setClientId(CLIENT_ID);
+ integ.setRedirectURI("https://simple-static.redirect/");
+ integ.setSecretKey(SECRET);
+ integ.setAuthorizeEndpoint(AUTHORIZE_URI);
+ integ.setTokenEndpoint(TOKEN_URI);
+ integ.setHealthCheckEndpoint(HEALTH_URI);
+ integ.initialize();
+
+ //set the duo integration strategy to lookup
+ action.setPasswordlessDuoIntegrationLookupStrategy(prc -> integ);
+
+ action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+ final DuoOIDCClientRegistry mockClientRegistry = Mockito.mock(DuoOIDCClientRegistry.class);
+ final DuoOIDCClient mockClient = Mockito.mock(DuoOIDCClient.class);
+ Mockito.when(mockClientRegistry.getClientOrCreate(any(DuoOIDCIntegration.class))).thenReturn(mockClient);
+
+ action.setClientRegistry(mockClientRegistry);
+ action.initialize();
+
+ final DuoPasswordlessContext passwordlessCtx =
+ prc.ensureSubcontext(AuthenticationContext.class).ensureSubcontext(DuoPasswordlessContext.class);
+ passwordlessCtx.setUsername("jdoe");
+
+ final Event event = action.execute(src);
+ //success here is a null event
+ assertNull(event);
+ //simple client, so no override set
+ final var duoContext = ac.getSubcontext(DuoOIDCAuthenticationContext.class);
+ assertNotNull(duoContext);
+ assert duoContext != null;
+ assertEquals(duoContext.getRedirectURIOverride(), null);
+ }
+
/**
* Test that should return an authentication exception if the integration is dynamic
* but a redirectURI strategy has not been set.
@@ -181,9 +230,53 @@ public class PopulateDuoAuthenticationContextTest extends AbstractDuoActionTest{
.getRedirectURIOverride(), "https://example.com/idp/profile/Authn/Duo/2FA/callback");
}
-
-
-
+ /**
+ * Test successful execution assuming a client that does not support dynamic redirect URIs.
+ *
+ * @throws ComponentInitializationException on error.
+ * @throws DuoClientException on error.
+ * @throws DuoRegistryException one error.
+ */
+ @Test
+ public void testPasswordlessExecuteSuccessWithDynamicClient()
+ throws ComponentInitializationException, DuoRegistryException, DuoClientException {
+ final DefaultDuoOIDCIntegration integ = createDummyDuoIntegration();
+ integ.setPasswordless(true);
+ //cleanout pre-registered redirect
+ integ.setRegisteredRedirectURI(null);
+ integ.initialize();
+
+ //set the duo integration strategy to lookup this
+ action.setPasswordlessDuoIntegrationLookupStrategy(prc -> integ);
+ action.setRedirectURICreationStrategy((http,duoInteg)
+ -> "https://example.com/idp/profile/Authn/Duo/2FA/callback");
+ action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+ //set http params
+ request.addHeader("Host", "example.com");
+ request.setServerPort(443);
+ request.setScheme("https");
+ //mock
+ final DuoOIDCClientRegistry mockClientRegistry = Mockito.mock(DuoOIDCClientRegistry.class);
+ final DuoOIDCClient mockClient = Mockito.mock(DuoOIDCClient.class);
+ Mockito.when(mockClientRegistry.getClientOrCreate(any(DuoOIDCIntegration.class))).thenReturn(mockClient);
+
+ action.setClientRegistry(mockClientRegistry);
+ action.initialize();
+
+ final DuoPasswordlessContext passwordlessCtx =
+ prc.ensureSubcontext(AuthenticationContext.class).ensureSubcontext(DuoPasswordlessContext.class);
+ passwordlessCtx.setUsername("jdoe");
+
+ final Event event = action.execute(src);
+ //success here is a null event
+ assertNull(event);
+ assertEquals(integ.getRedirectURI(), "https://example.com/idp/profile/Authn/Duo/2FA/callback");
+ final var duoContext = ac.getSubcontext(DuoOIDCAuthenticationContext.class);
+ assertNotNull(duoContext);
+ assert duoContext != null;
+ assertEquals(duoContext
+ .getRedirectURIOverride(), "https://example.com/idp/profile/Authn/Duo/2FA/callback");
+ }
/**
* Test unsuccessful execution if there is no duo integration specified.
@@ -233,6 +326,8 @@ public class PopulateDuoAuthenticationContextTest extends AbstractDuoActionTest{
public void testExecuteNullUsername() throws ComponentInitializationException,
DuoRegistryException, DuoClientException {
final DefaultDuoOIDCIntegration integ = createDummyDuoIntegration();
+ integ.initialize();
+
//set the duo integration strategy to lookup this
action.setStandardDuoIntegrationLookupStrategy(prc -> integ);
//lookup a username
@@ -259,6 +354,8 @@ public class PopulateDuoAuthenticationContextTest extends AbstractDuoActionTest{
public void testExecuteNullRedirectURI() throws ComponentInitializationException,
DuoRegistryException, DuoClientException {
final DefaultDuoOIDCIntegration integ = createDummyDuoIntegration();
+ integ.initialize();
+
//set the duo integration strategy to lookup this
action.setStandardDuoIntegrationLookupStrategy(prc -> integ);
//lookup a username
@@ -284,6 +381,8 @@ public class PopulateDuoAuthenticationContextTest extends AbstractDuoActionTest{
public void testExecuteClientException() throws ComponentInitializationException,
DuoRegistryException, DuoClientException {
final DefaultDuoOIDCIntegration integ = createDummyDuoIntegration();
+ integ.initialize();
+
//set the duo integration strategy to lookup this
action.setStandardDuoIntegrationLookupStrategy(prc -> integ);
//lookup a username
@@ -313,6 +412,8 @@ public class PopulateDuoAuthenticationContextTest extends AbstractDuoActionTest{
public void testExecuteNoHttpRequest() throws ComponentInitializationException,
DuoRegistryException, DuoClientException {
final DefaultDuoOIDCIntegration integ = createDummyDuoIntegration();
+ integ.initialize();
+
//set the duo integration strategy to lookup this
action.setStandardDuoIntegrationLookupStrategy(prc -> integ);
//lookup a username
@@ -343,6 +444,8 @@ public class PopulateDuoAuthenticationContextTest extends AbstractDuoActionTest{
public void testExecuteNoDuoContext() throws ComponentInitializationException,
DuoRegistryException, DuoClientException {
final DefaultDuoOIDCIntegration integ = createDummyDuoIntegration();
+ integ.initialize();
+
//set the duo integration strategy to lookup this
action.setStandardDuoIntegrationLookupStrategy(prc -> integ);
//lookup a username
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list