Upgrade to Quarkus 3.19.0.CR1 (#37492)

Closes #37436

Signed-off-by: Martin Bartoš <mabartos@redhat.com>
This commit is contained in:
Martin Bartoš 2025-02-24 18:52:01 +00:00 committed by GitHub
parent a3af12cf26
commit 6f0ed46404
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 170 additions and 139 deletions

View File

@ -13,3 +13,8 @@ would now be `http://example.com`.
To mitigate that, either make your reverse proxy include the port in the `X-Forwarded-Host` header or configure it to set
the `X-Forwarded-Port` header with the desired port.
=== Changes to installing Oracle JDBC driver
The required JAR for the Oracle JDBC driver that needs to be explicitly added to the distribution has changed.
Instead of providing `ojdbc11` JAR, use `ojdbc17` JAR as stated in the https://www.keycloak.org/server/db#_installing_the_oracle_database_driver[Installing the Oracle Database driver] guide.

View File

@ -53,15 +53,15 @@ or skip this section if you want to connect to a different database for which th
To install the Oracle Database driver for {project_name}:
. Download the `ojdbc11` and `orai18n` JAR files from one of the following sources:
. Download the `ojdbc17` and `orai18n` JAR files from one of the following sources:
.. *Zipped JDBC driver and Companion Jars* version ${properties["oracle-jdbc.version"]} from the https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html[Oracle driver download page].
.. Maven Central via `link:++https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc11/${properties["oracle-jdbc.version"]}/ojdbc11-${properties["oracle-jdbc.version"]}.jar++[ojdbc11]` and `link:++https://repo1.maven.org/maven2/com/oracle/database/nls/orai18n/${properties["oracle-jdbc.version"]}/orai18n-${properties["oracle-jdbc.version"]}.jar++[orai18n]`.
.. Maven Central via `link:++https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc17/${properties["oracle-jdbc.version"]}/ojdbc17-${properties["oracle-jdbc.version"]}.jar++[ojdbc17]` and `link:++https://repo1.maven.org/maven2/com/oracle/database/nls/orai18n/${properties["oracle-jdbc.version"]}/orai18n-${properties["oracle-jdbc.version"]}.jar++[orai18n]`.
.. Installation media recommended by the database vendor for the specific database in use.
. When running the unzipped distribution: Place the `ojdbc11` and `orai18n` JAR files in {project_name}'s `providers` folder
. When running the unzipped distribution: Place the `ojdbc17` and `orai18n` JAR files in {project_name}'s `providers` folder
. When running containers: Build a custom {project_name} image and add the JARs in the `providers` folder. When building a custom image for the Operator, those images need to be optimized images with all build-time options of {project_name} set.
+
@ -70,7 +70,7 @@ A minimal Containerfile to build an image which can be used with the {project_na
[source,dockerfile,subs="attributes+"]
----
FROM quay.io/keycloak/keycloak:{containerlabel}
ADD --chown=keycloak:keycloak --chmod=644 https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc11/${properties["oracle-jdbc.version"]}/ojdbc11-${properties["oracle-jdbc.version"]}.jar /opt/keycloak/providers/ojdbc11.jar
ADD --chown=keycloak:keycloak --chmod=644 https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc17/${properties["oracle-jdbc.version"]}/ojdbc17-${properties["oracle-jdbc.version"]}.jar /opt/keycloak/providers/ojdbc17.jar
ADD --chown=keycloak:keycloak --chmod=644 https://repo1.maven.org/maven2/com/oracle/database/nls/orai18n/${properties["oracle-jdbc.version"]}/orai18n-${properties["oracle-jdbc.version"]}.jar /opt/keycloak/providers/orai18n.jar
# Setting the build parameter for the database:
ENV KC_DB=oracle

View File

@ -52,8 +52,8 @@
<jboss.snapshots.repo.id>jboss-snapshots-repository</jboss.snapshots.repo.id>
<jboss.snapshots.repo.url>https://s01.oss.sonatype.org/content/repositories/snapshots/</jboss.snapshots.repo.url>
<quarkus.version>3.18.3</quarkus.version>
<quarkus.build.version>3.18.3</quarkus.build.version>
<quarkus.version>3.19.0.CR1</quarkus.version>
<quarkus.build.version>3.19.0.CR1</quarkus.build.version>
<project.build-time>${timestamp}</project.build-time>
@ -176,7 +176,7 @@
<oracledb.version>23.5</oracledb.version>
<oracledb.container>mirror.gcr.io/gvenzl/oracle-free:${oracledb.version}-slim-faststart</oracledb.container>
<!-- this is the oracle driver version also used in the Quarkus BOM -->
<oracle-jdbc.version>23.5.0.24.07</oracle-jdbc.version>
<oracle-jdbc.version>23.6.0.24.10</oracle-jdbc.version>
<!-- Test -->
<greenmail.version>2.1.0-alpha-1</greenmail.version>

View File

@ -9,6 +9,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@SuppressWarnings({"unchecked", "OptionalUsedAsFieldOrParameterType", "rawtypes"})
public class OptionBuilder<T> {
private static final List<String> BOOLEAN_TYPE_VALUES = List.of(Boolean.TRUE.toString(), Boolean.FALSE.toString());

View File

@ -210,8 +210,8 @@ public final class Database {
"mssql"
),
ORACLE("oracle",
"oracle.jdbc.xa.client.OracleXADataSource",
"oracle.jdbc.driver.OracleDriver",
"oracle.jdbc.datasource.OracleXADataSource",
"oracle.jdbc.OracleDriver",
"org.hibernate.dialect.OracleDialect",
"jdbc:oracle:thin:@//${kc.db-url-host:localhost}:${kc.db-url-port:1521}/${kc.db-url-database:keycloak}",
asList("liquibase.database.core.OracleDatabase")

View File

@ -305,7 +305,7 @@ class KeycloakProcessor {
@BuildStep
@Produce(CheckMultipleDatasourcesBuildStep.class)
void checkMultipleDatasourcesUseXA(TransactionManagerBuildTimeConfig transactionManagerConfig, DataSourcesBuildTimeConfig dataSourcesConfig, DataSourcesJdbcBuildTimeConfig jdbcConfig) {
if (transactionManagerConfig.unsafeMultipleLastResources
if (transactionManagerConfig.unsafeMultipleLastResources()
.orElse(UnsafeMultipleLastResourcesMode.DEFAULT) != UnsafeMultipleLastResourcesMode.FAIL) {
return;
}
@ -383,7 +383,7 @@ class KeycloakProcessor {
Properties properties = descriptor.getProperties();
// register a listener for customizing the unit configuration at runtime
runtimeConfigured.produce(new HibernateOrmIntegrationRuntimeConfiguredBuildItem("keycloak", descriptor.getName())
.setInitListener(recorder.createUserDefinedUnitListener(properties.getProperty(AvailableSettings.DATASOURCE))));
.setInitListener(recorder.createUserDefinedUnitListener(properties.getProperty(AvailableSettings.JAKARTA_JTA_DATASOURCE))));
userManagedEntities.addAll(descriptor.getManagedClassNames());
}
}

View File

@ -81,7 +81,7 @@
<exclusions>
<exclusion>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<artifactId>ojdbc17</artifactId>
</exclusion>
<exclusion>
<groupId>com.oracle.database.nls</groupId>

View File

@ -23,7 +23,6 @@ import io.quarkus.arc.Arc;
import io.quarkus.arc.InstanceHandle;
import io.quarkus.hibernate.orm.runtime.integration.HibernateOrmIntegrationRuntimeInitListener;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.runtime.ShutdownContext;
import io.quarkus.runtime.annotations.Recorder;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@ -70,9 +69,6 @@ import static org.keycloak.quarkus.runtime.configuration.Configuration.getKcConf
@Recorder
public class KeycloakRecorder {
public static final String DEFAULT_HEALTH_ENDPOINT = "/health";
public static final String DEFAULT_METRICS_ENDPOINT = "/metrics";
private static final Logger logger = Logger.getLogger(KeycloakRecorder.class);
public void initConfig() {
@ -169,20 +165,11 @@ public class KeycloakRecorder {
DeclarativeUserProfileProviderFactory.setDefaultConfig(configuration);
}
public void registerShutdownHook(ShutdownContext shutdownContext) {
shutdownContext.addShutdownTask(new Runnable() {
@Override
public void run() {
QuarkusKeycloakSessionFactory.getInstance().close();
}
});
}
public HibernateOrmIntegrationRuntimeInitListener createUserDefinedUnitListener(String name) {
return new HibernateOrmIntegrationRuntimeInitListener() {
@Override
public void contributeRuntimeProperties(BiConsumer<String, Object> propertyCollector) {
InstanceHandle<AgroalDataSource> instance = Arc.container().instance(
try (InstanceHandle<AgroalDataSource> instance = Arc.container().instance(
AgroalDataSource.class, new DataSource() {
@Override public Class<? extends Annotation> annotationType() {
return DataSource.class;
@ -191,8 +178,9 @@ public class KeycloakRecorder {
@Override public String value() {
return name;
}
});
propertyCollector.accept(AvailableSettings.DATASOURCE, instance.get());
})) {
propertyCollector.accept(AvailableSettings.JAKARTA_JTA_DATASOURCE, instance.get());
}
}
};
}

View File

@ -32,38 +32,45 @@ import io.smallrye.config.ConfigValue;
import picocli.CommandLine;
import picocli.CommandLine.ParseResult;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public final class ExecutionExceptionHandler implements CommandLine.IExecutionExceptionHandler {
private Logger logger;
private static Logger logger;
private boolean verbose;
private static Map<String, Function<Throwable, Throwable>> exceptionTransformers = new HashMap<>();
public ExecutionExceptionHandler() {}
@Override
public int handleExecutionException(Exception cause, CommandLine cmd, ParseResult parseResult) {
if (cause instanceof PropertyException) {
var exception = handleExceptionTransformers(cause);
if (exception instanceof PropertyException) {
PrintWriter writer = cmd.getErr();
writer.println(cmd.getColorScheme().errorText(cause.getMessage()));
if (verbose && cause.getCause() != null) {
dumpException(writer, cause.getCause());
writer.println(cmd.getColorScheme().errorText(exception.getMessage()));
if (verbose && exception.getCause() != null) {
dumpException(writer, exception.getCause());
}
return ShortErrorMessageHandler.getInvalidInputExitCode(cause, cmd);
return ShortErrorMessageHandler.getInvalidInputExitCode(exception, cmd);
}
error(cmd.getErr(), "Failed to run '" + parseResult.subcommands().stream()
.map(ParseResult::commandSpec)
.map(CommandLine.Model.CommandSpec::name)
.findFirst()
.orElse(Environment.getCommand()) + "' command.", cause);
.orElse(Environment.getCommand()) + "' command.", exception);
return cmd.getCommandSpec().exitCodeOnExecutionException();
}
public void error(PrintWriter errorWriter, String message, Throwable cause) {
var exception = handleExceptionTransformers(cause);
if (message != null) {
logError(errorWriter, "ERROR: " + message);
}
if (cause != null) {
dumpException(errorWriter, cause);
if (exception != null) {
dumpException(errorWriter, exception);
if (!verbose) {
logError(errorWriter, "For more details run the same command passing the '--verbose' option. Also you can use '--help' to see the details about the usage of the particular command.");
@ -121,7 +128,7 @@ public final class ExecutionExceptionHandler implements CommandLine.IExecutionEx
}
}
private Logger getLogger() {
private static Logger getLogger() {
if (logger == null) {
logger = Logger.getLogger(ExecutionExceptionHandler.class);
}
@ -131,4 +138,34 @@ public final class ExecutionExceptionHandler implements CommandLine.IExecutionEx
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
public static void addExceptionTransformer(Class<?> fromClass, Function<Throwable, Throwable> transformer) {
if (exceptionTransformers.get(fromClass.getName()) != null) {
getLogger().warnf("Transformer for the '%s' class is overridden", fromClass.getName());
}
exceptionTransformers.put(fromClass.getName(), transformer);
}
public static void resetExceptionTransformers() {
exceptionTransformers = new HashMap<>();
}
private static Throwable handleExceptionTransformers(Throwable exception) {
if (exception == null) {
return null;
}
if (exceptionTransformers.isEmpty()) {
return exception;
}
var stackTrace = exception.getStackTrace();
for (var trace : stackTrace) {
var transformer = exceptionTransformers.get(trace.getClassName());
if (transformer != null) {
return transformer.apply(exception);
}
}
return exception;
}
}

View File

@ -95,7 +95,7 @@ public class ShortErrorMessageHandler implements IParameterExceptionHandler {
return getInvalidInputExitCode(ex, cmd);
}
static int getInvalidInputExitCode(Exception ex, CommandLine cmd) {
static int getInvalidInputExitCode(Throwable ex, CommandLine cmd) {
return cmd.getExitCodeExceptionMapper() != null
? cmd.getExitCodeExceptionMapper().getExitCode(ex)
: cmd.getCommandSpec().exitCodeOnInvalidInput();

View File

@ -73,7 +73,8 @@ public class IgnoredArtifacts {
public static final Set<String> JDBC_H2 = Set.of(
"io.quarkus:quarkus-jdbc-h2",
"io.quarkus:quarkus-jdbc-h2-deployment",
"com.h2database:h2"
"com.h2database:h2",
"org.locationtech.jts:jts-core"
);
public static final Set<String> JDBC_POSTGRES = Set.of(
@ -103,7 +104,7 @@ public class IgnoredArtifacts {
public static final Set<String> JDBC_ORACLE = Set.of(
"io.quarkus:quarkus-jdbc-oracle",
"io.quarkus:quarkus-jdbc-oracle-deployment",
"com.oracle.database.jdbc:ojdbc11",
"com.oracle.database.jdbc:ojdbc17",
"com.oracle.database.nls:orai18n"
);

View File

@ -1,7 +1,6 @@
package org.keycloak.quarkus.runtime.configuration.mappers;
import io.quarkus.runtime.util.ClassPathUtils;
import io.quarkus.vertx.http.runtime.CertificateConfig;
import io.quarkus.vertx.http.runtime.options.TlsUtils;
import io.smallrye.config.ConfigSourceInterceptorContext;
@ -10,16 +9,17 @@ import org.keycloak.config.HttpOptions;
import org.keycloak.config.SecurityOptions;
import org.keycloak.quarkus.runtime.Environment;
import org.keycloak.quarkus.runtime.Messages;
import org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler;
import org.keycloak.quarkus.runtime.cli.PropertyException;
import org.keycloak.quarkus.runtime.configuration.Configuration;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getOptionalKcValue;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getOptionalValue;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
public final class HttpPropertyMappers {
@ -33,7 +33,28 @@ public final class HttpPropertyMappers {
private HttpPropertyMappers(){}
// Transform runtime exceptions obtained from Quarkus to ours with a relevant message
private static void setCustomExceptionTransformer() {
ExecutionExceptionHandler.addExceptionTransformer(TlsUtils.class, exception -> {
if (exception instanceof IOException ioe) {
return new PropertyException("Failed to load 'https-trust-store' or 'https-key-' material: " + ioe.getClass().getSimpleName() + " " + ioe.getMessage(), ioe);
} else if (exception instanceof IllegalArgumentException iae) {
if (iae.getMessage().contains(QUARKUS_HTTPS_TRUST_STORE_FILE_TYPE)) {
return new PropertyException("Unable to determine 'https-trust-store-type' automatically. " +
"Adjust the file extension or specify the property.", iae);
} else if (iae.getMessage().contains(QUARKUS_HTTPS_KEY_STORE_FILE_TYPE)) {
return new PropertyException("Unable to determine 'https-key-store-type' automatically. " +
"Adjust the file extension or specify the property.", iae);
} else {
return new PropertyException(iae.getMessage(), iae);
}
}
return exception;
});
}
public static PropertyMapper<?>[] getHttpPropertyMappers() {
setCustomExceptionTransformer();
return new PropertyMapper[] {
fromOption(HttpOptions.HTTP_ENABLED)
.to("quarkus.http.insecure-requests")
@ -138,57 +159,12 @@ public final class HttpPropertyMappers {
}
public static void validateConfig() {
boolean enabled = isHttpEnabled(Configuration.getOptionalKcValue(HttpOptions.HTTP_ENABLED.getKey()).orElse(null));
Optional<String> certFile = Configuration.getOptionalValue(QUARKUS_HTTPS_CERT_FILES);
Optional<String> keystoreFile = Configuration.getOptionalValue(QUARKUS_HTTPS_KEY_STORE_FILE);
boolean enabled = isHttpEnabled(getOptionalKcValue(HttpOptions.HTTP_ENABLED.getKey()).orElse(null));
Optional<String> certFile = getOptionalValue(QUARKUS_HTTPS_CERT_FILES);
Optional<String> keystoreFile = getOptionalValue(QUARKUS_HTTPS_KEY_STORE_FILE);
if (!enabled && certFile.isEmpty() && keystoreFile.isEmpty()) {
throw new PropertyException(Messages.httpsConfigurationNotSet());
}
CertificateConfig config = new CertificateConfig();
config.trustStoreFile = Configuration.getOptionalValue(QUARKUS_HTTPS_TRUST_STORE_FILE).map(Paths::get);
config.trustStorePassword = Configuration.getOptionalKcValue(HttpOptions.HTTPS_TRUST_STORE_PASSWORD.getKey());
config.trustStoreFileType = Configuration.getOptionalValue(QUARKUS_HTTPS_TRUST_STORE_FILE_TYPE);
config.trustStoreProvider = Configuration.getOptionalValue("quarkus.http.ssl.certificate.trust-store-provider");
config.trustStoreCertAlias = Configuration.getOptionalValue("quarkus.http.ssl.certificate.trust-store-cert-alias");
config.trustStoreFiles = Optional.empty();
config.keyStoreFile = keystoreFile.map(Paths::get);
config.keyStorePassword = Configuration.getOptionalKcValue(HttpOptions.HTTPS_KEY_STORE_PASSWORD.getKey());
config.keyStoreFileType = Configuration.getOptionalValue(QUARKUS_HTTPS_KEY_STORE_FILE_TYPE);
config.keyStoreProvider = Configuration.getOptionalValue("quarkus.http.ssl.certificate.key-store-provider");
config.keyStoreAlias = Configuration.getOptionalValue("quarkus.http.ssl.certificate.key-store-alias");
config.keyStoreAliasPassword = Configuration.getOptionalValue("quarkus.http.ssl.certificate.key-store-alias-password");
config.keyStoreAliasPasswordKey = Configuration.getOptionalValue("quarkus.http.ssl.certificate.key-store-alias-password-key");
config.keyStoreKeyAlias = Configuration.getOptionalValue("quarkus.http.ssl.certificate.key-store-key-alias");
config.keyFiles = Configuration.getOptionalValue(QUARKUS_HTTPS_CERT_KEY_FILES).map(Paths::get).map(List::of);
config.files = certFile.map(Paths::get).map(List::of);
try {
TlsUtils.computeTrustOptions(config, config.trustStorePassword);
} catch (IOException e) {
throw new PropertyException("Failed to load 'https-trust-store' material: " + e.getClass().getSimpleName() + " " + e.getMessage(), e);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains(QUARKUS_HTTPS_TRUST_STORE_FILE_TYPE)) {
throw new PropertyException("Unable to determine 'https-trust-store-type' automatically. " +
"Adjust the file extension or specify the property.", e);
}
throw new PropertyException(e.getMessage(), e);
}
try {
TlsUtils.computeKeyStoreOptions(config, config.keyStorePassword, config.keyStoreAliasPassword);
} catch (IOException e) {
throw new PropertyException("Failed to load 'https-key-' material: " + e.getClass().getSimpleName() + " " + e.getMessage(), e);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains(QUARKUS_HTTPS_KEY_STORE_FILE_TYPE)) {
throw new PropertyException("Unable to determine 'https-key-store-type' automatically. " +
"Adjust the file extension or specify the property.", e);
}
throw new PropertyException(e.getMessage(), e);
}
}
private static String transformPath(String value, ConfigSourceInterceptorContext context) {

View File

@ -45,7 +45,7 @@ public final class LoggingPropertyMappers {
// Console
fromOption(LoggingOptions.LOG_CONSOLE_OUTPUT)
.isEnabled(LoggingPropertyMappers::isConsoleEnabled, CONSOLE_ENABLED_MSG)
.to("quarkus.log.console.json")
.to("quarkus.log.console.json.enabled")
.paramLabel("output")
.transformer(LoggingPropertyMappers::resolveLogOutput)
.build(),
@ -112,7 +112,7 @@ public final class LoggingPropertyMappers {
.build(),
fromOption(LoggingOptions.LOG_FILE_OUTPUT)
.isEnabled(LoggingPropertyMappers::isFileEnabled, FILE_ENABLED_MSG)
.to("quarkus.log.file.json")
.to("quarkus.log.file.json.enabled")
.paramLabel("output")
.transformer(LoggingPropertyMappers::resolveLogOutput)
.build(),
@ -185,7 +185,7 @@ public final class LoggingPropertyMappers {
.build(),
fromOption(LoggingOptions.LOG_SYSLOG_OUTPUT)
.isEnabled(LoggingPropertyMappers::isSyslogEnabled, SYSLOG_ENABLED_MSG)
.to("quarkus.log.syslog.json")
.to("quarkus.log.syslog.json.enabled")
.paramLabel("output")
.transformer(LoggingPropertyMappers::resolveLogOutput)
.build(),
@ -199,7 +199,7 @@ public final class LoggingPropertyMappers {
}
public static boolean isConsoleJsonEnabled() {
return isConsoleEnabled() && Configuration.isTrue("quarkus.log.console.json");
return isConsoleEnabled() && Configuration.isTrue("quarkus.log.console.json.enabled");
}
public static boolean isFileEnabled() {
@ -207,7 +207,7 @@ public final class LoggingPropertyMappers {
}
public static boolean isFileJsonEnabled() {
return isFileEnabled() && Configuration.isTrue("quarkus.log.file.json");
return isFileEnabled() && Configuration.isTrue("quarkus.log.file.json.enabled");
}
public static boolean isSyslogEnabled() {
@ -215,7 +215,7 @@ public final class LoggingPropertyMappers {
}
public static boolean isSyslogJsonEnabled() {
return isSyslogEnabled() && Configuration.isTrue("quarkus.log.syslog.json");
return isSyslogEnabled() && Configuration.isTrue("quarkus.log.syslog.json.enabled");
}
private static BiFunction<String, ConfigSourceInterceptorContext, String> resolveLogHandler(String handler) {

View File

@ -270,6 +270,7 @@ public final class PropertyMappers {
}
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public List<PropertyMapper<?>> get(Object key) {
// First check if the requested option matches any wildcard mappers
String strKey = (String) key;

View File

@ -144,7 +144,7 @@ public class QuarkusJpaUpdaterProvider implements JpaUpdaterProvider {
// create DEPLOYMENT_ID column if it doesn't exist
if (!hasDeploymentIdColumn) {
ChangeLogHistoryService changelogHistoryService = ChangeLogHistoryServiceFactory.getInstance().getChangeLogService(database);
ChangeLogHistoryService changelogHistoryService = getChangeLogHistoryService().getChangeLogService(database);
changelogHistoryService.generateDeploymentId();
String deploymentId = changelogHistoryService.getDeploymentId();
@ -281,7 +281,11 @@ public class QuarkusJpaUpdaterProvider implements JpaUpdaterProvider {
private void resetLiquibaseServices(KeycloakLiquibase liquibase) {
liquibase.resetServices();
ChangeLogHistoryServiceFactory.getInstance().register(new CustomChangeLogHistoryService());
getChangeLogHistoryService().register(new CustomChangeLogHistoryService());
}
private ChangeLogHistoryServiceFactory getChangeLogHistoryService() {
return Scope.getCurrentScope().getSingleton(ChangeLogHistoryServiceFactory.class);
}
private List<ChangeSet> getLiquibaseUnrunChangeSets(Liquibase liquibase) {

View File

@ -25,6 +25,7 @@ import org.keycloak.models.KeycloakSession;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@SuppressWarnings({"unchecked", "resource"})
public final class QuarkusCacheManagerProvider implements ManagedCacheManagerProvider {
@Override

View File

@ -244,21 +244,6 @@ public class PicocliTest extends AbstractConfigurationTest {
+ "\nPossible solutions: --db-url, --db-url-host, --db-url-database, --db-url-port, --db-url-properties, --db-username, --db-password, --db-schema, --db-pool-initial-size, --db-pool-min-size, --db-pool-max-size, --db-driver, --db"));
}
@Test
public void httpStoreTypeValidation() {
NonRunningPicocli nonRunningPicocli = pseudoLaunch("start", "--https-key-store-file=not-there.ks", "--hostname-strict=false");
assertEquals(CommandLine.ExitCode.USAGE, nonRunningPicocli.exitCode);
assertThat(nonRunningPicocli.getErrString(), containsString("Unable to determine 'https-key-store-type' automatically. Adjust the file extension or specify the property"));
nonRunningPicocli = pseudoLaunch("start", "--https-key-store-file=not-there.ks", "--hostname-strict=false", "--https-key-store-type=jdk");
assertEquals(CommandLine.ExitCode.USAGE, nonRunningPicocli.exitCode);
assertThat(nonRunningPicocli.getErrString(), containsString("Failed to load 'https-key-' material: NoSuchFileException not-there.ks"));
nonRunningPicocli = pseudoLaunch("start", "--https-trust-store-file=not-there.jks", "--https-key-store-file=not-there.ks", "--hostname-strict=false", "--https-key-store-type=jdk");
assertEquals(CommandLine.ExitCode.USAGE, nonRunningPicocli.exitCode);
assertThat(nonRunningPicocli.getErrString(), containsString("No trust store password provided"));
}
@Test
public void testShowConfigHidesSystemProperties() {
setSystemProperty("kc.something", "password", () -> {
@ -335,6 +320,7 @@ public class PicocliTest extends AbstractConfigurationTest {
/**
* Runs a fake build to setup the state of the persisted build properties
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private void build(String... args) {
if (Stream.of(args).anyMatch("start-dev"::equals)) {
Environment.setRebuildCheck(); // auto-build

View File

@ -31,6 +31,7 @@ import org.junit.After;
import org.junit.BeforeClass;
import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler;
import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
import org.keycloak.quarkus.runtime.configuration.Configuration;
import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider;
@ -115,6 +116,7 @@ public abstract class AbstractConfigurationTest {
PersistedConfigSource.getInstance().getConfigValueProperties().clear();
Profile.reset();
Configuration.resetConfig();
ExecutionExceptionHandler.resetExceptionTransformers();
}
@After

View File

@ -88,7 +88,7 @@ public class LoggingConfigurationTest extends AbstractConfigurationTest {
"quarkus.log.syslog.app-name", "keycloak",
"quarkus.log.syslog.protocol", "tcp",
"quarkus.log.syslog.format", DEFAULT_LOG_FORMAT,
"quarkus.log.syslog.json", "false"
"quarkus.log.syslog.json.enabled", "false"
));
// The default max-length attribute is set in the org.jboss.logmanager.handlers.SyslogHandler if not specified in config
@ -129,7 +129,7 @@ public class LoggingConfigurationTest extends AbstractConfigurationTest {
"quarkus.log.syslog.app-name", "keycloak2",
"quarkus.log.syslog.protocol", "udp",
"quarkus.log.syslog.format", "some format",
"quarkus.log.syslog.json", "true"
"quarkus.log.syslog.json.enabled", "true"
));
}
@ -247,11 +247,11 @@ public class LoggingConfigurationTest extends AbstractConfigurationTest {
));
assertExternalConfig(Map.of(
"quarkus.log.console.json", "true",
"quarkus.log.console.json.enabled", "true",
"quarkus.log.console.json.log-format", "ecs",
"quarkus.log.file.json", "true",
"quarkus.log.file.json.enabled", "true",
"quarkus.log.file.json.log-format", "ecs",
"quarkus.log.syslog.json", "true",
"quarkus.log.syslog.json.enabled", "true",
"quarkus.log.syslog.json.log-format", "ecs"
));
}

View File

@ -89,7 +89,7 @@
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<artifactId>ojdbc17</artifactId>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -149,8 +149,7 @@ public class FipsDistTest {
CLIResult cliResult = dist.run("--verbose", "start", "--fips-mode=non-strict", "--https-key-store-password=passwordpassword",
"--https-trust-store-file=" + truststorePath, "--https-trust-store-password=passwordpassword");
cliResult.assertError("Unable to determine 'https-trust-store-type' automatically. Adjust the file extension or specify the property.");
cliResult.assertMessage("Unable to determine 'https-trust-store-type' automatically. Adjust the file extension or specify the property.");
dist.stop();
dist.copyOrReplaceFileFromClasspath("/server.keystore.pkcs12", Path.of("conf", "server.p12"));

View File

@ -17,13 +17,17 @@
package org.keycloak.it.cli.dist;
import io.quarkus.test.junit.main.Launch;
import org.junit.jupiter.api.Test;
import org.keycloak.it.junit5.extension.CLIResult;
import org.keycloak.it.junit5.extension.DistributionTest;
import org.keycloak.it.junit5.extension.RawDistOnly;
import org.keycloak.it.junit5.extension.TestProvider;
import org.keycloak.it.resource.realm.TestRealmResourceTestProvider;
import org.keycloak.it.utils.KeycloakDistribution;
import org.keycloak.it.utils.RawKeycloakDistribution;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@ -31,12 +35,8 @@ import java.util.concurrent.CompletableFuture;
import static io.restassured.RestAssured.when;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
/**
* @author Vaclav Muzikar <vmuzikar@redhat.com>
*/
@ -62,7 +62,30 @@ public class HttpDistTest {
@Test
@Launch({"start-dev", "--https-certificates-reload-period=wrong"})
public void testHttpCertificateReloadPeriod(LaunchResult result) {
assertThat(result.getErrorOutput(), containsString("Text cannot be parsed to a Duration"));
public void testHttpCertificateReloadPeriod(CLIResult result) {
result.assertError("Text cannot be parsed to a Duration");
}
@Test
public void httpStoreTypeValidation(KeycloakDistribution dist) {
CLIResult result = dist.run("start", "--https-key-store-file=not-there.ks", "--hostname-strict=false");
result.assertExitCode(-1);
result.assertMessage("ERROR: Unable to determine 'https-key-store-type' automatically. Adjust the file extension or specify the property");
result = dist.run("start", "--https-trust-store-file=not-there.ks", "--hostname-strict=false");
result.assertExitCode(-1);
result.assertMessage("ERROR: Unable to determine 'https-trust-store-type' automatically. Adjust the file extension or specify the property");
result = dist.run("start", "--https-key-store-file=not-there.ks", "--hostname-strict=false", "--https-key-store-type=jdk");
result.assertExitCode(-1);
result.assertMessage("ERROR: Failed to load 'https-trust-store' or 'https-key-' material: NoSuchFileException not-there.ks");
dist.copyOrReplaceFileFromClasspath("/server.keystore.pkcs12", Path.of("conf", "server.p12"));
RawKeycloakDistribution rawDist = dist.unwrap(RawKeycloakDistribution.class);
Path truststorePath = rawDist.getDistPath().resolve("conf").resolve("server.p12").toAbsolutePath();
result = dist.run("start", "--https-trust-store-file=" + truststorePath, "--hostname-strict=false");
result.assertExitCode(-1);
result.assertMessage("ERROR: No trust store password provided");
}
}

View File

@ -202,7 +202,8 @@ public class QuarkusPropertiesDistTest {
"--https-certificate-key-file=/tmp/kc/bin/../conf/server.key.pem" })
@Order(13)
void testHttpCertsPathTransformer(CLIResult cliResult) {
cliResult.assertError("Failed to load 'https-key-' material: NoSuchFileException /tmp/kc/bin/../conf/server.crt.pem");
cliResult.assertExitCode(1);
cliResult.assertMessage("Failed to load 'https-trust-store' or 'https-key-' material: NoSuchFileException");
}
@Test
@ -213,7 +214,8 @@ public class QuarkusPropertiesDistTest {
"--https-certificate-key-file=C:\\tmp\\kc\\bin\\..\\conf/server.key.pem" })
@Order(14)
void testHttpCertsPathTransformerOnWindows(CLIResult cliResult) {
cliResult.assertError("Failed to load 'https-key-' material: NoSuchFileException C:\\tmp\\kc\\bin\\..\\conf\\server.crt.pem");
cliResult.assertExitCode(1);
cliResult.assertMessage("ERROR: Failed to load 'https-trust-store' or 'https-key-' material: NoSuchFileException C:");
}
public static class AddConsoleHandlerFromQuarkusProps implements Consumer<KeycloakDistribution> {

View File

@ -46,7 +46,7 @@ public class OracleTest extends BasicDatabaseTest {
@Override
public void accept(KeycloakDistribution distribution) {
RawKeycloakDistribution rawDist = distribution.unwrap(RawKeycloakDistribution.class);
rawDist.copyProvider("com.oracle.database.jdbc", "ojdbc11");
rawDist.copyProvider("com.oracle.database.jdbc", "ojdbc17");
rawDist.copyProvider("com.oracle.database.nls", "orai18n");
}
}

View File

@ -108,7 +108,7 @@
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<artifactId>ojdbc17</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.database.nls</groupId>

View File

@ -85,6 +85,10 @@ public interface CLIResult extends LaunchResult {
getErrorOutput(), not(containsString(msg)));
}
default void assertExitCode(int code) {
assertThat("Exit codes do not match: ", exitCode(), is(code));
}
default void assertMessage(String message) {
assertThat(getOutput(), containsString(message));
}

View File

@ -138,6 +138,7 @@ public class KeycloakDistributionDecorator implements KeycloakDistribution {
}
if (type.isInstance(delegate)) {
//noinspection unchecked
return (D) delegate;
}

View File

@ -43,7 +43,7 @@
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<artifactId>ojdbc17</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -19,6 +19,6 @@ public class OracleDatabaseSupplier extends AbstractDatabaseSupplier {
@Override
public KeycloakServerConfigBuilder intercept(KeycloakServerConfigBuilder serverConfig, InstanceContext<TestDatabase, InjectTestDatabase> instanceContext) {
return super.intercept(serverConfig, instanceContext)
.dependency("com.oracle.database.jdbc", "ojdbc11");
.dependency("com.oracle.database.jdbc", "ojdbc17");
}
}

View File

@ -523,7 +523,7 @@
<!-- For EAP testing, it is recommended to override those with system properties pointing to GAV of more appropriate JDBC driver -->
<!-- for the particular EAP version -->
<jdbc.mvn.groupId>com.oracle.database.jdbc</jdbc.mvn.groupId>
<jdbc.mvn.artifactId>ojdbc11</jdbc.mvn.artifactId>
<jdbc.mvn.artifactId>ojdbc17</jdbc.mvn.artifactId>
<jdbc.mvn.version>${oracle-jdbc.version}</jdbc.mvn.version>
</properties>
</profile>

View File

@ -201,7 +201,7 @@
<artifactItems>
<artifactItem>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<artifactId>ojdbc17</artifactId>
<version>${oracle-jdbc.version}</version>
<type>jar</type>
<outputDirectory>${auth.server.home}/providers</outputDirectory>

View File

@ -24,7 +24,7 @@ import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.sdk.trace.internal.data.ExceptionEventData;
import io.opentelemetry.sdk.trace.data.ExceptionEventData;
import io.opentelemetry.semconv.ExceptionAttributes;
import org.jboss.arquillian.container.test.api.ContainerController;
import org.jboss.arquillian.test.api.ArquillianResource;

View File

@ -259,7 +259,7 @@
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<artifactId>ojdbc17</artifactId>
<version>${oracle-jdbc.version}</version>
<scope>compile</scope>
</dependency>