[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