[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