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

Phil Smart philip.smart at jisc.ac.uk
Thu Aug 8 16:08:44 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=766bdc84f9bed349da5848bc0958c55c32694f3e

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

commit 766bdc84f9bed349da5848bc0958c55c32694f3e
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Thu Aug 8 17:08:40 2024 +0100

    Add more flow tests
---
 .../impl/PopulateWebAuthnRegistrationContext.java  |   1 -
 .../YubicoWebauthnAuthenticationClientTest.java    |   8 +-
 .../webauthn/flow/AbstractWebAuthnFlowTest.java    |  57 +++++++++-
 .../authn/webauthn/flow/TestPasswordlessFlow.java  |   2 +-
 .../authn/webauthn/flow/TestSecondFactorFlow.java  |   2 +-
 .../authn/webauthn/flow/TestUsernameslessFlow.java | 117 ++++++++++++++++++++-
 .../authn/webauthn/impl/AbstractWebAuthnTest.java  |   2 +-
 ...kupRegisteredCredentialsFromUserHandleTest.java |   8 +-
 .../impl/ValidateWebAuthnAssertionTest.java        |   4 +-
 .../webauthn/storage/impl/MockAuthenticator.java   |  13 ++-
 10 files changed, 187 insertions(+), 27 deletions(-)

diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/PopulateWebAuthnRegistrationContext.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/PopulateWebAuthnRegistrationContext.java
index a28c6ca..4e909cf 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/PopulateWebAuthnRegistrationContext.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/PopulateWebAuthnRegistrationContext.java
@@ -62,7 +62,6 @@ public class PopulateWebAuthnRegistrationContext extends AbstractProfileAction {
     /** Constructor.*/
     public PopulateWebAuthnRegistrationContext() {
         // Default creates a WebAuthn registration context under the profile request context.
-        //TODO does this makes sense directly under the PRC?
         webAuthnRegistrationContextCreationStrategy =
                 new ChildContextLookup<>(WebAuthnRegistrationContext.class, true);
         usernameRequiredPredicate = PredicateSupport.alwaysFalse();
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 f621e00..933be35 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
@@ -201,7 +201,7 @@ public class YubicoWebauthnAuthenticationClientTest extends AbstractWebAuthnTest
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                    clientDataGet);
+                    clientDataGet, null);
 
         final AssertionResult result = 
                 client.validateAuthenticatorAssertionResponse(USERNAME, Base64Support.decode(USER_HANDLE_B64), 
@@ -249,7 +249,7 @@ public class YubicoWebauthnAuthenticationClientTest extends AbstractWebAuthnTest
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                    clientDataGet);
+                    clientDataGet, null);
         
         client.validateAuthenticatorAssertionResponse(USERNAME, Base64Support.decode(USER_HANDLE_B64), 
                 credentialRequestOptions, assertion);
@@ -294,7 +294,7 @@ public class YubicoWebauthnAuthenticationClientTest extends AbstractWebAuthnTest
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
         assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                clientDataGet);
+                clientDataGet, null);
     
         client.validateAuthenticatorAssertionResponse(USERNAME, Base64Support.decode(USER_HANDLE_B64), 
             credentialRequestOptions, assertion);
@@ -340,7 +340,7 @@ public class YubicoWebauthnAuthenticationClientTest extends AbstractWebAuthnTest
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
         assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                clientDataGet);
+                clientDataGet, null);
     
         client.validateAuthenticatorAssertionResponse(USERNAME, Base64Support.decode(USER_HANDLE_B64), 
             credentialRequestOptions, assertion);
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/AbstractWebAuthnFlowTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/AbstractWebAuthnFlowTest.java
index aae9c29..709abd1 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/AbstractWebAuthnFlowTest.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/AbstractWebAuthnFlowTest.java
@@ -374,7 +374,7 @@ public class AbstractWebAuthnFlowTest extends AbstractFlowTest {
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                    clientDataGet);
+                    clientDataGet, null);
         
        return assertion;
     }
