[java-idp-plugin-webauthn] branch main updated: Add more tests

Phil Smart philip.smart at jisc.ac.uk
Thu Jul 18 15:55:21 UTC 2024


This is an automated email from the git hooks/post-receive script.

philsmart pushed a commit to branch main
in repository java-idp-plugin-webauthn.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-webauthn.git;a=commit;h=7f1d0e8975c21844fa5de979c9b9e23549e3cbd5

The following commit(s) were added to refs/heads/main by this push:
     new 7f1d0e8  Add more tests
7f1d0e8 is described below

commit 7f1d0e8975c21844fa5de979c9b9e23549e3cbd5
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Thu Jul 18 16:55:18 2024 +0100

    Add more tests
---
 .../webauthn/admin/impl/AddDisplayNameTest.java    |  93 +++++++++++++++
 .../authn/webauthn/admin/impl/AddUserIdTest.java   |  59 +---------
 ...eatePublicKeyCredentialCreationOptionsTest.java | 108 +++++++++++++++++
 .../admin/impl/DeletePublicKeyCredentialTest.java  |  55 +--------
 ...ctKeyRemovalInformationFromFormRequestTest.java | 120 +++++++++++++++++++
 ...eyCredentialAttestationFromFormRequestTest.java | 130 +++++++++++++++++++++
 .../authn/webauthn/impl/AbstractWebAuthnTest.java  | 118 +++++++++++++++++++
 ...cKeyCredentialAssertionFromFormRequestTest.java | 103 ++++++++++++++++
 8 files changed, 678 insertions(+), 108 deletions(-)

diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddDisplayNameTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddDisplayNameTest.java
new file mode 100644
index 0000000..65dd2e2
--- /dev/null
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddDisplayNameTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.webauthn.admin.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import org.springframework.webflow.execution.Event;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.plugin.authn.webauthn.admin.WebAuthnRegistrationEventIds;
+import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
+import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnTest;
+import net.shibboleth.shared.component.ComponentInitializationException;
+
+/**
+ * Tests for {@link AddDisplayName}.
+ */
+public class AddDisplayNameTest extends AbstractWebAuthnTest {
+    
+    private AddDisplayName addAction;
+    
+    private WebAuthnRegistrationContext context;
+    
+    @Override
+    @BeforeMethod
+    public void setup() throws Exception {
+        super.setup();
+        context = addWebAuthnRegistrationContext();
+        addAction = new AddDisplayName();
+        addAction.setWebAuthnClient(client);
+        addAction.setCredentialRepository(credentialRepo);
+    }
+    
+    
+    @Test
+    public void testAddDisplayName() throws ComponentInitializationException {
+        addAction.setDisplayNameLookupStrategy(prc -> "john doe");
+        addAction.initialize();
+        
+        context.setUsername("jdoe");
+        
+        final Event result = addAction.execute(src);
+        assertNull(result);
+        assertNotNull(context.getDisplayName());
+        final String displayName = context.getDisplayName();
+        assert displayName != null;
+        assertEquals(displayName, "john doe");
+    }
+    
+    @Test
+    public void testAddDisplayName_NoUsernameInContext() throws ComponentInitializationException {
+        addAction.setDisplayNameLookupStrategy(prc -> "john doe");
+        addAction.initialize();
+        
+        final Event result = addAction.execute(src);
+        assertNotNull(result);
+        assert result != null;
+        assertEquals(result.getId(), WebAuthnRegistrationEventIds.INVALID_REGISTRATION_CTX);
+    }
+    
+    @Test
+    public void testAddDisplayName_NullDisplayName() throws ComponentInitializationException {
+        addAction.setDisplayNameLookupStrategy(prc ->null);
+        addAction.initialize();
+        context.setUsername("jdoe");
+        
+        final Event result = addAction.execute(src);
+        assertNotNull(result);
+        assert result != null;
+        assertEquals(result.getId(), WebAuthnRegistrationEventIds.INVALID_REGISTRATION);
+    }
+    
+    @Test(expectedExceptions = ComponentInitializationException.class)
+    public void testNoDisplayNamelookupStrategy() throws ComponentInitializationException {
+        addAction.initialize();       
+    }
+
+}
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddUserIdTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddUserIdTest.java
index 08eb64e..14865bf 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddUserIdTest.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddUserIdTest.java
@@ -18,32 +18,16 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Optional;
 import java.util.Random;
