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

Phil Smart philip.smart at jisc.ac.uk
Mon Sep 9 15:47:38 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=52cb429b883a998b8bf4a45a1575bf34b6e3caf3

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

commit 52cb429b883a998b8bf4a45a1575bf34b6e3caf3
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Mon Sep 9 16:47:35 2024 +0100

    JWEBAUTHN-22 - Support for different usernames in key registration
    
     - Added c14n to the username input either in the registration or
    passwordless flows
    
    https://shibboleth.atlassian.net/browse/JWEBAUTHN-22
---
 .../InitializeSubjectCanonicalizationContext.java  | 90 +++++++++++++++++++++
 .../UpdateWebAuthnContextWithC14nPrincipal.java    | 92 ++++++++++++++++++++++
 .../webauthn-registration-beans.xml                | 25 ++++++
 .../webauthn-registration-flow.xml                 | 27 ++++++-
 .../idp/flows/authn/WebAuthn/webauthn-beans.xml    | 12 +++
 .../idp/flows/authn/WebAuthn/webauthn-flow.xml     | 31 ++++++--
 .../authn/webauthn/conf/authn/webauthn.properties  |  6 ++
 7 files changed, 273 insertions(+), 10 deletions(-)

diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/InitializeSubjectCanonicalizationContext.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/InitializeSubjectCanonicalizationContext.java
new file mode 100644
index 0000000..6890f2d
--- /dev/null
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/InitializeSubjectCanonicalizationContext.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.webauthn.admin.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.security.auth.Subject;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
+import net.shibboleth.idp.authn.principal.UsernamePrincipal;
+import net.shibboleth.idp.plugin.authn.webauthn.context.BaseWebAuthnContext;
+import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnAction;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * An action that creates a new {@link SubjectCanonicalizationContext} out of the username in the base context,
+ * ready for the c14n flows to canonicalize.
+ * 
+ * @event {@link AuthnEventIds.UNKNOWN_USERNAME}
+ * @pre <pre>ProfileRequestContext.getSubcontext(WebAuthnRegistrationContext.class) != null</pre>
+ * @post a subject canonicalization context is created under the registration context ready for the c14n flows
+ */
+public class InitializeSubjectCanonicalizationContext extends AbstractWebAuthnAction<BaseWebAuthnContext> {
+    
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(InitializeSubjectCanonicalizationContext.class);
+    
+    /**
+     * Strategy used to find or create the {@link SubjectCanonicalizationContext} from the
+     * {@link ProfileRequestContext}.
+     */
+    @Nonnull private Function<ProfileRequestContext,SubjectCanonicalizationContext> scCtxLookupStrategy;
+
+    /**
+     * Constructor.
+     */
+    protected InitializeSubjectCanonicalizationContext() {
+        super(new ChildContextLookup<>(BaseWebAuthnContext.class));
+        scCtxLookupStrategy = new ChildContextLookup<>(SubjectCanonicalizationContext.class, true);
+    }
+    
+    /**
+     * Set the context lookup/creation strategy.
+     * 
+     * @param strategy  lookup/creation strategy function for {@link SubjectCanonicalizationContext}.
+     */
+    public void setLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,SubjectCanonicalizationContext> strategy) {
+        checkSetterPreconditions();
+        scCtxLookupStrategy = Constraint.isNotNull(strategy, "Strategy cannot be null");
+    }
+    
+    /** {@inheritDoc} */
+    @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+            @Nonnull final BaseWebAuthnContext context) {
+        
+        final String username = context.getUsername();
+        if (username == null) {
+            log.warn("{} Unable to find username in base WebAuthn context", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.UNKNOWN_USERNAME);
+            return;
+        }
+        final SubjectCanonicalizationContext c14n = scCtxLookupStrategy.apply(profileRequestContext);
+        final Subject subject = new Subject();
+        subject.getPrincipals().add(new UsernamePrincipal(username));
+        c14n.setSubject(subject);
+        
+    }
+
+}
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/UpdateWebAuthnContextWithC14nPrincipal.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/UpdateWebAuthnContextWithC14nPrincipal.java
new file mode 100644
index 0000000..fea4b40
--- /dev/null
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/UpdateWebAuthnContextWithC14nPrincipal.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.webauthn.admin.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
+import net.shibboleth.idp.plugin.authn.webauthn.context.BaseWebAuthnContext;
+import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnAction;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * A WebAuthn action that sets the principal name from the SubjectCanonicalizationContext back onto the WebAuthn
+ * context. It then removes the SubjectCanonicalizationContext from the parent, this can help avoid 
+ * conflicting/confusing situations where a new c14n context will be created by subsequent authentication steps.
+ * 
+ * @pre <pre>ProfileRequestContext.getSubcontext(BaseWebAuthnContext.class) != null</pre>
+ * @post <pre>ProfileRequestContext.getSubcontext(BaseWebAuthnContext.class).getUsername() != null</pre>
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ */
+public class UpdateWebAuthnContextWithC14nPrincipal extends AbstractWebAuthnAction<BaseWebAuthnContext> {
+    
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(UpdateWebAuthnContextWithC14nPrincipal.class);
+    
+    /**
+     * Strategy used to find the {@link SubjectCanonicalizationContext} from the
+     * {@link ProfileRequestContext}.
+     */
+    @Nonnull private Function<ProfileRequestContext,SubjectCanonicalizationContext> scCtxLookupStrategy;
+
+    /**
+     * Constructor.
+     */
+    protected UpdateWebAuthnContextWithC14nPrincipal() {
+        super(new ChildContextLookup<>(BaseWebAuthnContext.class));
+        scCtxLookupStrategy = new ChildContextLookup<>(SubjectCanonicalizationContext.class, false);
+    }
+    
+    /**
+     * Set the context lookup strategy.
+     * 
+     * @param strategy  lookup strategy function for {@link SubjectCanonicalizationContext}.
+     */
+    public void setLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,SubjectCanonicalizationContext> strategy) {
+        checkSetterPreconditions();
+        scCtxLookupStrategy = Constraint.isNotNull(strategy, "Strategy cannot be null");
+    }
+    
+    /** {@inheritDoc} */
+    @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+            @Nonnull final BaseWebAuthnContext context) {
+        
+        final SubjectCanonicalizationContext c14n = scCtxLookupStrategy.apply(profileRequestContext);
+        if (c14n == null) {
+            log.warn("{} Unable to find subject canonicalization context", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.UNKNOWN_USERNAME);
+            return;
+        }
+        // Update the username in the WebAuthn context to the c14n version
+        context.setUsername(c14n.getPrincipalName());
+        // Now remove the c14n context to avoid confusion with later authentication
+        c14n.removeFromParent();
+        log.debug("{} Updated WebAuthn context with username '{}' from the subject canonicalization context", 
+                getLogPrefix(), c14n.getPrincipalName());
+        
+    }
+
+}
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 17f200c..fb62679 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
@@ -18,6 +18,15 @@
         class="org.opensaml.messaging.context.navigate.ChildContextLookup"
         c:type="#{ T(net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext) }" />
         
