From 98fafa2a08d30279054e629956bc6837e3922aff Mon Sep 17 00:00:00 2001 From: rmartinc Date: Thu, 23 Apr 2026 12:10:48 +0200 Subject: [PATCH 1/3] Make acceptable AAGUID ckeck in WebAuthn stricter Closes #48388 Signed-off-by: rmartinc --- .../topics/authentication/webauthn.adoc | 2 +- .../topics/changes/changes-26_6_2.adoc | 12 +++++ .../admin/messages/messages_en.properties | 2 +- .../requiredactions/WebAuthnRegister.java | 31 ++++++----- .../WebAuthnRegisterAndLoginTest.java | 24 +++------ .../webauthn/AbstractWebAuthnVirtualTest.java | 1 + .../WebAuthnOtherSettingsTest.java | 53 +++++++++++++++++-- 7 files changed, 86 insertions(+), 39 deletions(-) create mode 100644 docs/documentation/upgrading/topics/changes/changes-26_6_2.adoc diff --git a/docs/documentation/server_admin/topics/authentication/webauthn.adoc b/docs/documentation/server_admin/topics/authentication/webauthn.adoc index d14a38fe6785..3bb2c93d5415 100644 --- a/docs/documentation/server_admin/topics/authentication/webauthn.adoc +++ b/docs/documentation/server_admin/topics/authentication/webauthn.adoc @@ -122,7 +122,7 @@ The configurable items and their description are as follows: |If enabled, {project_name} cannot re-register an already registered WebAuthn authenticator. |Acceptable AAGUIDs -|The white list of AAGUIDs which a WebAuthn authenticator must register against. +|The list of allowed AAGUIDs which a WebAuthn authenticator must register against. An AAGUID (Authenticator Attestation Global Unique Identifier) is a 128-bit identifier indicating the authenticator's type (e.g., make and model). This option needs the **Attestation conveyance preference** to be configured (normally `Direct`) to ensure a trusted AAGUID is passed. Default attestation `None` is not reliable, and can anonymize the AAGUID to zero value. If you setup **Acceptable AAGUIDs** only those authenticators are valid to register new WebAuthn credentials. |=== diff --git a/docs/documentation/upgrading/topics/changes/changes-26_6_2.adoc b/docs/documentation/upgrading/topics/changes/changes-26_6_2.adoc new file mode 100644 index 000000000000..e7522d0f579f --- /dev/null +++ b/docs/documentation/upgrading/topics/changes/changes-26_6_2.adoc @@ -0,0 +1,12 @@ +== Notable changes + +Notable changes may include internal behavior changes that prevent common misconfigurations, bugs that are fixed, or changes to simplify running {project_name}. +It also lists significant changes to internal APIs. + +=== WebAuthn acceptable AAGUIDs option restricts authenticators strictly + +The WebAuthn policy presents the option **Acceptable AAGUIDs** to restrict the authenticators that are allowed to register new credentials. The AAGUID (Authenticator Attestation Global Unique Identifier) is an identifier for the authenticator's type (e.g., make and model). This option requires the **Attestation conveyance preference** to be configured too (normally `Direct`), in order to force the authenticator to include the attestation inside the registration data. + +Since this release, when this option is setup, the attestation is required to be present and signed with a valid certificate for the {project_name} trust-store. The `None` attestation format is explicitly not permitted. Previously, there were some corner cases in which a self attestation was accepted. The change is expected to be harmless, but maybe there are combinations of authenticators and WebAuthn policies that can present issues. + +See chapter link:{adminguide_link}#_webauthn-policy[Managing policy] in the {adminguide_name} for more information. \ No newline at end of file diff --git a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties index 45f487cea203..7deb15cb3f07 100644 --- a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties +++ b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties @@ -1339,7 +1339,7 @@ revoke=Revoke admin=Admin syncUsersError=Could not sync users\: '{{error}}' generatedAccessTokenHelp=See the example access token, which will be generated and sent to the client when the selected user is authenticated. You can see claims and roles that the token will contain based on the effective protocol mappers and role scope mappings and also based on the claims and roles assigned to the actual user. -webAuthnPolicyAcceptableAaguidsHelp=The list of allowed AAGUIDs of which an authenticator can be registered. An AAGUID is a 128-bit identifier indicating the authenticator's type (e.g., make and model). +webAuthnPolicyAcceptableAaguidsHelp=The list of allowed AAGUIDs of which an authenticator can be registered. An AAGUID is a 128-bit identifier indicating the authenticator's type (e.g., make and model). This option needs the Attestation conveyance preference to be configured (normally `Direct`) to ensure a trusted AAGUID is passed. Default attestation `None` is not reliable, and can anonymize the AAGUID to zero value. keyPasswordHelp=Password for the private key frontchannelLogout=Front channel logout logoutConfirmation=Logout confirmation diff --git a/services/src/main/java/org/keycloak/authentication/requiredactions/WebAuthnRegister.java b/services/src/main/java/org/keycloak/authentication/requiredactions/WebAuthnRegister.java index 5bbe0f70dd92..ed79ba039e4a 100644 --- a/services/src/main/java/org/keycloak/authentication/requiredactions/WebAuthnRegister.java +++ b/services/src/main/java/org/keycloak/authentication/requiredactions/WebAuthnRegister.java @@ -67,6 +67,7 @@ import com.webauthn4j.data.attestation.authenticator.AttestedCredentialData; import com.webauthn4j.data.attestation.statement.AttestationStatement; import com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier; +import com.webauthn4j.data.attestation.statement.NoneAttestationStatement; import com.webauthn4j.data.client.Origin; import com.webauthn4j.data.client.challenge.Challenge; import com.webauthn4j.data.client.challenge.DefaultChallenge; @@ -268,7 +269,7 @@ public void processAction(RequiredActionContext context) { AuthenticatorUtil.logoutOtherSessions(context); } - WebAuthnRegistrationManager webAuthnRegistrationManager = createWebAuthnRegistrationManager(policy.getAttestationConveyancePreference()); + WebAuthnRegistrationManager webAuthnRegistrationManager = createWebAuthnRegistrationManager(policy); try { // parse RegistrationData registrationData = webAuthnRegistrationManager.parse(registrationRequest); @@ -318,11 +319,12 @@ public void processAction(RequiredActionContext context) { * Create WebAuthnRegistrationManager instance * Can be overridden in subclasses to customize the used attestation validators * - * @param attestationPreference The attestation selected in the policy + * @param policy The webauthn policy defined * @return webauthn4j WebAuthnRegistrationManager instance */ - protected WebAuthnRegistrationManager createWebAuthnRegistrationManager(String attestationPreference) { + protected WebAuthnRegistrationManager createWebAuthnRegistrationManager(WebAuthnPolicy policy) { List verifiers = new ArrayList<>(6); + final String attestationPreference = policy.getAttestationConveyancePreference(); if (attestationPreference == null || Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED.equals(attestationPreference) || AttestationConveyancePreference.NONE.getValue().equals(attestationPreference)) { @@ -334,10 +336,15 @@ protected WebAuthnRegistrationManager createWebAuthnRegistrationManager(String a verifiers.add(new AndroidSafetyNetAttestationStatementVerifier()); verifiers.add(new FIDOU2FAttestationStatementVerifier()); + DefaultSelfAttestationTrustworthinessVerifier selfAttestationVerifier = new DefaultSelfAttestationTrustworthinessVerifier(); + final List acceptableAaguids = policy.getAcceptableAaguids(); + // self attestation should be disabled to be sure the AAGUID can be trusted + selfAttestationVerifier.setSelfAttestationAllowed(acceptableAaguids == null || acceptableAaguids.isEmpty()); + return new WebAuthnRegistrationManager( verifiers, this.certPathtrustVerifier, - new DefaultSelfAttestationTrustworthinessVerifier(), + selfAttestationVerifier, Collections.emptyList(), // Custom Registration Verifier is not supported new ObjectConverter() ); @@ -406,20 +413,12 @@ private void showInfoAfterWebAuthnApiCreate(RegistrationData response) { private void checkAcceptedAuthenticator(RegistrationData response, WebAuthnPolicy policy) throws Exception { String aaguid = response.getAttestationObject().getAuthenticatorData().getAttestedCredentialData().getAaguid().toString(); List acceptableAaguids = policy.getAcceptableAaguids(); - boolean isAcceptedAuthenticator = false; if (acceptableAaguids != null && !acceptableAaguids.isEmpty()) { - for(String acceptableAaguid : acceptableAaguids) { - if (aaguid.equals(acceptableAaguid)) { - isAcceptedAuthenticator = true; - break; - } + if (NoneAttestationStatement.FORMAT.equals(response.getAttestationObject().getFormat())) { + throw new WebAuthnException("Acceptable AAGUIDs require an attestation format other than 'none'."); + } else if (acceptableAaguids.stream().noneMatch(acceptableAaguid -> aaguid.equals(acceptableAaguid))) { + throw new WebAuthnException("not acceptable aaguid = " + aaguid); } - } else { - // no accepted authenticators means accepting any kind of authenticator - isAcceptedAuthenticator = true; - } - if (!isAcceptedAuthenticator) { - throw new WebAuthnException("not acceptable aaguid = " + aaguid); } } diff --git a/tests/webauthn/src/test/java/org/keycloak/tests/webauthn/WebAuthnRegisterAndLoginTest.java b/tests/webauthn/src/test/java/org/keycloak/tests/webauthn/WebAuthnRegisterAndLoginTest.java index 549764681010..23b6097a2edf 100644 --- a/tests/webauthn/src/test/java/org/keycloak/tests/webauthn/WebAuthnRegisterAndLoginTest.java +++ b/tests/webauthn/src/test/java/org/keycloak/tests/webauthn/WebAuthnRegisterAndLoginTest.java @@ -17,7 +17,6 @@ package org.keycloak.tests.webauthn; import java.io.IOException; -import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -53,7 +52,6 @@ import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.keycloak.models.AuthenticationExecutionModel.Requirement.ALTERNATIVE; @@ -80,15 +78,6 @@ public class WebAuthnRegisterAndLoginTest extends AbstractWebAuthnVirtualTest { @InjectPage SelectAuthenticatorPage selectAuthenticatorPage; - @BeforeEach - public void customizeWebAuthnTestRealm() { - List acceptableAaguids = new ArrayList<>(); - acceptableAaguids.add("00000000-0000-0000-0000-000000000000"); - acceptableAaguids.add("6d44ba9b-f6ec-2e49-b930-0c8fe920cb73"); - - managedRealm.updateWithCleanup(r -> r.webAuthnPolicyAcceptableAaguids(acceptableAaguids)); - } - @Test public void registerUserSuccess() { String username = "registerUserSuccess"; @@ -481,13 +470,12 @@ private List getCredentials(String userId) { } private void updateRealmWithDefaultWebAuthnSettings() { - managedRealm.updateWithCleanup(r -> r.webAuthnPolicySignatureAlgorithms(List.of("ES256"))); - managedRealm.updateWithCleanup(r -> r.webAuthnPolicyAttestationConveyancePreference("none")); - managedRealm.updateWithCleanup(r -> r.webAuthnPolicyAuthenticatorAttachment("cross-platform")); - managedRealm.updateWithCleanup(r -> r.webAuthnPolicyRequireResidentKey("No")); - managedRealm.updateWithCleanup(r -> r.webAuthnPolicyRpId(null)); - managedRealm.updateWithCleanup(r -> r.webAuthnPolicyUserVerificationRequirement("preferred")); - managedRealm.updateWithCleanup(r -> r.webAuthnPolicyAcceptableAaguids(List.of(ALL_ZERO_AAGUID))); + managedRealm.updateWithCleanup(r -> r.webAuthnPolicySignatureAlgorithms(List.of("ES256")) + .webAuthnPolicyAttestationConveyancePreference("none") + .webAuthnPolicyAuthenticatorAttachment("cross-platform") + .webAuthnPolicyRequireResidentKey("No") + .webAuthnPolicyRpId(null) + .webAuthnPolicyUserVerificationRequirement("preferred")); } /** diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/webauthn/AbstractWebAuthnVirtualTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/webauthn/AbstractWebAuthnVirtualTest.java index ed5aa610ea39..71c16fe83aed 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/webauthn/AbstractWebAuthnVirtualTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/webauthn/AbstractWebAuthnVirtualTest.java @@ -121,6 +121,7 @@ public abstract class AbstractWebAuthnVirtualTest extends AbstractChangeImported protected static final String ALL_ZERO_AAGUID = "00000000-0000-0000-0000-000000000000"; protected static final String ALL_ONE_AAGUID = "11111111-1111-1111-1111-111111111111"; + protected static final String CHROME_AAGUID = "01020304-0506-0708-0102-030405060708"; protected static final String USERNAME = "UserWebAuthn"; protected static final String EMAIL = "UserWebAuthn@email"; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/webauthn/registration/WebAuthnOtherSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/webauthn/registration/WebAuthnOtherSettingsTest.java index c76efd245811..2e2d0baf50d6 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/webauthn/registration/WebAuthnOtherSettingsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/webauthn/registration/WebAuthnOtherSettingsTest.java @@ -169,19 +169,66 @@ public void acceptableAaguidsShouldBeEmptyOrNullByDefault() { @Test @IgnoreBrowserDriver(FirefoxDriver.class) // See https://github.com/keycloak/keycloak/issues/10368 public void excludeCredentials() throws IOException { - List acceptableAaguids = Collections.singletonList(ALL_ONE_AAGUID); + List acceptableAaguids = Collections.singletonList(ALL_ZERO_AAGUID); try (Closeable u = getWebAuthnRealmUpdater() .setWebAuthnPolicyAcceptableAaguids(acceptableAaguids) + .setWebAuthnPolicyAttestationConveyancePreference(AttestationConveyancePreference.DIRECT.getValue()) .update()) { + // webauthn virtual emulator in chrome sets a self signed certificate every time, truststore needs to be disabled + testingClient.testing().disableTruststoreSpi(); WebAuthnRealmData realmData = new WebAuthnRealmData(managedRealm.admin().toRepresentation(), isPasswordless()); - assertThat(realmData.getAcceptableAaguids(), Matchers.contains(ALL_ONE_AAGUID)); + assertThat(realmData.getAcceptableAaguids(), Matchers.contains(ALL_ZERO_AAGUID)); registerDefaultUser(); webAuthnErrorPage.assertCurrent(); - assertThat(webAuthnErrorPage.getError(), allOf(containsString("not acceptable aaguid"), containsString(ALL_ZERO_AAGUID))); + assertThat(webAuthnErrorPage.getError(), allOf(containsString("not acceptable aaguid"), containsString(CHROME_AAGUID))); + } finally { + testingClient.testing().reenableTruststoreSpi(); + } + } + + @Test + @IgnoreBrowserDriver(FirefoxDriver.class) // See https://github.com/keycloak/keycloak/issues/10368 + public void excludeCredentialsSuccess() throws IOException { + List acceptableAaguids = Collections.singletonList(CHROME_AAGUID); + + try (Closeable u = getWebAuthnRealmUpdater() + .setWebAuthnPolicyAcceptableAaguids(acceptableAaguids) + .setWebAuthnPolicyAttestationConveyancePreference(AttestationConveyancePreference.DIRECT.getValue()) + .update()) { + // webauthn virtual emulator in chrome sets a self signed certificate every time, truststore needs to be disabled + testingClient.testing().disableTruststoreSpi(); + + WebAuthnRealmData realmData = new WebAuthnRealmData(managedRealm.admin().toRepresentation(), isPasswordless()); + assertThat(realmData.getAcceptableAaguids(), Matchers.contains(CHROME_AAGUID)); + + registerDefaultUser(); + + appPage.assertCurrent(); + } finally { + testingClient.testing().reenableTruststoreSpi(); + } + } + + @Test + @IgnoreBrowserDriver(FirefoxDriver.class) // See https://github.com/keycloak/keycloak/issues/10368 + public void excludeCredentialsUsingNone() throws IOException { + List acceptableAaguids = Collections.singletonList(ALL_ZERO_AAGUID); + + try (Closeable u = getWebAuthnRealmUpdater() + .setWebAuthnPolicyAcceptableAaguids(acceptableAaguids) + .update()) { + + WebAuthnRealmData realmData = new WebAuthnRealmData(managedRealm.admin().toRepresentation(), isPasswordless()); + assertThat(realmData.getAcceptableAaguids(), Matchers.contains(ALL_ZERO_AAGUID)); + + registerDefaultUser(); + + webAuthnErrorPage.assertCurrent(); + assertThat(webAuthnErrorPage.getError(), containsString("Acceptable AAGUIDs require an attestation format other than 'none'.")); } } } From dc2a7fede1d86fdb5e1ac5f63c34f95c43363079 Mon Sep 17 00:00:00 2001 From: rmartinc Date: Fri, 24 Apr 2026 14:01:50 +0200 Subject: [PATCH 2/3] Check Acceptable AAGUIDs sets a attestation preference different to None in admin console Closes #48388 Signed-off-by: rmartinc --- .../admin/messages/messages_en.properties | 3 ++- .../policies/WebauthnPolicy.tsx | 21 +++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties index 7deb15cb3f07..13e3a74b207a 100644 --- a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties +++ b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties @@ -607,7 +607,8 @@ regenerate=Regenerate ignoreMissingGroups=Ignore missing groups sslType.external=External requests showMetaData=Show metadata -webAuthnPolicyAttestationConveyancePreferenceHelp=Communicates to an authenticator the preference of how to generate an attestation statement. +webAuthnPolicyAttestationConveyancePreferenceHelp=Communicates to an authenticator the preference of how to generate an attestation statement. None is used by specification if not specified. +acceptableAAGUIDsRequiresAttestation=Acceptable AAGUIDs require an attestation conveyance preference other than None top-level-flow-type.basic-flow=Basic flow groupRemoveError=Error removing group {error} temporaryPasswordHelpText=If enabled, the user must change the password on the next login diff --git a/js/apps/admin-ui/src/authentication/policies/WebauthnPolicy.tsx b/js/apps/admin-ui/src/authentication/policies/WebauthnPolicy.tsx index 210471d892e3..34bdac9d0646 100644 --- a/js/apps/admin-ui/src/authentication/policies/WebauthnPolicy.tsx +++ b/js/apps/admin-ui/src/authentication/policies/WebauthnPolicy.tsx @@ -1,4 +1,5 @@ import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; +import type { FieldValues } from "react-hook-form"; import { ActionGroup, AlertVariant, @@ -12,7 +13,7 @@ import { } from "@patternfly/react-core"; import { QuestionCircleIcon } from "@patternfly/react-icons"; import { useEffect } from "react"; -import { FormProvider, useForm } from "react-hook-form"; +import { FormProvider, useForm, Validate } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { HelpItem, @@ -79,6 +80,7 @@ type WeauthnSelectProps = { options: readonly string[]; labelPrefix?: string; isMultiSelect?: boolean; + validate?: Validate; }; const WebauthnSelect = ({ @@ -88,6 +90,7 @@ const WebauthnSelect = ({ options, labelPrefix, isMultiSelect = false, + validate, }: WeauthnSelectProps) => { const { t } = useTranslation(); return ( @@ -96,7 +99,7 @@ const WebauthnSelect = ({ label={label} labelIcon={labelIcon} variant={isMultiSelect ? "typeaheadMulti" : "single"} - controller={{ defaultValue: options[0] }} + controller={{ defaultValue: options[0], rules: { validate: validate } }} options={options.map((option) => ({ key: option, value: labelPrefix ? t(`${labelPrefix}.${option}`) : option, @@ -128,6 +131,7 @@ export const WebauthnPolicy = ({ handleSubmit, watch, formState: { isDirty }, + watch, } = form; const namePrefix = isPasswordLess @@ -152,6 +156,7 @@ export const WebauthnPolicy = ({ }; const isFeatureEnabled = useIsFeatureEnabled(); + const acceptableAAGUIDs = watch(`${namePrefix}AcceptableAaguids`, []); return ( @@ -196,6 +201,18 @@ export const WebauthnPolicy = ({ labelIcon={t("webAuthnPolicyAttestationConveyancePreferenceHelp")} options={ATTESTATION_PREFERENCE} labelPrefix="attestationPreference" + validate={(value) => { + const hasValidAAGUIDs = acceptableAAGUIDs.some( + (guid: string) => guid?.trim().length > 0, + ); + + if ( + (value === "none" || value === "not specified") && + hasValidAAGUIDs + ) { + return t("acceptableAAGUIDsRequiresAttestation"); + } + }} /> Date: Mon, 27 Apr 2026 10:57:08 +0200 Subject: [PATCH 3/3] Changes for rebase and review. Closes #48388 Signed-off-by: rmartinc --- docs/documentation/upgrading/topics/changes/changes-26_6_2.adoc | 2 +- .../theme/keycloak.v2/admin/messages/messages_en.properties | 2 +- js/apps/admin-ui/src/authentication/policies/WebauthnPolicy.tsx | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/documentation/upgrading/topics/changes/changes-26_6_2.adoc b/docs/documentation/upgrading/topics/changes/changes-26_6_2.adoc index e7522d0f579f..10b8e0af4232 100644 --- a/docs/documentation/upgrading/topics/changes/changes-26_6_2.adoc +++ b/docs/documentation/upgrading/topics/changes/changes-26_6_2.adoc @@ -7,6 +7,6 @@ It also lists significant changes to internal APIs. The WebAuthn policy presents the option **Acceptable AAGUIDs** to restrict the authenticators that are allowed to register new credentials. The AAGUID (Authenticator Attestation Global Unique Identifier) is an identifier for the authenticator's type (e.g., make and model). This option requires the **Attestation conveyance preference** to be configured too (normally `Direct`), in order to force the authenticator to include the attestation inside the registration data. -Since this release, when this option is setup, the attestation is required to be present and signed with a valid certificate for the {project_name} trust-store. The `None` attestation format is explicitly not permitted. Previously, there were some corner cases in which a self attestation was accepted. The change is expected to be harmless, but maybe there are combinations of authenticators and WebAuthn policies that can present issues. +Since this release, when this option is set up, the attestation is required to be present and signed with a valid certificate for the {project_name} trust-store. The `None` attestation format is explicitly not permitted. Previously, there were some corner cases in which a self attestation was accepted. The change is expected to be harmless, but maybe there are combinations of authenticators and WebAuthn policies that can present issues. See chapter link:{adminguide_link}#_webauthn-policy[Managing policy] in the {adminguide_name} for more information. \ No newline at end of file diff --git a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties index 13e3a74b207a..98b1a4c7078e 100644 --- a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties +++ b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties @@ -608,7 +608,7 @@ ignoreMissingGroups=Ignore missing groups sslType.external=External requests showMetaData=Show metadata webAuthnPolicyAttestationConveyancePreferenceHelp=Communicates to an authenticator the preference of how to generate an attestation statement. None is used by specification if not specified. -acceptableAAGUIDsRequiresAttestation=Acceptable AAGUIDs require an attestation conveyance preference other than None +acceptableAAGUIDsRequiresAttestation=Acceptable AAGUIDs require an attestation conveyance preference to be set and not None top-level-flow-type.basic-flow=Basic flow groupRemoveError=Error removing group {error} temporaryPasswordHelpText=If enabled, the user must change the password on the next login diff --git a/js/apps/admin-ui/src/authentication/policies/WebauthnPolicy.tsx b/js/apps/admin-ui/src/authentication/policies/WebauthnPolicy.tsx index 34bdac9d0646..b23a2e71656f 100644 --- a/js/apps/admin-ui/src/authentication/policies/WebauthnPolicy.tsx +++ b/js/apps/admin-ui/src/authentication/policies/WebauthnPolicy.tsx @@ -131,7 +131,6 @@ export const WebauthnPolicy = ({ handleSubmit, watch, formState: { isDirty }, - watch, } = form; const namePrefix = isPasswordLess