mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Changing default passwordless webauthn policy to follow recommended values in the documentation
Closes #40792 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
6b050776bc
commit
900d8c7400
@ -932,7 +932,7 @@ public class RealmAdapter implements StorageProviderRealmModel, JpaModel<RealmEn
|
||||
|
||||
@Override
|
||||
public WebAuthnPolicy getWebAuthnPolicy() {
|
||||
return getWebAuthnPolicy("");
|
||||
return getWebAuthnPolicy("", WebAuthnPolicyTwoFactorDefaults.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -943,7 +943,7 @@ public class RealmAdapter implements StorageProviderRealmModel, JpaModel<RealmEn
|
||||
@Override
|
||||
public WebAuthnPolicy getWebAuthnPolicyPasswordless() {
|
||||
// We will use some prefix for attributes related to passwordless WebAuthn policy
|
||||
return getWebAuthnPolicy(Constants.WEBAUTHN_PASSWORDLESS_PREFIX);
|
||||
return getWebAuthnPolicy(Constants.WEBAUTHN_PASSWORDLESS_PREFIX, WebAuthnPolicyPasswordlessDefaults.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -952,68 +952,81 @@ public class RealmAdapter implements StorageProviderRealmModel, JpaModel<RealmEn
|
||||
setWebAuthnPolicy(policy, Constants.WEBAUTHN_PASSWORDLESS_PREFIX);
|
||||
}
|
||||
|
||||
|
||||
private WebAuthnPolicy getWebAuthnPolicy(String attributePrefix) {
|
||||
private WebAuthnPolicy getWebAuthnPolicy(String attributePrefix, WebAuthnPolicy defaultConfig) {
|
||||
WebAuthnPolicy policy = new WebAuthnPolicy();
|
||||
|
||||
// mandatory parameters
|
||||
String rpEntityName = getAttribute(RealmAttributes.WEBAUTHN_POLICY_RP_ENTITY_NAME + attributePrefix);
|
||||
if (rpEntityName == null || rpEntityName.isEmpty())
|
||||
rpEntityName = Constants.DEFAULT_WEBAUTHN_POLICY_RP_ENTITY_NAME;
|
||||
rpEntityName = defaultConfig.getRpEntityName();
|
||||
policy.setRpEntityName(rpEntityName);
|
||||
|
||||
String signatureAlgorithmsString = getAttribute(RealmAttributes.WEBAUTHN_POLICY_SIGNATURE_ALGORITHMS + attributePrefix);
|
||||
if (signatureAlgorithmsString == null || signatureAlgorithmsString.isEmpty())
|
||||
signatureAlgorithmsString = Constants.DEFAULT_WEBAUTHN_POLICY_SIGNATURE_ALGORITHMS;
|
||||
List<String> signatureAlgorithms = Arrays.asList(signatureAlgorithmsString.split(","));
|
||||
List<String> signatureAlgorithms = (signatureAlgorithmsString == null || signatureAlgorithmsString.isEmpty())
|
||||
? defaultConfig.getSignatureAlgorithm()
|
||||
: Arrays.asList(signatureAlgorithmsString.split(","));
|
||||
policy.setSignatureAlgorithm(signatureAlgorithms);
|
||||
|
||||
// optional parameters
|
||||
String rpId = getAttribute(RealmAttributes.WEBAUTHN_POLICY_RP_ID + attributePrefix);
|
||||
if (rpId == null || rpId.isEmpty()) rpId = "";
|
||||
if (rpId == null || rpId.isEmpty()) {
|
||||
rpId = defaultConfig.getRpId();
|
||||
}
|
||||
policy.setRpId(rpId);
|
||||
|
||||
String attestationConveyancePreference = getAttribute(RealmAttributes.WEBAUTHN_POLICY_ATTESTATION_CONVEYANCE_PREFERENCE + attributePrefix);
|
||||
if (attestationConveyancePreference == null || attestationConveyancePreference.isEmpty())
|
||||
attestationConveyancePreference = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
if (attestationConveyancePreference == null || attestationConveyancePreference.isEmpty()) {
|
||||
attestationConveyancePreference = defaultConfig.getAttestationConveyancePreference();
|
||||
}
|
||||
policy.setAttestationConveyancePreference(attestationConveyancePreference);
|
||||
|
||||
String authenticatorAttachment = getAttribute(RealmAttributes.WEBAUTHN_POLICY_AUTHENTICATOR_ATTACHMENT + attributePrefix);
|
||||
if (authenticatorAttachment == null || authenticatorAttachment.isEmpty())
|
||||
authenticatorAttachment = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
if (authenticatorAttachment == null || authenticatorAttachment.isEmpty()) {
|
||||
authenticatorAttachment = defaultConfig.getAuthenticatorAttachment();
|
||||
}
|
||||
policy.setAuthenticatorAttachment(authenticatorAttachment);
|
||||
|
||||
String requireResidentKey = getAttribute(RealmAttributes.WEBAUTHN_POLICY_REQUIRE_RESIDENT_KEY + attributePrefix);
|
||||
if (requireResidentKey == null || requireResidentKey.isEmpty())
|
||||
requireResidentKey = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
if (requireResidentKey == null || requireResidentKey.isEmpty()) {
|
||||
requireResidentKey = defaultConfig.getRequireResidentKey();
|
||||
}
|
||||
policy.setRequireResidentKey(requireResidentKey);
|
||||
|
||||
String userVerificationRequirement = getAttribute(RealmAttributes.WEBAUTHN_POLICY_USER_VERIFICATION_REQUIREMENT + attributePrefix);
|
||||
if (userVerificationRequirement == null || userVerificationRequirement.isEmpty())
|
||||
userVerificationRequirement = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
if (userVerificationRequirement == null || userVerificationRequirement.isEmpty()) {
|
||||
userVerificationRequirement = defaultConfig.getUserVerificationRequirement();
|
||||
}
|
||||
policy.setUserVerificationRequirement(userVerificationRequirement);
|
||||
|
||||
String createTime = getAttribute(RealmAttributes.WEBAUTHN_POLICY_CREATE_TIMEOUT + attributePrefix);
|
||||
if (createTime != null) policy.setCreateTimeout(Integer.parseInt(createTime));
|
||||
else policy.setCreateTimeout(0);
|
||||
String createTimeoutString = getAttribute(RealmAttributes.WEBAUTHN_POLICY_CREATE_TIMEOUT + attributePrefix);
|
||||
int createTimeout = (createTimeoutString != null)
|
||||
? Integer.parseInt(createTimeoutString)
|
||||
: defaultConfig.getCreateTimeout();
|
||||
policy.setCreateTimeout(createTimeout);
|
||||
|
||||
String avoidSameAuthenticatorRegister = getAttribute(RealmAttributes.WEBAUTHN_POLICY_AVOID_SAME_AUTHENTICATOR_REGISTER + attributePrefix);
|
||||
if (avoidSameAuthenticatorRegister != null) policy.setAvoidSameAuthenticatorRegister(Boolean.parseBoolean(avoidSameAuthenticatorRegister));
|
||||
String avoidSameAuthenticatorRegisterString = getAttribute(RealmAttributes.WEBAUTHN_POLICY_AVOID_SAME_AUTHENTICATOR_REGISTER + attributePrefix);
|
||||
boolean avoidSameAuthenticatorRegister = (avoidSameAuthenticatorRegisterString != null)
|
||||
? Boolean.parseBoolean(avoidSameAuthenticatorRegisterString)
|
||||
: defaultConfig.isAvoidSameAuthenticatorRegister();
|
||||
policy.setAvoidSameAuthenticatorRegister(avoidSameAuthenticatorRegister);
|
||||
|
||||
String acceptableAaguidsString = getAttribute(RealmAttributes.WEBAUTHN_POLICY_ACCEPTABLE_AAGUIDS + attributePrefix);
|
||||
List<String> acceptableAaguids = new ArrayList<>();
|
||||
if (acceptableAaguidsString != null && !acceptableAaguidsString.isEmpty())
|
||||
acceptableAaguids = Arrays.asList(acceptableAaguidsString.split(","));
|
||||
List<String> acceptableAaguids = (acceptableAaguidsString != null && !acceptableAaguidsString.isEmpty())
|
||||
? Arrays.asList(acceptableAaguidsString.split(","))
|
||||
: defaultConfig.getAcceptableAaguids();
|
||||
policy.setAcceptableAaguids(acceptableAaguids);
|
||||
|
||||
String extraOriginsString = getAttribute(RealmAttributes.WEBAUTHN_POLICY_EXTRA_ORIGINS + attributePrefix);
|
||||
List<String> extraOrigins = new ArrayList<>();
|
||||
if (extraOriginsString != null && !extraOriginsString.isEmpty())
|
||||
extraOrigins = Arrays.asList(extraOriginsString.split(","));
|
||||
List<String> extraOrigins = (extraOriginsString != null && !extraOriginsString.isEmpty())
|
||||
? Arrays.asList(extraOriginsString.split(","))
|
||||
: defaultConfig.getExtraOrigins();
|
||||
policy.setExtraOrigins(extraOrigins);
|
||||
|
||||
String passkeysEnabled = getAttribute(RealmAttributes.WEBAUTHN_POLICY_PASSKEYS_ENABLED + attributePrefix);
|
||||
if (passkeysEnabled != null) policy.setPasskeysEnabled(Boolean.parseBoolean(passkeysEnabled));
|
||||
String passkeysEnabledString = getAttribute(RealmAttributes.WEBAUTHN_POLICY_PASSKEYS_ENABLED + attributePrefix);
|
||||
Boolean passKeysEnabled = (passkeysEnabledString != null)
|
||||
? Boolean.valueOf(passkeysEnabledString)
|
||||
: defaultConfig.isPasskeysEnabled();
|
||||
policy.setPasskeysEnabled(passKeysEnabled);
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
@ -59,12 +59,13 @@ import org.keycloak.models.ScopeContainerModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.WebAuthnPolicy;
|
||||
import org.keycloak.models.WebAuthnPolicyPasswordlessDefaults;
|
||||
import org.keycloak.models.WebAuthnPolicyTwoFactorDefaults;
|
||||
import org.keycloak.models.utils.ComponentUtil;
|
||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||
import org.keycloak.models.utils.DefaultKeyProviders;
|
||||
import org.keycloak.models.utils.DefaultRequiredActions;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.organization.OrganizationProvider;
|
||||
import org.keycloak.organization.validation.OrganizationsValidation;
|
||||
@ -1262,54 +1263,66 @@ public class DefaultExportImportManager implements ExportImportManager {
|
||||
|
||||
private static WebAuthnPolicy getWebAuthnPolicyTwoFactor(RealmRepresentation rep) {
|
||||
WebAuthnPolicy webAuthnPolicy = new WebAuthnPolicy();
|
||||
WebAuthnPolicy defaultConfig = WebAuthnPolicyTwoFactorDefaults.get();
|
||||
|
||||
String webAuthnPolicyRpEntityName = rep.getWebAuthnPolicyRpEntityName();
|
||||
if (webAuthnPolicyRpEntityName == null || webAuthnPolicyRpEntityName.isEmpty())
|
||||
webAuthnPolicyRpEntityName = Constants.DEFAULT_WEBAUTHN_POLICY_RP_ENTITY_NAME;
|
||||
webAuthnPolicyRpEntityName = defaultConfig.getRpEntityName();
|
||||
webAuthnPolicy.setRpEntityName(webAuthnPolicyRpEntityName);
|
||||
|
||||
List<String> webAuthnPolicySignatureAlgorithms = rep.getWebAuthnPolicySignatureAlgorithms();
|
||||
if (webAuthnPolicySignatureAlgorithms == null || webAuthnPolicySignatureAlgorithms.isEmpty())
|
||||
webAuthnPolicySignatureAlgorithms = Arrays.asList(Constants.DEFAULT_WEBAUTHN_POLICY_SIGNATURE_ALGORITHMS.split(","));
|
||||
webAuthnPolicySignatureAlgorithms = defaultConfig.getSignatureAlgorithm();
|
||||
webAuthnPolicy.setSignatureAlgorithm(webAuthnPolicySignatureAlgorithms);
|
||||
|
||||
String webAuthnPolicyRpId = rep.getWebAuthnPolicyRpId();
|
||||
if (webAuthnPolicyRpId == null || webAuthnPolicyRpId.isEmpty())
|
||||
webAuthnPolicyRpId = "";
|
||||
webAuthnPolicyRpId = defaultConfig.getRpId();
|
||||
webAuthnPolicy.setRpId(webAuthnPolicyRpId);
|
||||
|
||||
String webAuthnPolicyAttestationConveyancePreference = rep.getWebAuthnPolicyAttestationConveyancePreference();
|
||||
if (webAuthnPolicyAttestationConveyancePreference == null || webAuthnPolicyAttestationConveyancePreference.isEmpty())
|
||||
webAuthnPolicyAttestationConveyancePreference = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
webAuthnPolicyAttestationConveyancePreference = defaultConfig.getAttestationConveyancePreference();
|
||||
webAuthnPolicy.setAttestationConveyancePreference(webAuthnPolicyAttestationConveyancePreference);
|
||||
|
||||
String webAuthnPolicyAuthenticatorAttachment = rep.getWebAuthnPolicyAuthenticatorAttachment();
|
||||
if (webAuthnPolicyAuthenticatorAttachment == null || webAuthnPolicyAuthenticatorAttachment.isEmpty())
|
||||
webAuthnPolicyAuthenticatorAttachment = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
webAuthnPolicyAuthenticatorAttachment = defaultConfig.getAuthenticatorAttachment();
|
||||
webAuthnPolicy.setAuthenticatorAttachment(webAuthnPolicyAuthenticatorAttachment);
|
||||
|
||||
String webAuthnPolicyRequireResidentKey = rep.getWebAuthnPolicyRequireResidentKey();
|
||||
if (webAuthnPolicyRequireResidentKey == null || webAuthnPolicyRequireResidentKey.isEmpty())
|
||||
webAuthnPolicyRequireResidentKey = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
webAuthnPolicyRequireResidentKey = defaultConfig.getRequireResidentKey();
|
||||
webAuthnPolicy.setRequireResidentKey(webAuthnPolicyRequireResidentKey);
|
||||
|
||||
String webAuthnPolicyUserVerificationRequirement = rep.getWebAuthnPolicyUserVerificationRequirement();
|
||||
if (webAuthnPolicyUserVerificationRequirement == null || webAuthnPolicyUserVerificationRequirement.isEmpty())
|
||||
webAuthnPolicyUserVerificationRequirement = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
webAuthnPolicyUserVerificationRequirement = defaultConfig.getUserVerificationRequirement();
|
||||
webAuthnPolicy.setUserVerificationRequirement(webAuthnPolicyUserVerificationRequirement);
|
||||
|
||||
Integer webAuthnPolicyCreateTimeout = rep.getWebAuthnPolicyCreateTimeout();
|
||||
if (webAuthnPolicyCreateTimeout != null) webAuthnPolicy.setCreateTimeout(webAuthnPolicyCreateTimeout);
|
||||
else webAuthnPolicy.setCreateTimeout(0);
|
||||
if (webAuthnPolicyCreateTimeout == null) {
|
||||
webAuthnPolicyCreateTimeout = defaultConfig.getCreateTimeout();
|
||||
}
|
||||
webAuthnPolicy.setCreateTimeout(webAuthnPolicyCreateTimeout);
|
||||
|
||||
Boolean webAuthnPolicyAvoidSameAuthenticatorRegister = rep.isWebAuthnPolicyAvoidSameAuthenticatorRegister();
|
||||
if (webAuthnPolicyAvoidSameAuthenticatorRegister != null) webAuthnPolicy.setAvoidSameAuthenticatorRegister(webAuthnPolicyAvoidSameAuthenticatorRegister);
|
||||
if (webAuthnPolicyAvoidSameAuthenticatorRegister == null) {
|
||||
webAuthnPolicyAvoidSameAuthenticatorRegister = defaultConfig.isAvoidSameAuthenticatorRegister();
|
||||
}
|
||||
webAuthnPolicy.setAvoidSameAuthenticatorRegister(webAuthnPolicyAvoidSameAuthenticatorRegister);
|
||||
|
||||
List<String> webAuthnPolicyAcceptableAaguids = rep.getWebAuthnPolicyAcceptableAaguids();
|
||||
if (webAuthnPolicyAcceptableAaguids != null) webAuthnPolicy.setAcceptableAaguids(webAuthnPolicyAcceptableAaguids);
|
||||
if (webAuthnPolicyAcceptableAaguids == null) {
|
||||
webAuthnPolicyAcceptableAaguids = defaultConfig.getAcceptableAaguids();
|
||||
}
|
||||
webAuthnPolicy.setAcceptableAaguids(webAuthnPolicyAcceptableAaguids);
|
||||
|
||||
List<String> webAuthnPolicyExtraOrigins = rep.getWebAuthnPolicyExtraOrigins();
|
||||
if (webAuthnPolicyExtraOrigins != null) webAuthnPolicy.setExtraOrigins(webAuthnPolicyExtraOrigins);
|
||||
if (webAuthnPolicyExtraOrigins == null) {
|
||||
webAuthnPolicyExtraOrigins = defaultConfig.getExtraOrigins();
|
||||
}
|
||||
webAuthnPolicy.setExtraOrigins(webAuthnPolicyExtraOrigins);
|
||||
|
||||
return webAuthnPolicy;
|
||||
}
|
||||
@ -1317,57 +1330,72 @@ public class DefaultExportImportManager implements ExportImportManager {
|
||||
|
||||
private static WebAuthnPolicy getWebAuthnPolicyPasswordless(RealmRepresentation rep) {
|
||||
WebAuthnPolicy webAuthnPolicy = new WebAuthnPolicy();
|
||||
WebAuthnPolicy defaultConfig = WebAuthnPolicyPasswordlessDefaults.get();
|
||||
|
||||
String webAuthnPolicyRpEntityName = rep.getWebAuthnPolicyPasswordlessRpEntityName();
|
||||
if (webAuthnPolicyRpEntityName == null || webAuthnPolicyRpEntityName.isEmpty())
|
||||
webAuthnPolicyRpEntityName = Constants.DEFAULT_WEBAUTHN_POLICY_RP_ENTITY_NAME;
|
||||
webAuthnPolicyRpEntityName = defaultConfig.getRpEntityName();
|
||||
webAuthnPolicy.setRpEntityName(webAuthnPolicyRpEntityName);
|
||||
|
||||
List<String> webAuthnPolicySignatureAlgorithms = rep.getWebAuthnPolicyPasswordlessSignatureAlgorithms();
|
||||
if (webAuthnPolicySignatureAlgorithms == null || webAuthnPolicySignatureAlgorithms.isEmpty())
|
||||
webAuthnPolicySignatureAlgorithms = Arrays.asList(Constants.DEFAULT_WEBAUTHN_POLICY_SIGNATURE_ALGORITHMS.split(","));
|
||||
webAuthnPolicySignatureAlgorithms = defaultConfig.getSignatureAlgorithm();
|
||||
webAuthnPolicy.setSignatureAlgorithm(webAuthnPolicySignatureAlgorithms);
|
||||
|
||||
String webAuthnPolicyRpId = rep.getWebAuthnPolicyPasswordlessRpId();
|
||||
if (webAuthnPolicyRpId == null || webAuthnPolicyRpId.isEmpty())
|
||||
webAuthnPolicyRpId = "";
|
||||
webAuthnPolicyRpId = defaultConfig.getRpId();
|
||||
webAuthnPolicy.setRpId(webAuthnPolicyRpId);
|
||||
|
||||
String webAuthnPolicyAttestationConveyancePreference = rep.getWebAuthnPolicyPasswordlessAttestationConveyancePreference();
|
||||
if (webAuthnPolicyAttestationConveyancePreference == null || webAuthnPolicyAttestationConveyancePreference.isEmpty())
|
||||
webAuthnPolicyAttestationConveyancePreference = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
webAuthnPolicyAttestationConveyancePreference = defaultConfig.getAttestationConveyancePreference();
|
||||
webAuthnPolicy.setAttestationConveyancePreference(webAuthnPolicyAttestationConveyancePreference);
|
||||
|
||||
String webAuthnPolicyAuthenticatorAttachment = rep.getWebAuthnPolicyPasswordlessAuthenticatorAttachment();
|
||||
if (webAuthnPolicyAuthenticatorAttachment == null || webAuthnPolicyAuthenticatorAttachment.isEmpty())
|
||||
webAuthnPolicyAuthenticatorAttachment = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
webAuthnPolicyAuthenticatorAttachment = defaultConfig.getAuthenticatorAttachment();
|
||||
webAuthnPolicy.setAuthenticatorAttachment(webAuthnPolicyAuthenticatorAttachment);
|
||||
|
||||
String webAuthnPolicyRequireResidentKey = rep.getWebAuthnPolicyPasswordlessRequireResidentKey();
|
||||
if (webAuthnPolicyRequireResidentKey == null || webAuthnPolicyRequireResidentKey.isEmpty())
|
||||
webAuthnPolicyRequireResidentKey = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
webAuthnPolicyRequireResidentKey = defaultConfig.getRequireResidentKey();
|
||||
webAuthnPolicy.setRequireResidentKey(webAuthnPolicyRequireResidentKey);
|
||||
|
||||
String webAuthnPolicyUserVerificationRequirement = rep.getWebAuthnPolicyPasswordlessUserVerificationRequirement();
|
||||
if (webAuthnPolicyUserVerificationRequirement == null || webAuthnPolicyUserVerificationRequirement.isEmpty())
|
||||
webAuthnPolicyUserVerificationRequirement = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
webAuthnPolicyUserVerificationRequirement = defaultConfig.getUserVerificationRequirement();
|
||||
webAuthnPolicy.setUserVerificationRequirement(webAuthnPolicyUserVerificationRequirement);
|
||||
|
||||
Integer webAuthnPolicyCreateTimeout = rep.getWebAuthnPolicyPasswordlessCreateTimeout();
|
||||
if (webAuthnPolicyCreateTimeout != null) webAuthnPolicy.setCreateTimeout(webAuthnPolicyCreateTimeout);
|
||||
else webAuthnPolicy.setCreateTimeout(0);
|
||||
if (webAuthnPolicyCreateTimeout == null) {
|
||||
webAuthnPolicyCreateTimeout = defaultConfig.getCreateTimeout();
|
||||
}
|
||||
webAuthnPolicy.setCreateTimeout(webAuthnPolicyCreateTimeout);
|
||||
|
||||
Boolean webAuthnPolicyAvoidSameAuthenticatorRegister = rep.isWebAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister();
|
||||
if (webAuthnPolicyAvoidSameAuthenticatorRegister != null) webAuthnPolicy.setAvoidSameAuthenticatorRegister(webAuthnPolicyAvoidSameAuthenticatorRegister);
|
||||
if (webAuthnPolicyAvoidSameAuthenticatorRegister == null) {
|
||||
webAuthnPolicyAvoidSameAuthenticatorRegister = defaultConfig.isAvoidSameAuthenticatorRegister();
|
||||
}
|
||||
webAuthnPolicy.setAvoidSameAuthenticatorRegister(webAuthnPolicyAvoidSameAuthenticatorRegister);
|
||||
|
||||
List<String> webAuthnPolicyAcceptableAaguids = rep.getWebAuthnPolicyPasswordlessAcceptableAaguids();
|
||||
if (webAuthnPolicyAcceptableAaguids != null) webAuthnPolicy.setAcceptableAaguids(webAuthnPolicyAcceptableAaguids);
|
||||
if (webAuthnPolicyAcceptableAaguids == null) {
|
||||
webAuthnPolicyAcceptableAaguids = defaultConfig.getAcceptableAaguids();
|
||||
}
|
||||
webAuthnPolicy.setAcceptableAaguids(webAuthnPolicyAcceptableAaguids);
|
||||
|
||||
List<String> webAuthnPolicyExtraOrigins = rep.getWebAuthnPolicyPasswordlessExtraOrigins();
|
||||
if (webAuthnPolicyExtraOrigins != null) webAuthnPolicy.setExtraOrigins(webAuthnPolicyExtraOrigins);
|
||||
if (webAuthnPolicyExtraOrigins == null) {
|
||||
webAuthnPolicyExtraOrigins = defaultConfig.getExtraOrigins();
|
||||
}
|
||||
webAuthnPolicy.setExtraOrigins(webAuthnPolicyExtraOrigins);
|
||||
|
||||
Boolean webAuthnPolicyPasswordlessPasskeysEnabled = rep.getWebAuthnPolicyPasswordlessPasskeysEnabled();
|
||||
if (webAuthnPolicyPasswordlessPasskeysEnabled != null) webAuthnPolicy.setPasskeysEnabled(webAuthnPolicyPasswordlessPasskeysEnabled);
|
||||
if (webAuthnPolicyPasswordlessPasskeysEnabled == null) {
|
||||
webAuthnPolicyPasswordlessPasskeysEnabled = defaultConfig.isPasskeysEnabled();
|
||||
}
|
||||
webAuthnPolicy.setPasskeysEnabled(webAuthnPolicyPasswordlessPasskeysEnabled);
|
||||
|
||||
return webAuthnPolicy;
|
||||
}
|
||||
|
||||
@ -70,6 +70,11 @@ public final class Constants {
|
||||
public static final String DEFAULT_WEBAUTHN_POLICY_RP_ENTITY_NAME = "keycloak";
|
||||
// it stands for optional parameter not specified in WebAuthn
|
||||
public static final String DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED = "not specified";
|
||||
public static final String WEBAUTHN_POLICY_OPTION_REQUIRED = "required";
|
||||
public static final String WEBAUTHN_POLICY_OPTION_PREFERED = "preferred";
|
||||
public static final String WEBAUTHN_POLICY_OPTION_DISCOURAGED = "discouraged";
|
||||
public static final String WEBAUTHN_POLICY_OPTION_YES = "Yes";
|
||||
public static final String WEBAUTHN_POLICY_OPTION_NO = "No";
|
||||
|
||||
// Prefix used for the realm attributes and other places
|
||||
public static final String WEBAUTHN_PASSWORDLESS_PREFIX = "Passwordless";
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2025 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* 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 org.keycloak.models;
|
||||
|
||||
/**
|
||||
* Default values for the WebAuthn configuration when used as passwordless.
|
||||
*
|
||||
* @author rmartinc
|
||||
*/
|
||||
public class WebAuthnPolicyPasswordlessDefaults extends WebAuthnPolicyTwoFactorDefaults {
|
||||
|
||||
public static WebAuthnPolicy get() {
|
||||
return new WebAuthnPolicyPasswordlessDefaults();
|
||||
}
|
||||
|
||||
WebAuthnPolicyPasswordlessDefaults() {
|
||||
super();
|
||||
this.requireResidentKey = Constants.WEBAUTHN_POLICY_OPTION_YES;
|
||||
this.userVerificationRequirement = Constants.WEBAUTHN_POLICY_OPTION_REQUIRED;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2025 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* 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 org.keycloak.models;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.keycloak.storage.ReadOnlyException;
|
||||
|
||||
/**
|
||||
* Default values for the WebAuthn configuration when used as Two Factor.
|
||||
*
|
||||
* @author rmartinc
|
||||
*/
|
||||
public class WebAuthnPolicyTwoFactorDefaults extends WebAuthnPolicy {
|
||||
|
||||
public static WebAuthnPolicy get() {
|
||||
return new WebAuthnPolicyTwoFactorDefaults();
|
||||
}
|
||||
|
||||
WebAuthnPolicyTwoFactorDefaults() {
|
||||
this.rpEntityName = Constants.DEFAULT_WEBAUTHN_POLICY_RP_ENTITY_NAME;
|
||||
this.signatureAlgorithms = List.of(Constants.DEFAULT_WEBAUTHN_POLICY_SIGNATURE_ALGORITHMS.split(","));
|
||||
this.rpId = "";
|
||||
this.attestationConveyancePreference = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
this.authenticatorAttachment = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
this.requireResidentKey = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
this.userVerificationRequirement = Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
this.createTimeout = 0;
|
||||
this.avoidSameAuthenticatorRegister = false;
|
||||
this.acceptableAaguids = Collections.emptyList();
|
||||
this.extraOrigins = Collections.emptyList();
|
||||
this.passkeysEnabled = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRpEntityName(String rpEntityName) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSignatureAlgorithm(List<String> signatureAlgorithms) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRpId(String rpId) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttestationConveyancePreference(String attestationConveyancePreference) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticatorAttachment(String authenticatorAttachment) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequireResidentKey(String requireResidentKey) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVerificationRequirement(String userVerificationRequirement) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateTimeout(int createTimeout) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAvoidSameAuthenticatorRegister(boolean avoidSameAuthenticatorRegister) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptableAaguids(List<String> acceptableAaguids) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExtraOrigins(List<String> extraOrigins) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasskeysEnabled(Boolean passkeysEnabled) {
|
||||
throwReadOnlyException();
|
||||
}
|
||||
|
||||
private void throwReadOnlyException() {
|
||||
throw new ReadOnlyException("Default WebAuthnPolicy!");
|
||||
}
|
||||
}
|
||||
@ -53,12 +53,6 @@ public interface WebAuthnConstants {
|
||||
// key for storing onto AuthenticationSessionModel's Attribute challenge generated by RP(keycloak)
|
||||
String AUTH_CHALLENGE_NOTE = "WEBAUTH_CHALLENGE";
|
||||
|
||||
// option values on WebAuth API
|
||||
String OPTION_REQUIRED = "required";
|
||||
String OPTION_PREFERED = "preferred";
|
||||
String OPTION_DISCOURAGED = "discouraged";
|
||||
String OPTION_NOT_SPECIFIED = "";
|
||||
|
||||
/* WebAuthn events */
|
||||
|
||||
// Event key for credential id generated by navigator.credentials.create()
|
||||
|
||||
@ -43,6 +43,7 @@ import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.forms.login.LoginFormsProvider;
|
||||
import org.keycloak.forms.login.freemarker.model.WebAuthnAuthenticatorsBean;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
@ -209,7 +210,7 @@ public class WebAuthnAuthenticator implements Authenticator, CredentialValidator
|
||||
|
||||
boolean isUVFlagChecked = false;
|
||||
String userVerificationRequirement = getWebAuthnPolicy(context).getUserVerificationRequirement();
|
||||
if (WebAuthnConstants.OPTION_REQUIRED.equals(userVerificationRequirement)) isUVFlagChecked = true;
|
||||
if (Constants.WEBAUTHN_POLICY_OPTION_REQUIRED.equals(userVerificationRequirement)) isUVFlagChecked = true;
|
||||
|
||||
UserModel user = session.users().getUserById(context.getRealm(), userId);
|
||||
|
||||
|
||||
@ -245,7 +245,7 @@ public class WebAuthnRegister implements RequiredActionProvider, CredentialRegis
|
||||
Challenge challenge = new DefaultChallenge(context.getAuthenticationSession().getAuthNote(WebAuthnConstants.AUTH_CHALLENGE_NOTE));
|
||||
ServerProperty serverProperty = new ServerProperty(allOrigins, rpId, challenge, null);
|
||||
// check User Verification by considering a malicious user might modify the result of calling WebAuthn API
|
||||
boolean isUserVerificationRequired = policy.getUserVerificationRequirement().equals(WebAuthnConstants.OPTION_REQUIRED);
|
||||
boolean isUserVerificationRequired = policy.getUserVerificationRequirement().equals(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED);
|
||||
|
||||
final String transportsParam = params.getFirst(WebAuthnConstants.TRANSPORTS);
|
||||
|
||||
|
||||
@ -17,14 +17,13 @@
|
||||
|
||||
package org.keycloak.testsuite.webauthn.utils;
|
||||
|
||||
import org.keycloak.WebAuthnConstants;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.keycloak.models.Constants;
|
||||
|
||||
public enum PropertyRequirement {
|
||||
NOT_SPECIFIED(WebAuthnConstants.OPTION_NOT_SPECIFIED),
|
||||
YES("Yes"),
|
||||
NO("No");
|
||||
NOT_SPECIFIED(Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED),
|
||||
YES(Constants.WEBAUTHN_POLICY_OPTION_YES),
|
||||
NO(Constants.WEBAUTHN_POLICY_OPTION_NO);
|
||||
|
||||
private final String value;
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@ import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||
*/
|
||||
public class AppInitiatedActionWebAuthnTest extends AbstractAppInitiatedActionTest implements UseVirtualAuthenticators {
|
||||
|
||||
private VirtualAuthenticatorManager virtualManager;
|
||||
protected VirtualAuthenticatorManager virtualManager;
|
||||
|
||||
protected final String WEB_AUTHN_REGISTER_PROVIDER = isPasswordless() ? WebAuthnPasswordlessRegisterFactory.PROVIDER_ID : WebAuthnRegisterFactory.PROVIDER_ID;
|
||||
protected final String DEFAULT_USERNAME = "test-user@localhost";
|
||||
|
||||
@ -28,6 +28,7 @@ import org.keycloak.authentication.requiredactions.WebAuthnRegisterFactory;
|
||||
import org.keycloak.common.util.SecretGenerator;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.credential.WebAuthnCredentialModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
@ -52,8 +53,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.WebAuthnConstants.OPTION_DISCOURAGED;
|
||||
import static org.keycloak.WebAuthnConstants.OPTION_REQUIRED;
|
||||
import static org.keycloak.models.AuthenticationExecutionModel.Requirement.ALTERNATIVE;
|
||||
import static org.keycloak.models.AuthenticationExecutionModel.Requirement.REQUIRED;
|
||||
import static org.keycloak.testsuite.webauthn.utils.PropertyRequirement.NO;
|
||||
@ -387,9 +386,9 @@ public class WebAuthnIdlessTest extends AbstractWebAuthnVirtualTest {
|
||||
protected void setWebAuthnRealmSettings(boolean waRequireRK, boolean waRequireUV, boolean waplRequireRK, boolean waplRequireUV ) {
|
||||
|
||||
String waRequireRKString = waRequireRK ? YES.getValue() : NO.getValue();
|
||||
String waRequireUVString = waRequireUV ? OPTION_REQUIRED : OPTION_DISCOURAGED;
|
||||
String waRequireUVString = waRequireUV ? Constants.WEBAUTHN_POLICY_OPTION_REQUIRED : Constants.WEBAUTHN_POLICY_OPTION_DISCOURAGED;
|
||||
String waplRequireRKString = waplRequireRK ? YES.getValue() : NO.getValue();
|
||||
String waplRequireUVString = waplRequireUV ? OPTION_REQUIRED : OPTION_DISCOURAGED;
|
||||
String waplRequireUVString = waplRequireUV ? Constants.WEBAUTHN_POLICY_OPTION_REQUIRED : Constants.WEBAUTHN_POLICY_OPTION_DISCOURAGED;
|
||||
|
||||
RealmRepresentation realmRep = testRealm().toRepresentation();
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ package org.keycloak.testsuite.webauthn;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.WebAuthnConstants;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.credential.WebAuthnCredentialModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
@ -35,7 +36,6 @@ import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.WebAuthnConstants.OPTION_REQUIRED;
|
||||
import static org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions.DEFAULT;
|
||||
import static org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions.DEFAULT_RESIDENT_KEY;
|
||||
import static org.keycloak.testsuite.webauthn.utils.PropertyRequirement.YES;
|
||||
@ -53,14 +53,14 @@ public class WebAuthnPropertyTest extends AbstractWebAuthnVirtualTest {
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(YES.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED)
|
||||
.update()) {
|
||||
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData, notNullValue());
|
||||
assertThat(realmData.getRpEntityName(), is("localhost"));
|
||||
assertThat(realmData.getRequireResidentKey(), is(YES.getValue()));
|
||||
assertThat(realmData.getUserVerificationRequirement(), is(OPTION_REQUIRED));
|
||||
assertThat(realmData.getUserVerificationRequirement(), is(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED));
|
||||
|
||||
registerDefaultUser();
|
||||
|
||||
@ -111,14 +111,14 @@ public class WebAuthnPropertyTest extends AbstractWebAuthnVirtualTest {
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(YES.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED)
|
||||
.update()) {
|
||||
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData, notNullValue());
|
||||
assertThat(realmData.getRpEntityName(), is("localhost"));
|
||||
assertThat(realmData.getRequireResidentKey(), is(YES.getValue()));
|
||||
assertThat(realmData.getUserVerificationRequirement(), is(OPTION_REQUIRED));
|
||||
assertThat(realmData.getUserVerificationRequirement(), is(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED));
|
||||
|
||||
registerDefaultUser();
|
||||
|
||||
|
||||
@ -98,6 +98,10 @@ public abstract class AbstractWebAuthnAccountTest extends AbstractAuthTest imple
|
||||
}
|
||||
}
|
||||
|
||||
public VirtualAuthenticatorManager getVirtualAuthManager() {
|
||||
return webAuthnManager;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void navigateBeforeTest() {
|
||||
driver.manage().window().setSize(new Dimension(1920, 1080));
|
||||
|
||||
@ -27,6 +27,7 @@ import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.testsuite.arquillian.annotation.IgnoreBrowserDriver;
|
||||
import org.keycloak.testsuite.page.AbstractPatternFlyAlert;
|
||||
import org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions;
|
||||
import org.keycloak.testsuite.webauthn.pages.SigningInPage;
|
||||
import org.keycloak.testsuite.webauthn.pages.WebAuthnAuthenticatorsList;
|
||||
import org.keycloak.testsuite.webauthn.updaters.AbstractWebAuthnRealmUpdater;
|
||||
@ -87,12 +88,15 @@ public class WebAuthnSigningInTest extends AbstractWebAuthnAccountTest {
|
||||
@Test
|
||||
@IgnoreBrowserDriver(FirefoxDriver.class) // See https://github.com/keycloak/keycloak/issues/10368
|
||||
public void passwordlessWebAuthnTest() {
|
||||
getVirtualAuthManager().useAuthenticator(DefaultVirtualAuthOptions.DEFAULT_RESIDENT_KEY.getOptions());
|
||||
testWebAuthn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreBrowserDriver(FirefoxDriver.class) // See https://github.com/keycloak/keycloak/issues/10368
|
||||
public void createWebAuthnSameUserLabel() {
|
||||
getVirtualAuthManager().useAuthenticator(DefaultVirtualAuthOptions.DEFAULT_RESIDENT_KEY.getOptions());
|
||||
|
||||
final String SAME_LABEL = "key123";
|
||||
|
||||
SigningInPage.UserCredential webAuthn = addWebAuthnCredential(SAME_LABEL, false);
|
||||
@ -118,6 +122,8 @@ public class WebAuthnSigningInTest extends AbstractWebAuthnAccountTest {
|
||||
@Test
|
||||
@IgnoreBrowserDriver(FirefoxDriver.class) // See https://github.com/keycloak/keycloak/issues/10368
|
||||
public void multipleSecurityKeys() {
|
||||
getVirtualAuthManager().useAuthenticator(DefaultVirtualAuthOptions.DEFAULT_RESIDENT_KEY.getOptions());
|
||||
|
||||
final String LABEL = "SecurityKey#";
|
||||
|
||||
List<SigningInPage.UserCredential> createdCredentials = new ArrayList<>();
|
||||
@ -175,6 +181,7 @@ public class WebAuthnSigningInTest extends AbstractWebAuthnAccountTest {
|
||||
@Test
|
||||
@IgnoreBrowserDriver(FirefoxDriver.class) // See https://github.com/keycloak/keycloak/issues/10368
|
||||
public void avoidSameAuthenticatorRegisterPasswordless() throws IOException {
|
||||
getVirtualAuthManager().useAuthenticator(DefaultVirtualAuthOptions.DEFAULT_RESIDENT_KEY.getOptions());
|
||||
avoidSameAuthenticatorRegister(new PasswordLessRealmAttributeUpdater(testRealmResource()), webAuthnPwdlessCredentialType);
|
||||
}
|
||||
|
||||
@ -212,6 +219,8 @@ public class WebAuthnSigningInTest extends AbstractWebAuthnAccountTest {
|
||||
@Test
|
||||
@IgnoreBrowserDriver(FirefoxDriver.class) // See https://github.com/keycloak/keycloak/issues/10368
|
||||
public void notDisplayAvailableAuthenticatorsPasswordless() {
|
||||
getVirtualAuthManager().useAuthenticator(DefaultVirtualAuthOptions.DEFAULT_RESIDENT_KEY.getOptions());
|
||||
|
||||
addWebAuthnCredential("authenticator#1", true);
|
||||
addWebAuthnCredential("authenticator#2", true);
|
||||
|
||||
|
||||
@ -17,13 +17,25 @@
|
||||
|
||||
package org.keycloak.testsuite.webauthn.passwordless;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.keycloak.testsuite.util.BrowserDriverUtil;
|
||||
import org.keycloak.testsuite.webauthn.AbstractWebAuthnVirtualTest;
|
||||
import org.keycloak.testsuite.webauthn.AppInitiatedActionWebAuthnSkipIfExistsTest;
|
||||
import org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions;
|
||||
|
||||
/**
|
||||
* @author rmartinc
|
||||
*/
|
||||
public class AppInitiatedActionPwdLessSkipIfExistsTest extends AppInitiatedActionWebAuthnSkipIfExistsTest {
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUpVirtualAuthenticator() {
|
||||
if (!BrowserDriverUtil.isDriverFirefox(driver)) {
|
||||
virtualManager = AbstractWebAuthnVirtualTest.createDefaultVirtualManager(driver, DefaultVirtualAuthOptions.DEFAULT_RESIDENT_KEY.getOptions());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPasswordless() {
|
||||
return true;
|
||||
|
||||
@ -17,13 +17,25 @@
|
||||
|
||||
package org.keycloak.testsuite.webauthn.passwordless;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.keycloak.testsuite.util.BrowserDriverUtil;
|
||||
import org.keycloak.testsuite.webauthn.AbstractWebAuthnVirtualTest;
|
||||
import org.keycloak.testsuite.webauthn.AppInitiatedActionWebAuthnTest;
|
||||
import org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class AppInitiatedActionPwdLessTest extends AppInitiatedActionWebAuthnTest {
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUpVirtualAuthenticator() {
|
||||
if (!BrowserDriverUtil.isDriverFirefox(driver)) {
|
||||
virtualManager = AbstractWebAuthnVirtualTest.createDefaultVirtualManager(driver, DefaultVirtualAuthOptions.DEFAULT_RESIDENT_KEY.getOptions());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPasswordless() {
|
||||
return true;
|
||||
|
||||
@ -38,7 +38,6 @@ import org.keycloak.testsuite.pages.PageUtils;
|
||||
import org.keycloak.testsuite.util.WaitUtils;
|
||||
import org.keycloak.testsuite.webauthn.AbstractWebAuthnVirtualTest;
|
||||
import org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions;
|
||||
import org.keycloak.testsuite.webauthn.utils.PropertyRequirement;
|
||||
import org.openqa.selenium.firefox.FirefoxDriver;
|
||||
|
||||
/**
|
||||
@ -72,11 +71,11 @@ public class PasskeysConditionalUITest extends AbstractWebAuthnVirtualTest {
|
||||
// set passwordless policy for discoverable keys
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.YES.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.WEBAUTHN_POLICY_OPTION_YES)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED)
|
||||
.update()) {
|
||||
|
||||
checkWebAuthnConfiguration(PropertyRequirement.YES.getValue(), WebAuthnConstants.OPTION_REQUIRED);
|
||||
checkWebAuthnConfiguration(Constants.WEBAUTHN_POLICY_OPTION_YES, Constants.WEBAUTHN_POLICY_OPTION_REQUIRED);
|
||||
|
||||
registerDefaultUser();
|
||||
|
||||
@ -107,8 +106,8 @@ public class PasskeysConditionalUITest extends AbstractWebAuthnVirtualTest {
|
||||
// set passwordless policy not specified, key will not be discoverable
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.NOT_SPECIFIED.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED)
|
||||
.update()) {
|
||||
|
||||
checkWebAuthnConfiguration(Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED, Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED);
|
||||
|
||||
@ -28,6 +28,7 @@ import org.keycloak.common.Profile;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.credential.WebAuthnCredentialModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.organization.authentication.authenticators.browser.OrganizationAuthenticatorFactory;
|
||||
@ -42,11 +43,9 @@ import org.keycloak.testsuite.admin.AbstractAdminTest;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.arquillian.annotation.IgnoreBrowserDriver;
|
||||
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
||||
import org.keycloak.testsuite.util.WaitUtils;
|
||||
import org.keycloak.testsuite.webauthn.AbstractWebAuthnVirtualTest;
|
||||
import org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions;
|
||||
import org.keycloak.testsuite.webauthn.utils.PropertyRequirement;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.firefox.FirefoxDriver;
|
||||
@ -90,12 +89,12 @@ public class PasskeysOrganizationAuthenticationTest extends AbstractWebAuthnVirt
|
||||
// set passwordless policy for discoverable keys
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.YES.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.WEBAUTHN_POLICY_OPTION_YES)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
|
||||
.update()) {
|
||||
|
||||
checkWebAuthnConfiguration(PropertyRequirement.YES.getValue(), WebAuthnConstants.OPTION_REQUIRED);
|
||||
checkWebAuthnConfiguration(Constants.WEBAUTHN_POLICY_OPTION_YES, Constants.WEBAUTHN_POLICY_OPTION_REQUIRED);
|
||||
|
||||
registerDefaultUser();
|
||||
|
||||
@ -141,12 +140,12 @@ public class PasskeysOrganizationAuthenticationTest extends AbstractWebAuthnVirt
|
||||
// set passwordless policy for discoverable keys
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.YES.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.WEBAUTHN_POLICY_OPTION_YES)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
|
||||
.update()) {
|
||||
|
||||
checkWebAuthnConfiguration(PropertyRequirement.YES.getValue(), WebAuthnConstants.OPTION_REQUIRED);
|
||||
checkWebAuthnConfiguration(Constants.WEBAUTHN_POLICY_OPTION_YES, Constants.WEBAUTHN_POLICY_OPTION_REQUIRED);
|
||||
|
||||
registerDefaultUser();
|
||||
|
||||
@ -172,8 +171,8 @@ public class PasskeysOrganizationAuthenticationTest extends AbstractWebAuthnVirt
|
||||
// set passwordless policy not specified, key will not be discoverable
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.NOT_SPECIFIED.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
|
||||
.update()) {
|
||||
|
||||
@ -227,12 +226,12 @@ public class PasskeysOrganizationAuthenticationTest extends AbstractWebAuthnVirt
|
||||
// set passwordless policy for discoverable keys
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.YES.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.WEBAUTHN_POLICY_OPTION_YES)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
|
||||
.update()) {
|
||||
|
||||
checkWebAuthnConfiguration(PropertyRequirement.YES.getValue(), WebAuthnConstants.OPTION_REQUIRED);
|
||||
checkWebAuthnConfiguration(Constants.WEBAUTHN_POLICY_OPTION_YES, Constants.WEBAUTHN_POLICY_OPTION_REQUIRED);
|
||||
|
||||
registerDefaultUser();
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.models.credential.WebAuthnCredentialModel;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
|
||||
@ -45,7 +46,6 @@ import org.keycloak.testsuite.arquillian.annotation.IgnoreBrowserDriver;
|
||||
import org.keycloak.testsuite.util.WaitUtils;
|
||||
import org.keycloak.testsuite.webauthn.AbstractWebAuthnVirtualTest;
|
||||
import org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions;
|
||||
import org.keycloak.testsuite.webauthn.utils.PropertyRequirement;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.firefox.FirefoxDriver;
|
||||
@ -114,12 +114,12 @@ public class PasskeysUsernameFormTest extends AbstractWebAuthnVirtualTest {
|
||||
// set passwordless policy for discoverable keys
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.YES.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.WEBAUTHN_POLICY_OPTION_YES)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
|
||||
.update()) {
|
||||
|
||||
checkWebAuthnConfiguration(PropertyRequirement.YES.getValue(), WebAuthnConstants.OPTION_REQUIRED);
|
||||
checkWebAuthnConfiguration(Constants.WEBAUTHN_POLICY_OPTION_YES, Constants.WEBAUTHN_POLICY_OPTION_REQUIRED);
|
||||
|
||||
registerDefaultUser();
|
||||
|
||||
@ -162,8 +162,8 @@ public class PasskeysUsernameFormTest extends AbstractWebAuthnVirtualTest {
|
||||
// set passwordless policy not specified, key will not be discoverable
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.NOT_SPECIFIED.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
|
||||
.update()) {
|
||||
registerDefaultUser();
|
||||
@ -217,12 +217,12 @@ public class PasskeysUsernameFormTest extends AbstractWebAuthnVirtualTest {
|
||||
// set passwordless policy for discoverable keys
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.YES.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.WEBAUTHN_POLICY_OPTION_YES)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
|
||||
.update()) {
|
||||
|
||||
checkWebAuthnConfiguration(PropertyRequirement.YES.getValue(), WebAuthnConstants.OPTION_REQUIRED);
|
||||
checkWebAuthnConfiguration(Constants.WEBAUTHN_POLICY_OPTION_YES, Constants.WEBAUTHN_POLICY_OPTION_REQUIRED);
|
||||
|
||||
registerDefaultUser();
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ import org.keycloak.common.Profile;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.credential.WebAuthnCredentialModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
@ -40,7 +41,6 @@ import org.keycloak.testsuite.pages.SelectOrganizationPage;
|
||||
import org.keycloak.testsuite.util.WaitUtils;
|
||||
import org.keycloak.testsuite.webauthn.AbstractWebAuthnVirtualTest;
|
||||
import org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions;
|
||||
import org.keycloak.testsuite.webauthn.utils.PropertyRequirement;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.firefox.FirefoxDriver;
|
||||
|
||||
@ -77,12 +77,12 @@ public class PasskeysUsernamePasswordFormTest extends AbstractWebAuthnVirtualTes
|
||||
// set passwordless policy for discoverable keys
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.YES.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyRequireResidentKey(null)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(null)
|
||||
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
|
||||
.update()) {
|
||||
|
||||
checkWebAuthnConfiguration(PropertyRequirement.YES.getValue(), WebAuthnConstants.OPTION_REQUIRED);
|
||||
checkWebAuthnConfiguration(Constants.WEBAUTHN_POLICY_OPTION_YES, Constants.WEBAUTHN_POLICY_OPTION_REQUIRED);
|
||||
|
||||
registerDefaultUser();
|
||||
|
||||
@ -116,8 +116,8 @@ public class PasskeysUsernamePasswordFormTest extends AbstractWebAuthnVirtualTes
|
||||
// set passwordless policy not specified, key will not be discoverable
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.NOT_SPECIFIED.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED)
|
||||
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
|
||||
.update()) {
|
||||
registerDefaultUser();
|
||||
@ -166,12 +166,12 @@ public class PasskeysUsernamePasswordFormTest extends AbstractWebAuthnVirtualTes
|
||||
// set passwordless policy for discoverable keys
|
||||
try (Closeable c = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRpEntityName("localhost")
|
||||
.setWebAuthnPolicyRequireResidentKey(PropertyRequirement.YES.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(WebAuthnConstants.OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyRequireResidentKey(Constants.WEBAUTHN_POLICY_OPTION_YES)
|
||||
.setWebAuthnPolicyUserVerificationRequirement(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED)
|
||||
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
|
||||
.update()) {
|
||||
|
||||
checkWebAuthnConfiguration(PropertyRequirement.YES.getValue(), WebAuthnConstants.OPTION_REQUIRED);
|
||||
checkWebAuthnConfiguration(Constants.WEBAUTHN_POLICY_OPTION_YES, Constants.WEBAUTHN_POLICY_OPTION_REQUIRED);
|
||||
|
||||
registerDefaultUser();
|
||||
|
||||
|
||||
@ -35,8 +35,8 @@ import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.WebAuthnConstants.OPTION_REQUIRED;
|
||||
import static org.keycloak.models.Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
import static org.keycloak.models.Constants.WEBAUTHN_POLICY_OPTION_REQUIRED;
|
||||
import static org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions.DEFAULT_RESIDENT_KEY;
|
||||
|
||||
/**
|
||||
@ -70,7 +70,7 @@ public class ResidentKeyRegisterTest extends AbstractWebAuthnVirtualTest {
|
||||
|
||||
if (hasResidentKey) {
|
||||
getVirtualAuthManager().useAuthenticator(DEFAULT_RESIDENT_KEY.getOptions());
|
||||
userVerification = OPTION_REQUIRED;
|
||||
userVerification = WEBAUTHN_POLICY_OPTION_REQUIRED;
|
||||
} else {
|
||||
userVerification = DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user