+    <bean id="shibboleth.ChildLookup.WebAuthnRegistrationC14nContext" parent="shibboleth.Functions.Compose">
+        <constructor-arg name="g">
+            <bean class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+            c:type="#{ T(net.shibboleth.idp.authn.context.SubjectCanonicalizationContext) }" />
+        </constructor-arg>
+        <constructor-arg name="f" ref="shibboleth.ChildLookup.WebAuthnRegistrationContext"/>
+    </bean>
+    
+        
     <!-- Abstract parent beans -->    
           
     <bean id="AbstractWebAuthnRegistrationAction" scope="prototype" abstract="true"
@@ -28,6 +37,8 @@
     
     <!-- Flow beans -->
     
+    
+    <!-- Initial Username input collection -->
     <bean id="PopulateInitialWebAuthnRegistrationContext" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.PopulateWebAuthnRegistrationContext"
         p:usernameRequired="false">
@@ -45,6 +56,20 @@
         p:trim="%{idp.authn.webauthn.registration.username.trim:false}"
         p:transforms="#{getObject('shibboleth.authn.webauthn.registration.UsernameTransformations')}"/>
     
+    <bean id="InitializeSubjectCanonicalizationContext" parent="AbstractWebAuthnBaseAction"
+        class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.InitializeSubjectCanonicalizationContext" scope="prototype"
+         p:webAuthnContextLookupStrategy-ref="shibboleth.ChildLookup.WebAuthnRegistrationContext"/>
+    
+    <bean id="PopulateSubjectCanonicalizationContext" 
+        class="net.shibboleth.idp.authn.impl.PopulateSubjectCanonicalizationContext" scope="prototype"
+        p:availableFlows-ref="%{idp.authn.webauthn.registration.c14n.postUsernameFlows:shibboleth.PostLoginSubjectCanonicalizationFlows}" />   
+    
+    <bean id="UpdateRegistrationContextUsernameWithC14nPrincipal" parent="AbstractWebAuthnBaseAction" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.UpdateWebAuthnContextWithC14nPrincipal"
+        p:webAuthnContextLookupStrategy-ref="shibboleth.ChildLookup.WebAuthnRegistrationContext"/>
+    
+    <!-- Start of registration flow post authentication -->
+    
     <!-- 
         Important that this gets the username from the subject context, not the initial context that is created 
         Also, removes any initial registration contexts to avoid contamination.
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 7ad2a32..25e1f80 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
@@ -19,7 +19,8 @@
         <transition on="proceed" to="DecideIfUsernameCollectionIsRequired"/>
     </subflow-state>
     