-import java.util.TreeSet;
 
 import org.springframework.webflow.execution.Event;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import com.yubico.webauthn.RegisteredCredential;
-import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
-import com.yubico.webauthn.data.AuthenticatorTransport;
-import com.yubico.webauthn.data.ByteArray;
-import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs;
-import com.yubico.webauthn.data.PublicKeyCredential;
-import com.yubico.webauthn.data.UserIdentity;
-
 import net.shibboleth.idp.plugin.authn.webauthn.admin.WebAuthnRegistrationEventIds;
 import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
 import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnTest;
-import net.shibboleth.idp.plugin.authn.webauthn.storage.CredentialRegistration;
-import net.shibboleth.idp.plugin.authn.webauthn.storage.impl.MockAuthenticator;
 import net.shibboleth.shared.codec.Base64Support;
-import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.component.ComponentInitializationException;
 
 /**
@@ -100,48 +84,11 @@ public class AddUserIdTest extends AbstractWebAuthnTest {
     }
     
     @Test
-    public void testNewUserId_ExistingUserHandle() throws Exception {
-        
-        mockAuthenticator = new MockAuthenticator(RPID);
-        
+    public void testNewUserId_ExistingUserHandle() throws Exception {   
+       
         context.setUsername("jdoe");
         
-        final var user = UserIdentity.builder()
-                .name("jdoe")
-                .displayName("John Doe")
-                .id(ByteArray.fromBase64(USER_HANDLE_B64))
-                .build();
-        
-        final Map<String, String> clientDataCreate = createClientData("webauthn.create", ORIGIN, CHALLENGE_B64);
-        
-        final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> attestation = 
-                mockAuthenticator.createAuthenticatorAttestationResponse(CHALLENGE_B64, clientDataCreate, 
-                        Base64Support.decode(USER_HANDLE_B64));
-        
-        final var barray = ByteArray.fromBase64(USER_HANDLE_B64);
-        assert barray.getBase64().equals(USER_HANDLE_B64);
-        assert Arrays.equals(barray.getBytes(), Base64Support.decode(USER_HANDLE_B64));
-
-        
-        final RegisteredCredential credential = RegisteredCredential.builder()
-                .credentialId(attestation.getId())
-                .userHandle(ByteArray.fromBase64(USER_HANDLE_B64))
-                .publicKeyCose(attestation.getResponse().getParsedAuthenticatorData()
-                        .getAttestedCredentialData().get().getCredentialPublicKey())
-                .build();
-         
-         final var reg = CredentialRegistration.builder()
-                 .withUserIdentity(user)
-                 .withTransports(new TreeSet<AuthenticatorTransport>())
-                 .withRegistrationTime(Instant.now())
-                 .withCredential(credential)
-                 .withAttestationMetadata(CollectionSupport.emptySet())
-                 .withCredentialNickname("nickname")
-                 .withDiscoverable(Optional.of(Boolean.TRUE))
-                 .withUserVerified(true)
-                 .build();
-        
-        credentialRepo.addRegistrationByUsername("jdoe", reg);
+        credentialRepo.addRegistrationByUsername("jdoe", createCredentialRegistration());
         addAction.initialize();      
         
         final Event result = addAction.execute(src);
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/CreatePublicKeyCredentialCreationOptionsTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/CreatePublicKeyCredentialCreationOptionsTest.java
new file mode 100644
index 0000000..40a3377
--- /dev/null
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/CreatePublicKeyCredentialCreationOptionsTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.webauthn.admin.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import org.springframework.webflow.execution.Event;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.yubico.webauthn.data.AttestationConveyancePreference;
+import com.yubico.webauthn.data.ResidentKeyRequirement;
+import com.yubico.webauthn.data.UserVerificationRequirement;
+
+import net.shibboleth.idp.plugin.authn.webauthn.admin.WebAuthnRegistrationEventIds;
+import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
+import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnTest;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.ComponentInitializationException;
+
+/**
+ * Tests for {@link CreatePublicKeyCredentialCreationOptions}
+ */
+public class CreatePublicKeyCredentialCreationOptionsTest extends AbstractWebAuthnTest {
+    
+    private CreatePublicKeyCredentialCreationOptions action;
+    
+    private WebAuthnRegistrationContext context;
+    
+    @Override
+    @BeforeMethod
+    public void setup() throws Exception {
+        super.setup();
+        context = addWebAuthnRegistrationContext();
+        action = new CreatePublicKeyCredentialCreationOptions();
+        action.setWebAuthnClient(client);
+        action.setCredentialRepository(credentialRepo);
+        
+        
+        context.setUserVerificationRequirement(UserVerificationRequirement.PREFERRED);
+        context.setResidentKeyRequirement(ResidentKeyRequirement.PREFERRED);
+        context.setDisplayName("display name");
+        context.setUsername("username");
+        context.setUserId(generateRandomBytes(10));
+        context.setAttestationConveyancePreference(AttestationConveyancePreference.NONE);
+        
+    }
+    
+    @SuppressWarnings("null")
+    @Test
+    public void testCreateOptions() throws ComponentInitializationException {
+        context.setServerChallenge(generateRandomBytes(17));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertNull(result);
+        assertNotNull(context.getPublicKeyCredentialCreationOptions());
+        assertNotNull(context.getPublicKeyCredentialCreationOptions().getChallenge());
+        // we have not added any exclude credentials, so check empty
+        assertTrue(context.getPublicKeyCredentialCreationOptions().getExcludeCredentials().get().isEmpty());
+        
+    }
+    
+    @Test
+    public void testCreateOptions_NoChallenge() throws ComponentInitializationException {
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertNotNull(result);
+        assert result != null;
+        assertEquals(result.getId(), WebAuthnRegistrationEventIds.INVALID_REGISTRATION_CTX);
+        
+    }
+    
+    
+    @SuppressWarnings("null")
+    @Test
+    public void testCreateOptions_WithExcludeCredentials() throws Exception {
+        context.setServerChallenge(generateRandomBytes(17));
+        action.initialize();
+
+        context.setExistingCredentials(CollectionSupport.setOf(createCredentialRegistration()));
+        
+        final Event result = action.execute(src);
+        assertNull(result);
+        assertNotNull(context.getPublicKeyCredentialCreationOptions());
+        assertNotNull(context.getPublicKeyCredentialCreationOptions().getChallenge());
+        assertFalse(context.getPublicKeyCredentialCreationOptions().getExcludeCredentials().get().isEmpty());
+        
+    }
+
+}
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/DeletePublicKeyCredentialTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/DeletePublicKeyCredentialTest.java
index 6a14df1..de4afc9 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/DeletePublicKeyCredentialTest.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/DeletePublicKeyCredentialTest.java
@@ -18,31 +18,16 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Optional;
-import java.util.TreeSet;
-
 import org.springframework.webflow.execution.Event;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.yubico.webauthn.RegisteredCredential;
