diff --git a/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/KeycloakProcessor.java b/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/KeycloakProcessor.java index 9e782652f64..25fbf188056 100644 --- a/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/KeycloakProcessor.java +++ b/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/KeycloakProcessor.java @@ -100,6 +100,7 @@ import org.keycloak.quarkus.runtime.services.health.KeycloakClusterReadyHealthCh import org.keycloak.quarkus.runtime.services.health.KeycloakReadyHealthCheck; import org.keycloak.quarkus.runtime.storage.database.jpa.NamedJpaConnectionProviderFactory; import org.keycloak.quarkus.runtime.themes.FlatClasspathThemeResourceProviderFactory; +import org.keycloak.quarkus.runtime.validation.HibernateValidatorFactoryCustomizer; import org.keycloak.representations.provider.ScriptProviderDescriptor; import org.keycloak.representations.provider.ScriptProviderMetadata; import org.keycloak.representations.userprofile.config.UPConfig; @@ -130,6 +131,7 @@ import io.quarkus.bootstrap.logging.InitialConfigurator; import io.quarkus.datasource.deployment.spi.DevServicesDatasourceResultBuildItem; import io.quarkus.datasource.runtime.DataSourcesBuildTimeConfig; import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.IsTest; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.Consume; @@ -860,6 +862,16 @@ class KeycloakProcessor { removeBeans.produce(new BuildTimeConditionBuildItem(disabledBean.asClass(), false)); } + @BuildStep(onlyIfNot = IsTest.class) // needed for embedded Keycloak + void disableHibernateValidatorCustomizer(BuildProducer removeBeans, CombinedIndexBuildItem index) { + if (!Profile.isFeatureEnabled(Profile.Feature.CLIENT_ADMIN_API_V2)) { + // disables the filter + ClassInfo disabledBean = index.getIndex() + .getClassByName(DotName.createSimple(HibernateValidatorFactoryCustomizer.class.getName())); + removeBeans.produce(new BuildTimeConditionBuildItem(disabledBean.asClass(), false)); + } + } + @BuildStep void disableMdcContextFilter(BuildProducer removeBeans, CombinedIndexBuildItem index) { if (!Configuration.isTrue(LoggingOptions.LOG_MDC_ENABLED)) { diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/IgnoredArtifacts.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/IgnoredArtifacts.java index 061e65062dd..65e7c3e97a7 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/IgnoredArtifacts.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/IgnoredArtifacts.java @@ -46,7 +46,8 @@ public class IgnoredArtifacts { metrics(), otelMetrics(), openApi(), - openApiSwagger() + openApiSwagger(), + hibernateValidator() ) .flatMap(Collection::stream) .collect(Collectors.toUnmodifiableSet()); @@ -212,4 +213,17 @@ public class IgnoredArtifacts { boolean isEnabled = Configuration.isTrue(OpenApiOptions.OPENAPI_UI_ENABLED); return !isEnabled ? OPENAPI_SWAGGER : emptySet(); } + + // Hibernate Validator + public static Set HIBERNATE_VALIDATOR = Set.of( + "io.quarkus:quarkus-hibernate-validator", + "io.quarkus:quarkus-hibernate-validator-deployment", + "io.quarkus:quarkus-hibernate-validator-spi", + "org.hibernate.validator:hibernate-validator" + ); + + private static Set hibernateValidator() { + boolean isEnabled = Profile.isFeatureEnabled(Profile.Feature.CLIENT_ADMIN_API_V2); + return !isEnabled ? HIBERNATE_VALIDATOR : emptySet(); + } } diff --git a/quarkus/runtime/src/test/java/org/keycloak/quarkus/runtime/configuration/IgnoredArtifactsTest.java b/quarkus/runtime/src/test/java/org/keycloak/quarkus/runtime/configuration/IgnoredArtifactsTest.java index 18af23c94d4..f9b722e5471 100644 --- a/quarkus/runtime/src/test/java/org/keycloak/quarkus/runtime/configuration/IgnoredArtifactsTest.java +++ b/quarkus/runtime/src/test/java/org/keycloak/quarkus/runtime/configuration/IgnoredArtifactsTest.java @@ -44,8 +44,11 @@ import static org.keycloak.quarkus.runtime.configuration.IgnoredArtifacts.JDBC_O import static org.keycloak.quarkus.runtime.configuration.IgnoredArtifacts.JDBC_POSTGRES; import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX; +import static org.hamcrest.CoreMatchers.everyItem; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.in; import static org.junit.Assert.assertTrue; public class IgnoredArtifactsTest extends AbstractConfigurationTest { @@ -61,10 +64,7 @@ public class IgnoredArtifactsTest extends AbstractConfigurationTest { @Test public void fipsEnabled() { - Properties properties = new Properties(); - properties.setProperty("keycloak.profile.feature.fips", "enabled"); - var profile = Profile.configure(new PropertiesProfileConfigResolver(properties)); - + var profile = getProfileWithEnabledFeature(Profile.Feature.FIPS); assertThat(profile.isFeatureEnabled(Profile.Feature.FIPS), is(true)); var ignoredArtifacts = IgnoredArtifacts.getDefaultIgnoredArtifacts(); @@ -172,6 +172,21 @@ public class IgnoredArtifactsTest extends AbstractConfigurationTest { assertIgnoredArtifacts(IgnoredArtifacts.OPENAPI_SWAGGER, OpenApiOptions.OPENAPI_UI_ENABLED); } + @Test + public void hibernateValidator() { + var profile = Profile.defaults(); + assertThat(profile.isFeatureEnabled(Profile.Feature.CLIENT_ADMIN_API_V2), is(false)); + + var ignoredArtifacts = IgnoredArtifacts.getDefaultIgnoredArtifacts(); + assertThat(IgnoredArtifacts.HIBERNATE_VALIDATOR, everyItem(in(ignoredArtifacts))); + + profile = getProfileWithEnabledFeature(Profile.Feature.CLIENT_ADMIN_API_V2); + assertThat(profile.isFeatureEnabled(Profile.Feature.CLIENT_ADMIN_API_V2), is(true)); + + ignoredArtifacts = IgnoredArtifacts.getDefaultIgnoredArtifacts(); + assertThat(IgnoredArtifacts.HIBERNATE_VALIDATOR, everyItem(not(in(ignoredArtifacts)))); + } + private void assertIgnoredArtifacts(Set artifactsSet, Option enabledOption) { assertIgnoredArtifacts(artifactsSet, enabledOption, true); } @@ -185,4 +200,10 @@ public class IgnoredArtifactsTest extends AbstractConfigurationTest { assertThat(artifacts.containsAll(artifactsSet), is(!disabledByDefault)); }); } + + private Profile getProfileWithEnabledFeature(Profile.Feature feature) { + Properties properties = new Properties(); + properties.setProperty("keycloak.profile.feature.%s".formatted(feature.name().toLowerCase()), "enabled"); + return Profile.configure(new PropertiesProfileConfigResolver(properties)); + } } diff --git a/services/pom.xml b/services/pom.xml index fe99d0d5c6c..eafdb555821 100755 --- a/services/pom.xml +++ b/services/pom.xml @@ -81,11 +81,6 @@ org.twitter4j twitter4j-core - - org.hibernate.validator - hibernate-validator - ${hibernate-validator.version} - org.jboss.logging jboss-logging diff --git a/services/src/main/java/org/keycloak/services/error/KeycloakErrorHandler.java b/services/src/main/java/org/keycloak/services/error/KeycloakErrorHandler.java index f9d7975e4c6..e65e218925a 100644 --- a/services/src/main/java/org/keycloak/services/error/KeycloakErrorHandler.java +++ b/services/src/main/java/org/keycloak/services/error/KeycloakErrorHandler.java @@ -8,7 +8,6 @@ import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; -import jakarta.validation.ValidationException; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.Response; @@ -102,8 +101,6 @@ public class KeycloakErrorHandler implements ExceptionMapper { error.setErrorDescription("Cannot parse the JSON"); } else if (isServerError) { error.setErrorDescription("For more on this error consult the server log."); - } else if (throwable instanceof ValidationException) { - error.setErrorDescription(throwable.getMessage()); } return Response.status(responseStatus)