@@ -382,21 +382,70 @@ public class AbstractWebAuthnFlowTest extends AbstractFlowTest {
     /**
      * Create a credential authentication assertion response from the mock authenticator.
      * 
+     * @param credentialId the credential ID to find the correct credential to sign the request with
+     * @param challenge the challenge to use
      * @return the credential registration 
      * 
      * @throws Exception on error
      */
     protected PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
-                createAssertionReponseFromCredentialID(
+                createAssertionReponseFrom(
                         final byte[] credentialId, final byte[] challenge) throws Exception {
 
+        return createAssertionReponseFrom(credentialId, challenge, ORIGIN);
+    }
+    
+    /**
+     * Create a credential authentication assertion response from the mock authenticator.
+     * 
+     * @param credentialId the credential ID to find the correct credential to sign the request with
+     * @param challenge the challenge to use
+     * @param the origin to use
+     * 
+     * @return the credential registration 
+     * 
+     * @throws Exception on error
+     */
+    protected PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
+                createAssertionReponseFrom(
+                        final byte[] credentialId, final byte[] challenge, final String origin) throws Exception {
+
+        final String challengeB64 = Base64Support.encodeURLSafe(challenge);
+        final Map<String, String> clientDataGet = createClientData("webauthn.get", origin, challengeB64); 
+        
+        // Now generate an assertion (authentication) and check it is valid
+        final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
+            assertion = mockAuthenticator.createAuthenticatorAssertionResponse(credentialId, 
+                    clientDataGet, null);
+        
+       return assertion;
+    }
+    
+    /**
+     * Create a credential authentication assertion response from the mock authenticator.
+     * 
+     * @param credentialId the credential ID to find the correct credential to sign the request with
+     * @param challenge the challenge to use
+     * @param the origin to use
+     * @param userHandle the userHandle to use in the assertion response (overrides the one that was stored in the 
+     *          attestation)
+     * 
+     * @return the credential registration 
+     * 
+     * @throws Exception on error
+     */
+    protected PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
+                createAssertionReponseFrom(
+                        final byte[] credentialId, final byte[] challenge, final String origin, final byte[] userHandle) 
+                                throws Exception {
+
         final String challengeB64 = Base64Support.encodeURLSafe(challenge);
-        final Map<String, String> clientDataGet = createClientData("webauthn.get", ORIGIN, challengeB64); 
+        final Map<String, String> clientDataGet = createClientData("webauthn.get", origin, challengeB64); 
         
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(credentialId, 
-                    clientDataGet);
+                    clientDataGet, userHandle);
         
        return assertion;
     }
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestPasswordlessFlow.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestPasswordlessFlow.java
index d841df0..aa46e0d 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestPasswordlessFlow.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestPasswordlessFlow.java
@@ -98,7 +98,7 @@ public class TestPasswordlessFlow extends AbstractWebAuthnFlowTest{
         final ByteArray challenge = authnContext.getPublicKeyCredentialRequestOptions().getChallenge();
         
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
-        assertionResponse = createAssertionReponseFromCredentialID(
+        assertionResponse = createAssertionReponseFrom(
                 registration.getCredential().getCredentialId().getBytes(), challenge.getBytes());
 
         final String assertionResponseJson = jsonMapper.writeValueAsString(assertionResponse);
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestSecondFactorFlow.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestSecondFactorFlow.java
index ee5e10f..de94724 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestSecondFactorFlow.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestSecondFactorFlow.java
@@ -91,7 +91,7 @@ public class TestSecondFactorFlow extends AbstractWebAuthnFlowTest{
         final ByteArray challenge = authnContext.getPublicKeyCredentialRequestOptions().getChallenge();
         
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
-        assertionResponse = createAssertionReponseFromCredentialID(
+        assertionResponse = createAssertionReponseFrom(
                 registration.getCredential().getCredentialId().getBytes(), challenge.getBytes());
 
         final String assertionResponseJson = jsonMapper.writeValueAsString(assertionResponse);
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestUsernameslessFlow.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestUsernameslessFlow.java
index 81fa5ec..c35ade3 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestUsernameslessFlow.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/flow/TestUsernameslessFlow.java
@@ -31,6 +31,7 @@ import com.yubico.webauthn.data.ByteArray;
 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.idp.plugin.authn.webauthn.impl.ExtractPublicKeyCredentialAssertionFromFormRequest;
 import net.shibboleth.idp.plugin.authn.webauthn.storage.CredentialRegistration;
@@ -87,7 +88,7 @@ public class TestUsernameslessFlow extends AbstractWebAuthnFlowTest{
         final ByteArray challenge = authnContext.getPublicKeyCredentialRequestOptions().getChallenge();
         
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
-        assertionResponse = createAssertionReponseFromCredentialID(
+        assertionResponse = createAssertionReponseFrom(
                 registration.getCredential().getCredentialId().getBytes(), challenge.getBytes());
 
         final String assertionResponseJson = jsonMapper.writeValueAsString(assertionResponse);
@@ -106,6 +107,114 @@ public class TestUsernameslessFlow extends AbstractWebAuthnFlowTest{
 
     }
     
+    @SuppressWarnings("null")
+    @Test
+    public void testUsernamelessFlow_WrongOrigin() throws Exception {
+        
+        //Register a credential for use.
+        final CredentialRegistration registration = 
+                createCredentialRegistration(USERNAME, DISPLAY_NAME, USER_HANDLE_B64);
+        credentialRepo.addRegistrationByUsername(USERNAME, registration);
+        
+        final var prc = buildProfileRequestContext(false, false, null);
+
+        final Pair<FlowExecutionResult, FlowExecutionImpl> result = launchExecution(FLOW_ID, null, externalContext, 
+                addToConversationScopeMap(Map.of("opensamlProfileRequestContext", prc)));
+
+        assertFlowExecutionActive(result.getSecond());
+        assertCurrentStateEquals("DisplayWebAuthnView", result.getSecond());
+        assertPublicKeyCredentialRequestOptions(prc, false, true);
+        
+        // Do assertion validation half of flow
+        
+        // Get the challenge that was set into the PublicKeyCredentialRequestOptions. 
+        // otherwise we will end up signing a different one, which will provide its own test.
+        final WebAuthnAuthenticationContext authnContext = getWebAuthnAuthenticationContext(prc);
+        final ByteArray challenge = authnContext.getPublicKeyCredentialRequestOptions().getChallenge();
+        
+        final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
+        assertionResponse = createAssertionReponseFrom(
+                registration.getCredential().getCredentialId().getBytes(), challenge.getBytes(), "wrong.origin.com");
+
+        final String assertionResponseJson = jsonMapper.writeValueAsString(assertionResponse);
+        
+        // Re-set external context to holder
+        ExternalContextHolder.setExternalContext(externalContext);
+        setHttpFormRequest("POST", Map.of(ExtractPublicKeyCredentialAssertionFromFormRequest.DEFAULT_PARAMETER_NAME, 
+                assertionResponseJson));
+        externalContext.setEventId("proceed");
+        result.getSecond().setCurrentState("DisplayWebAuthnView");
+        result.getSecond().resume(externalContext);
+        
+        
+        assertEquals(result.getSecond().getOutcome().getId(),  AuthnEventIds.INVALID_CREDENTIALS);
+        assertAuthenticationFailureConditions(prc);
+
+    }
+    
+    /** 
+     * Test a validation error that the user identified by the overriden assertion userHandle is not in possession of 
+     * the credential used to sign the assertion response (as identified by the credentialID in the authenticator data 
+     * in the response).
+     * 
+     * @throws Exception
+     */
+    @SuppressWarnings("null")
+    @Test
+    public void testUsernamelessFlow_WrongUserHandleForUsername() throws Exception {      
+      
+        //Register a credential for use for the actual/real user.
+        final CredentialRegistration registration = 
+                createCredentialRegistration(USERNAME, DISPLAY_NAME, USER_HANDLE_B64);
+        credentialRepo.addRegistrationByUsername(USERNAME, registration);
+        
+        //Register a second users credential with different 
+        final var userHandleSecondUserB64 = "2fixsNecxhORZpf4LMU9nA==";
+        final ByteArray userHandleBytesSecondUser = ByteArray.fromBase64(userHandleSecondUserB64);        
+        final CredentialRegistration registrationTwo = 
+                createCredentialRegistration("second-user", "second user", userHandleSecondUserB64);
+        credentialRepo.addRegistrationByUsername("second-user", registrationTwo);
+        
+        final var prc = buildProfileRequestContext(false, false, null);
+
+        final Pair<FlowExecutionResult, FlowExecutionImpl> result = launchExecution(FLOW_ID, null, externalContext, 
+                addToConversationScopeMap(Map.of("opensamlProfileRequestContext", prc)));
+
+        assertFlowExecutionActive(result.getSecond());
+        assertCurrentStateEquals("DisplayWebAuthnView", result.getSecond());
+        assertPublicKeyCredentialRequestOptions(prc, false, true);
+        
+        // Do assertion validation half of flow
+        
+        // Get the challenge that was set into the PublicKeyCredentialRequestOptions. 
+        // otherwise we will end up signing a different one, which will provide its own test.
+        final WebAuthnAuthenticationContext authnContext = getWebAuthnAuthenticationContext(prc);
+        final ByteArray challenge = authnContext.getPublicKeyCredentialRequestOptions().getChallenge();        
+       
+        // Create an assertion response using the credential (and credentialID) from the real user, but using the 
+        // second users userHandle. This should fail, as the userHandle does not link to a user with that credential
+        final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
+        assertionResponse = createAssertionReponseFrom(
+                registration.getCredential().getCredentialId().getBytes(), challenge.getBytes(), "wrong.origin.com", 
+                userHandleBytesSecondUser.getBytes());
+
+        final String assertionResponseJson = jsonMapper.writeValueAsString(assertionResponse);
+        
+        // Re-set external context to holder
+        ExternalContextHolder.setExternalContext(externalContext);
+        setHttpFormRequest("POST", Map.of(ExtractPublicKeyCredentialAssertionFromFormRequest.DEFAULT_PARAMETER_NAME, 
+                assertionResponseJson));
+        externalContext.setEventId("proceed");
+        result.getSecond().setCurrentState("DisplayWebAuthnView");
+        result.getSecond().resume(externalContext);
+        
+        
+        assertEquals(result.getSecond().getOutcome().getId(),  AuthnEventIds.INVALID_CREDENTIALS);
+        assertAuthenticationFailureConditions(prc);
+
+    }
+   
+    
     @SuppressWarnings("null")
     @Test
     public void testUsernamelessFlow_NoAssertionResponse() throws Exception {
@@ -132,7 +241,7 @@ public class TestUsernameslessFlow extends AbstractWebAuthnFlowTest{
         final ByteArray challenge = authnContext.getPublicKeyCredentialRequestOptions().getChallenge();
         
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
-        assertionResponse = createAssertionReponseFromCredentialID(
+        assertionResponse = createAssertionReponseFrom(
                 registration.getCredential().getCredentialId().getBytes(), challenge.getBytes());
 
         final String assertionResponseJson = jsonMapper.writeValueAsString(assertionResponse);
@@ -172,7 +281,7 @@ public class TestUsernameslessFlow extends AbstractWebAuthnFlowTest{
         
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
         // Generate a challenge which is not the same as the one generated by the flow
-        assertionResponse = createAssertionReponseFromCredentialID(
+        assertionResponse = createAssertionReponseFrom(
                 registration.getCredential().getCredentialId().getBytes(), generateRandomBytes(32));
 
         final String assertionResponseJson = jsonMapper.writeValueAsString(assertionResponse);
@@ -215,7 +324,7 @@ public class TestUsernameslessFlow extends AbstractWebAuthnFlowTest{
         final ByteArray challenge = authnContext.getPublicKeyCredentialRequestOptions().getChallenge();
         
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>
-        assertionResponse = createAssertionReponseFromCredentialID(
+        assertionResponse = createAssertionReponseFrom(
                 registration.getCredential().getCredentialId().getBytes(), challenge.getBytes());
 
         final String assertionResponseJson = jsonMapper.writeValueAsString(assertionResponse);
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 51d00af..f826daa 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
@@ -395,7 +395,7 @@ public abstract class AbstractWebAuthnTest {
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                    clientDataGet);
+                    clientDataGet, null);
         
        return assertion;
     }
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/LookupRegisteredCredentialsFromUserHandleTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/LookupRegisteredCredentialsFromUserHandleTest.java
index d9bde51..c240d97 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/LookupRegisteredCredentialsFromUserHandleTest.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/LookupRegisteredCredentialsFromUserHandleTest.java
@@ -110,7 +110,7 @@ public class LookupRegisteredCredentialsFromUserHandleTest extends AbstractWebAu
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                    clientDataGet);
+                    clientDataGet, null);
         
         webAuthnContext.setPublicKeyCredentialAssertionResponse(assertion);
         
@@ -165,7 +165,7 @@ public class LookupRegisteredCredentialsFromUserHandleTest extends AbstractWebAu
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                    clientDataGet);
+                    clientDataGet, null);
         
         webAuthnContext.setPublicKeyCredentialAssertionResponse(assertion);
         
@@ -194,7 +194,7 @@ public class LookupRegisteredCredentialsFromUserHandleTest extends AbstractWebAu
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                    clientDataGet);
+                    clientDataGet, null);
         
         webAuthnContext.setPublicKeyCredentialAssertionResponse(assertion);
         
@@ -224,7 +224,7 @@ public class LookupRegisteredCredentialsFromUserHandleTest extends AbstractWebAu
         // Now generate an assertion (authentication) and check it is valid
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                    clientDataGet);
+                    clientDataGet, null);
         
         webAuthnContext.setPublicKeyCredentialAssertionResponse(assertion);
         
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
index cd3ed88..a5134ea 100644
--- 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
@@ -102,7 +102,7 @@ public class ValidateWebAuthnAssertionTest extends AbstractWebAuthnTest {
 
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                    clientDataGet);
+                    clientDataGet, null);
         
         //Set the assertion (authentication) response based on the credential we've already registered
         context.setPublicKeyCredentialAssertionResponse(assertion);
@@ -123,7 +123,7 @@ public class ValidateWebAuthnAssertionTest extends AbstractWebAuthnTest {
 
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
             assertion = mockAuthenticator.createAuthenticatorAssertionResponse(attestation.getId().getBytes(), 
-                    clientDataGet);
+                    clientDataGet, null);
         
         //Set the assertion (authentication) response based on the credential we've already registered
         context.setPublicKeyCredentialAssertionResponse(assertion);
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/MockAuthenticator.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/MockAuthenticator.java
index b9ee8d7..3e29b85 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/MockAuthenticator.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/MockAuthenticator.java
@@ -218,14 +218,15 @@ public class MockAuthenticator {
      * 
      * @param credentialId the credential identifier to give this credential, should be one that is registered.
      * @param clientData the client data passed by the 'client' (browser) during registration.
-     * 
+     * @param overrideUserHandle if set, override the userHandle in the assertion response. Normally the userHandle 
+     *      comes from what was stored in the attestation when the key was created. 
      * @return the public key credential assertion
      * 
      * @throws Exception on error
      */
     public com.yubico.webauthn.data.PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> 
-        createAuthenticatorAssertionResponse(@Nonnull final byte[] credentialId, final Map<String, String> clientData) 
-                throws Exception {
+        createAuthenticatorAssertionResponse(@Nonnull final byte[] credentialId, final Map<String, String> clientData, 
+                final byte[] overrideUserHandle) throws Exception {
         
         final var credentialb64 = Base64Support.encodeURLSafe(credentialId);
         final var publicKeyAttestation = createdCredentialsMaps.get(credentialb64);
@@ -241,13 +242,15 @@ public class MockAuthenticator {
                 sign(authenticatorData, clientDataCompactSerialization, 
                         publicKeyAttestation.getResponse().getPrivateKey());
         
+        final var userHandle = overrideUserHandle != null ? overrideUserHandle : 
+            publicKeyAttestation.getResponse().getUserHandle();
         final var pkCred = new PublicKeyCredential<Assertion, AuthenticatonExtensionsClientOutputs>(rawCredentialIdentifier,
-                new Assertion(clientDataCompactSerialization.getBytes(), authenticatorData, signature, 
-                        publicKeyAttestation.getResponse().getUserHandle()),
+                new Assertion(clientDataCompactSerialization.getBytes(), authenticatorData, signature, userHandle),
                 new AuthenticatonExtensionsClientOutputs());
         
         //convert from the test type to the correct type for the rest of the system
         final var assertionAsJson = jsonMapper.writeValueAsString(pkCred);
+        log.debug("Created assertion response '{}'", assertionAsJson);
         return com.yubico.webauthn.data.PublicKeyCredential.parseAssertionResponseJson(assertionAsJson);
         
     }

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


More information about the commits mailing list