[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