[java-idp-plugin-duo] branch dev/JDUO-82 updated: Add admin client tests
Phil Smart
philip.smart at jisc.ac.uk
Mon Jan 8 10:49:34 UTC 2024
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch dev/JDUO-82
in repository java-idp-plugin-duo.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-duo.git;a=commit;h=6c85a27ed1276cf6551a5ae6e89ef1145ddcb399
The following commit(s) were added to refs/heads/dev/JDUO-82 by this push:
new 6c85a27e Add admin client tests
6c85a27e is described below
commit 6c85a27ed1276cf6551a5ae6e89ef1145ddcb399
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Mon Jan 8 10:49:31 2024 +0000
Add admin client tests
---
.../authn/duo/impl/DefaultDuoAdminClient.java | 2 +-
.../authn/duo/impl/DefaultDuoAdminClientTest.java | 394 +++++++++++++++++++++
2 files changed, 395 insertions(+), 1 deletion(-)
diff --git a/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/DefaultDuoAdminClient.java b/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/DefaultDuoAdminClient.java
index e5fc6dfd..45663fcb 100644
--- a/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/DefaultDuoAdminClient.java
+++ b/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/impl/DefaultDuoAdminClient.java
@@ -174,7 +174,7 @@ public class DefaultDuoAdminClient extends AbstractIdentifiableInitializableComp
}
final User user = response.get(0);
if (user == null) {
- throw new DuoException("User API response did not contain a single user");
+ throw new DuoException("User API response did not contain a user");
}
return user;
diff --git a/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/DefaultDuoAdminClientTest.java b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/DefaultDuoAdminClientTest.java
new file mode 100644
index 00000000..8e6e6977
--- /dev/null
+++ b/idp-duo-impl/src/test/java/net/shibboleth/idp/plugin/authn/duo/impl/DefaultDuoAdminClientTest.java
@@ -0,0 +1,394 @@
+/*
+ * Licensed 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.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.hc.client5.http.classic.HttpClient;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.mockito.Mockito;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import net.shibboleth.idp.authn.duo.BasicDuoIntegration;
+import net.shibboleth.idp.plugin.authn.duo.DuoAdminResponseWrapper;
+import net.shibboleth.idp.plugin.authn.duo.DuoException;
+import net.shibboleth.idp.plugin.authn.duo.model.User;
+import net.shibboleth.shared.component.ComponentInitializationException;
+
+/**
+ * Tests for {@link DefaultDuoAdminClient}.
+ */
+public class DefaultDuoAdminClientTest {
+
+ /** The client to test.*/
+ private DefaultDuoAdminClient client;
+
+ private static final String GOOD_RESPONSE =
+ """
+ {
+ "response": [
+ {
+ "alias1": null,
+ "alias2": null,
+ "alias3": null,
+ "alias4": null,
+ "aliases": {},
+ "created": 1592986174,
+ "desktoptokens": [],
+ "email": "",
+ "firstname": null,
+ "groups": [],
+ "is_enrolled": true,
+ "last_directory_sync": null,
+ "last_login": 1704368292,
+ "lastname": null,
+ "lockout_reason": null,
+ "notes": "",
+ "phones": [],
+ "realname": "",
+ "status": "active",
+ "tokens": [],
+ "u2ftokens": [
+ {
+ "date_added": 1629107332,
+ "registration_id": "DDFKJNBVWFRFFD"
+ }
+ ],
+ "user_id": "FWREGFEROGJER",
+ "username": "jdoe",
+ "webauthncredentials": [
+ {
+ "credential_name": "Security Key",
+ "date_added": 1643124774,
+ "label": "Passkey",
+ "webauthnkey": "DDFKJNBVWFRFFDD"
+ },
+ {
+ "credential_name": "Security key",
+ "date_added": 1701874074,
+ "label": "Security key",
+ "webauthnkey": "DDFKJNBVWFRFFDDD"
+ },
+ {
+ "credential_name": "Passkey",
+ "date_added": 1704280068,
+ "label": "Passkey",
+ "webauthnkey": "DDFKJNBVWFRFFDDDD"
+ }
+ ]
+ }
+ ],
+ "stat": "OK"
+ }
+ """;
+
+ private static final String TWO_USER_RESPONSE =
+ """
+ {
+ "response": [
+ {
+ "user_id": "FWREGFEROGJERFEFE",
+ "username": "jdoe"
+ },
+ {
+ "user_id": "FWREGFEROGJER",
+ "username": "jdoe"
+ }
+ ],
+ "stat": "OK"
+ }
+ """;
+
+ private static final String UNEXPECTED_RESPONSE_STATUS =
+ """
+ {
+ "response": [
+ {
+ "created": 1592986174,
+ "desktoptokens": [],
+ "email": "",
+ "firstname": null,
+ "groups": [],
+ "is_enrolled": true,
+ "last_directory_sync": null,
+ "last_login": 1704368292,
+ "lastname": null,
+ "lockout_reason": null,
+ "notes": "",
+ "phones": [],
+ "realname": "",
+ "status": "active",
+ "tokens": [],
+ "user_id": "FWREGFEROGJER",
+ "username": "jdoe"
+ }
+ ],
+ "stat": "FAIL"
+ }
+ """;
+
+ /** Incorrect return format.*/
+ private static final String INCOMPATIBLE_RESPONSE =
+ """
+ {
+ "bad_response": [],
+ "stat": "OK"
+ }
+ """;
+
+ /** Failed response.*/
+ private static final String FAIL_RESPONSE =
+ """
+ {
+ "stat": "FAIL",
+ "code": 40002,
+ "message": "Invalid request parameters",
+ "message_detail": "username"
+ }
+ """;
+
+ @BeforeMethod
+ public void setup() {
+ client = new DefaultDuoAdminClient();
+ client.setId("test-client");
+ client.setAdminDuoIntegrationLookupStrategy(prc -> {
+ final BasicDuoIntegration integration = new BasicDuoIntegration();
+ integration.setAPIHost("example.com");
+ integration.setIntegrationKey("integrationkey");
+ integration.setSecretKey("secretkey");
+ try {
+ integration.initialize();
+ } catch (final ComponentInitializationException e) {
+ fail(e.getMessage());
+ }
+ return integration;
+ });
+ }
+
+
+ @Test(expectedExceptions = ComponentInitializationException.class)
+ public void testClientSetup_NothingSet() throws ComponentInitializationException {
+ client.initialize();
+ }
+
+ @Test(expectedExceptions = ComponentInitializationException.class)
+ public void testClientSetup_NoObjectMapper() throws ComponentInitializationException {
+ client.setHttpClient(Mockito.mock(HttpClient.class));
+ client.initialize();
+ }
+
+ @Test(expectedExceptions = ComponentInitializationException.class)
+ public void testClientSetup_NoHttpClient() throws ComponentInitializationException {
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+ }
+
+ @Test(expectedExceptions = DuoException.class)
+ public void testClientGetUsers_EmptyResponse() throws Exception {
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final ClassicHttpResponse httpResponse = Mockito.mock(ClassicHttpResponse.class);
+
+ Mockito.when(httpResponse.getCode()).thenReturn(200);
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(""));
+ Mockito.when(httpClient.executeOpen((HttpHost) Mockito.any(), (ClassicHttpRequest) Mockito.any(),
+ (HttpContext) Mockito.any())).thenReturn(httpResponse);
+
+ client.setHttpClient(httpClient);
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+
+ client.getUser(new ProfileRequestContext(), "jdoe");
+ }
+
+ @Test(expectedExceptions = DuoException.class)
+ public void testClientGetUsers_ServerError() throws Exception {
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final ClassicHttpResponse httpResponse = Mockito.mock(ClassicHttpResponse.class);
+
+ Mockito.when(httpResponse.getCode()).thenReturn(500);
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(""));
+ Mockito.when(httpClient.executeOpen((HttpHost) Mockito.any(), (ClassicHttpRequest) Mockito.any(),
+ (HttpContext) Mockito.any())).thenReturn(httpResponse);
+
+ client.setHttpClient(httpClient);
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+
+ client.getUser(new ProfileRequestContext(), "jdoe");
+ }
+
+ @Test(expectedExceptions = DuoException.class)
+ public void testClientGetUsers_BadRequest() throws Exception {
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final ClassicHttpResponse httpResponse = Mockito.mock(ClassicHttpResponse.class);
+
+ Mockito.when(httpResponse.getCode()).thenReturn(400);
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(FAIL_RESPONSE));
+ Mockito.when(httpClient.executeOpen((HttpHost) Mockito.any(), (ClassicHttpRequest) Mockito.any(),
+ (HttpContext) Mockito.any())).thenReturn(httpResponse);
+
+ client.setHttpClient(httpClient);
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+
+ client.getUser(new ProfileRequestContext(), "jdoe");
+ }
+
+ @Test
+ public void testClientGetUsers_OK() throws Exception {
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final ClassicHttpResponse httpResponse = Mockito.mock(ClassicHttpResponse.class);
+
+ Mockito.when(httpResponse.getCode()).thenReturn(200);
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(GOOD_RESPONSE));
+ Mockito.when(httpClient.executeOpen((HttpHost) Mockito.any(), (ClassicHttpRequest) Mockito.any(),
+ (HttpContext) Mockito.any())).thenReturn(httpResponse);
+
+ client.setHttpClient(httpClient);
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+
+ final User user = client.getUser(new ProfileRequestContext(), "jdoe");
+ assertNotNull(user);
+ assertEquals(user.getUsername(), "jdoe");
+ assertEquals(user.getWebAuthnCredentials().size(), 3);
+ }
+
+ @Test(expectedExceptions = DuoException.class)
+ public void testClientGetUsers_IncompatibleResponse() throws Exception {
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final ClassicHttpResponse httpResponse = Mockito.mock(ClassicHttpResponse.class);
+
+ Mockito.when(httpResponse.getCode()).thenReturn(200);
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(INCOMPATIBLE_RESPONSE));
+ Mockito.when(httpClient.executeOpen((HttpHost) Mockito.any(), (ClassicHttpRequest) Mockito.any(),
+ (HttpContext) Mockito.any())).thenReturn(httpResponse);
+
+ client.setHttpClient(httpClient);
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+
+ client.getUser(new ProfileRequestContext(), "jdoe");
+ }
+
+ @Test(expectedExceptions = DuoException.class)
+ public void testClientGetUsers_NoResponseBody() throws Exception {
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final ClassicHttpResponse httpResponse = Mockito.mock(ClassicHttpResponse.class);
+
+ Mockito.when(httpResponse.getCode()).thenReturn(200);
+ Mockito.when(httpResponse.getEntity()).thenReturn(null);
+ Mockito.when(httpClient.executeOpen((HttpHost) Mockito.any(), (ClassicHttpRequest) Mockito.any(),
+ (HttpContext) Mockito.any())).thenReturn(httpResponse);
+
+ client.setHttpClient(httpClient);
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+
+ client.getUser(new ProfileRequestContext(), "jdoe");
+ }
+
+ @Test(expectedExceptions = DuoException.class)
+ public void testClientGetUsers_NoIntegration() throws Exception {
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final ClassicHttpResponse httpResponse = Mockito.mock(ClassicHttpResponse.class);
+
+ Mockito.when(httpResponse.getCode()).thenReturn(200);
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(GOOD_RESPONSE));
+ Mockito.when(httpClient.executeOpen((HttpHost) Mockito.any(), (ClassicHttpRequest) Mockito.any(),
+ (HttpContext) Mockito.any())).thenReturn(httpResponse);
+
+ client.setHttpClient(httpClient);
+ client.setAdminDuoIntegrationLookupStrategy(prc->null);
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+
+ client.getUser(new ProfileRequestContext(), "jdoe");
+ }
+
+ @Test(expectedExceptions = DuoException.class)
+ public void testClientGetUsers_TwoUsersReturned() throws Exception {
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final ClassicHttpResponse httpResponse = Mockito.mock(ClassicHttpResponse.class);
+
+ Mockito.when(httpResponse.getCode()).thenReturn(200);
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(TWO_USER_RESPONSE));
+ Mockito.when(httpClient.executeOpen((HttpHost) Mockito.any(), (ClassicHttpRequest) Mockito.any(),
+ (HttpContext) Mockito.any())).thenReturn(httpResponse);
+
+ client.setHttpClient(httpClient);
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+
+ client.getUser(new ProfileRequestContext(), "jdoe");
+ }
+
+ @Test(expectedExceptions = DuoException.class)
+ public void testClientGetUsers_UnexpectedResponseStatus() throws Exception {
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final ClassicHttpResponse httpResponse = Mockito.mock(ClassicHttpResponse.class);
+
+ Mockito.when(httpResponse.getCode()).thenReturn(200);
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(UNEXPECTED_RESPONSE_STATUS));
+ Mockito.when(httpClient.executeOpen((HttpHost) Mockito.any(), (ClassicHttpRequest) Mockito.any(),
+ (HttpContext) Mockito.any())).thenReturn(httpResponse);
+
+ client.setHttpClient(httpClient);
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+
+ client.getUser(new ProfileRequestContext(), "jdoe");
+ }
+
+ @Test
+ public void testClientRetrieve_OK() throws Exception {
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final ClassicHttpResponse httpResponse = Mockito.mock(ClassicHttpResponse.class);
+
+ Mockito.when(httpResponse.getCode()).thenReturn(200);
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(GOOD_RESPONSE));
+ Mockito.when(httpClient.executeOpen((HttpHost) Mockito.any(), (ClassicHttpRequest) Mockito.any(),
+ (HttpContext) Mockito.any())).thenReturn(httpResponse);
+
+ client.setHttpClient(httpClient);
+ client.setObjectMapper(new ObjectMapper());
+ client.initialize();
+
+ final DuoAdminResponseWrapper<List<User>> userWrapper =
+ client.retrieve(new ProfileRequestContext(),"/admin/v1/users", Map.of("username","jdoe"),
+ new TypeReference<DuoAdminResponseWrapper<List<User>>>() {});
+
+ assertNotNull(userWrapper);
+ assertNotNull(userWrapper.getResponse());
+ assertEquals(userWrapper.getResponse().size(), 1);
+ assertEquals(userWrapper.getResponse().get(0).getUsername(), "jdoe");
+ }
+
+
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list