-import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
-import com.yubico.webauthn.data.AuthenticatorTransport;
-import com.yubico.webauthn.data.ByteArray;
-import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs;
-import com.yubico.webauthn.data.PublicKeyCredential;
-import com.yubico.webauthn.data.UserIdentity;
 
 import net.shibboleth.idp.plugin.authn.webauthn.admin.WebAuthnRegistrationEventIds;
 import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
 import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnTest;
 import net.shibboleth.idp.plugin.authn.webauthn.storage.CredentialRegistration;
-import net.shibboleth.idp.plugin.authn.webauthn.storage.impl.MockAuthenticator;
-import net.shibboleth.shared.codec.Base64Support;
-import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.component.ComponentInitializationException;
 
 /**
@@ -65,44 +50,10 @@ public class DeletePublicKeyCredentialTest extends AbstractWebAuthnTest {
         context = addWebAuthnRegistrationContext();
         
         action = new DeletePublicKeyCredential();
-        action.setWebAuthnClient(client);
-        
-        mockAuthenticator = new MockAuthenticator(RPID);
-        
-        final var user = UserIdentity.builder()
-                .name("jdoe")
-                .displayName("John Doe")
-                .id(ByteArray.fromBase64(USER_HANDLE_B64))
-                .build();
-        
-        final Map<String, String> clientDataCreate = createClientData("webauthn.create", ORIGIN, CHALLENGE_B64);
-        
-        final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> attestation = 
-                mockAuthenticator.createAuthenticatorAttestationResponse(CHALLENGE_B64, clientDataCreate, 
-                        Base64Support.decode(USER_HANDLE_B64));
-        
-        final var barray = ByteArray.fromBase64(USER_HANDLE_B64);
-        assert barray.getBase64().equals(USER_HANDLE_B64);
-        assert Arrays.equals(barray.getBytes(), Base64Support.decode(USER_HANDLE_B64));
-
+        action.setWebAuthnClient(client);   
         
-        credential = RegisteredCredential.builder()
-                .credentialId(attestation.getId())
-                .userHandle(ByteArray.fromBase64(USER_HANDLE_B64))
-                .publicKeyCose(attestation.getResponse().getParsedAuthenticatorData()
-                        .getAttestedCredentialData().get().getCredentialPublicKey())
-                .build();
-         
-         reg = CredentialRegistration.builder()
-                 .withUserIdentity(user)
-                 .withTransports(new TreeSet<AuthenticatorTransport>())
-                 .withRegistrationTime(Instant.now())
-                 .withCredential(credential)
-                 .withAttestationMetadata(CollectionSupport.emptySet())
-                 .withCredentialNickname("nickname")
-                 .withDiscoverable(Optional.of(Boolean.TRUE))
-                 .withUserVerified(true)
-                 .build();
+        reg = createCredentialRegistration();
+        credential = reg.getCredential();
         
         credentialRepo.addRegistrationByUsername("jdoe", reg);
         
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/ExtractKeyRemovalInformationFromFormRequestTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/ExtractKeyRemovalInformationFromFormRequestTest.java
new file mode 100644
index 0000000..ad28e8e
--- /dev/null
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/ExtractKeyRemovalInformationFromFormRequestTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.webauthn.admin.impl;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import org.opensaml.messaging.context.BaseContext;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.webflow.execution.Event;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.plugin.authn.webauthn.admin.WebAuthnRegistrationEventIds;
+import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
+import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnTest;
+import net.shibboleth.shared.codec.Base64Support;
+import net.shibboleth.shared.testing.ConstantSupplier;
+
+/**
+ * Tests for {@link ExtractKeyRemovalInformationFromFormRequest}
+ */
+public class ExtractKeyRemovalInformationFromFormRequestTest extends AbstractWebAuthnTest {
+    
+    private ExtractKeyRemovalInformationFromFormRequest action;
+    
+    private WebAuthnRegistrationContext context;
+    
+    private MockHttpServletRequest request;
+    
+    @Override
+    @BeforeMethod
+    public void setup() throws Exception {
+        super.setup();
+        context = addWebAuthnRegistrationContext();
+        
+        request = new MockHttpServletRequest();
+        
+        action = new ExtractKeyRemovalInformationFromFormRequest();
+    } 
+    
+    @Test
+    public void testExtraction() throws Exception {
+        final SimpleContext contextToUpdate = new SimpleContext();
+        action.setContextSettingConsumer((prc, bytes) -> contextToUpdate.setCredentialIdToRemove(bytes));
+        
+        final byte[] credentialIdBytes = generateRandomBytes(16);
+        final String credentialIdb64 = Base64Support.encodeURLSafe(credentialIdBytes);
+        
+        request.addParameter(ExtractKeyRemovalInformationFromFormRequest.DEFAULT_PARAMETER_NAME, 
+                new String[]{credentialIdb64});
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertNull(result);
+        assertNotNull(contextToUpdate);
+        assert contextToUpdate != null;
+        assertNotNull(contextToUpdate.getCredentialIdToRemove());
+        
+    }
+    
+    @Test
+    public void testExtraction_NoCredentialIdFound() throws Exception {
+        final SimpleContext contextToUpdate = new SimpleContext();
+        action.setContextSettingConsumer((prc, bytes) -> contextToUpdate.setCredentialIdToRemove(bytes));
+
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertFailure(result,  WebAuthnRegistrationEventIds.INVALID_ADMIN_ACTION);
+        
+    }
+    
+    @Test
+    public void testExtraction_CredentialIdCouldNotBeBase64Decoded() throws Exception {
+        final SimpleContext contextToUpdate = new SimpleContext();
+        action.setContextSettingConsumer((prc, bytes) -> contextToUpdate.setCredentialIdToRemove(bytes));
+
+        request.addParameter(ExtractKeyRemovalInformationFromFormRequest.DEFAULT_PARAMETER_NAME, 
+                new String[]{"not-encoded"});
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertFailure(result,  WebAuthnRegistrationEventIds.INVALID_ADMIN_ACTION);
+        
+    }
+    
+    /** Simple context to store the update.*/
+    private class SimpleContext extends BaseContext {
+        
+        private byte[] credentialIdToRemove;
+        
+        public SimpleContext() {
+        }
+        
+        public void setCredentialIdToRemove(final byte[] credId) {
+            this.credentialIdToRemove = credId;
+        }
+
+        public byte[] getCredentialIdToRemove() {
+            return credentialIdToRemove;
+        }
+    }
+
+}
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/ExtractPublicKeyCredentialAttestationFromFormRequestTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/ExtractPublicKeyCredentialAttestationFromFormRequestTest.java
new file mode 100644
index 0000000..3eedc47
--- /dev/null
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/ExtractPublicKeyCredentialAttestationFromFormRequestTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.webauthn.admin.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.webflow.execution.Event;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
+import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs;
+import com.yubico.webauthn.data.PublicKeyCredential;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.plugin.authn.webauthn.admin.WebAuthnRegistrationEventIds;
+import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
+import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnTest;
+import net.shibboleth.shared.testing.ConstantSupplier;
+
+/**
+ * Tests for {@link ExtractPublicKeyCredentialAttestationFromFormRequest}
+ */
+public class ExtractPublicKeyCredentialAttestationFromFormRequestTest extends AbstractWebAuthnTest {
+    
+    private ExtractPublicKeyCredentialAttestationFromFormRequest action;
+    
+    private WebAuthnRegistrationContext context;
+    
+    private MockHttpServletRequest request;
+    
+    @Override
+    @BeforeMethod
+    public void setup() throws Exception {
+        super.setup();
+        context = addWebAuthnRegistrationContext();        
+        request = new MockHttpServletRequest();        
+        action = new ExtractPublicKeyCredentialAttestationFromFormRequest();
+        action.setWebAuthnClient(client);
+        action.setCredentialRepository(credentialRepo);
+    } 
+    
+    @SuppressWarnings("null")
+    @Test
+    public void testExtraction() throws Exception {
+        
+        final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs>
+            attestationResponse = createAttestationReponse();
+ 
+        final String attestationResponseJson = jsonMapper.writeValueAsString(attestationResponse);
+        
+        request.addParameter(ExtractPublicKeyCredentialAttestationFromFormRequest.DEFAULT_PARAMETER_NAME, 
+                attestationResponseJson);
+        request.addParameter(ExtractPublicKeyCredentialAttestationFromFormRequest.DEFAULT_NICKNAME_FIELD_NAME, 
+                "nickname");
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertNull(result);
+        assertNotNull(context.getCredentialNickname());
+        assertNotNull(context.getPublicKeyCredentialAttestationResponse());
+        assertEquals(context.getCredentialNickname(),"nickname");
+        assertEquals(context.getPublicKeyCredentialAttestationResponse().getId(), attestationResponse.getId()); 
+    }
+    
+    @SuppressWarnings("null")
+    @Test
+    public void testExtraction_BadPublicKeyCredential() throws Exception {
+        
+        request.addParameter(ExtractPublicKeyCredentialAttestationFromFormRequest.DEFAULT_PARAMETER_NAME, 
+                "this-is-not-good");
+        request.addParameter(ExtractPublicKeyCredentialAttestationFromFormRequest.DEFAULT_NICKNAME_FIELD_NAME, 
+                "nickname");
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertFailure(result, WebAuthnRegistrationEventIds.INVALID_REGISTRATION);       
+    }
+    
+    @SuppressWarnings("null")
+    @Test
+    public void testExtraction_NoCredentialInResponse() throws Exception {
+        
+        request.addParameter(ExtractPublicKeyCredentialAttestationFromFormRequest.DEFAULT_NICKNAME_FIELD_NAME, 
+                "nickname");
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertFailure(result, AuthnEventIds.NO_CREDENTIALS);        
+    }
+    
+    @SuppressWarnings("null")
+    @Test
+    public void testExtraction_NoNicknameInResponse() throws Exception {
+        
+        final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs>
+            attestationResponse = createAttestationReponse();
+ 
+        final String attestationResponseJson = jsonMapper.writeValueAsString(attestationResponse);
+        
+        request.addParameter(ExtractPublicKeyCredentialAttestationFromFormRequest.DEFAULT_PARAMETER_NAME, 
+                attestationResponseJson);
+
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertFailure(result, WebAuthnRegistrationEventIds.INVALID_REGISTRATION);  
+    }
+    
+
+}
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/AbstractWebAuthnTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/AbstractWebAuthnTest.java
index cedd238..4aa0e56 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/AbstractWebAuthnTest.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/AbstractWebAuthnTest.java
@@ -14,16 +14,23 @@
 
 package net.shibboleth.idp.plugin.authn.webauthn.impl;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
 import java.net.UnknownHostException;
