[java-idp-plugin-webauthn] branch main updated: Add internal Registration and Assertion result objects

Phil Smart philip.smart at jisc.ac.uk
Fri Mar 22 17:43:32 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=4574618441368c4bbfca0243431207ffb4710efa

The following commit(s) were added to refs/heads/main by this push:
     new 4574618  Add internal Registration and Assertion result objects
4574618 is described below

commit 4574618441368c4bbfca0243431207ffb4710efa
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Mar 22 17:43:29 2024 +0000

    Add internal Registration and Assertion result objects
    
     - We can not instantiate the Yubico variants, so we need our own
     - Also add more tests
     - Create new Mock WebAuthn clients (so as not to rely as much on
    Yubico's client for the tests). Still WIP.
---
 .../authn/webauthn/authn/AssertionResult.java      | 102 ++++++++++
 .../authn/webauthn/authn/RegistrationResult.java   | 221 +++++++++++++++++++++
 .../client/WebAuthnAuthenticationClient.java       |   9 +-
 .../context/WebAuthnRegistrationContext.java       |   3 +-
 .../admin/impl/StorePublicKeyCredential.java       |   2 +-
 .../ValidateAuthenticatorAttestationResponse.java  |   8 +-
 .../impl/YubicoWebAuthnAuthenticationClient.java   |  25 ++-
 .../webauthn/impl/ValidateWebAuthnAssertion.java   |   6 +-
 .../impl/ExceptionThrowingMockWebAuthnClient.java  |   5 +-
 .../webauthn/client/impl/MockWebAuthnClient.java   | 179 +++++++++++++++++
 .../YubicoWebauthnAuthenticationClientTest.java    |   4 +-
 .../authn/webauthn/impl/AbstractWebAuthnTest.java  |  35 +++-
 .../impl/ValidateWebAuthnAssertionTest.java        | 133 +++++++++++++
 13 files changed, 703 insertions(+), 29 deletions(-)

diff --git a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/authn/AssertionResult.java b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/authn/AssertionResult.java
new file mode 100644
index 0000000..7bbed4e
--- /dev/null
+++ b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/authn/AssertionResult.java
@@ -0,0 +1,102 @@
+/*
+ * 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.authn;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationClient;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+
+/**
+ * The result of calling {@link WebAuthnAuthenticationClient#validateAuthenticatorAssertionResponse(String, byte[], 
+ * com.yubico.webauthn.data.PublicKeyCredentialRequestOptions, com.yubico.webauthn.data.PublicKeyCredential)}
+ */
+//TODO javadoc etc. when finalised
+public class AssertionResult {
+    
+    /** Is this assertion valid?*/
+    private final boolean success;
+    
+    /** The username of the user this result corresponds to.*/
+    @Nonnull @NotEmpty private final String username;
+    
+    /** Is the signature count valid?*/
+    private final boolean signatureCounterValid;
+    
+    /**
+     * @return Returns the success.
+     */
+    public final boolean isSuccess() {
+        return success;
+    }
+
+
+    /**
+     * @return Returns the username.
+     */
+    public final String getUsername() {
+        return username;
+    }
+
+
+    /**
+     * @return Returns the signatureCounterValid.
+     */
+    public final boolean isSignatureCounterValid() {
+        return signatureCounterValid;
+    }
+
+
+    private AssertionResult(final Builder builder) {
+        this.success = builder.success;
+        this.username = builder.username;
+        this.signatureCounterValid = builder.signatureCounterValid;
+    }
+
+    
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    
+    public static final class Builder {
+        private boolean success;
+        private String username;
+        private boolean signatureCounterValid;
+
+        private Builder() {
+        }
+
+        public Builder withSuccess(final boolean success) {
+            this.success = success;
+            return this;
+        }
+
+        public Builder withUsername(final String username) {
+            this.username = username;
+            return this;
+        }
+
+        public Builder withSignatureCounterValid(final boolean signatureCounterValid) {
+            this.signatureCounterValid = signatureCounterValid;
+            return this;
+        }
+
+        public AssertionResult build() {
+            return new AssertionResult(this);
+        }
+    }
+
+}
diff --git a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/authn/RegistrationResult.java b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/authn/RegistrationResult.java
new file mode 100644
index 0000000..3d6f915
--- /dev/null
+++ b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/authn/RegistrationResult.java
@@ -0,0 +1,221 @@
+/*
+ * 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.authn;
+
+import java.util.Optional;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import com.yubico.webauthn.data.AttestationType;
+import com.yubico.webauthn.data.AttestedCredentialData;
+import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
+import com.yubico.webauthn.data.ByteArray;
+import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs;
+import com.yubico.webauthn.data.PublicKeyCredential;
+import com.yubico.webauthn.data.PublicKeyCredentialDescriptor;
+
+import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationClient;
+
+/**
+ * The result of a call to {@link WebAuthnAuthenticationClient#validateAuthenticatorAttestationResponse
+ * (com.yubico.webauthn.data.PublicKeyCredentialCreationOptions, com.yubico.webauthn.data.PublicKeyCredential)}
+ */
+ at ThreadSafe
+ at Immutable
+//TODO JavaDoc etc. once finalised
+//TODO credential is just held here, it comes from the original response. In which case this class is mostly convient to
+// access fields inside the credential.
+public class RegistrationResult {
+    
+    /** 
+     * Is the attestation signature valid. Does it link to a trusted root attestation.
+     * 
+     * <p>Note, this is different than if the assertion signature is valid.</p>
+     */
+    private final boolean attestationTrusted;
+    
+    /** 
+     * The attestation type that was used for this credential. This only applies to attestation statements 
+     * if requested.
+     */
+    @Nonnull private final AttestationType attestationType;
+    
+    /** The verified attestation response.*/
+    @Nonnull private final 
+    PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> credential;
+
+    
+    private RegistrationResult(final Builder builder) {
+        this.attestationTrusted = builder.attestationTrusted;
+        this.attestationType = builder.attestationType;
+        this.credential = builder.credential;
+    }
+
+    /** 
+     * Get the builder used to construct this object.
+     * 
+     * @return the builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }    
+
+    
+    /**
+     * Is the attestation signature valid. Does it link to a trusted root attestation.
+     * 
+     * <p>Note, this is different than if the assertion signature is valid.</p>
+     *
+     * @return true if the attestation signature is valid, false otherwise.
+     */
+    public final boolean isAttestationTrusted() {
+        return attestationTrusted;
+    }
+
+    /**
+     * The attestation type that was used for this credential. This only applies to attestation statements 
+     * iff requested.
+     * 
+     * @return the attestation type.
+     */
+    public final AttestationType getAttestationType() {
+        return attestationType;
+    }
+    
+    /**
+     * Get the credential ID and transports of the created credential. 
+     * 
+     * @return the credential ID and transports of the created credential.
+     */
+    public PublicKeyCredentialDescriptor getKeyId() {
+        return PublicKeyCredentialDescriptor.builder()
+                .id(credential.getId())
+                .type(credential.getType())
+                .transports(credential.getResponse().getTransports())
+                .build();
+    }
+
+    /**
+     * Get the public key of the created credential in COSE format.
+     * 
+     * @return the public key, <code>null</code> if not found.
+     */
+    @Nullable public ByteArray getPublicKeyCose() {
+        final Optional<AttestedCredentialData> attestedCredentialData = credential
+                .getResponse()
+                .getAttestation()
+                .getAuthenticatorData()
+                .getAttestedCredentialData();
+        if (attestedCredentialData.isPresent()) {
+            return attestedCredentialData.get().getCredentialPublicKey();
+        }      
+        return null;
+    }
+
+
+    /**
+     * Get the AAGUID of the authenticator. 
+     * 
+     * @return the AAGUID of the authenticator, <code>null</code> if not found.
+     */
+    @Nullable public ByteArray getAaguid() {
+        final Optional<AttestedCredentialData> attestedCredentialData = credential
+                .getResponse()
+                .getAttestation()
+                .getAuthenticatorData()
+                .getAttestedCredentialData();
+        
+        if (attestedCredentialData.isPresent()) {
+            return attestedCredentialData.get().getAaguid();
+        }
+        return null;
+        
+    }
+    
+
+    /**
+     * Try to determine if this credential is a discoverable (passkey) type by inspecting the ResidentKey flag inside
+     * the credential properties extension. 
+     * 
+     * @return true if the credential is disoverable (a passkey), false if it is not, or empty if not know e.g. 
+     *          the extensions were not returned.
+     */
+    @Nonnull public Optional<Boolean> isDiscoverable() {
+        final ClientRegistrationExtensionOutputs clientExtensions = credential.getClientExtensionResults();
+        if (!clientExtensions.getExtensionIds().isEmpty() && clientExtensions.getCredProps().isPresent()) {
+            return clientExtensions.getCredProps().flatMap(credProps -> credProps.getRk());
+        }
+        return Optional.empty();
+    }
+
+
+    /**
+     * Was the user verified by a suitable authorization guester during the registration ceremony? 
+     * 
+     * @return true if the authenticator claims to have performed user verification, false otherwise.
+     */
+    public boolean isUserVerified() {
+        return credential.getResponse().getParsedAuthenticatorData().getFlags().UV;
+    }
+
+
+    /**
+     * Get the attestation response.
+     * 
+     * @return the credential
+     */
+    public final 
+    PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> getCredential() {
+        return credential;
+    }
+
+    /** The builder.*/
+    public static final class Builder {
+        private boolean attestationTrusted;
+        private AttestationType attestationType;
+        private PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> credential;
+
+        private Builder() {
+        }
+
+        public Builder withAttestationTrusted(final boolean attestationTrusted) {
+            this.attestationTrusted = attestationTrusted;
+            return this;
+        }
+
+        public Builder withAttestationType(final AttestationType attestationType) {
+            this.attestationType = attestationType;
+            return this;
+        }
+
+        public Builder withCredential(
+                final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> credential) {
+            this.credential = credential;
+            return this;
+        }
+
+        public RegistrationResult build() {
+            return new RegistrationResult(this);
+        }
+    }
+
+
+
+
+    
+}
diff --git a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/WebAuthnAuthenticationClient.java b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/WebAuthnAuthenticationClient.java
index a248160..8b55117 100644
--- a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/WebAuthnAuthenticationClient.java
+++ b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/WebAuthnAuthenticationClient.java
@@ -4,8 +4,6 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.ThreadSafe;
 
-import com.yubico.webauthn.AssertionResult;
-import com.yubico.webauthn.RegistrationResult;
 import com.yubico.webauthn.data.AuthenticatorAssertionResponse;
 import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
 import com.yubico.webauthn.data.ClientAssertionExtensionOutputs;
@@ -15,7 +13,9 @@ import com.yubico.webauthn.data.PublicKeyCredentialCreationOptions;
 import com.yubico.webauthn.data.PublicKeyCredentialRequestOptions;
 
 import net.shibboleth.idp.plugin.authn.webauthn.admin.CredentialCreationOptionsParameters;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.AssertionResult;
 import net.shibboleth.idp.plugin.authn.webauthn.authn.CredentialRequestOptionsParameters;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.RegistrationResult;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.AssertionFailureException;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.RegistrationFailureException;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.WebAuthnAuthenticationClientException;
@@ -72,9 +72,8 @@ public interface WebAuthnAuthenticationClient {
       * 
       * @throws AssertionFailureException if the assertion is not valid
       */
-     //TODO would need our own AssertionResult to make this usuable beyond Yubico.
      //TODO do we need a userId supplied here?
-     AssertionResult validateAuthenticatorAssertionResponse(@Nullable final String username, 
+     @Nonnull AssertionResult validateAuthenticatorAssertionResponse(@Nullable final String username, 
              @Nullable final byte[] userId, 
              @Nonnull final PublicKeyCredentialRequestOptions publicKeyCredentialRequestOptions, 
              @Nonnull final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
@@ -91,7 +90,7 @@ public interface WebAuthnAuthenticationClient {
      * 
      * @throws RegistrationFailureException if the registration is not valid
      */
-     RegistrationResult validateAuthenticatorAttestationResponse(
+     @Nonnull RegistrationResult validateAuthenticatorAttestationResponse(
              @Nonnull final PublicKeyCredentialCreationOptions publicKeyCredentialCreationOptions, 
              @Nonnull final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> 
              authenticatorAttestationResponse) throws RegistrationFailureException;       
diff --git a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/WebAuthnRegistrationContext.java b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/WebAuthnRegistrationContext.java
index 54d88db..5051c25 100644
--- a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/WebAuthnRegistrationContext.java
+++ b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/WebAuthnRegistrationContext.java
@@ -4,7 +4,6 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.NotThreadSafe;
 
-import com.yubico.webauthn.RegistrationResult;
 import com.yubico.webauthn.data.AttestationConveyancePreference;
 import com.yubico.webauthn.data.AuthenticatorAttachment;
 import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
@@ -13,6 +12,8 @@ import com.yubico.webauthn.data.PublicKeyCredential;
 import com.yubico.webauthn.data.PublicKeyCredentialCreationOptions;
 import com.yubico.webauthn.data.ResidentKeyRequirement;
 
+import net.shibboleth.idp.plugin.authn.webauthn.authn.RegistrationResult;
+
 
 /** 
  * Registration context for processing WebAuthn Registration Ceremonies. This context is intended for registration of
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/StorePublicKeyCredential.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/StorePublicKeyCredential.java
index 90e40bd..0255a32 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/StorePublicKeyCredential.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/StorePublicKeyCredential.java
@@ -35,11 +35,11 @@ import com.yubico.fido.metadata.AAGUID;
 import com.yubico.fido.metadata.FidoMetadataService;
 import com.yubico.fido.metadata.MetadataBLOBPayloadEntry;
 import com.yubico.webauthn.RegisteredCredential;
-import com.yubico.webauthn.RegistrationResult;
 import com.yubico.webauthn.data.ByteArray;
 import com.yubico.webauthn.data.UserIdentity;
 
 import net.shibboleth.idp.plugin.authn.webauthn.admin.WebAuthnRegistrationEventIds;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.RegistrationResult;
 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.impl.CredentialRegistrationSerializer;
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/ValidateAuthenticatorAttestationResponse.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/ValidateAuthenticatorAttestationResponse.java
index e30a2f7..b01436c 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/ValidateAuthenticatorAttestationResponse.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/ValidateAuthenticatorAttestationResponse.java
@@ -23,13 +23,14 @@ import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 
-import com.yubico.webauthn.RegistrationResult;
 import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
+import com.yubico.webauthn.data.ByteArray;
 import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs;
 import com.yubico.webauthn.data.PublicKeyCredential;
 import com.yubico.webauthn.data.PublicKeyCredentialCreationOptions;
 
 import net.shibboleth.idp.plugin.authn.webauthn.admin.WebAuthnRegistrationEventIds;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.RegistrationResult;
 import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.RegistrationFailureException;
 import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
@@ -93,9 +94,10 @@ public class ValidateAuthenticatorAttestationResponse extends AbstractWebAuthnRe
             // If untrusted attestations are not allowed, it will not get this far. This is only useful to log if
             // untrusted attestations are allowed and the metadata has been loaded and the attestation has been 
             // checked.
+            final ByteArray aaguid = credentialPublicKey.getAaguid();
+            final String athenticator = aaguid != null ? aaguid.getHex() : "unknown";
             log.debug("{} Was attestation for authenticator '{}' trusted? {}", getLogPrefix(), 
-                    credentialPublicKey.getAaguid().getHex(),
-                    credentialPublicKey.isAttestationTrusted() ? "Yes" : "No");
+                    athenticator, credentialPublicKey.isAttestationTrusted() ? "Yes" : "No");
             // If valid. Add back to context
             context.setRegistrationResult(credentialPublicKey);
             log.info("{} Public Key Registration was valid", getLogPrefix());
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebAuthnAuthenticationClient.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebAuthnAuthenticationClient.java
index b76f216..84e826b 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebAuthnAuthenticationClient.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebAuthnAuthenticationClient.java
@@ -24,10 +24,8 @@ import javax.annotation.concurrent.ThreadSafe;
 import org.slf4j.Logger;
 
 import com.yubico.webauthn.AssertionRequest;
-import com.yubico.webauthn.AssertionResult;
 import com.yubico.webauthn.FinishAssertionOptions;
 import com.yubico.webauthn.FinishRegistrationOptions;
-import com.yubico.webauthn.RegistrationResult;
 import com.yubico.webauthn.RelyingParty;
 import com.yubico.webauthn.data.AuthenticatorAssertionResponse;
 import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
@@ -44,7 +42,9 @@ import com.yubico.webauthn.data.UserIdentity;
 import com.yubico.webauthn.exception.RegistrationFailedException;
 
 import net.shibboleth.idp.plugin.authn.webauthn.admin.CredentialCreationOptionsParameters;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.AssertionResult;
 import net.shibboleth.idp.plugin.authn.webauthn.authn.CredentialRequestOptionsParameters;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.RegistrationResult;
 import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationClient;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.AssertionFailureException;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.RegistrationFailureException;
@@ -175,7 +175,7 @@ public class YubicoWebAuthnAuthenticationClient implements WebAuthnAuthenticatio
                         username, userId);
             }
 
-            final AssertionResult result = rp.finishAssertion(FinishAssertionOptions.builder()
+            final com.yubico.webauthn.AssertionResult result = rp.finishAssertion(FinishAssertionOptions.builder()
                     .request(requestAssertion)
                     .response(authenticatorAssertionResponse)
                     .build());
@@ -187,7 +187,13 @@ public class YubicoWebAuthnAuthenticationClient implements WebAuthnAuthenticatio
                 // I think this is *always* true if valid, and will throw if not valid. But just in case.
                 throw new AssertionFailureException("Authenticator assertion was not valid");
             }
-            return result;
+            final AssertionResult assertionResult = AssertionResult.builder()
+                    .withSignatureCounterValid(result.isSignatureCounterValid())
+                    .withSuccess(result.isSuccess())
+                    .withUsername(result.getUsername())
+                    .build();
+            assert assertionResult != null;
+            return assertionResult;
             
         }  catch (final Exception e) {
             throw new AssertionFailureException(e);
@@ -204,10 +210,19 @@ public class YubicoWebAuthnAuthenticationClient implements WebAuthnAuthenticatio
         try {            
             log.trace("Public Key Credential to validate '{}'", authenticatorAttestationResponse);  
             
-            return rp.finishRegistration(FinishRegistrationOptions.builder()
+            final com.yubico.webauthn.RegistrationResult result = rp.finishRegistration(FinishRegistrationOptions.builder()
                     .request(publicKeyCredentialCreationOptions)
                     .response(authenticatorAttestationResponse)
                     .build());
+            
+            final RegistrationResult registrationResult = RegistrationResult.builder()
+                    .withAttestationTrusted(result.isAttestationTrusted())
+                    .withAttestationType(result.getAttestationType())
+                    .withCredential(authenticatorAttestationResponse)
+                    .build();
+            
+            assert registrationResult != null;
+            return registrationResult;
 
         } catch (final RegistrationFailedException e) {
            throw new RegistrationFailureException(e);
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidateWebAuthnAssertion.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidateWebAuthnAssertion.java
index fddc8f0..11e6e55 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidateWebAuthnAssertion.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidateWebAuthnAssertion.java
@@ -10,7 +10,6 @@ import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 
-import com.yubico.webauthn.AssertionResult;
 import com.yubico.webauthn.data.AuthenticatorAssertionResponse;
 import com.yubico.webauthn.data.ClientAssertionExtensionOutputs;
 import com.yubico.webauthn.data.PublicKeyCredential;
@@ -20,6 +19,7 @@ import net.shibboleth.idp.authn.AbstractValidationAction;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.AssertionResult;
 import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationClient;
 import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnAuthenticationContext;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.AssertionFailureException;
@@ -125,6 +125,10 @@ public class ValidateWebAuthnAssertion extends AbstractValidationAction {
             final AssertionResult result = webAuthnClient.validateAuthenticatorAssertionResponse(
                     context.getUsername(), context.getUserId(), publicKeyCredentialRequestOptions, assertion);
             
+            if (!result.isSuccess()) {
+                throw new AssertionFailureException("Assestion was not valid");
+            }
+            
             log.info("{} WebAuthn authentication succeeded for '{}'",getLogPrefix(),result.getUsername());
             context.setUsername(result.getUsername());
             buildAuthenticationResult(profileRequestContext, authenticationContext);
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/ExceptionThrowingMockWebAuthnClient.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/ExceptionThrowingMockWebAuthnClient.java
index 176c35e..e8c9a1b 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/ExceptionThrowingMockWebAuthnClient.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/ExceptionThrowingMockWebAuthnClient.java
@@ -14,8 +14,7 @@
 
 package net.shibboleth.idp.plugin.authn.webauthn.client.impl;
 
-import com.yubico.webauthn.AssertionResult;
-import com.yubico.webauthn.RegistrationResult;
+
 import com.yubico.webauthn.data.AuthenticatorAssertionResponse;
 import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
 import com.yubico.webauthn.data.ClientAssertionExtensionOutputs;
@@ -25,7 +24,9 @@ import com.yubico.webauthn.data.PublicKeyCredentialCreationOptions;
 import com.yubico.webauthn.data.PublicKeyCredentialRequestOptions;
 
 import net.shibboleth.idp.plugin.authn.webauthn.admin.CredentialCreationOptionsParameters;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.AssertionResult;
 import net.shibboleth.idp.plugin.authn.webauthn.authn.CredentialRequestOptionsParameters;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.RegistrationResult;
 import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationClient;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.AssertionFailureException;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.RegistrationFailureException;
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/MockWebAuthnClient.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/MockWebAuthnClient.java
new file mode 100644
index 0000000..0131aa1
--- /dev/null
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/MockWebAuthnClient.java
@@ -0,0 +1,179 @@
+/*
+ * 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.client.impl;
+
+
+import java.util.List;
+import java.util.Optional;
+
+import javax.annotation.Nonnull;
+
+import com.yubico.webauthn.RelyingParty;
+import com.yubico.webauthn.data.AttestationType;
+import com.yubico.webauthn.data.AuthenticatorAssertionResponse;
+import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
+import com.yubico.webauthn.data.AuthenticatorSelectionCriteria;
+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.PublicKeyCredentialRequestOptions;
+import com.yubico.webauthn.data.RegistrationExtensionInputs;
+import com.yubico.webauthn.data.UserIdentity;
+
+import net.shibboleth.idp.plugin.authn.webauthn.admin.CredentialCreationOptionsParameters;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.AssertionResult;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.CredentialRequestOptionsParameters;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.RegistrationResult;
+import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationClient;
+import net.shibboleth.idp.plugin.authn.webauthn.exception.AssertionFailureException;
+import net.shibboleth.idp.plugin.authn.webauthn.exception.RegistrationFailureException;
+import net.shibboleth.idp.plugin.authn.webauthn.exception.WebAuthnAuthenticationClientException;
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * A Mock WebAuthnClient 
+ */
+//TODO can we mock the options request etc? seems harder
+public class MockWebAuthnClient implements WebAuthnAuthenticationClient {
+    
+    /** Is the assertion response valid.*/
+    private final boolean assertionResponseSuccess;
+    
+    /** Is the signature count valid.*/
+    private final boolean signatureCount;  
+    
+    /** Information pertaining to the relying party.*/
+    @Nonnull private final RelyingParty rp;
+    
+    @Nonnull @NonnullElements private final List<PublicKeyCredentialParameters>  preferredPublickeyParams = 
+            CollectionSupport.listOf(
+            PublicKeyCredentialParameters.ES256,
+            PublicKeyCredentialParameters.EdDSA,
+            PublicKeyCredentialParameters.ES384,
+            PublicKeyCredentialParameters.ES512,
+            PublicKeyCredentialParameters.RS256,
+            PublicKeyCredentialParameters.RS384,
+            PublicKeyCredentialParameters.RS512);
+    
+
+    /**
+     * Constructor.
+     *
+     * @param assertionResponseSuccess Is the assertion response valid
+     * @param signatureCount Is the signature count in the assertion response valid
+     */
+    public MockWebAuthnClient(@Nonnull final RelyingParty relyingParty,
+            final boolean assertionResponseSuccess, final boolean signatureCount) {
+        super();
+        rp = Constraint.isNotNull(relyingParty, "The reyling party configuration can not be null");
+        this.assertionResponseSuccess = assertionResponseSuccess;
+        this.signatureCount = signatureCount;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public PublicKeyCredentialRequestOptions createAuthenticationRequest(
+            final CredentialRequestOptionsParameters requestParams) throws WebAuthnAuthenticationClientException {
+        
+        final PublicKeyCredentialRequestOptions request = PublicKeyCredentialRequestOptions.builder()
+                .challenge(new ByteArray(requestParams.getChallenge()))
+                .rpId(rp.getIdentity().getId())
+                .allowCredentials(Optional.ofNullable(requestParams.getAllowCredentials()))
+                .userVerification(requestParams.getUserVerificationRequirement())
+                .timeout(Optional.of(60000l))
+                .build();
+        if (request == null) {
+            throw new WebAuthnAuthenticationClientException("Unable to build public key credential request options");
+        }
+        return request;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public PublicKeyCredentialCreationOptions createRegistrationRequest(
+            final CredentialCreationOptionsParameters creationOptions) throws WebAuthnAuthenticationClientException {
+        
+        final UserIdentity identity = 
+                UserIdentity.builder().name(creationOptions.getUsername())
+                    .displayName(creationOptions.getUsername())
+                    .id(new ByteArray(creationOptions.getUserId()))
+                    .build();
+
+        RegistrationExtensionInputs extensions;
+        if (creationOptions.isEnableCredProperties()) {
+            extensions = RegistrationExtensionInputs.builder().credProps().build();
+        } else {
+            extensions = RegistrationExtensionInputs.builder().build();
+        }
+        
+        final PublicKeyCredentialCreationOptions creation = PublicKeyCredentialCreationOptions.builder()
+                    .rp(rp.getIdentity())
+                    .user(identity)
+                    .challenge(new ByteArray(creationOptions.getChallenge()))
+                    .pubKeyCredParams(preferredPublickeyParams)
+                    .excludeCredentials(creationOptions.getExcludeCredentials())
+                    .attestation(creationOptions.getAttestationConveyancePreference())
+                    .authenticatorSelection(AuthenticatorSelectionCriteria.builder()
+                            .userVerification(creationOptions.getUserVerificationRequirement())
+                            .residentKey(creationOptions.getResidentKeyRequirement())
+                            .authenticatorAttachment(creationOptions.getAuthenticatorAttachment())
+                            .build())
+                    .extensions(extensions)
+                    .timeout(Optional.empty()).build();
+        if (creation == null) {
+            throw new WebAuthnAuthenticationClientException("Unable to build public key credential creation options");
+        }
+        return creation;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public AssertionResult validateAuthenticatorAssertionResponse(final String username, final byte[] userId,
+            final PublicKeyCredentialRequestOptions publicKeyCredentialRequestOptions,
+            final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> authenticatorAssertionResponse)
+            throws AssertionFailureException {
+        
+        final AssertionResult assertionResult = AssertionResult.builder()
+                .withSignatureCounterValid(signatureCount)
+                .withSuccess(assertionResponseSuccess)
+                .withUsername(username)
+                .build();
+        assert assertionResult != null;
+        return assertionResult;
+        
+        
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public RegistrationResult validateAuthenticatorAttestationResponse(
+            final PublicKeyCredentialCreationOptions publicKeyCredentialCreationOptions,
+            final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> authenticatorAttestationResponse)
+            throws RegistrationFailureException {
+
+        return RegistrationResult.builder()
+                .withAttestationTrusted(true)
+                .withAttestationType(AttestationType.NONE)
+                .withCredential(authenticatorAttestationResponse)
+                .build();
+        
+    }
+
+}
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClientTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClientTest.java
index b4c0cbc..eaf1eda 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClientTest.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClientTest.java
@@ -25,9 +25,7 @@ import java.util.TreeSet;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import com.yubico.webauthn.AssertionResult;
 import com.yubico.webauthn.RegisteredCredential;
-import com.yubico.webauthn.RegistrationResult;
 import com.yubico.webauthn.RelyingParty;
 import com.yubico.webauthn.data.AuthenticatorAssertionResponse;
 import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
@@ -42,6 +40,8 @@ import com.yubico.webauthn.data.RelyingPartyIdentity;
 import com.yubico.webauthn.data.UserIdentity;
 import com.yubico.webauthn.data.UserVerificationRequirement;
 
+import net.shibboleth.idp.plugin.authn.webauthn.authn.AssertionResult;
+import net.shibboleth.idp.plugin.authn.webauthn.authn.RegistrationResult;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.AssertionFailureException;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.RegistrationFailureException;
 import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnTest;
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 4bbc26b..e4ca99f 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
@@ -19,6 +19,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Random;
 
 import javax.annotation.Nonnull;
 
@@ -39,9 +40,10 @@ import com.yubico.webauthn.data.PublicKeyCredentialParameters;
 import com.yubico.webauthn.data.RelyingPartyIdentity;
 import com.yubico.webauthn.data.UserIdentity;
 
+import net.shibboleth.idp.authn.AuthenticationFlowDescriptor;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationClient;
-import net.shibboleth.idp.plugin.authn.webauthn.client.impl.YubicoWebauthnClientFactory;
+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;
@@ -97,6 +99,9 @@ public abstract class AbstractWebAuthnTest {
     /** A mocked credential repository to use.*/
     protected StorageServiceCredentialRepository credentialRepo;
     
+    /** The relying party.*/
+    protected RelyingParty rp;
+    
     /** List of acceptable public key algorithms.*/
     @Nonnull protected final List<PublicKeyCredentialParameters> preferredPublickeyParams =
             CollectionSupport.listOf(
@@ -129,6 +134,9 @@ public abstract class AbstractWebAuthnTest {
         webAuthnContext = new WebAuthnAuthenticationContext();
         assert null != prc;
         ac = new AuthenticationContext();
+        final AuthenticationFlowDescriptor afd = new AuthenticationFlowDescriptor();
+        afd.setId("authn/WebAuthn");
+        ac.setAttemptedFlow(afd);
         ac.setAuthenticatingAuthority("https://idp.example.com");       
         assert null != ac;
         prc.addSubcontext(ac);
@@ -139,7 +147,7 @@ public abstract class AbstractWebAuthnTest {
         prc.addSubcontext(webAuthnRegContext);
         
         //Move this test to one of the client, this should use a mock and less specific data types
-        final RelyingParty rp = RelyingParty.builder().identity(
+        rp = RelyingParty.builder().identity(
                 RelyingPartyIdentity
                 .builder()
                 .id("idp.example.com")
@@ -164,13 +172,8 @@ public abstract class AbstractWebAuthnTest {
 
         webAuthnRegContext.setPublicKeyCredentialCreationOptions(credentialCreationOptions);
         // TODO Should create a mock factory
-        final YubicoWebauthnClientFactory factory = new YubicoWebauthnClientFactory();
-        factory.setPreferredPublickeyParams(preferredPublickeyParams.stream().map(alg -> alg.getAlg().name()).toList());
-        factory.setCredentialRepository(new InMemoryRegistrationStorage());
-        factory.setRelyingPartyId("idp.example.com");
-        factory.setRelyingPartyName("Demo IdP as a WebAuthn RP");
-        factory.initialize();     
-        client = factory.getObject();
+        
+        client = new MockWebAuthnClient(rp, true, true);
         
         // The im-memory repo is for testing only
         credentialRepo = new InMemoryRegistrationStorage();
@@ -235,6 +238,20 @@ public abstract class AbstractWebAuthnTest {
                 .setBody(body));
     }
     
+    /**
+     * Generate a 'number' of random bytes
+     * 
+     * @param number the number of random bytes
+     * 
+     * @return the random bytes
+     */
+    protected byte[] generateRandomBytes(final int number) {
+        final Random random = new Random();
+        final byte[] byteArray = new byte[number];
+        random.nextBytes(byteArray);
+        return byteArray;
+    }
+    
     
     
     /**
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidateWebAuthnAssertionTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidateWebAuthnAssertionTest.java
new file mode 100644
index 0000000..859a2af
--- /dev/null
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidateWebAuthnAssertionTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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 java.util.Map;
+import java.util.Optional;
+
+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.AuthenticatorAttestationResponse;
+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.PublicKeyCredentialRequestOptions;
+import com.yubico.webauthn.data.UserIdentity;
+import com.yubico.webauthn.data.UserVerificationRequirement;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.plugin.authn.webauthn.client.impl.MockWebAuthnClient;
+import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnAuthenticationContext;
+import net.shibboleth.shared.codec.Base64Support;
+import net.shibboleth.shared.codec.DecodingException;
+
+/**
+ * Tests for {@link ValidateWebAuthnAssertion}
+ */
+public class ValidateWebAuthnAssertionTest extends AbstractWebAuthnTest {
+    
+    private ValidateWebAuthnAssertion action;
+    
+    private WebAuthnAuthenticationContext context;
+    
+    private PublicKeyCredentialRequestOptions credentialRequestOptions;
+    
+    private UserIdentity userIdentity;
+    
+    private PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> attestation;
+    
+    /**
+     * {@inheritDoc}
+     * 
+     * Need to register a credential to user first, be before we can test a valid assertion (authentication) response.
+     */
+    @Override
+    @BeforeMethod
+    public void setup() throws Exception {
+        super.setup();
+        context = addWebAuthnAuthenticationContext();
+        mockAuthenticator = new MockAuthenticator(RPID);
+        
+        action = new ValidateWebAuthnAssertion();
+        action.setWebAuthnClient(new MockWebAuthnClient(rp, true, true));
+        
+        final Map<String, String> clientDataCreate = createClientData("webauthn.create", ORIGIN, CHALLENGE_B64); 
+        
+        attestation = 
+                mockAuthenticator.createAuthenticatorAttestationResponse(CHALLENGE_B64, clientDataCreate, 
+                        Base64Support.decode(USER_HANDLE_B64));
+        
+        credentialRequestOptions =
+                PublicKeyCredentialRequestOptions.builder()
+                    .challenge(new ByteArray(Base64Support.decode(CHALLENGE_B64)))
+                    .rpId(rp.getIdentity().getId())
+                    .userVerification(UserVerificationRequirement.REQUIRED)
+                    .timeout(Optional.of(60000l))
+                    .build();
+        context.setPublicKeyCredentialRequestOptions(credentialRequestOptions);
+
+       
+
+    } 
+    
+    @Test
+    public void testValidAssertion() throws DecodingException, Exception {   
+        context.setUsername(USERNAME);
+        action.initialize();
+        
+        final Map<String, String> clientDataGet = createClientData("webauthn.get", ORIGIN, CHALLENGE_B64);         
+
+        final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
+            assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
+                    clientDataGet);
+        
+        //Set the assertion (authentication) response based on the credential we've already registered
+        context.setAuthenticatorAssertionResponse(assertion);
+        
+        final Event event = action.execute(src);
+        assertNull(event);
+    }
+    
+    @Test
+    public void testInValidAssertion_NotSuccessful() throws DecodingException, Exception {   
+        action.setWebAuthnClient(new MockWebAuthnClient(rp, false, true));
+        
+        context.setUsername(USERNAME);
+        action.initialize();
+        
+        final Map<String, String> clientDataGet = createClientData("webauthn.get", ORIGIN, CHALLENGE_B64);         
+
+        final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
+            assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
+                    clientDataGet);
+        
+        //Set the assertion (authentication) response based on the credential we've already registered
+        context.setAuthenticatorAssertionResponse(assertion);
+        
+        final Event event = action.execute(src);
+        assertNotNull(event);
+        assert event != null;
+        assertEquals(event.getId(), AuthnEventIds.INVALID_CREDENTIALS);
+    }
+
+}

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


More information about the commits mailing list