From 6f992915d737ff71b63b9a809b27fae29d6f66f3 Mon Sep 17 00:00:00 2001 From: mposolda Date: Mon, 30 Oct 2023 14:46:10 +0100 Subject: [PATCH] Move some UserProfile and Validation classes into keycloak-server-spi closes #24387 --- .../org/keycloak/validate/Validators.java | 240 ------------------ .../validators/ValidatorConfigValidator.java | 2 +- .../org.keycloak.validate.ValidatorFactory | 3 +- .../userprofile/AttributeContext.java | 0 .../userprofile/AttributeGroupMetadata.java | 0 .../userprofile/AttributeMetadata.java | 0 .../AttributeValidatorMetadata.java | 0 .../org/keycloak/userprofile/Attributes.java | 0 ...UserProfileAttributeValidationContext.java | 0 .../userprofile/UserProfileContext.java | 0 .../userprofile/UserProfileMetadata.java | 0 .../validate/AbstractSimpleValidator.java | 0 .../validate/AbstractStringValidator.java | 0 .../keycloak/validate/SimpleValidator.java | 0 .../keycloak/validate/ValidationContext.java | 0 .../keycloak/validate/ValidationError.java | 0 .../keycloak/validate/ValidationResult.java | 0 .../java/org/keycloak/validate/Validator.java | 35 +-- .../keycloak/validate/ValidatorConfig.java | 0 .../keycloak/validate/ValidatorFactory.java | 0 .../org/keycloak/validate/ValidatorSPI.java | 0 .../org/keycloak/validate/Validators.java | 131 ++++++++++ .../ImmutableAttributeValidator.java | 7 +- .../validation}/BuiltinValidatorsTest.java | 122 ++++++--- .../validation/SimpleValidators.java | 82 ++++++ .../testsuite/validation/ValidatorTest.java | 18 +- .../testsuite/validation/ValidatorsTest.java | 107 +++++--- 27 files changed, 396 insertions(+), 351 deletions(-) delete mode 100644 server-spi-private/src/main/java/org/keycloak/validate/Validators.java rename {server-spi-private => server-spi}/src/main/java/org/keycloak/userprofile/AttributeContext.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/userprofile/AttributeGroupMetadata.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/userprofile/AttributeMetadata.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/userprofile/AttributeValidatorMetadata.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/userprofile/Attributes.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/userprofile/UserProfileAttributeValidationContext.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/userprofile/UserProfileContext.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/userprofile/UserProfileMetadata.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/validate/AbstractSimpleValidator.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/validate/AbstractStringValidator.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/validate/SimpleValidator.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/validate/ValidationContext.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/validate/ValidationError.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/validate/ValidationResult.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/validate/Validator.java (75%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/validate/ValidatorConfig.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/validate/ValidatorFactory.java (100%) rename {server-spi-private => server-spi}/src/main/java/org/keycloak/validate/ValidatorSPI.java (100%) create mode 100644 server-spi/src/main/java/org/keycloak/validate/Validators.java rename {server-spi-private/src/test/java/org/keycloak/validate => testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation}/BuiltinValidatorsTest.java (81%) create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/SimpleValidators.java rename server-spi-private/src/test/java/org/keycloak/validate/ValidatorTest.java => testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/ValidatorsTest.java (76%) diff --git a/server-spi-private/src/main/java/org/keycloak/validate/Validators.java b/server-spi-private/src/main/java/org/keycloak/validate/Validators.java deleted file mode 100644 index 2311a77980..0000000000 --- a/server-spi-private/src/main/java/org/keycloak/validate/Validators.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2021 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.validate; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.validate.validators.LocalDateValidator; -import org.keycloak.validate.validators.EmailValidator; -import org.keycloak.validate.validators.IntegerValidator; -import org.keycloak.validate.validators.LengthValidator; -import org.keycloak.validate.validators.NotBlankValidator; -import org.keycloak.validate.validators.NotEmptyValidator; -import org.keycloak.validate.validators.OptionsValidator; -import org.keycloak.validate.validators.DoubleValidator; -import org.keycloak.validate.validators.PatternValidator; -import org.keycloak.validate.validators.UriValidator; -import org.keycloak.validate.validators.ValidatorConfigValidator; - -/** - * Facade for Validation functions with support for {@link Validator} implementation lookup by id. - */ -public class Validators { - - /** - * Holds a mapping of internal {@link SimpleValidator} to allow look-up via provider id. - */ - private static final Map INTERNAL_VALIDATORS; - - static { - List list = Arrays.asList( - LengthValidator.INSTANCE, - NotEmptyValidator.INSTANCE, - UriValidator.INSTANCE, - EmailValidator.INSTANCE, - NotBlankValidator.INSTANCE, - PatternValidator.INSTANCE, - DoubleValidator.INSTANCE, - IntegerValidator.INSTANCE, - ValidatorConfigValidator.INSTANCE, - OptionsValidator.INSTANCE - ); - - INTERNAL_VALIDATORS = list.stream().collect(Collectors.toMap(SimpleValidator::getId, v -> v)); - } - - /** - * Holds the {@link KeycloakSession}. - */ - private final KeycloakSession session; - - /** - * Creates a new {@link Validators} instance with the given {@link KeycloakSession}. - * - * @param session - */ - public Validators(KeycloakSession session) { - this.session = session; - } - - /** - * Look-up for a built-in or registered {@link Validator} with the given provider {@code id}. - * - * @param id - * @return - * @see #validator(KeycloakSession, String) - */ - public Validator validator(String id) { - return validator(session, id); - } - - /** - * Look-up for a built-in or registered {@link ValidatorFactory} with the given provider {@code id}. - * - * @param id - * @return - * @see #validatorFactory(KeycloakSession, String) - */ - public ValidatorFactory validatorFactory(String id) { - return validatorFactory(session, id); - } - - /** - * Validates the {@link ValidatorConfig} of {@link Validator} referenced by the given provider {@code id}. - * - * @param id - * @param config - * @return - * @see #validateConfig(KeycloakSession, String, ValidatorConfig) - */ - public ValidationResult validateConfig(String id, ValidatorConfig config) { - return validateConfig(session, id, config); - } - - /* static import friendly accessor methods for built-in validators */ - - public static Validator getInternalValidatorById(String id) { - return INTERNAL_VALIDATORS.get(id); - } - - public static ValidatorFactory getInternalValidatorFactoryById(String id) { - return INTERNAL_VALIDATORS.get(id); - } - - public static Map getInternalValidators() { - return Collections.unmodifiableMap(INTERNAL_VALIDATORS); - } - - public static NotBlankValidator notBlankValidator() { - return NotBlankValidator.INSTANCE; - } - - public static NotEmptyValidator notEmptyValidator() { - return NotEmptyValidator.INSTANCE; - } - - public static LengthValidator lengthValidator() { - return LengthValidator.INSTANCE; - } - - public static UriValidator uriValidator() { - return UriValidator.INSTANCE; - } - - public static EmailValidator emailValidator() { - return EmailValidator.INSTANCE; - } - - public static PatternValidator patternValidator() { - return PatternValidator.INSTANCE; - } - - public static DoubleValidator doubleValidator() { - return DoubleValidator.INSTANCE; - } - - public static IntegerValidator integerValidator() { - return IntegerValidator.INSTANCE; - } - - public static LocalDateValidator dateValidator() { - return LocalDateValidator.INSTANCE; - } - - public static OptionsValidator optionsValidator() { - return OptionsValidator.INSTANCE; - } - - public static ValidatorConfigValidator validatorConfigValidator() { - return ValidatorConfigValidator.INSTANCE; - } - - /** - * Look-up up for a built-in or registered {@link Validator} with the given validatorId. - * - * @param session the {@link KeycloakSession} - * @param id the id of the validator - * @return the {@link Validator} or {@literal null} - */ - public static Validator validator(KeycloakSession session, String id) { - - // Fast-path for internal Validators - Validator validator = getInternalValidatorById(id); - if (validator != null) { - return validator; - } - - if (session == null) { - return null; - } - - // Lookup validator in registry - return session.getProvider(Validator.class, id); - } - - /** - * Look-up for a built-in or registered {@link ValidatorFactory} with the given validatorId. - *