+import java.time.Instant;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Random;
+import java.util.TreeSet;
 
 import javax.annotation.Nonnull;
 
 import org.opensaml.profile.context.ProfileRequestContext;
+import org.springframework.webflow.execution.Event;
 import org.springframework.webflow.execution.RequestContext;
 
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -33,8 +40,15 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.json.JsonMapper;
 import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.yubico.webauthn.RegisteredCredential;
 import com.yubico.webauthn.RelyingParty;
+import com.yubico.webauthn.data.AuthenticatorAssertionResponse;
+import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
+import com.yubico.webauthn.data.AuthenticatorTransport;
 import com.yubico.webauthn.data.ByteArray;
+import com.yubico.webauthn.data.ClientAssertionExtensionOutputs;
+import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs;
+import com.yubico.webauthn.data.PublicKeyCredential;
 import com.yubico.webauthn.data.PublicKeyCredentialCreationOptions;
 import com.yubico.webauthn.data.PublicKeyCredentialParameters;
 import com.yubico.webauthn.data.RelyingPartyIdentity;
@@ -47,6 +61,7 @@ import net.shibboleth.idp.plugin.authn.webauthn.client.impl.MockWebAuthnClient;
 import net.shibboleth.idp.plugin.authn.webauthn.context.BaseWebAuthnContext;
 import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnAuthenticationContext;
 import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
