[java-idp-plugin-webauthn] branch main updated: Cleanup user.id in WebAuthn client

Phil Smart philip.smart at jisc.ac.uk
Tue May 21 10:24:42 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=f8f8d5692a7020471d9ac49fd6f7096d2288acf2

The following commit(s) were added to refs/heads/main by this push:
     new f8f8d56  Cleanup user.id in WebAuthn client
f8f8d56 is described below

commit f8f8d5692a7020471d9ac49fd6f7096d2288acf2
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Tue May 21 11:24:37 2024 +0100

    Cleanup user.id in WebAuthn client
---
 .../webauthn/client/WebAuthnAuthenticationClient.java   |  1 -
 .../authn/webauthn/context/BaseWebAuthnContext.java     |  5 ++++-
 .../webauthn/context/WebAuthnAuthenticationContext.java |  3 ++-
 .../client/impl/YubicoWebAuthnAuthenticationClient.java |  5 -----
 .../client/impl/YubicoWebauthnClientFactory.java        |  2 +-
 .../webauthn/impl/LookupRegisteredCredentials.java      | 17 ++++++++++++++---
 .../authn/webauthn/impl/ValidateWebAuthnAssertion.java  |  5 ++---
 7 files changed, 23 insertions(+), 15 deletions(-)

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 54cd9c4..876cff7 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
@@ -74,7 +74,6 @@ public interface WebAuthnAuthenticationClient {
       * 
       * @throws AssertionFailureException if the assertion is not valid
       */
-     //TODO do we need a userId supplied here?
      @Nonnull AssertionResult validateAuthenticatorAssertionResponse(@Nullable final String username, 
              @Nullable final byte[] userId, 
              @Nonnull final PublicKeyCredentialRequestOptions publicKeyCredentialRequestOptions, 
diff --git a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/BaseWebAuthnContext.java b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/BaseWebAuthnContext.java
index 49195d6..f75779e 100644
--- a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/BaseWebAuthnContext.java
+++ b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/BaseWebAuthnContext.java
@@ -50,7 +50,10 @@ public class BaseWebAuthnContext extends BaseContext {
     /** The challenge sent to the authenticator in both registration and authentication ceremonies.*/
     @Nullable private byte[] serverChallenge;
     
-    /** The user.id supplied to the authenticator during registration. Generated by the IdP.*/
+    /** 
+     * The user.id supplied to the authenticator during registration. Generated by the IdP. Returned in assertion
+     * responses as a userHandle.
+     */
     @Nullable private byte[] userId;
         
     /** Does the authentication/registration require user verification? */
diff --git a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/WebAuthnAuthenticationContext.java b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/WebAuthnAuthenticationContext.java
index 6cd6832..9bbedfd 100644
--- a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/WebAuthnAuthenticationContext.java
+++ b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/WebAuthnAuthenticationContext.java
@@ -30,7 +30,8 @@ public final class WebAuthnAuthenticationContext extends BaseWebAuthnContext {
     
     /** An assertion response that is the result of an authentication.*/
     @Nullable 
-    private PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> authenticatorAssertionResponse;
+    private 
+    PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> authenticatorAssertionResponse;
    
     /** The public key credential request options for authentication.*/ 
     @Nullable private PublicKeyCredentialRequestOptions publicKeyCredentialRequestOptions;
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 4307585..ee18734 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
@@ -96,10 +96,6 @@ public class YubicoWebAuthnAuthenticationClient implements WebAuthnAuthenticatio
                     .challenge(new ByteArray(requestParams.getChallenge()))
                     .rpId(rp.getIdentity().getId())
                     .allowCredentials(Optional.ofNullable(requestParams.getAllowCredentials()))
-//                        .extensions(
-//                            startAssertionOptions
-//                                .getExtensions()
-//                                .merge(startAssertionOptions.getExtensions().toBuilder().appid(appId).build()))
                     .userVerification(requestParams.getUserVerificationRequirement())
                     .timeout(Optional.of(60000l))
                     .build();
@@ -163,7 +159,6 @@ public class YubicoWebAuthnAuthenticationClient implements WebAuthnAuthenticatio
             
             final AssertionRequest requestAssertion = AssertionRequest.builder()
                 .publicKeyCredentialRequestOptions(publicKeyCredentialRequestOptions)
-                //TODO userHandle will always be null here. Check this?
                 .userHandle(Optional.ofNullable(userId != null ? new ByteArray(userId) : null))
                 .username(Optional.ofNullable(username))
                 .build();
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactory.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactory.java
index 85b6c31..c1af8be 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactory.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactory.java
@@ -48,7 +48,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 
 /**
- * Spring factory beans for creating a {@link YubicoWebAuthnAuthenticationClient}.
+ * Spring factory bean for creating a {@link YubicoWebAuthnAuthenticationClient}.
  */
 @ThreadSafe
 public class YubicoWebauthnClientFactory extends AbstractInitializableComponent 
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/LookupRegisteredCredentials.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/LookupRegisteredCredentials.java
index 4bfc777..1178b97 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/LookupRegisteredCredentials.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/LookupRegisteredCredentials.java
@@ -15,6 +15,7 @@
 package net.shibboleth.idp.plugin.authn.webauthn.impl;
 
 import java.util.Collection;
+import java.util.Optional;
 import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
@@ -24,6 +25,8 @@ import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 
+import com.yubico.webauthn.data.ByteArray;
+
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.plugin.authn.webauthn.authn.WebAuthnAuthenticationEventIds;
 import net.shibboleth.idp.plugin.authn.webauthn.context.BaseWebAuthnContext;
@@ -35,12 +38,13 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
  * An action that lookups existing registered credentials based on the username contained in the WebAuthn context 
- * and sets them back onto the context. If no credentials exist and the trigger event condition is set, an error 
- * event will be produced.
+ * and sets them back onto the context. Also sets the user.id from the userHandle associated with the username.
+ * If no credentials exist and the trigger event condition is set, an error event will be produced.
  * 
  * @event {@link AuthnEventIds#INVALID_AUTHN_CTX}
  * @post BaseWebAuthnContext.setExistingCredentials() is either null if no existing credentials are found, or contains
- * the credentials from the credential repository
+ * the credentials from the credential repository. {@link BaseWebAuthnContext#getUserId()} != null if the userHandle is
+ * found from the username. 
  */
 public class LookupRegisteredCredentials extends AbstractWebAuthnBaseAction {
 
@@ -112,6 +116,13 @@ public class LookupRegisteredCredentials extends AbstractWebAuthnBaseAction {
         log.debug("{} Found '{}' registered credentials for '{}'", getLogPrefix(), credentials.size(), username);
         context.setExistingCredentials(credentials);
         
+        final Optional<ByteArray> userHandle = getCredentialRepository().getUserHandleForUsername(username);
+        if (userHandle.isPresent()) {
+            final byte[] userId = userHandle.get().getBytes();
+            assert userId != null;
+            context.setUserId(userId);
+        }
+        
         if (triggerEventOnNoCredentialsPredicate.test(profileRequestContext) && credentials.isEmpty()) {
             log.debug("{} Triggering event '{}' ", getLogPrefix(), noCredentialsEventId);
             ActionSupport.buildEvent(profileRequestContext, noCredentialsEventId);
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 6ac925d..54e0c7b 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
@@ -35,7 +35,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 /**
  * An action that validates a WebAuthn Authenticator Assertion that results from a call to WebAuthn's 'get' 
  * (authentication) API. If successful, populates the Subject with a {@link UsernamePrincipal} based on the username in
- * the authentication context.
+ * the authentication context and a {@link WebAuthnUserIdPrinicpal} based on the user.id in the authentication context.
  * 
  * @event {@link AuthnEventIds#INVALID_CREDENTIALS}
  * @event {@link AuthnEventIds#INVALID_AUTHN_CTX}
@@ -130,11 +130,10 @@ public class ValidateWebAuthnAssertion extends AbstractValidationAction {
         final PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> assertion = 
                 context.getAuthenticatorAssertionResponse();
        
-        // TODO username can be null in a usernameless flow
         if (assertion == null) {
             log.warn("{} No authenticator assertion found, {} can not authenticate", 
                     getLogPrefix(),context.getUsername());
-            handleError(profileRequestContext, authenticationContext, "InvalidResponseType",
+            handleError(profileRequestContext, authenticationContext, AuthnEventIds.INVALID_CREDENTIALS,
                     AuthnEventIds.INVALID_CREDENTIALS);
             recordFailure(profileRequestContext);              
             return; 

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


More information about the commits mailing list