[java-idp-plugin-webauthn] branch main updated: JWEBAUTHN-22 - Support for different usernames in key registration

Phil Smart philip.smart at jisc.ac.uk
Thu Sep 12 14:31:48 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=60ff21a7906ed393a126e6cd2871c12492950384

The following commit(s) were added to refs/heads/main by this push:
     new 60ff21a  JWEBAUTHN-22 - Support for different usernames in key registration
60ff21a is described below

commit 60ff21a7906ed393a126e6cd2871c12492950384
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Thu Sep 12 15:31:45 2024 +0100

    JWEBAUTHN-22 - Support for different usernames in key registration
    
     - Completely decoupled the user.name sent to the authenticator during
    registration from the username the IdP stores the credential against. By
    default, this is still from the SubjectContext (the principal name of
    the authenticated user), but now it can be configured against any
    strategy you want, including the attribute strategy used by the
    displayName and userId creation actions.
    
     https://shibboleth.atlassian.net/browse/JWEBAUTHN-22
---
 .../webauthn/context/BaseWebAuthnContext.java      | 25 ++++---
 .../context/WebAuthnRegistrationContext.java       | 30 +++++++-
 .../authn/webauthn/admin/impl/AddDisplayName.java  |  9 +--
 .../impl/{AddDisplayName.java => AddUserName.java} | 79 ++++++++++++----------
 .../CreatePublicKeyCredentialCreationOptions.java  |  2 +-
 .../admin/impl/DeletePublicKeyCredential.java      |  2 +-
 .../admin/impl/StorePublicKeyCredential.java       | 20 ++++--
 .../ValidateAuthenticatorAttestationResponse.java  |  4 +-
 .../audit/impl/WebAuthnUsernameAuditExtractor.java |  3 +-
 .../PopulateWebAuthnAuthenticationContext.java     |  2 +-
 .../webauthn-registration-beans.xml                |  6 +-
 .../webauthn-registration-flow.xml                 |  3 +-
 .../authn/webauthn/conf/authn/webauthn.properties  |  2 +-
 13 files changed, 122 insertions(+), 65 deletions(-)

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 adb2db3..0e2d3ae 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
@@ -35,8 +35,14 @@ import net.shibboleth.shared.logic.Constraint;
 public class BaseWebAuthnContext extends BaseContext {
     
     /** 
-     * The user.name of the user. If {@code null} in the authentication ceremony and we can not determine the 
-     * user.id (and hence public key) to use, and the flow will require a discoverable credential.
+     * The internal IdP username of the user, used as a key to store credentials against. In the registration flow, 
+     * this is likely the principal name of the authenticated user. In the passwordless flow, this is likely a c14n 
+     * version of the username input by the user. In the usernameless flow, this will be set to the username key 
+     * from the registered credential after authentication.
+     * <p> 
+     * If {@code null} in the authentication ceremony and we can not determine the 
+     * user.id (and hence public key) to use, the flow will require a discoverable credential.
+     * </p>
      */
     @Nullable private String username;
     
@@ -68,18 +74,18 @@ public class BaseWebAuthnContext extends BaseContext {
     }
     
     /**
-     * Gets the username (WebAuthn user.name).
+     * Gets the internal IdP username.
      * 
-     * @return the user.name
+     * @return the internal username
      */
     @Nullable public String getUsername() {
         return username;
     }
 
     /**
-     * Sets the username (WebAuthn user.name). 
+     * Sets the internal IdP username.
      * 
-     * @param name the user.name
+     * @param name the internal username
      * 
      * @return this context
      */
@@ -139,7 +145,7 @@ public class BaseWebAuthnContext extends BaseContext {
     
     
     /**
-     * Set the user.id used to map public key credentials to the user's account. Maximum 64 bytes.
+     * Set the WebAuthn user.id used to map public key credentials to the user's account. Maximum 64 bytes.
      * 
      * @param id The user.id to set.
      * 
@@ -153,8 +159,9 @@ public class BaseWebAuthnContext extends BaseContext {
     }
     
     /**
-     * Get the user.id used to map public key credentials to the user's account. Sent to the authenticator during 
-     * credential creation. Referred to as the userHandle in responses from the authenticator during authentication.
+     * Get the WebAuthn user.id used to map public key credentials to the user's account. Sent to the authenticator 
+     * during credential creation. Referred to as the userHandle in responses from the authenticator during 
+     * authentication.
      * 
      * @return the user.id.
      */
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 dfb822a..8a8568e 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
@@ -36,8 +36,11 @@ import net.shibboleth.idp.plugin.authn.webauthn.admin.RegistrationResult;
 @NotThreadSafe
 public final class WebAuthnRegistrationContext extends BaseWebAuthnContext {
 
-    /** The original username. */
-    @Nullable private String username;
+    /** 
+     * The WebAuthn user.name of the user. A human-palatable  identifier for a user account. It is intended only 
+     * for display by the authenticator, and to help the user select between accounts.
+     */
+    @Nullable private String webAuthnUsername;
     
     /** A public key credential containing the assertion response that is the result of creating a new credential.*/
     @Nullable private PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> 
@@ -76,6 +79,29 @@ public final class WebAuthnRegistrationContext extends BaseWebAuthnContext {
      */
     @Nullable private String displayName;
     
+    
+
+    /**
+     * Set the WebAuthn user.name of the user to use during credential registration.  A human-palatable 
+     * identifier for a user account. It is intended only for display.
+     * 
+     * @param username The WebAuthn user.name to set.
+     */
+    @Nonnull public BaseWebAuthnContext setWebAuthnUsername(@Nullable final String username) {
+        webAuthnUsername = username;
+        return this;
+    }
+    
+    /**
+     * The WebAuthn user.name of the user to use during credential registration. A human-palatable 
+     * identifier for a user account. It is intended only for display.
+     * 
+     * @return the WebAuthn user.name.
+     */
+    @Nullable public String getWebAuthnUsername() {
+        return webAuthnUsername;
+    }
+    
     /**
      * Set the authenticator attachment requirement. {@code null} would represent either possibility.
      * 
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddDisplayName.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddDisplayName.java
index 583f404..8aeabd6 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddDisplayName.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddDisplayName.java
@@ -34,7 +34,8 @@ import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
- * An action to generate or lookup a user.displayName. The display name is for display purposes only. 
+ * An action to generate or lookup a user.displayName. The display name is by the authenticator for display purposes 
+ * only. 
  * 
  * @event {@link WebAuthnRegistrationEventIds#INVALID_REGISTRATION}
  * @pre <pre>ProfileRequestContext.getSubcontext(WebAuthnRegistrationContext.class) != null</pre>
@@ -48,7 +49,7 @@ public class AddDisplayName extends AbstractWebAuthnAction<WebAuthnRegistrationC
     /** Strategy used to lookup the user.displayName. */
     @NonnullAfterInit private Function<ProfileRequestContext,String> displayNameLookupStrategy;
     
-    /** The stashed username.*/
+    /** The stashed internal username.*/
     @NonnullBeforeExec private String username;
     
     /** Constructor.*/
@@ -65,7 +66,7 @@ public class AddDisplayName extends AbstractWebAuthnAction<WebAuthnRegistrationC
             @Nonnull final Function<ProfileRequestContext,String> strategy) {
         checkSetterPreconditions();
         displayNameLookupStrategy =
-                Constraint.isNotNull(strategy, "Challenge Generator cannot be null");
+                Constraint.isNotNull(strategy, "DisplayName lookup strategy cannot be null");
     }
     
     /** {@inheritDoc} */
@@ -74,7 +75,7 @@ public class AddDisplayName extends AbstractWebAuthnAction<WebAuthnRegistrationC
         super.doInitialize();
         
         if (displayNameLookupStrategy == null) {
-            throw new ComponentInitializationException("DisplayName generation strategy can not be null");
+            throw new ComponentInitializationException("DisplayName lookup strategy can not be null");
         }
     }
     
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddDisplayName.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddUserName.java
similarity index 63%
copy from webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddDisplayName.java
copy to webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddUserName.java
index 583f404..c62e798 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddDisplayName.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AddUserName.java
@@ -14,7 +14,6 @@
 
 package net.shibboleth.idp.plugin.authn.webauthn.admin.impl;
 
-import java.nio.charset.StandardCharsets;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -27,6 +26,7 @@ import org.slf4j.Logger;
 import net.shibboleth.idp.plugin.authn.webauthn.admin.WebAuthnRegistrationEventIds;
 import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
 import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnAction;
+import net.shibboleth.idp.plugin.authn.webauthn.storage.WebAuthnCredentialRepository;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.component.ComponentInitializationException;
@@ -34,50 +34,61 @@ import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
- * An action to generate or lookup a user.displayName. The display name is for display purposes only. 
+ * An action to generate or lookup a WebAuthn user.name. the user.name is a human-palatable identifier for a user 
+ * account. It is intended only for display by the authenticator, for example, aiding the user in determining the 
+ * difference between user accounts with similar displayNames. This can be different than the internal username used
+ * within the IdP to store credentials against.
+ * 
+ * <p>Used during the registration process, added to PublicKeyCredentialCreationOptions.</p>
  * 
  * @event {@link WebAuthnRegistrationEventIds#INVALID_REGISTRATION}
  * @pre <pre>ProfileRequestContext.getSubcontext(WebAuthnRegistrationContext.class) != null</pre>
- * @post a displayName is added to the registration context
+ * @post a user.name is added to the registration context
  */
-public class AddDisplayName extends AbstractWebAuthnAction<WebAuthnRegistrationContext> {
+public class AddUserName extends AbstractWebAuthnAction<WebAuthnRegistrationContext> {
     
     /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(AddDisplayName.class);
+    @Nonnull private final Logger log = LoggerFactory.getLogger(AddUserName.class);
    
-    /** Strategy used to lookup the user.displayName. */
-    @NonnullAfterInit private Function<ProfileRequestContext,String> displayNameLookupStrategy;
+    /** Strategy used to lookup or create the user.name. */
+    @NonnullAfterInit private Function<ProfileRequestContext,String> userNameLookupStrategy;
     
-    /** The stashed username.*/
+    /** The stashed internal username.*/
     @NonnullBeforeExec private String username;
     
-    /** Constructor.*/
-    protected AddDisplayName() {
-        super(new ChildContextLookup<>(WebAuthnRegistrationContext.class));
+    /** The credential repository to use.*/
+    @NonnullAfterInit private WebAuthnCredentialRepository repository;
+    
+    /** Constructor. */
+    public AddUserName() {
+        super(new ChildContextLookup<>(WebAuthnRegistrationContext.class));        
     }
-        
+    
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        repository = getCredentialRepository();
+        if (repository == null) {
+            throw new ComponentInitializationException("Credential repository can not be null");
+        }
+        if (userNameLookupStrategy == null) {
+            throw new ComponentInitializationException("User.name lookup strategy can not be null");
+        }
+    }
+    
     /**
-     * Set the strategy used to generate the user.displayName.
+     * Set the strategy used to lookup or create the user.name.
      * 
      * @param strategy the strategy
      */
-    public void setDisplayNameLookupStrategy(
+    public void setUserNameLookupStrategy(
             @Nonnull final Function<ProfileRequestContext,String> strategy) {
         checkSetterPreconditions();
-        displayNameLookupStrategy =
+        userNameLookupStrategy =
                 Constraint.isNotNull(strategy, "Challenge Generator cannot be null");
     }
     
-    /** {@inheritDoc} */
-    @Override
-    protected void doInitialize() throws ComponentInitializationException {
-        super.doInitialize();
-        
-        if (displayNameLookupStrategy == null) {
-            throw new ComponentInitializationException("DisplayName generation strategy can not be null");
-        }
-    }
-    
     /** {@inheritDoc} */
     @Override
     protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
@@ -100,19 +111,17 @@ public class AddDisplayName extends AbstractWebAuthnAction<WebAuthnRegistrationC
     /** {@inheritDoc} */
     @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final WebAuthnRegistrationContext context) {
-             
-        final String displayName = displayNameLookupStrategy.apply(profileRequestContext);
-        if (displayName == null) {
-            log.trace("{} DisplayName was null for user '{}'", getLogPrefix(), username);
+        
+        final String webAuthnUserName = userNameLookupStrategy.apply(profileRequestContext);
+        if (webAuthnUserName == null) {
+            log.trace("{} User.name was null for user '{}'", getLogPrefix(), username);
             ActionSupport.buildEvent(profileRequestContext, WebAuthnRegistrationEventIds.INVALID_REGISTRATION);
             return;
         }
-        if (displayName.getBytes(StandardCharsets.UTF_8).length > 64) {
-            log.trace("{} DisplayName exceeds 64 bytes and might get truncated by the authenticator", getLogPrefix());
-        }
-        log.trace("{} Populating DisplayName '{}'",getLogPrefix(),displayName);
-        context.setDisplayName(displayName); 
+        log.trace("{} Populating User.name '{}' for user '{}'",getLogPrefix(),webAuthnUserName, username);
+        context.setWebAuthnUsername(webAuthnUserName);
              
-    }        
+    }   
+
     
 }
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/CreatePublicKeyCredentialCreationOptions.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/CreatePublicKeyCredentialCreationOptions.java
index 805c60e..2152326 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/CreatePublicKeyCredentialCreationOptions.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/CreatePublicKeyCredentialCreationOptions.java
@@ -83,7 +83,7 @@ public class CreatePublicKeyCredentialCreationOptions extends AbstractWebAuthnAc
             ActionSupport.buildEvent(profileRequestContext, WebAuthnRegistrationEventIds.INVALID_REGISTRATION_CTX);
             return;
         }
-        final String username = context.getUsername();
+        final String username = context.getWebAuthnUsername();
         if (username == null) {
             log.error("{} user.name is null",getLogPrefix());
             ActionSupport.buildEvent(profileRequestContext, WebAuthnRegistrationEventIds.INVALID_REGISTRATION_CTX);
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/DeletePublicKeyCredential.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/DeletePublicKeyCredential.java
index 601dd03..b3065fe 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/DeletePublicKeyCredential.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/DeletePublicKeyCredential.java
@@ -73,7 +73,7 @@ public class DeletePublicKeyCredential extends AbstractWebAuthnAuditingAction<We
             @Nonnull final WebAuthnRegistrationContext context) {
 
         // This should come from the context before the registration page i.e. it should not come from a form the user
-        // can manipulate.
+        // can manipulate (it should be the authenticated user).
         final String username = context.getUsername();
         if (username == null) {
             log.error("{} Unable to find username in registration context", getLogPrefix());
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 aae9ed7..6b94af8 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
@@ -44,10 +44,10 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 /**
  * An action that adds the public key credential in the registration context to the credential repository.
  * 
- * <p>Importantly, the registration is stored against the user in the context (the authenticated user). This way, even 
- * if the user changed the webauthn create request in the browser (e.g. to a different userId), it will still be 
- * registered against the authenticated user. This prevents a different user from registering a credential against
- * somebody else's account.</p>
+ * <p>Importantly, the registration is stored against the username in the context (the authenticated user), not the 
+ * WebAuthn user.name. This way, even if the user changed the webauthn create request in the browser 
+ * (e.g. to a different userId), it will still be registered against the authenticated user. This prevents a 
+ * user from registering a credential against somebody else's account.</p>
  * 
  * @event {WebAuthnRegistrationEventIds#INVALID_REGISTRATION}
  * @pre <pre>ProfileRequestContext.getSubcontext(WebAuthnRegistrationContext.class) != null</pre>
@@ -81,7 +81,8 @@ public class StorePublicKeyCredential extends AbstractWebAuthnAuditingAction<Web
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final WebAuthnRegistrationContext context) {
-
+        
+        // Importantly this is the internal IdP username
         final String username = context.getUsername();
         if (username == null) {
             log.error("Unable to find username in registration context");
@@ -89,6 +90,13 @@ public class StorePublicKeyCredential extends AbstractWebAuthnAuditingAction<Web
             return;
         } 
         
+        final String webAuthnUsername = context.getWebAuthnUsername();
+        if (webAuthnUsername == null) {
+            log.error("Unable to find user.name in registration context");
+            ActionSupport.buildEvent(profileRequestContext, WebAuthnRegistrationEventIds.INVALID_REGISTRATION);
+            return;
+        } 
+        
         final String displayName = context.getDisplayName();
         if (displayName == null) {
             log.error("Unable to find displayName in registration context");
@@ -113,7 +121,7 @@ public class StorePublicKeyCredential extends AbstractWebAuthnAuditingAction<Web
                     .build();
             
             final UserIdentity user = UserIdentity.builder()
-                    .name(username)
+                    .name(webAuthnUsername)
                     .displayName(displayName)
                     .id(new ByteArray(context.getUserId()))
                     .build();
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 e73c836..3a8c3aa 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
@@ -101,8 +101,8 @@ public class ValidateAuthenticatorAttestationResponse extends AbstractWebAuthnAc
                 getWebAuthnClient().validateAuthenticatorAttestationResponse(pkCredCreationOptions, attestation);
             
             // 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.
+            // untrusted attestations are allowed and the metadata has been loaded and the attestation statement has 
+            // been validated.
             final ByteArray aaguid = credentialPublicKey.getAaguid();
             final String athenticator = aaguid != null ? aaguid.getHex() : "unknown";
             log.debug("{} Was attestation for authenticator '{}' trusted? {}", getLogPrefix(), 
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/audit/impl/WebAuthnUsernameAuditExtractor.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/audit/impl/WebAuthnUsernameAuditExtractor.java
index 4abdece..c8d6747 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/audit/impl/WebAuthnUsernameAuditExtractor.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/audit/impl/WebAuthnUsernameAuditExtractor.java
@@ -24,7 +24,8 @@ import net.shibboleth.idp.plugin.authn.webauthn.audit.AbstractWebAuthnAuditExtra
 import net.shibboleth.idp.plugin.authn.webauthn.context.BaseWebAuthnContext;
 
 /**
- * {@link Function} that returns the username from the {@link BaseWebAuthnContext}, if any.
+ * {@link Function} that returns the internal username from the {@link BaseWebAuthnContext}, if any. Noting this is
+ * not necessarily the user.name sent to the authenticator.
  */
 public class WebAuthnUsernameAuditExtractor extends AbstractWebAuthnAuditExtractor<String> {    
 
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/PopulateWebAuthnAuthenticationContext.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/PopulateWebAuthnAuthenticationContext.java
index 11952ce..6edfc5f 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/PopulateWebAuthnAuthenticationContext.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/PopulateWebAuthnAuthenticationContext.java
@@ -38,7 +38,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 /**
  * An action to create (or lookup) the {@link WebAuthnAuthenticationContext} and populate 
  * with the username found from the username lookup strategy. The username can be <code>null</code> if 
- * <code>usernameRequiredPredicate</code> is false.
+ * <code>usernameRequiredPredicate</code> is false, otherwise it must be present.
  * 
  * @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
  * @event {@link org.opensaml.profile.action.EventIds#INVALID_PROFILE_CTX}
diff --git a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/webauthn-registration/webauthn-registration-beans.xml b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/webauthn-registration/webauthn-registration-beans.xml
index 7904d4a..d87d209 100644
--- a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/webauthn-registration/webauthn-registration-beans.xml
+++ b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/webauthn-registration/webauthn-registration-beans.xml
@@ -78,7 +78,7 @@
         class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.PopulateWebAuthnRegistrationContext"
         p:usernameRequired="true"
         p:removeExistingRegistrationContext="true"
-        p:usernameLookupStrategy="#{getObject('%{idp.authn.webauthn.registration.username.strategy:shibboleth.authn.webauthn.SubjectContextUsernameLookupStrategy}')}">
+        p:usernameLookupStrategy="#{getObject('%{idp.authn.webauthn.registration.principalname.strategy:shibboleth.authn.webauthn.SubjectContextUsernameLookupStrategy}')}">
     </bean>        
     
     <bean id="shibboleth.authn.webauthn.SubjectContextUsernameLookupStrategy" lazy-init="true" scope="singleton"
@@ -118,6 +118,10 @@
         class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.AddUserId"
         p:userIdGeneratorStrategy="#{getObject('%{idp.authn.webauthn.registration.userid.strategy:shibboleth.authn.webauthn.RandomUserIdGenerator}')}"/>
     
+    <bean id="AddUserName" parent="AbstractWebAuthnRegistrationAction" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.AddUserName"
+         p:userNameLookupStrategy="#{getObject('%{idp.authn.webauthn.registration.username.strategy:shibboleth.authn.webauthn.SubjectContextUsernameLookupStrategy}')}"/>
+    
     <bean id="AddDisplayName" parent="AbstractWebAuthnRegistrationAction" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.AddDisplayName"
         p:displayNameLookupStrategy="#{getObject('%{idp.authn.webauthn.registration.displayname.strategy:shibboleth.authn.webauthn.SubjectContextDisplayNameLookupStrategy}')}"/>
diff --git a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/webauthn-registration/webauthn-registration-flow.xml b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/webauthn-registration/webauthn-registration-flow.xml
index 3e7e9ac..6fc4904 100644
--- a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/webauthn-registration/webauthn-registration-flow.xml
+++ b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/webauthn-registration/webauthn-registration-flow.xml
@@ -92,11 +92,12 @@
         <evaluate expression="PopulateWebAuthnRegistrationContext"/>
         <evaluate expression="LookupRegisteredCredentials"/>      
         <evaluate expression="GenerateServerChallenge"/>
+        <evaluate expression="AddUserName"/>
         <evaluate expression="AddUserId"/>
         <evaluate expression="AddDisplayName"/>
         <evaluate expression="AddResidentKeyRequirement"/>
         <evaluate expression="AddAuthenticatorAttachmentRequirement"/>
-         <evaluate expression="AddAttestationConveyancePreference"/>
+        <evaluate expression="AddAttestationConveyancePreference"/>
         <evaluate expression="AddUserVerificationRequired"/>
         <evaluate expression="CreatePublicKeyCredentialCreationOptions"/>
         <evaluate expression="'proceed'" />
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/authn/webauthn.properties b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/authn/webauthn.properties
index 58dd648..126929b 100644
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/authn/webauthn.properties
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/authn/webauthn.properties
@@ -144,7 +144,7 @@ idp.authn.webauthn.supportedPrincipals = \
 #idp.authn.webauthn.signalEventOnNoCredentialsRegisteredForUserHandle = false
 #idp.authn.webauthn.userHandleNoRegisteredCredentialsEventId = NoCredentialsRegisteredForUserHandle
 
-# Basic transformations that should be applied to the username that is collected as part of the usernameless flow
+# Basic transformations that should be applied to the username that is collected as part of the passwordless flow
 #idp.authn.webauthn.passwordless.username.uppercase = false
 #idp.authn.webauthn.passwordless.username.lowercase = false
 #idp.authn.webauthn.passwordless.username.trim = false

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


More information about the commits mailing list