+import net.shibboleth.idp.plugin.authn.webauthn.storage.CredentialRegistration;
 import net.shibboleth.idp.plugin.authn.webauthn.storage.StorageServiceCredentialRepository;
 import net.shibboleth.idp.plugin.authn.webauthn.storage.impl.InMemoryRegistrationStorage;
 import net.shibboleth.idp.plugin.authn.webauthn.storage.impl.MockAuthenticator;
@@ -162,6 +177,7 @@ public abstract class AbstractWebAuthnTest {
                 UserIdentity.builder().name("test-user").displayName("test user")
                 .id(new ByteArray(Base64Support.decode(USER_HANDLE_B64))).build();
         
+        //TODO why are we creating this here
         final PublicKeyCredentialCreationOptions credentialCreationOptions =
                 PublicKeyCredentialCreationOptions.builder()
                     .rp(rp.getIdentity())
@@ -178,6 +194,9 @@ public abstract class AbstractWebAuthnTest {
         
         // The im-memory repo is for testing only
         credentialRepo = new InMemoryRegistrationStorage();
+        
+        mockAuthenticator = new MockAuthenticator(RPID);
+         
     }  
     
     
@@ -272,7 +291,106 @@ public abstract class AbstractWebAuthnTest {
         obj.put("type", type);
         return obj;        
     }
+    
+    /** 
+     * Assert a failure (non-proceed) event has occured.
+     * 
+     * @param event the event to test
+     * @param eventId the result event Id
+     */
+    protected void assertFailure(final Event event, final String eventId) {
+        assertNotNull(event);
+        assert event != null;
+        assertEquals(event.getId(), eventId);
+    }
 
+    /**
+     * Create a credential registration with a new attestation response from the mock authenticator.
+     * 
+     * @return the credential registration 
+     * 
+     * @throws Exception on error
+     */
+    protected CredentialRegistration createCredentialRegistration() throws Exception {
+
+        final var user = UserIdentity.builder()
+                .name("jdoe")
+                .displayName("John Doe")
+                .id(ByteArray.fromBase64(USER_HANDLE_B64))
+                .build();
+       
+        
+        final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> attestation = 
+                createAttestationReponse();
+        
+        final var barray = ByteArray.fromBase64(USER_HANDLE_B64);
+        assert barray.getBase64().equals(USER_HANDLE_B64);
+        assert Arrays.equals(barray.getBytes(), Base64Support.decode(USER_HANDLE_B64));
+
+        
+        final RegisteredCredential credential = RegisteredCredential.builder()
+                .credentialId(attestation.getId())
+                .userHandle(ByteArray.fromBase64(USER_HANDLE_B64))
+                .publicKeyCose(attestation.getResponse().getParsedAuthenticatorData()
+                        .getAttestedCredentialData().get().getCredentialPublicKey())
+                .build();
+         
+         final var reg = CredentialRegistration.builder()
+                 .withUserIdentity(user)
+                 .withTransports(new TreeSet<AuthenticatorTransport>())
+                 .withRegistrationTime(Instant.now())
+                 .withCredential(credential)
+                 .withAttestationMetadata(CollectionSupport.emptySet())
+                 .withCredentialNickname("nickname")
+                 .withDiscoverable(Optional.of(Boolean.TRUE))
+                 .withUserVerified(true)
+                 .build();
+         
+         return reg;
+    }
+    
+    /**
+     * Create a credential registration attestation response from the mock authenticator.
+     * 
+     * @return the credential registration 
+     * 
+     * @throws Exception on error
+     */
+    protected PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs>
+                createAttestationReponse() throws Exception {
+
+        
+        final Map<String, String> clientDataCreate = createClientData("webauthn.create", ORIGIN, CHALLENGE_B64);
+        
+        final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> attestation = 
+                mockAuthenticator.createAuthenticatorAttestationResponse(CHALLENGE_B64, clientDataCreate, 
+                        Base64Support.decode(USER_HANDLE_B64));
+        
+       return attestation;
+    }
+    
+    /**
+     * Create a credential authentication assertion response from the mock authenticator.
+     * 
+     * @return the credential registration 
+     * 
+     * @throws Exception on error
+     */
+    protected PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
+                createAssertionReponse() throws Exception {
+        
+        //need to create on first
+        final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> attestation = 
+                    createAttestationReponse();
+        final Map<String, String> clientDataGet = createClientData("webauthn.get", ORIGIN, CHALLENGE_B64); 
+        
+        // Now generate an assertion (authentication) and check it is valid
+        final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
+            assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
+                    clientDataGet);
+        
+       return assertion;
+    }
      
     
 
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ExtractPublicKeyCredentialAssertionFromFormRequestTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ExtractPublicKeyCredentialAssertionFromFormRequestTest.java
new file mode 100644
index 0000000..1b1a6e0
--- /dev/null
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ExtractPublicKeyCredentialAssertionFromFormRequestTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.webauthn.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.webflow.execution.Event;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.yubico.webauthn.data.AuthenticatorAssertionResponse;
+import com.yubico.webauthn.data.ClientAssertionExtensionOutputs;
+import com.yubico.webauthn.data.PublicKeyCredential;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnAuthenticationContext;
+import net.shibboleth.shared.testing.ConstantSupplier;
+
+/**
+ * Tests for {@link ExtractPublicKeyCredentialAssertionFromFormRequest}
+ */
+public class ExtractPublicKeyCredentialAssertionFromFormRequestTest extends AbstractWebAuthnTest {
+    
+    private ExtractPublicKeyCredentialAssertionFromFormRequest action;
+    
+    private WebAuthnAuthenticationContext context;
+    
+    private MockHttpServletRequest request;
+    
+    @Override
+    @BeforeMethod
+    public void setup() throws Exception {
+        super.setup();
+        context = addWebAuthnAuthenticationContext();        
+        request = new MockHttpServletRequest();        
+        action = new ExtractPublicKeyCredentialAssertionFromFormRequest();
+        action.setWebAuthnClient(client);
+        action.setCredentialRepository(credentialRepo);
+        action.setObjectMapper(jsonMapper);
+    } 
+    
+    @SuppressWarnings("null")
+    @Test
+    public void testExtraction() throws Exception {
+        
+        final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
+            assertionResponse = createAssertionReponse();
+ 
+        final String assertionResponseJson = jsonMapper.writeValueAsString(assertionResponse);
+        
+        request.addParameter(ExtractPublicKeyCredentialAssertionFromFormRequest.DEFAULT_PARAMETER_NAME, 
+                assertionResponseJson);
+
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertNull(result);
+        assertNotNull(context.getPublicKeyCredentialAssertionResponse());
+        assertEquals(context.getPublicKeyCredentialAssertionResponse().getId(), assertionResponse.getId()); 
+    }
+    
+    @Test
+    public void testExtraction_BadPublicKeyCredential() throws Exception {
+        
+        request.addParameter(ExtractPublicKeyCredentialAssertionFromFormRequest.DEFAULT_PARAMETER_NAME, 
+                "bad-public-key-assertion");
+    
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertFailure(result, AuthnEventIds.NO_CREDENTIALS);       
+    }
+    
+    @SuppressWarnings("null")
+    @Test
+    public void testExtraction_NoCredentialInResponse() throws Exception {
+
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        action.initialize();
+        
+        final Event result = action.execute(src);
+        assertFailure(result, AuthnEventIds.NO_CREDENTIALS);        
+    }
+
+
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list