- * This is intended for users who want to dynamically create new {@link Validator} instances, validate - * {@link ValidatorConfig} configurations or create default configurations for a {@link Validator}. - * - * @param session the {@link KeycloakSession} - * @param id the id of the validator - * @return the {@link Validator} or {@literal null} - */ - public static ValidatorFactory validatorFactory(KeycloakSession session, String id) { - - // Fast-path for internal Validators - ValidatorFactory factory = getInternalValidatorFactoryById(id); - if (factory != null) { - return factory; - } - - if (session == null) { - return null; - } - - // Lookup factory in registry - KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); - return (ValidatorFactory) sessionFactory.getProviderFactory(Validator.class, id); - } - - /** - * Validates the {@link ValidatorConfig} of {@link Validator} referenced by the given provider {@code id}. - * - * @param session - * @param id of the validator - * @param config to be validated - * @return - */ - public static ValidationResult validateConfig(KeycloakSession session, String id, ValidatorConfig config) { - - ValidatorFactory validatorFactory = validatorFactory(session, id); - if (validatorFactory != null) { - return validatorFactory.validateConfig(session, config); - } - - // We could not find a ValidationFactory to validate that config, so we assume the config is valid. - return ValidationResult.OK; - } -} diff --git a/server-spi-private/src/main/java/org/keycloak/validate/validators/ValidatorConfigValidator.java b/server-spi-private/src/main/java/org/keycloak/validate/validators/ValidatorConfigValidator.java index 1eb3144b6b..a496318347 100644 --- a/server-spi-private/src/main/java/org/keycloak/validate/validators/ValidatorConfigValidator.java +++ b/server-spi-private/src/main/java/org/keycloak/validate/validators/ValidatorConfigValidator.java @@ -57,7 +57,7 @@ public class ValidatorConfigValidator implements SimpleValidator { public static final ValidatorConfigValidator INSTANCE = new ValidatorConfigValidator(); - private ValidatorConfigValidator() { + public ValidatorConfigValidator() { } @Override diff --git a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.validate.ValidatorFactory b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.validate.ValidatorFactory index 5694637d68..560a8b68b0 100644 --- a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.validate.ValidatorFactory +++ b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.validate.ValidatorFactory @@ -7,4 +7,5 @@ org.keycloak.validate.validators.PatternValidator org.keycloak.validate.validators.DoubleValidator org.keycloak.validate.validators.IntegerValidator org.keycloak.validate.validators.LocalDateValidator -org.keycloak.validate.validators.OptionsValidator \ No newline at end of file +org.keycloak.validate.validators.OptionsValidator +org.keycloak.validate.validators.ValidatorConfigValidator diff --git a/server-spi-private/src/main/java/org/keycloak/userprofile/AttributeContext.java b/server-spi/src/main/java/org/keycloak/userprofile/AttributeContext.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/userprofile/AttributeContext.java rename to server-spi/src/main/java/org/keycloak/userprofile/AttributeContext.java diff --git a/server-spi-private/src/main/java/org/keycloak/userprofile/AttributeGroupMetadata.java b/server-spi/src/main/java/org/keycloak/userprofile/AttributeGroupMetadata.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/userprofile/AttributeGroupMetadata.java rename to server-spi/src/main/java/org/keycloak/userprofile/AttributeGroupMetadata.java diff --git a/server-spi-private/src/main/java/org/keycloak/userprofile/AttributeMetadata.java b/server-spi/src/main/java/org/keycloak/userprofile/AttributeMetadata.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/userprofile/AttributeMetadata.java rename to server-spi/src/main/java/org/keycloak/userprofile/AttributeMetadata.java diff --git a/server-spi-private/src/main/java/org/keycloak/userprofile/AttributeValidatorMetadata.java b/server-spi/src/main/java/org/keycloak/userprofile/AttributeValidatorMetadata.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/userprofile/AttributeValidatorMetadata.java rename to server-spi/src/main/java/org/keycloak/userprofile/AttributeValidatorMetadata.java diff --git a/server-spi-private/src/main/java/org/keycloak/userprofile/Attributes.java b/server-spi/src/main/java/org/keycloak/userprofile/Attributes.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/userprofile/Attributes.java rename to server-spi/src/main/java/org/keycloak/userprofile/Attributes.java diff --git a/server-spi-private/src/main/java/org/keycloak/userprofile/UserProfileAttributeValidationContext.java b/server-spi/src/main/java/org/keycloak/userprofile/UserProfileAttributeValidationContext.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/userprofile/UserProfileAttributeValidationContext.java rename to server-spi/src/main/java/org/keycloak/userprofile/UserProfileAttributeValidationContext.java diff --git a/server-spi-private/src/main/java/org/keycloak/userprofile/UserProfileContext.java b/server-spi/src/main/java/org/keycloak/userprofile/UserProfileContext.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/userprofile/UserProfileContext.java rename to server-spi/src/main/java/org/keycloak/userprofile/UserProfileContext.java diff --git a/server-spi-private/src/main/java/org/keycloak/userprofile/UserProfileMetadata.java b/server-spi/src/main/java/org/keycloak/userprofile/UserProfileMetadata.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/userprofile/UserProfileMetadata.java rename to server-spi/src/main/java/org/keycloak/userprofile/UserProfileMetadata.java diff --git a/server-spi-private/src/main/java/org/keycloak/validate/AbstractSimpleValidator.java b/server-spi/src/main/java/org/keycloak/validate/AbstractSimpleValidator.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/validate/AbstractSimpleValidator.java rename to server-spi/src/main/java/org/keycloak/validate/AbstractSimpleValidator.java diff --git a/server-spi-private/src/main/java/org/keycloak/validate/AbstractStringValidator.java b/server-spi/src/main/java/org/keycloak/validate/AbstractStringValidator.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/validate/AbstractStringValidator.java rename to server-spi/src/main/java/org/keycloak/validate/AbstractStringValidator.java diff --git a/server-spi-private/src/main/java/org/keycloak/validate/SimpleValidator.java b/server-spi/src/main/java/org/keycloak/validate/SimpleValidator.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/validate/SimpleValidator.java rename to server-spi/src/main/java/org/keycloak/validate/SimpleValidator.java diff --git a/server-spi-private/src/main/java/org/keycloak/validate/ValidationContext.java b/server-spi/src/main/java/org/keycloak/validate/ValidationContext.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/validate/ValidationContext.java rename to server-spi/src/main/java/org/keycloak/validate/ValidationContext.java diff --git a/server-spi-private/src/main/java/org/keycloak/validate/ValidationError.java b/server-spi/src/main/java/org/keycloak/validate/ValidationError.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/validate/ValidationError.java rename to server-spi/src/main/java/org/keycloak/validate/ValidationError.java diff --git a/server-spi-private/src/main/java/org/keycloak/validate/ValidationResult.java b/server-spi/src/main/java/org/keycloak/validate/ValidationResult.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/validate/ValidationResult.java rename to server-spi/src/main/java/org/keycloak/validate/ValidationResult.java diff --git a/server-spi-private/src/main/java/org/keycloak/validate/Validator.java b/server-spi/src/main/java/org/keycloak/validate/Validator.java similarity index 75% rename from server-spi-private/src/main/java/org/keycloak/validate/Validator.java rename to server-spi/src/main/java/org/keycloak/validate/Validator.java index dfd08a7652..41e3042605 100644 --- a/server-spi-private/src/main/java/org/keycloak/validate/Validator.java +++ b/server-spi/src/main/java/org/keycloak/validate/Validator.java @@ -1,18 +1,20 @@ /* - * Copyright 2021 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. + * Copyright 2023 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 + * 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 + * 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. * - * 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.validate; @@ -40,17 +42,6 @@ public interface Validator extends Provider { return validate(input, "input", new ValidationContext(), ValidatorConfig.EMPTY); } - /** - * Validates the given {@code input} with an additional {@code config}. - * - * @param input the value to validate - * @param config parameterization for the current validation - * @return the validation context with the outcome of the validation - */ - default ValidationContext validate(Object input, ValidatorConfig config) { - return validate(input, "input", new ValidationContext(), config); - } - /** * Validates the given {@code input}. * diff --git a/server-spi-private/src/main/java/org/keycloak/validate/ValidatorConfig.java b/server-spi/src/main/java/org/keycloak/validate/ValidatorConfig.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/validate/ValidatorConfig.java rename to server-spi/src/main/java/org/keycloak/validate/ValidatorConfig.java diff --git a/server-spi-private/src/main/java/org/keycloak/validate/ValidatorFactory.java b/server-spi/src/main/java/org/keycloak/validate/ValidatorFactory.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/validate/ValidatorFactory.java rename to server-spi/src/main/java/org/keycloak/validate/ValidatorFactory.java diff --git a/server-spi-private/src/main/java/org/keycloak/validate/ValidatorSPI.java b/server-spi/src/main/java/org/keycloak/validate/ValidatorSPI.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/validate/ValidatorSPI.java rename to server-spi/src/main/java/org/keycloak/validate/ValidatorSPI.java diff --git a/server-spi/src/main/java/org/keycloak/validate/Validators.java b/server-spi/src/main/java/org/keycloak/validate/Validators.java new file mode 100644 index 0000000000..07d62d81fd --- /dev/null +++ b/server-spi/src/main/java/org/keycloak/validate/Validators.java @@ -0,0 +1,131 @@ +/* + * Copyright 2023 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.validate; + +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; + +/** + * Facade for Validation functions with support for {@link Validator} implementation lookup by id. + */ +public class Validators { + + /** + * Holds the {@link KeycloakSession}. + */ + private final KeycloakSession session; + + /** + * Creates a new {@link Validators} instance with the given {@link KeycloakSession}. + * + * @param session + */ + public Validators(KeycloakSession session) { + this.session = session; + } + + /** + * Look-up for a built-in or registered {@link Validator} with the given provider {@code id}. + * + * @param id + * @return + * @see #validator(KeycloakSession, String) + */ + public Validator validator(String id) { + return validator(session, id); + } + + /** + * Look-up for a built-in or registered {@link ValidatorFactory} with the given provider {@code id}. + * + * @param id + * @return + * @see #validatorFactory(KeycloakSession, String) + */ + public ValidatorFactory validatorFactory(String id) { + return validatorFactory(session, id); + } + + /** + * Validates the {@link ValidatorConfig} of {@link Validator} referenced by the given provider {@code id}. + * + * @param id + * @param config + * @return + * @see #validateConfig(KeycloakSession, String, ValidatorConfig) + */ + public ValidationResult validateConfig(String id, ValidatorConfig config) { + return validateConfig(session, id, config); + } + + /** + * Look-up up for a built-in or registered {@link Validator} with the given validatorId. + * + * @param session the {@link KeycloakSession} + * @param id the id of the validator + * @return the {@link Validator} or {@literal null} + */ + public static Validator validator(KeycloakSession session, String id) { + if (session == null) { + throw new IllegalArgumentException("KeycloakSession must be not null"); + } + + // Lookup validator in registry + return session.getProvider(Validator.class, id); + } + + /** + * Look-up for a built-in or registered {@link ValidatorFactory} with the given validatorId. + *

+ * This is intended for users who want to dynamically create new {@link Validator} instances, validate + * {@link ValidatorConfig} configurations or create default configurations for a {@link Validator}. + * + * @param session the {@link KeycloakSession} + * @param id the id of the validator + * @return the {@link Validator} or {@literal null} + */ + public static ValidatorFactory validatorFactory(KeycloakSession session, String id) { + if (session == null) { + throw new IllegalArgumentException("KeycloakSession must be not null"); + } + + // Lookup factory in registry + KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); + return (ValidatorFactory) sessionFactory.getProviderFactory(Validator.class, id); + } + + /** + * Validates the {@link ValidatorConfig} of {@link Validator} referenced by the given provider {@code id}. + * + * @param session + * @param id of the validator + * @param config to be validated + * @return + */ + public static ValidationResult validateConfig(KeycloakSession session, String id, ValidatorConfig config) { + + ValidatorFactory validatorFactory = validatorFactory(session, id); + if (validatorFactory != null) { + return validatorFactory.validateConfig(session, config); + } + + // We could not find a ValidationFactory to validate that config, so we assume the config is valid. + return ValidationResult.OK; + } +} diff --git a/services/src/main/java/org/keycloak/userprofile/validator/ImmutableAttributeValidator.java b/services/src/main/java/org/keycloak/userprofile/validator/ImmutableAttributeValidator.java index 3b588adbff..5fb4ec75e6 100644 --- a/services/src/main/java/org/keycloak/userprofile/validator/ImmutableAttributeValidator.java +++ b/services/src/main/java/org/keycloak/userprofile/validator/ImmutableAttributeValidator.java @@ -17,23 +17,20 @@ package org.keycloak.userprofile.validator; import static org.keycloak.common.util.CollectionUtil.collectionEquals; -import static org.keycloak.validate.Validators.notBlankValidator; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -import org.keycloak.common.util.CollectionUtil; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.userprofile.AttributeContext; -import org.keycloak.userprofile.AttributeValidatorMetadata; import org.keycloak.userprofile.UserProfileAttributeValidationContext; import org.keycloak.validate.SimpleValidator; import org.keycloak.validate.ValidationContext; import org.keycloak.validate.ValidationError; import org.keycloak.validate.ValidatorConfig; -import org.keycloak.validate.Validators; +import org.keycloak.validate.validators.NotBlankValidator; /** * A validator that fails when the attribute is marked as read only and its value has changed. @@ -65,7 +62,7 @@ public class ImmutableAttributeValidator implements SimpleValidator { List values = (List) input; if (!collectionEquals(currentValue, values) && isReadOnly(attributeContext)) { - if (currentValue.isEmpty() && !notBlankValidator().validate(values).isValid()) { + if (currentValue.isEmpty() && !NotBlankValidator.INSTANCE.validate(values).isValid()) { return context; } diff --git a/server-spi-private/src/test/java/org/keycloak/validate/BuiltinValidatorsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/BuiltinValidatorsTest.java similarity index 81% rename from server-spi-private/src/test/java/org/keycloak/validate/BuiltinValidatorsTest.java rename to testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/BuiltinValidatorsTest.java index 7bbacd4fc3..151d12349a 100644 --- a/server-spi-private/src/test/java/org/keycloak/validate/BuiltinValidatorsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/BuiltinValidatorsTest.java @@ -1,4 +1,23 @@ -package org.keycloak.validate; +/* + * Copyright 2023 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.testsuite.validation; import static org.keycloak.validate.ValidatorConfig.configFromMap; @@ -11,6 +30,17 @@ import java.util.regex.Pattern; import org.junit.Assert; import org.junit.Test; +import org.keycloak.models.KeycloakSession; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.AbstractKeycloakTest; +import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; +import org.keycloak.testsuite.arquillian.annotation.ModelTest; +import org.keycloak.validate.AbstractSimpleValidator; +import org.keycloak.validate.ValidationContext; +import org.keycloak.validate.ValidationError; +import org.keycloak.validate.ValidationResult; +import org.keycloak.validate.Validator; +import org.keycloak.validate.ValidatorConfig; import org.keycloak.validate.validators.DoubleValidator; import org.keycloak.validate.validators.EmailValidator; import org.keycloak.validate.validators.IntegerValidator; @@ -21,14 +51,18 @@ import org.keycloak.validate.validators.UriValidator; import com.google.common.collect.ImmutableMap; -public class BuiltinValidatorsTest { +public class BuiltinValidatorsTest extends AbstractKeycloakTest { private static final ValidatorConfig valConfigIgnoreEmptyValues = ValidatorConfig.builder().config(AbstractSimpleValidator.IGNORE_EMPTY_VALUE, true).build(); + @Override + public void addTestRealms(List testRealms) { + } + @Test public void testLengthValidator() { - Validator validator = Validators.lengthValidator(); + Validator validator = SimpleValidators.lengthValidator(); // null and empty values handling Assert.assertFalse(validator.validate(null, "name", configFromMap(ImmutableMap.of(LengthValidator.KEY_MIN, 1))).isValid()); @@ -84,12 +118,13 @@ public class BuiltinValidatorsTest { } @Test - public void testLengthValidator_ConfigValidation() { + @ModelTest + public void testLengthValidator_ConfigValidation(KeycloakSession session) { // invalid min and max config values ValidatorConfig config = new ValidatorConfig(ImmutableMap.of(LengthValidator.KEY_MIN, new Object(), LengthValidator.KEY_MAX, "invalid")); - ValidationResult result = Validators.validatorConfigValidator().validate(config, LengthValidator.ID).toResult(); + ValidationResult result = SimpleValidators.validatorConfigValidator().validate(config, LengthValidator.ID, new ValidationContext(session)).toResult(); Assert.assertFalse(result.isValid()); ValidationError[] errors = result.getErrors().toArray(new ValidationError[0]); @@ -105,25 +140,25 @@ public class BuiltinValidatorsTest { Assert.assertEquals(LengthValidator.KEY_MAX, error1.getInputHint()); // empty config - result = Validators.validatorConfigValidator().validate(null, LengthValidator.ID).toResult(); + result = SimpleValidators.validatorConfigValidator().validate(null, LengthValidator.ID, new ValidationContext(session)).toResult(); Assert.assertEquals(2, result.getErrors().size()); - result = Validators.validatorConfigValidator().validate(ValidatorConfig.EMPTY, LengthValidator.ID).toResult(); + result = SimpleValidators.validatorConfigValidator().validate(ValidatorConfig.EMPTY, LengthValidator.ID, new ValidationContext(session)).toResult(); Assert.assertEquals(2, result.getErrors().size()); // correct config - Assert.assertTrue(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(LengthValidator.KEY_MIN, "10")), LengthValidator.ID).toResult().isValid()); - Assert.assertTrue(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(LengthValidator.KEY_MAX, "10")), LengthValidator.ID).toResult().isValid()); - Assert.assertTrue(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(LengthValidator.KEY_MIN, "10", LengthValidator.KEY_MAX, "10")), LengthValidator.ID).toResult().isValid()); + Assert.assertTrue(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(LengthValidator.KEY_MIN, "10")), LengthValidator.ID, new ValidationContext(session)).toResult().isValid()); + Assert.assertTrue(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(LengthValidator.KEY_MAX, "10")), LengthValidator.ID, new ValidationContext(session)).toResult().isValid()); + Assert.assertTrue(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(LengthValidator.KEY_MIN, "10", LengthValidator.KEY_MAX, "10")), LengthValidator.ID, new ValidationContext(session)).toResult().isValid()); // max is smaller than min - Assert.assertFalse(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(LengthValidator.KEY_MIN, "10", LengthValidator.KEY_MAX, "9")), LengthValidator.ID).toResult().isValid()); + Assert.assertFalse(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(LengthValidator.KEY_MIN, "10", LengthValidator.KEY_MAX, "9")), LengthValidator.ID, new ValidationContext(session)).toResult().isValid()); } @Test public void testEmailValidator() { // this also validates StringFormatValidatorBase for simple values - Validator validator = Validators.emailValidator(); + Validator validator = SimpleValidators.emailValidator(); Assert.assertFalse(validator.validate(null, "email").isValid()); Assert.assertFalse(validator.validate("", "email").isValid()); @@ -156,7 +191,7 @@ public class BuiltinValidatorsTest { @Test public void testAbstractSimpleValidatorSupportForCollections() { - Validator validator = Validators.emailValidator(); + Validator validator = SimpleValidators.emailValidator(); List valuesCollection = new ArrayList<>(); @@ -180,7 +215,7 @@ public class BuiltinValidatorsTest { @Test public void testNotBlankValidator() { - Validator validator = Validators.notBlankValidator(); + Validator validator = SimpleValidators.notBlankValidator(); // simple String value Assert.assertTrue(validator.validate("tester", "username").isValid()); @@ -203,7 +238,7 @@ public class BuiltinValidatorsTest { @Test public void testNotEmptyValidator() { - Validator validator = Validators.notEmptyValidator(); + Validator validator = SimpleValidators.notEmptyValidator(); Assert.assertTrue(validator.validate("tester", "username").isValid()); Assert.assertTrue(validator.validate(" ", "username").isValid()); @@ -221,7 +256,7 @@ public class BuiltinValidatorsTest { @Test public void testDoubleValidator() { - Validator validator = Validators.doubleValidator(); + Validator validator = SimpleValidators.doubleValidator(); // null value and empty String Assert.assertFalse(validator.validate(null, "null").isValid()); @@ -285,12 +320,13 @@ public class BuiltinValidatorsTest { } @Test - public void testDoubleValidator_ConfigValidation() { + @ModelTest + public void testDoubleValidator_ConfigValidation(KeycloakSession session) { // invalid min and max config values ValidatorConfig config = new ValidatorConfig(ImmutableMap.of(DoubleValidator.KEY_MIN, new Object(), DoubleValidator.KEY_MAX, "invalid")); - ValidationResult result = Validators.validatorConfigValidator().validate(config, DoubleValidator.ID).toResult(); + ValidationResult result = SimpleValidators.validatorConfigValidator().validate(config, DoubleValidator.ID, new ValidationContext(session)).toResult(); Assert.assertFalse(result.isValid()); ValidationError[] errors = result.getErrors().toArray(new ValidationError[0]); @@ -306,23 +342,23 @@ public class BuiltinValidatorsTest { Assert.assertEquals(DoubleValidator.KEY_MAX, error1.getInputHint()); // empty config - result = Validators.validatorConfigValidator().validate(null, DoubleValidator.ID).toResult(); + result = SimpleValidators.validatorConfigValidator().validate(null, DoubleValidator.ID, new ValidationContext(session)).toResult(); Assert.assertEquals(0, result.getErrors().size()); - result = Validators.validatorConfigValidator().validate(ValidatorConfig.EMPTY, DoubleValidator.ID).toResult(); + result = SimpleValidators.validatorConfigValidator().validate(ValidatorConfig.EMPTY, DoubleValidator.ID, new ValidationContext(session)).toResult(); Assert.assertEquals(0, result.getErrors().size()); // correct config - Assert.assertTrue(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(DoubleValidator.KEY_MIN, "10.1")), DoubleValidator.ID).toResult().isValid()); - Assert.assertTrue(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(DoubleValidator.KEY_MAX, "10.1")), DoubleValidator.ID).toResult().isValid()); - Assert.assertTrue(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(DoubleValidator.KEY_MIN, "10.1", DoubleValidator.KEY_MAX, "11")), DoubleValidator.ID).toResult().isValid()); + Assert.assertTrue(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(DoubleValidator.KEY_MIN, "10.1")), DoubleValidator.ID, new ValidationContext(session)).toResult().isValid()); + Assert.assertTrue(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(DoubleValidator.KEY_MAX, "10.1")), DoubleValidator.ID, new ValidationContext(session)).toResult().isValid()); + Assert.assertTrue(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(DoubleValidator.KEY_MIN, "10.1", DoubleValidator.KEY_MAX, "11")), DoubleValidator.ID, new ValidationContext(session)).toResult().isValid()); // max is smaller than min - Assert.assertFalse(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(DoubleValidator.KEY_MIN, "10.1", DoubleValidator.KEY_MAX, "10.1")), DoubleValidator.ID).toResult().isValid()); + Assert.assertFalse(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(DoubleValidator.KEY_MIN, "10.1", DoubleValidator.KEY_MAX, "10.1")), DoubleValidator.ID, new ValidationContext(session)).toResult().isValid()); } @Test public void testIntegerValidator() { - Validator validator = Validators.integerValidator(); + Validator validator = SimpleValidators.integerValidator(); // null value and empty String Assert.assertFalse(validator.validate(null, "null").isValid()); @@ -387,12 +423,13 @@ public class BuiltinValidatorsTest { } @Test - public void testIntegerValidator_ConfigValidation() { + @ModelTest + public void testIntegerValidator_ConfigValidation(KeycloakSession session) { // invalid min and max config values ValidatorConfig config = new ValidatorConfig(ImmutableMap.of(IntegerValidator.KEY_MIN, new Object(), IntegerValidator.KEY_MAX, "invalid")); - ValidationResult result = Validators.validatorConfigValidator().validate(config, IntegerValidator.ID).toResult(); + ValidationResult result = SimpleValidators.validatorConfigValidator().validate(config, IntegerValidator.ID, new ValidationContext(session)).toResult(); Assert.assertFalse(result.isValid()); ValidationError[] errors = result.getErrors().toArray(new ValidationError[0]); @@ -408,24 +445,24 @@ public class BuiltinValidatorsTest { Assert.assertEquals(IntegerValidator.KEY_MAX, error1.getInputHint()); // empty config - result = Validators.validatorConfigValidator().validate(null, IntegerValidator.ID).toResult(); + result = SimpleValidators.validatorConfigValidator().validate(null, IntegerValidator.ID, new ValidationContext(session)).toResult(); Assert.assertEquals(0, result.getErrors().size()); - result = Validators.validatorConfigValidator().validate(ValidatorConfig.EMPTY, IntegerValidator.ID).toResult(); + result = SimpleValidators.validatorConfigValidator().validate(ValidatorConfig.EMPTY, IntegerValidator.ID, new ValidationContext(session)).toResult(); Assert.assertEquals(0, result.getErrors().size()); // correct config - Assert.assertTrue(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(IntegerValidator.KEY_MIN, "10")), IntegerValidator.ID).toResult().isValid()); - Assert.assertTrue(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(IntegerValidator.KEY_MAX, "10")), IntegerValidator.ID).toResult().isValid()); - Assert.assertTrue(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(IntegerValidator.KEY_MIN, "10", IntegerValidator.KEY_MAX, "11")), IntegerValidator.ID).toResult().isValid()); + Assert.assertTrue(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(IntegerValidator.KEY_MIN, "10")), IntegerValidator.ID, new ValidationContext(session)).toResult().isValid()); + Assert.assertTrue(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(IntegerValidator.KEY_MAX, "10")), IntegerValidator.ID, new ValidationContext(session)).toResult().isValid()); + Assert.assertTrue(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(IntegerValidator.KEY_MIN, "10", IntegerValidator.KEY_MAX, "11")), IntegerValidator.ID, new ValidationContext(session)).toResult().isValid()); // max is smaller than min - Assert.assertFalse(Validators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(IntegerValidator.KEY_MIN, "10", IntegerValidator.KEY_MAX, "10")), IntegerValidator.ID).toResult().isValid()); + Assert.assertFalse(SimpleValidators.validatorConfigValidator().validate(new ValidatorConfig(ImmutableMap.of(IntegerValidator.KEY_MIN, "10", IntegerValidator.KEY_MAX, "10")), IntegerValidator.ID, new ValidationContext(session)).toResult().isValid()); } @Test public void testPatternValidator() { - Validator validator = Validators.patternValidator(); + Validator validator = SimpleValidators.patternValidator(); // Pattern object in the configuration ValidatorConfig config = configFromMap(Collections.singletonMap(PatternValidator.CFG_PATTERN, Pattern.compile("^start-.*-end$"))); @@ -456,7 +493,7 @@ public class BuiltinValidatorsTest { @Test public void testUriValidator() throws Exception { - Validator validator = Validators.uriValidator(); + Validator validator = SimpleValidators.uriValidator(); Assert.assertTrue(validator.validate(null, "baseUrl").isValid()); Assert.assertTrue(validator.validate("", "baseUrl").isValid()); @@ -472,14 +509,14 @@ public class BuiltinValidatorsTest { Assert.assertFalse(validator.validate("https://localhost:3000/#someFragment", "baseUrl", config).isValid()); // it is also possible to call dedicated validation methods on a built-in validator - Assert.assertTrue(Validators.uriValidator().validateUri(new URI("https://customurl"), Collections.singleton("https"), true, true)); + Assert.assertTrue(SimpleValidators.uriValidator().validateUri(new URI("https://customurl"), Collections.singleton("https"), true, true)); - Assert.assertFalse(Validators.uriValidator().validateUri(new URI("http://customurl"), Collections.singleton("https"), true, true)); + Assert.assertFalse(SimpleValidators.uriValidator().validateUri(new URI("http://customurl"), Collections.singleton("https"), true, true)); } @Test public void testOptionsValidator(){ - Validator validator = Validators.optionsValidator(); + Validator validator = SimpleValidators.optionsValidator(); // options not configured - always invalid Assert.assertFalse(validator.validate(null, "test", ValidatorConfig.builder().config(OptionsValidator.KEY_OPTIONS, null).build()).isValid()); @@ -517,16 +554,17 @@ public class BuiltinValidatorsTest { } @Test - public void testOptionsValidator_Config_Validation() { + @ModelTest + public void testOptionsValidator_Config_Validation(KeycloakSession session) { - ValidationResult result = Validators.validatorConfigValidator().validate(ValidatorConfig.builder().build(), OptionsValidator.ID).toResult(); + ValidationResult result = SimpleValidators.validatorConfigValidator().validate(ValidatorConfig.builder().build(), OptionsValidator.ID, new ValidationContext(session)).toResult(); Assert.assertFalse(result.isValid()); // invalid type of the config value - result = Validators.validatorConfigValidator().validate(ValidatorConfig.builder().config(OptionsValidator.KEY_OPTIONS, "a").build(), OptionsValidator.ID).toResult(); + result = SimpleValidators.validatorConfigValidator().validate(ValidatorConfig.builder().config(OptionsValidator.KEY_OPTIONS, "a").build(), OptionsValidator.ID, new ValidationContext(session)).toResult(); Assert.assertFalse(result.isValid()); - result = Validators.validatorConfigValidator().validate(ValidatorConfig.builder().config(OptionsValidator.KEY_OPTIONS, Arrays.asList("opt1")).build(), OptionsValidator.ID).toResult(); + result = SimpleValidators.validatorConfigValidator().validate(ValidatorConfig.builder().config(OptionsValidator.KEY_OPTIONS, Arrays.asList("opt1")).build(), OptionsValidator.ID, new ValidationContext(session)).toResult(); Assert.assertTrue(result.isValid()); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/SimpleValidators.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/SimpleValidators.java new file mode 100644 index 0000000000..2175b21125 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/SimpleValidators.java @@ -0,0 +1,82 @@ +/* + * Copyright 2023 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.testsuite.validation; + +import org.keycloak.validate.validators.DoubleValidator; +import org.keycloak.validate.validators.EmailValidator; +import org.keycloak.validate.validators.IntegerValidator; +import org.keycloak.validate.validators.LengthValidator; +import org.keycloak.validate.validators.LocalDateValidator; +import org.keycloak.validate.validators.NotBlankValidator; +import org.keycloak.validate.validators.NotEmptyValidator; +import org.keycloak.validate.validators.OptionsValidator; +import org.keycloak.validate.validators.PatternValidator; +import org.keycloak.validate.validators.UriValidator; +import org.keycloak.validate.validators.ValidatorConfigValidator; + +/** + * @author Marek Posolda + */ +public class SimpleValidators { + + public static NotBlankValidator notBlankValidator() { + return NotBlankValidator.INSTANCE; + } + + public static NotEmptyValidator notEmptyValidator() { + return NotEmptyValidator.INSTANCE; + } + + public static LengthValidator lengthValidator() { + return LengthValidator.INSTANCE; + } + + public static UriValidator uriValidator() { + return UriValidator.INSTANCE; + } + + public static EmailValidator emailValidator() { + return EmailValidator.INSTANCE; + } + + public static PatternValidator patternValidator() { + return PatternValidator.INSTANCE; + } + + public static DoubleValidator doubleValidator() { + return DoubleValidator.INSTANCE; + } + + public static IntegerValidator integerValidator() { + return IntegerValidator.INSTANCE; + } + + public static LocalDateValidator dateValidator() { + return LocalDateValidator.INSTANCE; + } + + public static OptionsValidator optionsValidator() { + return OptionsValidator.INSTANCE; + } + + public static ValidatorConfigValidator validatorConfigValidator() { + return ValidatorConfigValidator.INSTANCE; + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/ValidatorTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/ValidatorTest.java index b0404723a7..97eb75af74 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/ValidatorTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/ValidatorTest.java @@ -51,21 +51,21 @@ public class ValidatorTest extends AbstractTestRealmKeycloakTest { } private static void testDateValidator(KeycloakSession session) { - assertTrue(Validators.dateValidator().validate(null, new ValidationContext(session)).isValid()); - assertTrue(Validators.dateValidator().validate("", new ValidationContext(session)).isValid()); + assertTrue(SimpleValidators.dateValidator().validate(null, new ValidationContext(session)).isValid()); + assertTrue(SimpleValidators.dateValidator().validate("", new ValidationContext(session)).isValid()); // defaults to Locale.ENGLISH as per default locale selector - assertFalse(Validators.dateValidator().validate("13/12/2021", new ValidationContext(session)).isValid()); - assertFalse(Validators.dateValidator().validate("13/12/21", new ValidationContext(session)).isValid()); - assertTrue(Validators.dateValidator().validate("12/13/2021", new ValidationContext(session)).isValid()); + assertFalse(SimpleValidators.dateValidator().validate("13/12/2021", new ValidationContext(session)).isValid()); + assertFalse(SimpleValidators.dateValidator().validate("13/12/21", new ValidationContext(session)).isValid()); + assertTrue(SimpleValidators.dateValidator().validate("12/13/2021", new ValidationContext(session)).isValid()); RealmModel realm = session.getContext().getRealm(); realm.setInternationalizationEnabled(true); realm.setDefaultLocale(Locale.FRANCE.getLanguage()); - assertTrue(Validators.dateValidator().validate("13/12/21", new ValidationContext(session)).isValid()); - assertTrue(Validators.dateValidator().validate("13/12/2021", new ValidationContext(session)).isValid()); - assertFalse(Validators.dateValidator().validate("12/13/2021", new ValidationContext(session)).isValid()); + assertTrue(SimpleValidators.dateValidator().validate("13/12/21", new ValidationContext(session)).isValid()); + assertTrue(SimpleValidators.dateValidator().validate("13/12/2021", new ValidationContext(session)).isValid()); + assertFalse(SimpleValidators.dateValidator().validate("12/13/2021", new ValidationContext(session)).isValid()); UserModel alice = session.users().getUserByUsername(realm, "alice"); @@ -75,6 +75,6 @@ public class ValidatorTest extends AbstractTestRealmKeycloakTest { context.getAttributes().put(UserModel.class.getName(), alice); - assertFalse(Validators.dateValidator().validate("13/12/2021", context).isValid()); + assertFalse(SimpleValidators.dateValidator().validate("13/12/2021", context).isValid()); } } diff --git a/server-spi-private/src/test/java/org/keycloak/validate/ValidatorTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/ValidatorsTest.java similarity index 76% rename from server-spi-private/src/test/java/org/keycloak/validate/ValidatorTest.java rename to testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/ValidatorsTest.java index f4d7952e14..f28724d71f 100644 --- a/server-spi-private/src/test/java/org/keycloak/validate/ValidatorTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/validation/ValidatorsTest.java @@ -1,4 +1,23 @@ -package org.keycloak.validate; +/* + * Copyright 2023 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.testsuite.validation; import static org.keycloak.validate.ValidatorConfig.configFromMap; @@ -14,28 +33,41 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Assert; import org.junit.Test; import org.keycloak.models.KeycloakSession; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.AbstractKeycloakTest; +import org.keycloak.testsuite.arquillian.annotation.ModelTest; +import org.keycloak.validate.SimpleValidator; +import org.keycloak.validate.ValidationContext; +import org.keycloak.validate.ValidationError; +import org.keycloak.validate.ValidationResult; +import org.keycloak.validate.Validator; +import org.keycloak.validate.ValidatorConfig; +import org.keycloak.validate.Validators; import org.keycloak.validate.validators.EmailValidator; import org.keycloak.validate.validators.LengthValidator; import org.keycloak.validate.validators.NotBlankValidator; import org.keycloak.validate.validators.ValidatorConfigValidator; -public class ValidatorTest { +public class ValidatorsTest extends AbstractKeycloakTest { - KeycloakSession session = null; + @Override + public void addTestRealms(List testRealms) { + } @Test public void simpleValidation() { - Validator validator = Validators.notEmptyValidator(); + Validator validator = SimpleValidators.notEmptyValidator(); Assert.assertTrue(validator.validate("a").isValid()); Assert.assertFalse(validator.validate("").isValid()); } @Test - public void simpleValidationWithContext() { + @ModelTest + public void simpleValidationWithContext(KeycloakSession session) { - Validator validator = Validators.lengthValidator(); + Validator validator = SimpleValidators.lengthValidator(); ValidationContext context = new ValidationContext(session); validator.validate("a", "username", context); @@ -45,17 +77,19 @@ public class ValidatorTest { } @Test - public void simpleValidationFluent() { + @ModelTest + public void simpleValidationFluent(KeycloakSession session) { ValidationContext context = new ValidationContext(session); - ValidationResult result = Validators.lengthValidator().validate("a", "username", context).toResult(); + ValidationResult result = SimpleValidators.lengthValidator().validate("a", "username", context).toResult(); Assert.assertTrue(result.isValid()); } @Test - public void simpleValidationLookup() { + @ModelTest + public void simpleValidationLookup(KeycloakSession session) { // later: session.validators().validator(LengthValidator.ID); Validator validator = Validators.validator(session, LengthValidator.ID); @@ -68,7 +102,8 @@ public class ValidatorTest { } @Test - public void simpleValidationError() { + @ModelTest + public void simpleValidationError(KeycloakSession session) { Validator validator = LengthValidator.INSTANCE; @@ -104,20 +139,21 @@ public class ValidatorTest { public void acceptOnError() { AtomicBoolean bool1 = new AtomicBoolean(); - Validators.notEmptyValidator().validate("a").toResult().ifNotValidAccept(r -> bool1.set(true)); + SimpleValidators.notEmptyValidator().validate("a").toResult().ifNotValidAccept(r -> bool1.set(true)); Assert.assertFalse(bool1.get()); AtomicBoolean bool2 = new AtomicBoolean(); - Validators.notEmptyValidator().validate("").toResult().ifNotValidAccept(r -> bool2.set(true)); + SimpleValidators.notEmptyValidator().validate("").toResult().ifNotValidAccept(r -> bool2.set(true)); Assert.assertTrue(bool2.get()); } @Test - public void forEachError() { + @ModelTest + public void forEachError(KeycloakSession session) { List errors = new ArrayList<>(); MockAddress faultyAddress = new MockAddress("", "Saint-Maur-des-Fossés", null, "Germany"); - MockAddressValidator.INSTANCE.validate(faultyAddress, "address").toResult().forEachError(e -> { + MockAddressValidator.INSTANCE.validate(faultyAddress, "address", new ValidationContext(session)).toResult().forEachError(e -> { errors.add(e.getMessage()); }); @@ -125,7 +161,8 @@ public class ValidatorTest { } @Test - public void formatError() { + @ModelTest + public void formatError(KeycloakSession session) { Map miniResourceBundle = new HashMap<>(); miniResourceBundle.put("error-invalid-blank", "{0} is blank: <{1}>"); @@ -133,7 +170,7 @@ public class ValidatorTest { List errors = new ArrayList<>(); MockAddress faultyAddress = new MockAddress("", "Saint-Maur-des-Fossés", null, "Germany"); - MockAddressValidator.INSTANCE.validate(faultyAddress, "address").toResult().forEachError(e -> { + MockAddressValidator.INSTANCE.validate(faultyAddress, "address", new ValidationContext(session)).toResult().forEachError(e -> { errors.add(e.formatMessage((message, args) -> MessageFormat.format(miniResourceBundle.getOrDefault(message, message), args))); }); @@ -141,15 +178,16 @@ public class ValidatorTest { } @Test - public void multipleValidations() { + @ModelTest + public void multipleValidations(KeycloakSession session) { ValidationContext context = new ValidationContext(session); String input = "aaa"; String inputHint = "username"; - Validators.lengthValidator().validate(input, inputHint, context); - Validators.notEmptyValidator().validate(input, inputHint, context); + SimpleValidators.lengthValidator().validate(input, inputHint, context); + SimpleValidators.notEmptyValidator().validate(input, inputHint, context); ValidationResult result = context.toResult(); @@ -157,15 +195,16 @@ public class ValidatorTest { } @Test - public void multipleValidationsError() { + @ModelTest + public void multipleValidationsError(KeycloakSession session) { ValidationContext context = new ValidationContext(session); String input = " "; String inputHint = "username"; - Validators.lengthValidator().validate(input, inputHint, context, configFromMap(Collections.singletonMap(LengthValidator.KEY_MIN, 1))); - Validators.notBlankValidator().validate(input, inputHint, context); + SimpleValidators.lengthValidator().validate(input, inputHint, context, configFromMap(Collections.singletonMap(LengthValidator.KEY_MIN, 1))); + SimpleValidators.notBlankValidator().validate(input, inputHint, context); ValidationResult result = context.toResult(); @@ -184,7 +223,8 @@ public class ValidatorTest { } @Test - public void validateValidatorConfigSimple() { + @ModelTest + public void validateValidatorConfigSimple(KeycloakSession session) { SimpleValidator validator = LengthValidator.INSTANCE; @@ -197,8 +237,9 @@ public class ValidatorTest { } @Test - public void validateEmailValidator() { - SimpleValidator validator = Validators.emailValidator(); + @ModelTest + public void validateEmailValidator(KeycloakSession session) { + SimpleValidator validator = SimpleValidators.emailValidator(); Assert.assertTrue(validator.validateConfig(session, null).isValid()); Assert.assertTrue(validator.validateConfig(session, ValidatorConfig.EMPTY).isValid()); @@ -215,7 +256,8 @@ public class ValidatorTest { } @Test - public void validateValidatorConfigMultipleOptions() { + @ModelTest + public void validateValidatorConfigMultipleOptions(KeycloakSession session) { SimpleValidator validator = LengthValidator.INSTANCE; @@ -229,7 +271,8 @@ public class ValidatorTest { } @Test - public void validateValidatorConfigMultipleOptionsInvalidValues() { + @ModelTest + public void validateValidatorConfigMultipleOptionsInvalidValues(KeycloakSession session) { SimpleValidator validator = LengthValidator.INSTANCE; @@ -253,7 +296,8 @@ public class ValidatorTest { } @Test - public void validateValidatorConfigViaValidatorFactory() { + @ModelTest + public void validateValidatorConfigViaValidatorFactory(KeycloakSession session) { Map config = new HashMap<>(); config.put("min", "a"); @@ -275,15 +319,16 @@ public class ValidatorTest { } @Test - public void nestedValidation() { + @ModelTest + public void nestedValidation(KeycloakSession session) { Assert.assertTrue(MockAddressValidator.INSTANCE.validate( new MockAddress("4848 Arcu St.", "Saint-Maur-des-Fossés", "02206", "Germany") - , "address").isValid()); + , "address", new ValidationContext(session)).isValid()); ValidationResult result = MockAddressValidator.INSTANCE.validate( new MockAddress("", "Saint-Maur-des-Fossés", null, "Germany") - , "address").toResult(); + , "address", new ValidationContext(session)).toResult(); Assert.assertFalse(result.isValid()); Assert.assertEquals(2, result.getErrors().size());