-    <!-- Has username collection been configured -->
+    <!-- Has username collection been configured. Username collection is not a requirement of the flow, it adds
+    WebAuthn credentials to an inital context which can inform the MFA flow -->
     <decision-state id="DecideIfUsernameCollectionIsRequired">
         <if test="IsAdminUsernameCollectionEnabled.test(opensamlProfileRequestContext)"
             then="CollectUsernameView" 
@@ -50,12 +51,32 @@
     <action-state id="ExtractUsernameAndPopulateContext">
         <evaluate expression="PopulateInitialWebAuthnRegistrationContext"/>
         <evaluate expression="ExtractUsernameFromForm"/>
-        <evaluate expression="LookupRegisteredCredentials"/>
+        <evaluate expression="InitializeSubjectCanonicalizationContext"/>
+        <evaluate expression="PopulateSubjectCanonicalizationContext" />
         <evaluate expression="'proceed'" />
         
         <!-- Branch to determine if authentication is required. -->
-        <transition on="proceed" to="DoAdminPreamble" />
+        <transition on="proceed" to="CallSubjectCanonicalization" />
     </action-state>
+    
+    <!-- Call the c14n subflow here so we can c14n the username input by the user to lookup the correct credentials
+    and align with the authentication result -->
+    <subflow-state id="CallSubjectCanonicalization" subflow="c14n">
+        <input name="calledAsSubflow" value="true" />
+        <transition on="proceed" to="LookupRegisteredCredentials" />
+
+        <transition on="SubjectCanonicalizationError" to="ReselectFlow" />
+    </subflow-state>
+    
+    <!-- After we canonicalize the username input, use that to lookup registered credentials -->
+    <action-state id="LookupRegisteredCredentials">
+        <evaluate expression="UpdateRegistrationContextUsernameWithC14nPrincipal"/>
+        <evaluate expression="LookupRegisteredCredentials"/>        
+        <evaluate expression="'proceed'" />
+        
+        <!-- Branch to determine if authentication is required. -->
+        <transition on="proceed" to="DoAdminPreamble" />
+     </action-state>
 
     <!-- Resume actual flow processing. -->
 
diff --git a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-beans.xml b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-beans.xml
index a6b046a..0ef4752 100644
--- a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-beans.xml
+++ b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-beans.xml
@@ -86,6 +86,18 @@
         p:lowercase="%{idp.authn.webauthn.passwordless.username.lowercase:false}"
         p:trim="%{idp.authn.webauthn.passwordless.username.trim:false}"
         p:transforms="#{getObject('shibboleth.authn.webauthn.passwordless.UsernameTransformations')}"/>
+        
+    <bean id="InitializeSubjectCanonicalizationContext" parent="AbstractWebAuthnBaseAction"
+        class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.InitializeSubjectCanonicalizationContext" scope="prototype"
+        p:webAuthnContextLookupStrategy-ref="shibboleth.ChildLookup.WebAuthnAuthenticationContextFromAuthenticationContext"/>
+        
+    <bean id="PopulateSubjectCanonicalizationContext" 
+        class="net.shibboleth.idp.authn.impl.PopulateSubjectCanonicalizationContext" scope="prototype"
+        p:availableFlows-ref="%{idp.authn.webauthn.passwordless.c14n.postUsernameFlows:shibboleth.PostLoginSubjectCanonicalizationFlows}" />
+        
+    <bean id="UpdateUsernameInContextWithC14nPrincipal" parent="AbstractWebAuthnBaseAction" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.UpdateWebAuthnContextWithC14nPrincipal"
+        p:webAuthnContextLookupStrategy-ref="shibboleth.ChildLookup.WebAuthnAuthenticationContextFromAuthenticationContext"/>
     
     <bean id="EnsureAllowedCredentialsIsEmpty" parent="AbstractWebAuthnAuthenticationAction" scope="prototype"
     class="net.shibboleth.idp.plugin.authn.webauthn.impl.EnsureAllowedCredentialsIsEmpty"/>
