[java-idp-plugin-webauthn] branch main updated: Add tests for webauthn user.name different than IdP username

Phil Smart philip.smart at jisc.ac.uk
Mon Sep 16 11:08:59 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=4e00c1cc00cc2cb24d5e26da53172e06e6fe5ccd

The following commit(s) were added to refs/heads/main by this push:
     new 4e00c1c  Add tests for webauthn user.name different than IdP username
4e00c1c is described below

commit 4e00c1cc00cc2cb24d5e26da53172e06e6fe5ccd
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Mon Sep 16 12:08:57 2024 +0100

    Add tests for webauthn user.name different than IdP username
---
 .../webauthn/flow/AbstractWebAuthnFlowTest.java    | 35 +++++++++++++
 .../authn/webauthn/flow/TestUsernameslessFlow.java | 58 ++++++++++++++++++++++
 2 files changed, 93 insertions(+)

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 82d8de2..1e2ce59 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
@@ -331,6 +331,41 @@ public class AbstractWebAuthnFlowTest extends AbstractFlowTest {
         assertEquals(subject.getPrincipals(WebAuthnUserIdPrinicpal.class).iterator().next().getName(),userId);
     }
     
+    /**
+     * Assert conditions required to test the WebAuthn flow has produced a valid authentication result. This includes:
+     * <ul>
+     * <li>A username principal that matches the username given</li>
+     * <li>A WebAuthnUserIdPrincipal.</li>
+     * <li>An authentication results from the authn/WebAuthn flow.</li>
+     * </ul>
+     * 
+     * @param prc the profile request context
+     * @param requiresUsernamePrincipal set to true if the WebAuthn authentication result should contain a 
+     *          username principal. Only false if we assume a previous factor contains a UsernamePrincipal.
+     * @throws EncodingException on error
+     */
+    @SuppressWarnings("null")
+    protected void assertAuthenticationSuccessConditionsWithUsername(final ProfileRequestContext prc, 
+            final boolean requiresUsernamePrincipal, final String username) throws EncodingException {
+        assertNotNull(prc.getSubcontext(AuthenticationContext.class));
+        final var ac = prc.getSubcontext(AuthenticationContext.class);
+        assertNotNull(ac.getAuthenticationResult());
+        final var webAuthnContext = ac.getSubcontext(WebAuthnAuthenticationContext.class);
+        final var authnResult = ac.getAuthenticationResult();
+        assertEquals(authnResult.getAuthenticationFlowId(), "authn/WebAuthn");
+        final Subject subject = authnResult.getSubject();
+        if (requiresUsernamePrincipal) {
+            assertNotNull(subject.getPrincipals(UsernamePrincipal.class));
+            assertEquals(subject.getPrincipals(UsernamePrincipal.class).size(), 1);
+            assertEquals(subject.getPrincipals(UsernamePrincipal.class).iterator().next().getName(), username);
+        }
+        assertNotNull(subject.getPrincipals(WebAuthnUserIdPrinicpal.class));
+        assertEquals(subject.getPrincipals(WebAuthnUserIdPrinicpal.class).size(), 1);
+        final byte[] userIdBytes = webAuthnContext.getUserId();
+        final String userId = Base64Support.encode(userIdBytes, false);
+        assertEquals(subject.getPrincipals(WebAuthnUserIdPrinicpal.class).iterator().next().getName(),userId);
+    }
+    
     /**
      * Assert conditions required to test the WebAuthn flow has produced an invalid authentication result.
      * 
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 24819d1..5701886 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
@@ -107,6 +107,64 @@ public class TestUsernameslessFlow extends AbstractWebAuthnFlowTest{
 
     }
     
+    @SuppressWarnings("null")
+    @Test
+    public void testUsernamelessFlow_WebAuthnUsernameDifferentThanIdPUsername() throws Exception {
+        
+        //Register a credential for use.
+        final CredentialRegistration registration = 
+                createCredentialRegistration(USERNAME, DISPLAY_NAME, USER_HANDLE_B64);
+        
+        // Now change the username to be different than the user in the WebAuthn identity
+        final var regWithDifferentUsername = CredentialRegistration.builder()
+                .withUserIdentity(registration.getUserIdentity())
+                .withUsername("different-idp-username")
+                .withTransports(registration.getTransports())
+                .withRegistrationTime(registration.getRegistrationTime())
+                .withCredential(registration.getCredential())
+                .withCredentialNickname(registration.getNickname())
+                .withDiscoverable(registration.isDiscoverable())
+                .withUserVerified(registration.isUserVerified())
+                .build();
+        
+        credentialRepo.addRegistrationByUsername("different-idp-username", regWithDifferentUsername);
+        
+        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());
+
+        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);
+        
+        // assert end conditions, no existing result or principal. So this should produce a Username principal
+        assertEquals(result.getSecond().getOutcome().getId(), "proceed");
+        assertAuthenticationSuccessConditionsWithUsername(prc, true, "different-idp-username");
+
+    }
+    
     @SuppressWarnings("null")
     @Test
     public void testUsernamelessFlow_UserNotVerified() throws Exception {

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


More information about the commits mailing list