[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