diff --git a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-flow.xml b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-flow.xml
index c9cbbce..bf832ed 100644
--- a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-flow.xml
+++ b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-flow.xml
@@ -17,7 +17,7 @@
     </decision-state>
     
     <!-- 
-        Passwordless login. If Passwordless: do not require ResidentKey, require UV, UP, and provide previous credentials based on username.
+        Passwordless login: If Passwordless: do not require ResidentKey, require UV, UP, and provide previous credentials based on username.
      -->
      <action-state id="PasswordlessLogin">
         <evaluate expression="PopulateWebAuthnAuthenticationContextPasswordless"/>
@@ -55,19 +55,36 @@
     
     <action-state id="PasswordlessLoginExtractUsername">
         <evaluate expression="ExtractUsernameFromForm"/>
+        <evaluate expression="InitializeSubjectCanonicalizationContext"/>
+        <evaluate expression="PopulateSubjectCanonicalizationContext" />
         <evaluate expression="'proceed'" />
-        <transition on="proceed" to="PasswordlessLoginProceed" />    
-    </action-state>    
+        <transition on="proceed" to="CallSubjectCanonicalization" />    
+    </action-state> 
     
-    <action-state id="PasswordlessLoginProceed">
+    <!-- Call the c14n subflow here so we can c14n the username input by the user to lookup the correct credentials -->
+    <subflow-state id="CallSubjectCanonicalization" subflow="c14n">
+        <input name="calledAsSubflow" value="true" />
+        <transition on="proceed" to="UpdateUsernameFromC14nContext" />
+
+        <transition on="SubjectCanonicalizationError" to="ReselectFlow" />
+    </subflow-state>
+    
+    <action-state id="UpdateUsernameFromC14nContext">
+        <evaluate expression="UpdateUsernameInContextWithC14nPrincipal"/>
+        
+        <evaluate expression="'proceed'" />
+        <transition on="proceed" to="PasswordlessLoginProceed" />       
+    </action-state>
+    
+    <action-state id="PasswordlessLoginProceed">        
         <evaluate expression="LookupRegisteredCredentials"/>
         <evaluate expression="AddUserVerificationRequired"/>
         <evaluate expression="'proceed'" />
         <transition on="proceed" to="GenerateAuthenticationCeremonyOptions" />    
-    </action-state>  
+    </action-state>
     
     <!-- 
-        Usernameless login. If Usernameless: require ResidentKey, UV, UP, and provide no previous credentials.
+        Usernameless login: If Usernameless: require ResidentKey, UV, UP, and provide no previous credentials.
      -->   
     <action-state id="UsernamelessLogin">
         <evaluate expression="PopulateWebAuthnAuthenticationContextUsernameless"/>
@@ -78,7 +95,7 @@
     </action-state>
     
     <!-- 
-        Second Factor login. If we are running after a first factor, perform 2FA only. Needs existing username.
+        Second Factor login: If we are running after a first factor, perform 2FA only. Needs existing username.
      -->
     <action-state id="SecondFactorLogin">
         <evaluate expression="PopulateWebAuthnAuthenticationContextFor2FA"/>
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 d932664..58dd648 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
@@ -88,6 +88,9 @@ idp.authn.webauthn.supportedPrincipals = \
 #idp.authn.webauthn.registration.username.lowercase = false
 #idp.authn.webauthn.registration.username.trim = false
 
+# The ID of the bean that supplies the c14n flows that are applied to the username entered during the registration flow
+#idp.authn.webauthn.registration.c14n.postUsernameFlows = shibboleth.PostLoginSubjectCanonicalizationFlows
+
 #idp.authn.webauthn.registration.genericMessageID = 
 #idp.authn.webauthn.registration.infoMessageFunction = DefaultRegistrationInfoMessageFunction
 #idp.authn.webauthn.registration.errorMessageFunction = DefaultRegistrationErrorMessageFunction
@@ -146,6 +149,9 @@ idp.authn.webauthn.supportedPrincipals = \
 #idp.authn.webauthn.passwordless.username.lowercase = false
 #idp.authn.webauthn.passwordless.username.trim = false
 
+# The ID of the bean that supplies the c14n flows that are applied to the username entered during the passwordless flow
+#idp.authn.webauthn.passwordless.c14n.postUsernameFlows = shibboleth.PostLoginSubjectCanonicalizationFlows
+
 # Audit
 #idp.authn.webauthn.audit.enabled = false
 

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


More information about the commits mailing list