task: upgrading to quarkus 3.7.0.CR1 (#26203)

there are several downgrades from the quarkus versions, and some
additional logic needed to handle changes with re-creating the
configuration

Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
Steven Hawkins 2024-01-31 13:23:07 -05:00 committed by GitHub
parent a43ba73b93
commit 37acb2fd09
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 182 additions and 122 deletions

View file

@ -18,6 +18,7 @@
package org.keycloak.crypto.def;
import org.bouncycastle.asn1.ASN1IA5String;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERIA5String;
@ -338,8 +339,8 @@ public class BCOCSPProvider extends OCSPProvider {
// https://www.ietf.org/rfc/rfc2560.txt, if nextUpdate is not set,
// the responder is indicating that newer update is avilable all the time
long current = date == null ? System.currentTimeMillis() : date.getTime();
Date stop = new Date(current + (long) TIME_SKEW);
Date start = new Date(current - (long) TIME_SKEW);
Date stop = new Date(current + TIME_SKEW);
Date start = new Date(current - TIME_SKEW);
Iterator<SingleResp> iter = Arrays.asList(basicOcspResponse.getResponses()).iterator();
SingleResp singleRes = null;
@ -436,7 +437,7 @@ public class BCOCSPProvider extends OCSPProvider {
if (ad.getAccessMethod().equals(AccessDescription.id_ad_ocsp)) {
// See https://www.ietf.org/rfc/rfc2560.txt, 3.1 Certificate Content
if (ad.getAccessLocation().getTagNo() == GeneralName.uniformResourceIdentifier) {
DERIA5String value = DERIA5String.getInstance(ad.getAccessLocation().getName());
ASN1IA5String value = DERIA5String.getInstance(ad.getAccessLocation().getName());
responderURIs.add(value.getString());
}
}

View file

@ -23,6 +23,8 @@ import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.ASN1UTF8String;
import org.bouncycastle.asn1.BERTags;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
import org.bouncycastle.asn1.x500.RDN;
@ -162,7 +164,7 @@ public class BCUserIdentityExtractorProvider extends UserIdentityExtractorProvi
tempOid = oid.getId();
ASN1Encodable principalNameEncoded = asn1Sequence.getObjectAt(1);
DERUTF8String principalName = DERUTF8String.getInstance(unwrap(principalNameEncoded));
ASN1UTF8String principalName = DERUTF8String.getInstance(unwrap(principalNameEncoded));
tempOtherName = principalName.getString();
@ -195,8 +197,8 @@ public class BCUserIdentityExtractorProvider extends UserIdentityExtractorProvi
private ASN1Encodable unwrap(ASN1Encodable encodable) {
while (encodable instanceof ASN1TaggedObject) {
ASN1TaggedObject taggedObj = (ASN1TaggedObject) encodable;
encodable = taggedObj.getObject();
ASN1TaggedObject taggedObj = ASN1TaggedObject.getInstance(encodable, BERTags.CONTEXT_SPECIFIC);
encodable = taggedObj.getBaseObject().toASN1Primitive();
}
return encodable;

View file

@ -67,18 +67,6 @@
<artifactId>quarkus-operator-sdk-bundle-generator</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-client</artifactId>

View file

@ -18,6 +18,7 @@
package org.keycloak.operator;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;
import java.util.Map;
@ -36,4 +37,17 @@ public interface Config {
Map<String, String> podLabels();
}
// workarounds for OLM env values
// to be removed after https://github.com/keycloak/keycloak/issues/12352
@WithDefault("keycloak-operator")
String name();
interface Condition {
@WithDefault("keycloak-operator.v999-SNAPSHOT")
String name();
}
Condition condition();
}

View file

@ -23,9 +23,7 @@ import io.fabric8.kubernetes.api.model.EnvVarBuilder;
import io.fabric8.kubernetes.api.model.EnvVarSource;
import io.fabric8.kubernetes.api.model.EnvVarSourceBuilder;
import io.fabric8.kubernetes.api.model.PodSpec;
import io.fabric8.kubernetes.api.model.PodSpecFluent.ContainersNested;
import io.fabric8.kubernetes.api.model.PodTemplateSpec;
import io.fabric8.kubernetes.api.model.PodTemplateSpecFluent.SpecNested;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.api.model.SecretKeySelector;
import io.fabric8.kubernetes.api.model.VolumeBuilder;
@ -33,7 +31,7 @@ import io.fabric8.kubernetes.api.model.VolumeMountBuilder;
import io.fabric8.kubernetes.api.model.apps.StatefulSet;
import io.fabric8.kubernetes.api.model.apps.StatefulSetBuilder;
import io.fabric8.kubernetes.api.model.apps.StatefulSetSpec;
import io.fabric8.kubernetes.api.model.apps.StatefulSetSpecFluent.TemplateNested;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
@ -103,10 +101,10 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
addTruststores(primary, baseDeployment, kcContainer, allSecrets);
addEnvVars(baseDeployment, primary, allSecrets);
Optional.ofNullable(primary.getSpec().getCacheSpec())
.ifPresent(c -> configureCache(primary, baseDeployment, kcContainer, c));
.ifPresent(c -> configureCache(primary, baseDeployment, kcContainer, c, context.getClient()));
if (!allSecrets.isEmpty()) {
watchedResources.annotateDeployment(new ArrayList<>(allSecrets), Secret.class, baseDeployment, this.client);
watchedResources.annotateDeployment(new ArrayList<>(allSecrets), Secret.class, baseDeployment, context.getClient());
}
StatefulSet existingDeployment = context.getSecondaryResource(StatefulSet.class).orElse(null);
@ -128,7 +126,7 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
return baseDeployment;
}
private void configureCache(Keycloak keycloakCR, StatefulSet deployment, Container kcContainer, CacheSpec spec) {
private void configureCache(Keycloak keycloakCR, StatefulSet deployment, Container kcContainer, CacheSpec spec, KubernetesClient client) {
Optional.ofNullable(spec.getConfigMapFile()).ifPresent(configFile -> {
if (configFile.getName() == null || configFile.getKey() == null) {
throw new IllegalStateException("Cache file ConfigMap requires both a name and a key");
@ -151,7 +149,7 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
kcContainer.getVolumeMounts().add(0, volumeMount);
// currently the only configmap we're watching
watchedResources.annotateDeployment(List.of(configFile.getName()), ConfigMap.class, deployment, this.client);
watchedResources.annotateDeployment(List.of(configFile.getName()), ConfigMap.class, deployment, client);
});
}
@ -249,12 +247,7 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
}
// there isn't currently an editOrNewFirstContainer, so we need to do this manually
ContainersNested<SpecNested<TemplateNested<io.fabric8.kubernetes.api.model.apps.StatefulSetFluent.SpecNested<StatefulSetBuilder>>>> containerBuilder = null;
if (specBuilder.buildContainers().isEmpty()) {
containerBuilder = specBuilder.addNewContainer();
} else {
containerBuilder = specBuilder.editFirstContainer();
}
var containerBuilder = specBuilder.buildContainers().isEmpty() ? specBuilder.addNewContainer() : specBuilder.editFirstContainer();
containerBuilder.withName("keycloak");

View file

@ -57,7 +57,6 @@ public class KeycloakRealmImportController implements Reconciler<KeycloakRealmIm
@Override
public Map<String, EventSource> prepareEventSources(EventSourceContext<KeycloakRealmImport> context) {
this.jobDependentResource = new KeycloakRealmImportJobDependentResource();
this.jobDependentResource.setKubernetesClient(context.getClient());
return EventSourceInitializer.nameEventSourcesFromDependentResource(context, jobDependentResource);
}

View file

@ -20,8 +20,6 @@ package org.keycloak.operator.testsuite.integration;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodSpecFluent.ContainersNested;
import io.fabric8.kubernetes.api.model.PodTemplateSpecFluent.SpecNested;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.apps.StatefulSet;
@ -59,9 +57,7 @@ import org.keycloak.operator.Constants;
import org.keycloak.operator.controllers.KeycloakDeploymentDependentResource;
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakSpecBuilder;
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakSpecFluent.UnsupportedNested;
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatus;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.UnsupportedSpecFluent.PodTemplateNested;
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImport;
import org.keycloak.operator.testsuite.utils.K8sUtils;
import org.opentest4j.TestAbortedException;
@ -405,12 +401,8 @@ public class BaseOperatorTest implements QuarkusTestAfterEachCallback {
public static Keycloak disableProbes(Keycloak keycloak) {
KeycloakSpecBuilder specBuilder = new KeycloakSpecBuilder(keycloak.getSpec());
var podTemplateSpecBuilder = specBuilder.editOrNewUnsupported().editOrNewPodTemplate().editOrNewSpec();
ContainersNested<SpecNested<PodTemplateNested<UnsupportedNested<KeycloakSpecBuilder>>>> containerBuilder = null;
if (podTemplateSpecBuilder.hasContainers()) {
containerBuilder = podTemplateSpecBuilder.editContainer(0);
} else {
containerBuilder = podTemplateSpecBuilder.addNewContainer();
}
var containerBuilder = podTemplateSpecBuilder.hasContainers() ? podTemplateSpecBuilder.editContainer(0)
: podTemplateSpecBuilder.addNewContainer();
keycloak.setSpec(containerBuilder.withNewLivenessProbe().withNewExec().addToCommand("true").endExec()
.endLivenessProbe().withNewReadinessProbe().withNewExec().addToCommand("true").endExec()
.endReadinessProbe().withNewStartupProbe().withNewExec().addToCommand("true").endExec()

30
pom.xml
View file

@ -45,8 +45,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.2.9.Final</quarkus.version>
<quarkus.build.version>3.2.9.Final</quarkus.build.version>
<quarkus.version>3.7.0.CR1</quarkus.version>
<quarkus.build.version>3.7.0.CR1</quarkus.build.version>
<project.build-time>${timestamp}</project.build-time>
@ -86,6 +86,8 @@
<!-- TODO Are these correct versions? -->
<bouncycastle.pkixfips.version>1.0.7</bouncycastle.pkixfips.version>
<!-- 1.0.2.4 exhibits class loading issues -->
<bouncycastle.bcfips.version>1.0.2.3</bouncycastle.bcfips.version>
<cxf.version>3.3.10</cxf.version>
<cxf.jetty.version>3.3.10</cxf.jetty.version>
@ -106,8 +108,6 @@
<servlet.api.30.version>1.0.2.Final</servlet.api.30.version>
<jboss-jaxrs-api_2.1_spec>2.0.2.Final</jboss-jaxrs-api_2.1_spec>
<jboss-servlet-api_4.0_spec>2.0.0.Final</jboss-servlet-api_4.0_spec>
<jboss.logmanager>2.1.19.Final</jboss.logmanager>
<jboss.marshalling.version>2.0.11.Final</jboss.marshalling.version>
<jboss.spec.javax.xml.bind.jboss-jaxb-api_2.3_spec.version>2.0.1.Final</jboss.spec.javax.xml.bind.jboss-jaxb-api_2.3_spec.version>
<jboss.spec.javax.servlet.jsp.jboss-jsp-api_2.3_spec.version>2.0.0.Final</jboss.spec.javax.servlet.jsp.jboss-jsp-api_2.3_spec.version>
<log4j.version>1.2.17</log4j.version>
@ -427,6 +427,13 @@
<artifactId>bcpkix-fips</artifactId>
<version>${bouncycastle.pkixfips.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bc-fips</artifactId>
<version>${bouncycastle.bcfips.version}</version>
</dependency>
<dependency>
<groupId>com.github.ua-parser</groupId>
<artifactId>uap-java</artifactId>
@ -557,11 +564,6 @@
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.logmanager</groupId>
<artifactId>jboss-logmanager</artifactId>
<version>${jboss.logmanager}</version>
</dependency>
<dependency>
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
<artifactId>owasp-java-html-sanitizer</artifactId>
@ -894,16 +896,6 @@
<artifactId>undertow-server</artifactId>
<version>${elytron.undertow-server.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling</artifactId>
<version>${jboss.marshalling.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling-river</artifactId>
<version>${jboss.marshalling.version}</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>

View file

@ -29,7 +29,6 @@ import io.quarkus.deployment.annotations.Consume;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Produce;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.BootstrapConfigSetupCompleteBuildItem;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
@ -44,6 +43,7 @@ import io.quarkus.resteasy.reactive.server.spi.MethodScannerBuildItem;
import io.quarkus.runtime.configuration.ConfigurationException;
import io.quarkus.runtime.configuration.ProfileManager;
import io.quarkus.vertx.http.deployment.RouteBuildItem;
import io.quarkus.resteasy.reactive.spi.IgnoreStackMixingBuildItem;
import io.smallrye.config.ConfigValue;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
@ -207,6 +207,11 @@ class KeycloakProcessor {
return new DeployedScriptSAMLProtocolMapper(metadata);
}
@BuildStep
IgnoreStackMixingBuildItem getIgnoreStackMixing() {
return new IgnoreStackMixingBuildItem();
}
@BuildStep
FeatureBuildItem getFeature() {
return new FeatureBuildItem("keycloak");
@ -286,7 +291,7 @@ class KeycloakProcessor {
*
* <p>The {@code hibernate-orm} extension expects that the dialect is statically
* set to the persistence unit if there is any from the classpath and we use this method to obtain the dialect from the configuration
* file so that we can build the application with whatever dialect we want. In addition to the dialect, we should also be
* file so that we can build the application with whatever dialect we want. In addition to the dialect, we should also be
* allowed to set any additional defaults that we think that makes sense.
*
* @param config
@ -459,9 +464,9 @@ class KeycloakProcessor {
.map(ParsedPersistenceXmlDescriptor::getName)
.filter(Predicate.not("keycloak-default"::equals)).forEach((String unitName) -> {
NamedJpaConnectionProviderFactory factory = new NamedJpaConnectionProviderFactory();
factory.setUnitName(unitName);
factories.get(spi).get(JpaConnectionProvider.class).put(unitName, NamedJpaConnectionProviderFactory.class);
preConfiguredProviders.put(unitName, factory);
});
@ -662,7 +667,6 @@ class KeycloakProcessor {
}));
}
@Consume(BootstrapConfigSetupCompleteBuildItem.class)
@Consume(ProfileBuildItem.class)
@Produce(CryptoProviderInitBuildItem.class)
@BuildStep

View file

@ -58,7 +58,7 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
super(parseArguments(), NAME, 600);
}
public static void setCliArgs(String[] args) {
public static void setCliArgs(String... args) {
System.setProperty(CLI_ARGS, String.join(ARG_SEPARATOR, args));
}

View file

@ -43,6 +43,7 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.Config;
import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider;
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
@ -57,7 +58,6 @@ public class ConfigurationTest {
private static final Properties SYSTEM_PROPERTIES = (Properties) System.getProperties().clone();
private static final Map<String, String> ENVIRONMENT_VARIABLES = new HashMap<>(System.getenv());
private static final String ARG_SEPARATOR = ";;";
@SuppressWarnings("unchecked")
public static void putEnvVar(String name, String value) {
@ -158,7 +158,7 @@ public class ConfigurationTest {
@Test
public void testCLIPriorityOverSysProp() {
System.setProperty("kc.spi.hostname.default.frontend-url", "http://propvar.unittest");
System.setProperty(CLI_ARGS, "--spi-hostname-default-frontend-url=http://cli.unittest");
ConfigArgsConfigSource.setCliArgs("--spi-hostname-default-frontend-url=http://cli.unittest");
assertEquals("http://cli.unittest", initConfig("hostname", "default").get("frontendUrl"));
}
@ -187,53 +187,53 @@ public class ConfigurationTest {
@Test
public void testCommandLineArguments() {
System.setProperty(CLI_ARGS, "--spi-hostname-default-frontend-url=http://fromargs.unittest" + ARG_SEPARATOR + "--no-ssl");
ConfigArgsConfigSource.setCliArgs("--spi-hostname-default-frontend-url=http://fromargs.unittest", "--no-ssl");
assertEquals("http://fromargs.unittest", initConfig("hostname", "default").get("frontendUrl"));
}
@Test
public void testSpiConfigurationUsingCommandLineArguments() {
System.setProperty(CLI_ARGS, "--spi-hostname-default-frontend-url=http://spifull.unittest");
ConfigArgsConfigSource.setCliArgs("--spi-hostname-default-frontend-url=http://spifull.unittest");
assertEquals("http://spifull.unittest", initConfig("hostname", "default").get("frontendUrl"));
// test multi-word SPI names using camel cases
System.setProperty(CLI_ARGS, "--spi-action-token-handler-verify-email-some-property=test");
ConfigArgsConfigSource.setCliArgs("--spi-action-token-handler-verify-email-some-property=test");
assertEquals("test", initConfig("action-token-handler", "verify-email").get("some-property"));
System.setProperty(CLI_ARGS, "--spi-action-token-handler-verify-email-some-property=test");
ConfigArgsConfigSource.setCliArgs("--spi-action-token-handler-verify-email-some-property=test");
assertEquals("test", initConfig("actionTokenHandler", "verifyEmail").get("someProperty"));
// test multi-word SPI names using slashes
System.setProperty(CLI_ARGS, "--spi-client-registration-openid-connect-static-jwk-url=http://c.jwk.url");
ConfigArgsConfigSource.setCliArgs("--spi-client-registration-openid-connect-static-jwk-url=http://c.jwk.url");
assertEquals("http://c.jwk.url", initConfig("client-registration", "openid-connect").get("static-jwk-url"));
}
@Test
public void testResolveTransformedValue() {
System.setProperty(CLI_ARGS, "");
ConfigArgsConfigSource.setCliArgs("");
assertEquals("none", createConfig().getConfigValue("kc.proxy").getValue());
System.setProperty(CLI_ARGS, "--proxy=none");
ConfigArgsConfigSource.setCliArgs("--proxy=none");
assertEquals("none", createConfig().getConfigValue("kc.proxy").getValue());
System.setProperty(CLI_ARGS, "");
ConfigArgsConfigSource.setCliArgs("");
assertEquals("none", createConfig().getConfigValue("kc.proxy").getValue());
System.setProperty(CLI_ARGS, "--proxy=none" + ARG_SEPARATOR + "--http-enabled=false");
ConfigArgsConfigSource.setCliArgs("--proxy=none", "--http-enabled=false");
assertEquals("false", createConfig().getConfigValue("kc.http-enabled").getValue());
System.setProperty(CLI_ARGS, "--proxy=none" + ARG_SEPARATOR + "--http-enabled=true");
ConfigArgsConfigSource.setCliArgs("--proxy=none", "--http-enabled=true");
assertEquals("true", createConfig().getConfigValue("kc.http-enabled").getValue());
}
@Test
public void testPropertyNamesFromConfig() {
System.setProperty(CLI_ARGS, "--spi-client-registration-openid-connect-static-jwk-url=http://c.jwk.url");
ConfigArgsConfigSource.setCliArgs("--spi-client-registration-openid-connect-static-jwk-url=http://c.jwk.url");
Config.Scope config = initConfig("client-registration", "openid-connect");
assertEquals(1, config.getPropertyNames().size());
assertEquals("http://c.jwk.url", config.get("static-jwk-url"));
System.setProperty(CLI_ARGS, "--vault-dir=secrets");
ConfigArgsConfigSource.setCliArgs("--vault-dir=secrets");
config = initConfig("vault", FilesPlainTextVaultProviderFactory.ID);
assertEquals(1, config.getPropertyNames().size());
assertEquals("secrets", config.get("dir"));
System.setProperty(CLI_ARGS, "--vault-type=JKS");
ConfigArgsConfigSource.setCliArgs("--vault-type=JKS");
config = initConfig("vault", FilesKeystoreVaultProviderFactory.ID);
assertEquals(1, config.getPropertyNames().size());
assertEquals("JKS", config.get("type"));
@ -255,7 +255,7 @@ public class ConfigurationTest {
@Test
public void testPropertyMapping() {
System.setProperty(CLI_ARGS, "--db=mariadb" + ARG_SEPARATOR + "--db-url=jdbc:mariadb://localhost/keycloak");
ConfigArgsConfigSource.setCliArgs("--db=mariadb", "--db-url=jdbc:mariadb://localhost/keycloak");
SmallRyeConfig config = createConfig();
assertEquals(MariaDBDialect.class.getName(), config.getConfigValue("kc.db-dialect").getValue());
assertEquals("jdbc:mariadb://localhost/keycloak", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
@ -263,7 +263,7 @@ public class ConfigurationTest {
@Test
public void testDatabaseUrlProperties() {
System.setProperty(CLI_ARGS, "--db=mariadb" + ARG_SEPARATOR + "--db-url=jdbc:mariadb:aurora://foo/bar?a=1&b=2");
ConfigArgsConfigSource.setCliArgs("--db=mariadb", "--db-url=jdbc:mariadb:aurora://foo/bar?a=1&b=2");
SmallRyeConfig config = createConfig();
assertEquals(MariaDBDialect.class.getName(), config.getConfigValue("kc.db-dialect").getValue());
assertEquals("jdbc:mariadb:aurora://foo/bar?a=1&b=2", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
@ -271,7 +271,7 @@ public class ConfigurationTest {
@Test
public void testDatabaseDefaults() {
System.setProperty(CLI_ARGS, "--db=dev-file");
ConfigArgsConfigSource.setCliArgs("--db=dev-file");
SmallRyeConfig config = createConfig();
assertEquals(H2Dialect.class.getName(), config.getConfigValue("kc.db-dialect").getValue());
@ -283,23 +283,23 @@ public class ConfigurationTest {
assertEquals("jdbc:h2:file:" + userHomeUri + "data/h2/keycloakdb;;AUTO_SERVER=TRUE;NON_KEYWORDS=VALUE", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
System.setProperty(CLI_ARGS, "--db=dev-mem");
ConfigArgsConfigSource.setCliArgs("--db=dev-mem");
config = createConfig();
assertEquals(H2Dialect.class.getName(), config.getConfigValue("kc.db-dialect").getValue());
assertEquals("jdbc:h2:mem:keycloakdb;NON_KEYWORDS=VALUE", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
assertEquals("h2", config.getConfigValue("quarkus.datasource.db-kind").getValue());
System.setProperty(CLI_ARGS, "--db=dev-mem" + ARG_SEPARATOR + "--db-username=other");
ConfigArgsConfigSource.setCliArgs("--db=dev-mem", "--db-username=other");
config = createConfig();
assertEquals("sa", config.getConfigValue("quarkus.datasource.username").getValue());
// should be untransformed
assertEquals("other", config.getConfigValue("kc.db-username").getValue());
System.setProperty(CLI_ARGS, "--db=postgres" + ARG_SEPARATOR + "--db-username=other");
ConfigArgsConfigSource.setCliArgs("--db=postgres", "--db-username=other");
config = createConfig();
assertEquals("other", config.getConfigValue("quarkus.datasource.username").getValue());
System.setProperty(CLI_ARGS, "--db=postgres");
ConfigArgsConfigSource.setCliArgs("--db=postgres");
config = createConfig();
// username should not be set, either as the quarkus or kc property
assertEquals(null, config.getConfigValue("quarkus.datasource.username").getValue());
@ -308,7 +308,7 @@ public class ConfigurationTest {
@Test
public void testDatabaseKindProperties() {
System.setProperty(CLI_ARGS, "--db=postgres" + ARG_SEPARATOR + "--db-url=jdbc:postgresql://localhost/keycloak" + ARG_SEPARATOR + "--db-username=postgres");
ConfigArgsConfigSource.setCliArgs("--db=postgres", "--db-url=jdbc:postgresql://localhost/keycloak", "--db-username=postgres");
SmallRyeConfig config = createConfig();
assertEquals("org.hibernate.dialect.PostgreSQLDialect",
config.getConfigValue("kc.db-dialect").getValue());
@ -319,7 +319,7 @@ public class ConfigurationTest {
@Test
public void testDefaultDbPropertiesGetApplied() {
System.setProperty(CLI_ARGS, "--db=postgres" + ARG_SEPARATOR + "--db-url-host=myhost" + ARG_SEPARATOR + "--db-url-database=kcdb" + ARG_SEPARATOR + "--db-url-properties=?foo=bar");
ConfigArgsConfigSource.setCliArgs("--db=postgres", "--db-url-host=myhost", "--db-url-database=kcdb", "--db-url-properties=?foo=bar");
SmallRyeConfig config = createConfig();
assertEquals("org.hibernate.dialect.PostgreSQLDialect",
config.getConfigValue("kc.db-dialect").getValue());
@ -329,7 +329,7 @@ public class ConfigurationTest {
@Test
public void testRemoveSpaceFromValue() {
System.setProperty(CLI_ARGS, "--db=postgres ");
ConfigArgsConfigSource.setCliArgs("--db=postgres ");
SmallRyeConfig config = createConfig();
assertEquals("org.hibernate.dialect.PostgreSQLDialect",
config.getConfigValue("kc.db-dialect").getValue());
@ -338,7 +338,7 @@ public class ConfigurationTest {
@Test
public void testDefaultDbPortGetApplied() {
System.setProperty(CLI_ARGS, "--db=mssql" + ARG_SEPARATOR + "--db-url-host=myhost" + ARG_SEPARATOR + "--db-url-database=kcdb" + ARG_SEPARATOR + "--db-url-port=1234" + ARG_SEPARATOR + "--db-url-properties=?foo=bar");
ConfigArgsConfigSource.setCliArgs("--db=mssql", "--db-url-host=myhost", "--db-url-database=kcdb", "--db-url-port=1234", "--db-url-properties=?foo=bar");
SmallRyeConfig config = createConfig();
assertEquals("org.hibernate.dialect.SQLServerDialect",
config.getConfigValue("kc.db-dialect").getValue());
@ -348,7 +348,7 @@ public class ConfigurationTest {
@Test
public void testSetDbUrlOverridesDefaultDataSource() {
System.setProperty(CLI_ARGS, "--db=mariadb" + ARG_SEPARATOR + "--db-url-host=myhost" + ARG_SEPARATOR + "--db-url=jdbc:mariadb://localhost/keycloak");
ConfigArgsConfigSource.setCliArgs("--db=mariadb", "--db-url-host=myhost", "--db-url=jdbc:mariadb://localhost/keycloak");
SmallRyeConfig config = createConfig();
assertEquals("org.hibernate.dialect.MariaDBDialect",
config.getConfigValue("kc.db-dialect").getValue());
@ -360,31 +360,31 @@ public class ConfigurationTest {
public void testDatabaseProperties() {
System.setProperty("kc.db-url-properties", ";;test=test;test1=test1");
System.setProperty("kc.db-url-path", "test-dir");
System.setProperty(CLI_ARGS, "--db=dev-file");
ConfigArgsConfigSource.setCliArgs("--db=dev-file");
SmallRyeConfig config = createConfig();
assertEquals(H2Dialect.class.getName(), config.getConfigValue("kc.db-dialect").getValue());
assertEquals("jdbc:h2:file:test-dir/data/h2/keycloakdb;;test=test;test1=test1;NON_KEYWORDS=VALUE", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
assertEquals("xa", config.getConfigValue("quarkus.datasource.jdbc.transactions").getValue());
System.setProperty(CLI_ARGS, "");
ConfigArgsConfigSource.setCliArgs("");
config = createConfig();
assertEquals(H2Dialect.class.getName(), config.getConfigValue("kc.db-dialect").getValue());
assertEquals("jdbc:h2:file:test-dir/data/h2/keycloakdb;;test=test;test1=test1;NON_KEYWORDS=VALUE", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
System.setProperty("kc.db-url-properties", "?test=test&test1=test1");
System.setProperty(CLI_ARGS, "--db=mariadb");
ConfigArgsConfigSource.setCliArgs("--db=mariadb");
config = createConfig();
assertEquals("jdbc:mariadb://localhost:3306/keycloak?test=test&test1=test1", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
assertEquals(MariaDBDialect.class.getName(), config.getConfigValue("kc.db-dialect").getValue());
assertEquals(MariaDbDataSource.class.getName(), config.getConfigValue("quarkus.datasource.jdbc.driver").getValue());
System.setProperty(CLI_ARGS, "--db=postgres");
ConfigArgsConfigSource.setCliArgs("--db=postgres");
config = createConfig();
assertEquals("jdbc:postgresql://localhost:5432/keycloak?test=test&test1=test1", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
assertEquals(PostgreSQLDialect.class.getName(), config.getConfigValue("kc.db-dialect").getValue());
assertEquals(PGXADataSource.class.getName(), config.getConfigValue("quarkus.datasource.jdbc.driver").getValue());
System.setProperty(CLI_ARGS, "--db-schema=test-schema");
ConfigArgsConfigSource.setCliArgs("--db-schema=test-schema");
config = createConfig();
assertEquals("test-schema", config.getConfigValue("kc.db-schema").getValue());
assertEquals("test-schema", config.getConfigValue("kc.db-schema").getValue());
@ -419,34 +419,34 @@ public class ConfigurationTest {
// If explicitly set, then it is always used regardless of the profile
System.clearProperty(Environment.PROFILE);
System.setProperty(CLI_ARGS, "--cache=cluster-foo.xml");
ConfigArgsConfigSource.setCliArgs("--cache=cluster-foo.xml");
Assert.assertEquals("cluster-foo.xml", initConfig("connectionsInfinispan", "quarkus").get("configFile"));
System.setProperty(Environment.PROFILE, "dev");
Assert.assertEquals("cluster-foo.xml", initConfig("connectionsInfinispan", "quarkus").get("configFile"));
System.setProperty(CLI_ARGS, "--cache-stack=foo");
ConfigArgsConfigSource.setCliArgs("--cache-stack=foo");
Assert.assertEquals("foo", initConfig("connectionsInfinispan", "quarkus").get("stack"));
}
@Test
public void testCommaSeparatedArgValues() {
System.setProperty(CLI_ARGS, "--spi-client-jpa-searchable-attributes=bar,foo");
ConfigArgsConfigSource.setCliArgs("--spi-client-jpa-searchable-attributes=bar,foo");
assertEquals("bar,foo", initConfig("client-jpa").get("searchable-attributes"));
System.setProperty(CLI_ARGS, "--spi-client-jpa-searchable-attributes=bar,foo,foo bar");
ConfigArgsConfigSource.setCliArgs("--spi-client-jpa-searchable-attributes=bar,foo,foo bar");
assertEquals("bar,foo,foo bar", initConfig("client-jpa").get("searchable-attributes"));
System.setProperty(CLI_ARGS, "--spi-client-jpa-searchable-attributes=bar,foo, \"foo bar\"");
ConfigArgsConfigSource.setCliArgs("--spi-client-jpa-searchable-attributes=bar,foo, \"foo bar\"");
assertEquals("bar,foo, \"foo bar\"", initConfig("client-jpa").get("searchable-attributes"));
System.setProperty(CLI_ARGS, "--spi-client-jpa-searchable-attributes=bar,foo, \"foo bar\"" + ARG_SEPARATOR + "--spi-hostname-default-frontend-url=http://foo.unittest");
ConfigArgsConfigSource.setCliArgs("--spi-client-jpa-searchable-attributes=bar,foo, \"foo bar\"", "--spi-hostname-default-frontend-url=http://foo.unittest");
assertEquals("http://foo.unittest", initConfig("hostname-default").get("frontend-url"));
}
@Test
public void testDatabaseDriverSetExplicitly() {
System.setProperty(CLI_ARGS, "--db=mssql" + ARG_SEPARATOR + "--db-url=jdbc:sqlserver://localhost/keycloak");
ConfigArgsConfigSource.setCliArgs("--db=mssql", "--db-url=jdbc:sqlserver://localhost/keycloak");
System.setProperty("kc.db-driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver");
System.setProperty("kc.transaction-xa-enabled", "false");
assertTrue(System.getProperty(CLI_ARGS, "").contains("mssql"));
@ -459,20 +459,20 @@ public class ConfigurationTest {
@Test
public void testDatabaseDialectSetExplicitly() {
System.setProperty(CLI_ARGS, "--db-dialect=user-defined");
ConfigArgsConfigSource.setCliArgs("--db-dialect=user-defined");
assertEquals("user-defined", createConfig().getRawValue("kc.db-dialect"));
}
@Test
public void testTransactionTypeChangesDriver() {
System.setProperty(CLI_ARGS, "--db=mssql" + ARG_SEPARATOR + "--transaction-xa-enabled=false");
ConfigArgsConfigSource.setCliArgs("--db=mssql", "--transaction-xa-enabled=false");
assertTrue(System.getProperty(CLI_ARGS, "").contains("mssql"));
SmallRyeConfig jtaEnabledConfig = createConfig();
assertEquals("com.microsoft.sqlserver.jdbc.SQLServerDriver", jtaEnabledConfig.getConfigValue("quarkus.datasource.jdbc.driver").getValue());
assertEquals("enabled", jtaEnabledConfig.getConfigValue("quarkus.datasource.jdbc.transactions").getValue());
System.setProperty(CLI_ARGS, "--db=mssql" + ARG_SEPARATOR + "--transaction-xa-enabled=true");
ConfigArgsConfigSource.setCliArgs("--db=mssql", "--transaction-xa-enabled=true");
assertTrue(System.getProperty(CLI_ARGS, "").contains("mssql"));
SmallRyeConfig xaConfig = createConfig();
@ -482,42 +482,42 @@ public class ConfigurationTest {
@Test
public void testResolveHealthOption() {
System.setProperty(CLI_ARGS, "--health-enabled=true");
ConfigArgsConfigSource.setCliArgs("--health-enabled=true");
SmallRyeConfig config = createConfig();
assertEquals("true", config.getConfigValue("quarkus.health.extensions.enabled").getValue());
System.setProperty(CLI_ARGS, "");
ConfigArgsConfigSource.setCliArgs("");
config = createConfig();
assertEquals("false", config.getConfigValue("quarkus.health.extensions.enabled").getValue());
}
@Test
public void testResolveMetricsOption() {
System.setProperty(CLI_ARGS, "--metrics-enabled=true");
ConfigArgsConfigSource.setCliArgs("--metrics-enabled=true");
SmallRyeConfig config = createConfig();
assertEquals("true", config.getConfigValue("quarkus.datasource.metrics.enabled").getValue());
}
@Test
public void testLogHandlerConfig() {
System.setProperty(CLI_ARGS, "--log=console,file");
ConfigArgsConfigSource.setCliArgs("--log=console,file");
SmallRyeConfig config = createConfig();
assertEquals("true", config.getConfigValue("quarkus.log.console.enable").getValue());
assertEquals("true", config.getConfigValue("quarkus.log.file.enable").getValue());
assertEquals("false", config.getConfigValue("quarkus.log.handler.gelf.enabled").getValue());
System.setProperty(CLI_ARGS, "--log=file");
ConfigArgsConfigSource.setCliArgs("--log=file");
SmallRyeConfig config2 = createConfig();
assertEquals("false", config2.getConfigValue("quarkus.log.console.enable").getValue());
assertEquals("true", config2.getConfigValue("quarkus.log.file.enable").getValue());
assertEquals("false", config2.getConfigValue("quarkus.log.handler.gelf.enabled").getValue());
System.setProperty(CLI_ARGS, "--log=console");
ConfigArgsConfigSource.setCliArgs("--log=console");
SmallRyeConfig config3 = createConfig();
assertEquals("true", config3.getConfigValue("quarkus.log.console.enable").getValue());
assertEquals("false", config3.getConfigValue("quarkus.log.file.enable").getValue());
assertEquals("false", config3.getConfigValue("quarkus.log.handler.gelf.enabled").getValue());
System.setProperty(CLI_ARGS, "--log=console,gelf");
ConfigArgsConfigSource.setCliArgs("--log=console,gelf");
SmallRyeConfig config4 = createConfig();
assertEquals("true", config4.getConfigValue("quarkus.log.console.enable").getValue());
assertEquals("false", config4.getConfigValue("quarkus.log.file.enable").getValue());
@ -526,7 +526,7 @@ public class ConfigurationTest {
@Test
public void testOptionValueWithEqualSign() {
System.setProperty(CLI_ARGS, "--db=postgres" + ARG_SEPARATOR + "--db-password=my_secret=");
ConfigArgsConfigSource.setCliArgs("--db=postgres", "--db-password=my_secret=");
SmallRyeConfig config = createConfig();
assertEquals("my_secret=", config.getConfigValue("kc.db-password").getValue());
}
@ -577,7 +577,12 @@ public class ConfigurationTest {
private SmallRyeConfig createConfig() {
KeycloakConfigSourceProvider.reload();
ConfigProviderResolver.setInstance(null);
return ConfigUtils.configBuilder(true, LaunchMode.NORMAL).build();
// older versions of quarkus implicitly picked up this config, now we
// must set it manually
SmallRyeConfig config = ConfigUtils.configBuilder(true, LaunchMode.NORMAL).build();
SmallRyeConfigProviderResolver resolver = new SmallRyeConfigProviderResolver();
resolver.registerConfig(config, Thread.currentThread().getContextClassLoader());
ConfigProviderResolver.setInstance(resolver);
return config;
}
}

View file

@ -20,7 +20,9 @@ package org.keycloak.it.cli;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.keycloak.it.junit5.extension.CLITest;
import org.keycloak.it.junit5.extension.ConfigurationTestResource;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import org.keycloak.quarkus.runtime.cli.command.ShowConfig;
@ -28,6 +30,7 @@ import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
import static org.keycloak.quarkus.runtime.cli.command.Main.CONFIG_FILE_LONG_NAME;
@QuarkusTestResource(value = ConfigurationTestResource.class, restrictToAnnotatedClass = true)
@CLITest
public class ShowConfigCommandTest {

View file

@ -23,6 +23,9 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.extension.ExtendWith;
/**
* When used for in-vm tests, use {@link ConfigurationTestResource} to reset the configuration
*/
@Target(ElementType.TYPE)
@ExtendWith({ CLITestExtension.class })
@Retention(RetentionPolicy.RUNTIME)

View file

@ -59,11 +59,12 @@ import static org.keycloak.quarkus.runtime.cli.command.Main.CONFIG_FILE_SHORT_NA
public class CLITestExtension extends QuarkusMainTestExtension {
private static final String SYS_PROPS = "sys-props";
private static final String KEY_VALUE_SEPARATOR = "[= ]";
private static final String KEY_VALUE_SEPARATOR = "[=]";
private KeycloakDistribution dist;
private DatabaseContainer databaseContainer;
private InfinispanContainer infinispanContainer;
private CLIResult result;
static String[] CLI_ARGS = new String[0];
@Override
public void beforeEach(ExtensionContext context) throws Exception {
@ -71,13 +72,13 @@ public class CLITestExtension extends QuarkusMainTestExtension {
Launch launch = context.getRequiredTestMethod().getAnnotation(Launch.class);
getStore(context).put(SYS_PROPS, new HashMap<>(System.getProperties()));
if (launch != null) {
if (launch != null && distConfig == null) {
for (String arg : launch.value()) {
if (arg.contains(CONFIG_FILE_SHORT_NAME) || arg.contains(CONFIG_FILE_LONG_NAME)) {
Pattern kvSeparator = Pattern.compile(KEY_VALUE_SEPARATOR);
String[] cfKeyValue = kvSeparator.split(arg);
setProperty(KeycloakPropertiesConfigSource.KEYCLOAK_CONFIG_FILE_PROP, cfKeyValue[1]);
} else if (distConfig == null && arg.startsWith("-D")) {
} else if (arg.startsWith("-D")) {
// allow setting system properties from JVM tests
int keyValueSeparator = arg.indexOf('=');
@ -114,6 +115,7 @@ public class CLITestExtension extends QuarkusMainTestExtension {
result = dist.run(Stream.concat(List.of(launch.value()).stream(), List.of(distConfig.defaultOptions()).stream()).collect(Collectors.toList()));
}
} else {
CLI_ARGS = launch == null ? new String[] {} : launch.value();
configureProfile(context);
super.beforeEach(context);
}

View file

@ -0,0 +1,57 @@
/*
* Copyright 2024 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.it.junit5.extension;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.configuration.ConfigUtils;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigProviderResolver;
import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider;
import java.util.Map;
/**
* Used to reset the configuration for {@link CLITest}s
*/
public class ConfigurationTestResource implements QuarkusTestResourceLifecycleManager {
@Override
public Map<String, String> start() {
return Map.of();
}
@Override
public void stop() {
}
@Override
public void inject(Object testInstance) {
ConfigArgsConfigSource.setCliArgs(CLITestExtension.CLI_ARGS);
KeycloakConfigSourceProvider.reload();
SmallRyeConfig config = ConfigUtils.configBuilder(true, LaunchMode.NORMAL).build();
SmallRyeConfigProviderResolver resolver = new SmallRyeConfigProviderResolver();
resolver.registerConfig(config, Thread.currentThread().getContextClassLoader());
ConfigProviderResolver.setInstance(resolver);
}
}

View file

@ -65,6 +65,11 @@
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-controller</artifactId>
</dependency>
<!-- pick up the transitive dependencies for the quarkus logmanager -->
<dependency>
<groupId>org.jboss.logmanager</groupId>
<artifactId>jboss-logmanager</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak.testsuite</groupId>
<artifactId>integration-arquillian-testsuite-providers-deployment</artifactId>