diff --git a/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakPolicyEnforcerBuildStep.java b/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakPolicyEnforcerBuildStep.java
index 3e7a54d0a37e1..0e06027a53539 100644
--- a/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakPolicyEnforcerBuildStep.java
+++ b/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakPolicyEnforcerBuildStep.java
@@ -25,7 +25,7 @@ public class KeycloakPolicyEnforcerBuildStep {
RequireBodyHandlerBuildItem requireBody(OidcBuildTimeConfig oidcBuildTimeConfig,
KeycloakPolicyEnforcerRecorder recorder,
KeycloakPolicyEnforcerConfig runtimeConfig) {
- if (oidcBuildTimeConfig.enabled) {
+ if (oidcBuildTimeConfig.enabled()) {
return new RequireBodyHandlerBuildItem(recorder.createBodyHandlerRequiredEvaluator(runtimeConfig));
}
return null;
@@ -33,7 +33,7 @@ RequireBodyHandlerBuildItem requireBody(OidcBuildTimeConfig oidcBuildTimeConfig,
@BuildStep
public AdditionalBeanBuildItem beans(OidcBuildTimeConfig oidcBuildTimeConfig) {
- if (oidcBuildTimeConfig.enabled) {
+ if (oidcBuildTimeConfig.enabled()) {
return AdditionalBeanBuildItem.builder().setUnremovable()
.addBeanClass(KeycloakPolicyEnforcerAuthorizer.class)
.addBeanClass(DefaultPolicyEnforcerResolver.class)
diff --git a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/DefaultPolicyEnforcerResolver.java b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/DefaultPolicyEnforcerResolver.java
index 6ab41a3ffbc00..f7ec6d61f7215 100644
--- a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/DefaultPolicyEnforcerResolver.java
+++ b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/DefaultPolicyEnforcerResolver.java
@@ -20,6 +20,7 @@
import io.quarkus.oidc.common.runtime.OidcTlsSupport;
import io.quarkus.oidc.runtime.BlockingTaskRunner;
import io.quarkus.oidc.runtime.OidcConfig;
+import io.quarkus.oidc.runtime.OidcUtils;
import io.quarkus.security.spi.runtime.BlockingSecurityExecutor;
import io.quarkus.tls.TlsConfigurationRegistry;
import io.quarkus.vertx.http.runtime.HttpConfiguration;
@@ -48,8 +49,9 @@ public class DefaultPolicyEnforcerResolver implements PolicyEnforcerResolver {
this.tlsSupport = OidcTlsSupport.empty();
}
- var defaultTenantTlsSupport = tlsSupport.forConfig(oidcConfig.defaultTenant.tls);
- this.defaultPolicyEnforcer = createPolicyEnforcer(oidcConfig.defaultTenant, config.defaultTenant(),
+ var defaultTenantConfig = new OidcTenantConfig(oidcConfig.defaultTenant(), OidcUtils.DEFAULT_TENANT_ID);
+ var defaultTenantTlsSupport = tlsSupport.forConfig(defaultTenantConfig.tls);
+ this.defaultPolicyEnforcer = createPolicyEnforcer(defaultTenantConfig, config.defaultTenant(),
defaultTenantTlsSupport);
this.namedPolicyEnforcers = createNamedPolicyEnforcers(oidcConfig, config, tlsSupport);
if (configResolver.isResolvable()) {
diff --git a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerUtil.java b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerUtil.java
index ae3a94a39f840..47330c2f01caa 100644
--- a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerUtil.java
+++ b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerUtil.java
@@ -226,13 +226,13 @@ private static boolean isNotComplexConfigKey(String key) {
static OidcTenantConfig getOidcTenantConfig(OidcConfig oidcConfig, String tenant) {
if (tenant == null || DEFAULT_TENANT_ID.equals(tenant)) {
- return oidcConfig.defaultTenant;
+ return new OidcTenantConfig(oidcConfig.defaultTenant(), DEFAULT_TENANT_ID);
}
- OidcTenantConfig oidcTenantConfig = oidcConfig.namedTenants.get(tenant);
+ var oidcTenantConfig = oidcConfig.namedTenants().get(tenant);
if (oidcTenantConfig == null) {
throw new ConfigurationException("Failed to find a matching OidcTenantConfig for tenant: " + tenant);
}
- return oidcTenantConfig;
+ return new OidcTenantConfig(oidcTenantConfig, tenant);
}
}
diff --git a/extensions/oidc-client-registration/deployment/pom.xml b/extensions/oidc-client-registration/deployment/pom.xml
index e4720ae98627a..0102ce66aeb18 100644
--- a/extensions/oidc-client-registration/deployment/pom.xml
+++ b/extensions/oidc-client-registration/deployment/pom.xml
@@ -54,9 +54,6 @@
${project.version}
-
- -AlegacyConfigRoot=true
-
diff --git a/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/OidcClientRegistrationBuildStep.java b/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/OidcClientRegistrationBuildStep.java
index f0d71493b33d2..cbc6ac342ee32 100644
--- a/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/OidcClientRegistrationBuildStep.java
+++ b/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/OidcClientRegistrationBuildStep.java
@@ -61,7 +61,7 @@ public static class IsEnabled implements BooleanSupplier {
OidcClientRegistrationBuildTimeConfig config;
public boolean getAsBoolean() {
- return config.enabled;
+ return config.enabled();
}
}
}
diff --git a/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/OidcClientRegistrationBuildTimeConfig.java b/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/OidcClientRegistrationBuildTimeConfig.java
index 98d78afa9acf1..6da2cab23cdee 100644
--- a/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/OidcClientRegistrationBuildTimeConfig.java
+++ b/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/OidcClientRegistrationBuildTimeConfig.java
@@ -1,16 +1,18 @@
package io.quarkus.oidc.client.registration.deployment;
-import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigRoot;
+import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.WithDefault;
/**
* Build time configuration for OIDC client registration.
*/
+@ConfigMapping(prefix = "quarkus.oidc-client-registration")
@ConfigRoot
-public class OidcClientRegistrationBuildTimeConfig {
+public interface OidcClientRegistrationBuildTimeConfig {
/**
* If the OIDC client registration extension is enabled.
*/
- @ConfigItem(defaultValue = "true")
- public boolean enabled;
+ @WithDefault("true")
+ boolean enabled();
}
diff --git a/extensions/oidc-client-registration/runtime/pom.xml b/extensions/oidc-client-registration/runtime/pom.xml
index 5a7b0038d55bb..7661a208f4e82 100644
--- a/extensions/oidc-client-registration/runtime/pom.xml
+++ b/extensions/oidc-client-registration/runtime/pom.xml
@@ -57,9 +57,6 @@
${project.version}
-
- -AlegacyConfigRoot=true
-
diff --git a/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/OidcClientRegistrationConfig.java b/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/OidcClientRegistrationConfig.java
index 871d3a515c4c7..40abcea94284e 100644
--- a/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/OidcClientRegistrationConfig.java
+++ b/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/OidcClientRegistrationConfig.java
@@ -5,72 +5,80 @@
import java.util.Optional;
import io.quarkus.oidc.common.runtime.OidcCommonConfig;
-import io.quarkus.runtime.annotations.ConfigGroup;
-import io.quarkus.runtime.annotations.ConfigItem;
//https://datatracker.ietf.org/doc/html/rfc7592
//https://openid.net/specs/openid-connect-registration-1_0.html
-@ConfigGroup
public class OidcClientRegistrationConfig extends OidcCommonConfig {
+ public OidcClientRegistrationConfig() {
+
+ }
+
+ public OidcClientRegistrationConfig(io.quarkus.oidc.client.registration.runtime.OidcClientRegistrationConfig mapping) {
+ super(mapping);
+ id = mapping.id();
+ registrationEnabled = mapping.registrationEnabled();
+ registerEarly = mapping.registerEarly();
+ initialToken = mapping.initialToken();
+ metadata.addConfigMappingValues(mapping.metadata());
+ }
+
/**
* OIDC Client Registration id
*/
- @ConfigItem
public Optional id = Optional.empty();
/**
* If this client registration configuration is enabled.
*/
- @ConfigItem(defaultValue = "true")
public boolean registrationEnabled = true;
/**
* If the client configured with {@link #metadata} must be registered at startup.
*/
- @ConfigItem(defaultValue = "true")
public boolean registerEarly = true;
/**
* Initial access token
*/
- @ConfigItem
public Optional initialToken = Optional.empty();
/**
* Client metadata
*/
- @ConfigItem
public Metadata metadata = new Metadata();
/**
* Client metadata
*/
- @ConfigGroup
public static class Metadata {
/**
* Client name
*/
- @ConfigItem
public Optional clientName = Optional.empty();
/**
* Redirect URI
*/
- @ConfigItem
public Optional redirectUri = Optional.empty();
/**
* Post Logout URI
*/
- @ConfigItem
public Optional postLogoutUri = Optional.empty();
/**
* Additional metadata properties
*/
- @ConfigItem
public Map extraProps = new HashMap<>();
+
+ private void addConfigMappingValues(
+ io.quarkus.oidc.client.registration.runtime.OidcClientRegistrationConfig.Metadata mapping) {
+ this.clientName = mapping.clientName();
+ this.redirectUri = mapping.redirectUri();
+ this.postLogoutUri = mapping.postLogoutUri();
+ this.extraProps.putAll(mapping.extraProps());
+ }
}
}
diff --git a/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationConfig.java b/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationConfig.java
new file mode 100644
index 0000000000000..e7b461772ad41
--- /dev/null
+++ b/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationConfig.java
@@ -0,0 +1,65 @@
+package io.quarkus.oidc.client.registration.runtime;
+
+import java.util.Map;
+import java.util.Optional;
+
+import io.quarkus.oidc.common.runtime.config.OidcCommonConfig;
+import io.smallrye.config.WithDefault;
+
+//https://datatracker.ietf.org/doc/html/rfc7592
+//https://openid.net/specs/openid-connect-registration-1_0.html
+
+public interface OidcClientRegistrationConfig extends OidcCommonConfig {
+
+ /**
+ * OIDC Client Registration id
+ */
+ Optional id();
+
+ /**
+ * If this client registration configuration is enabled.
+ */
+ @WithDefault("true")
+ boolean registrationEnabled();
+
+ /**
+ * If the client configured with {@link #metadata} must be registered at startup.
+ */
+ @WithDefault("true")
+ boolean registerEarly();
+
+ /**
+ * Initial access token
+ */
+ Optional initialToken();
+
+ /**
+ * Client metadata
+ */
+ Metadata metadata();
+
+ /**
+ * Client metadata
+ */
+ interface Metadata {
+ /**
+ * Client name
+ */
+ Optional clientName();
+
+ /**
+ * Redirect URI
+ */
+ Optional redirectUri();
+
+ /**
+ * Post Logout URI
+ */
+ Optional postLogoutUri();
+
+ /**
+ * Additional metadata properties
+ */
+ Map extraProps();
+ }
+}
diff --git a/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationRecorder.java b/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationRecorder.java
index 0016d5b585422..efc913a6935ab 100644
--- a/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationRecorder.java
+++ b/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationRecorder.java
@@ -41,15 +41,16 @@ public OidcClientRegistrations setup(OidcClientRegistrationsConfig oidcClientReg
Supplier vertx, Supplier registrySupplier) {
var tlsSupport = OidcTlsSupport.of(registrySupplier);
- OidcClientRegistration defaultClientReg = createOidcClientRegistration(oidcClientRegsConfig.defaultClientRegistration,
+ var defaultClientRegistration = new OidcClientRegistrationConfig(oidcClientRegsConfig.defaultClientRegistration());
+ OidcClientRegistration defaultClientReg = createOidcClientRegistration(defaultClientRegistration,
tlsSupport, vertx);
Map staticOidcClientRegs = new HashMap<>();
- for (Map.Entry config : oidcClientRegsConfig.namedClientRegistrations
- .entrySet()) {
+ for (var config : oidcClientRegsConfig.namedClientRegistrations().entrySet()) {
+ var namedClientRegistration = new OidcClientRegistrationConfig(config.getValue());
staticOidcClientRegs.put(config.getKey(),
- createOidcClientRegistration(config.getValue(), tlsSupport, vertx));
+ createOidcClientRegistration(namedClientRegistration, tlsSupport, vertx));
}
return new OidcClientRegistrationsImpl(defaultClientReg, staticOidcClientRegs,
diff --git a/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationsConfig.java b/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationsConfig.java
index 5d2772fdc7fd7..976897060e91b 100644
--- a/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationsConfig.java
+++ b/extensions/oidc-client-registration/runtime/src/main/java/io/quarkus/oidc/client/registration/runtime/OidcClientRegistrationsConfig.java
@@ -2,27 +2,28 @@
import java.util.Map;
-import io.quarkus.oidc.client.registration.OidcClientRegistrationConfig;
import io.quarkus.runtime.annotations.ConfigDocMapKey;
import io.quarkus.runtime.annotations.ConfigDocSection;
-import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
+import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.WithParentName;
-@ConfigRoot(name = "oidc-client-registration", phase = ConfigPhase.RUN_TIME)
-public class OidcClientRegistrationsConfig {
+@ConfigMapping(prefix = "quarkus.oidc-client-registration")
+@ConfigRoot(phase = ConfigPhase.RUN_TIME)
+public interface OidcClientRegistrationsConfig {
/**
* The default client registration.
*/
- @ConfigItem(name = ConfigItem.PARENT)
- public OidcClientRegistrationConfig defaultClientRegistration;
+ @WithParentName
+ OidcClientRegistrationConfig defaultClientRegistration();
/**
* Additional named client registrations.
*/
@ConfigDocSection
@ConfigDocMapKey("id")
- @ConfigItem(name = ConfigItem.PARENT)
- public Map namedClientRegistrations;
+ @WithParentName
+ Map namedClientRegistrations();
}
diff --git a/extensions/oidc-client-registration/runtime/src/test/java/io/quarkus/oidc/client/registration/OidcClientRegistrationConfigImpl.java b/extensions/oidc-client-registration/runtime/src/test/java/io/quarkus/oidc/client/registration/OidcClientRegistrationConfigImpl.java
new file mode 100644
index 0000000000000..2fd0dba336ef8
--- /dev/null
+++ b/extensions/oidc-client-registration/runtime/src/test/java/io/quarkus/oidc/client/registration/OidcClientRegistrationConfigImpl.java
@@ -0,0 +1,277 @@
+package io.quarkus.oidc.client.registration;
+
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.OptionalInt;
+
+import io.quarkus.oidc.client.registration.runtime.OidcClientRegistrationConfig;
+
+final class OidcClientRegistrationConfigImpl implements OidcClientRegistrationConfig {
+
+ enum ConfigMappingMethods {
+ ID,
+ REGISTRATION_ENABLED,
+ REGISTER_EARLY,
+ INITIAL_TOKEN,
+ METADATA,
+ METADATA_CLIENT_NAME,
+ METADATA_REDIRECT_URI,
+ METADATA_POST_LOGOUT_URI,
+ METADATA_EXTRA_PROPS,
+ AUTH_SERVER_URL,
+ DISCOVERY_ENABLED,
+ REGISTRATION_PATH,
+ CONNECTION_DELAY,
+ CONNECTION_RETRY_COUNT,
+ CONNECTION_TIMEOUT,
+ USE_BLOCKING_DNS_LOOKUP,
+ MAX_POOL_SIZE,
+ FOLLOW_REDIRECTS,
+ PROXY,
+ PROXY_HOST,
+ PROXY_PORT,
+ PROXY_USERNAME,
+ PROXY_PASSWORD,
+ TLS,
+ TLS_CONFIGURATION,
+ TLS_VERIFICATION,
+ TLS_KEYSTORE_FILE,
+ TLS_KEYSTORE_FILE_TYPE,
+ TLS_KEYSTORE_PROVIDER,
+ TLS_KEYSTORE_PASSWORD,
+ TLS_KEYSTORE_KEY_ALIAS,
+ TLS_KEYSTORE_KEY_PASSWORD,
+ TLS_TRUSTSTORE_PASSWORD,
+ TLS_TRUSTSTORE_FILE,
+ TLS_TRUSTSTORE_CERT_ALIAS,
+ TLS_TRUSTSTORE_FILE_TYPE,
+ TLS_TRUSTSTORE_PROVIDER
+ }
+
+ final Map invocationsRecorder = new HashMap<>();
+
+ @Override
+ public Optional id() {
+ invocationsRecorder.put(ConfigMappingMethods.ID, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public boolean registrationEnabled() {
+ invocationsRecorder.put(ConfigMappingMethods.REGISTRATION_ENABLED, true);
+ return false;
+ }
+
+ @Override
+ public boolean registerEarly() {
+ invocationsRecorder.put(ConfigMappingMethods.REGISTER_EARLY, true);
+ return false;
+ }
+
+ @Override
+ public Optional initialToken() {
+ invocationsRecorder.put(ConfigMappingMethods.INITIAL_TOKEN, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Metadata metadata() {
+ invocationsRecorder.put(ConfigMappingMethods.METADATA, true);
+ return new Metadata() {
+ @Override
+ public Optional clientName() {
+ invocationsRecorder.put(ConfigMappingMethods.METADATA_CLIENT_NAME, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional redirectUri() {
+ invocationsRecorder.put(ConfigMappingMethods.METADATA_REDIRECT_URI, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional postLogoutUri() {
+ invocationsRecorder.put(ConfigMappingMethods.METADATA_POST_LOGOUT_URI, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Map extraProps() {
+ invocationsRecorder.put(ConfigMappingMethods.METADATA_EXTRA_PROPS, true);
+ return Map.of();
+ }
+ };
+ }
+
+ @Override
+ public Optional authServerUrl() {
+ invocationsRecorder.put(ConfigMappingMethods.AUTH_SERVER_URL, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional discoveryEnabled() {
+ invocationsRecorder.put(ConfigMappingMethods.DISCOVERY_ENABLED, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional registrationPath() {
+ invocationsRecorder.put(ConfigMappingMethods.REGISTRATION_PATH, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional connectionDelay() {
+ invocationsRecorder.put(ConfigMappingMethods.CONNECTION_DELAY, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public int connectionRetryCount() {
+ invocationsRecorder.put(ConfigMappingMethods.CONNECTION_RETRY_COUNT, true);
+ return 0;
+ }
+
+ @Override
+ public Duration connectionTimeout() {
+ invocationsRecorder.put(ConfigMappingMethods.CONNECTION_TIMEOUT, true);
+ return null;
+ }
+
+ @Override
+ public boolean useBlockingDnsLookup() {
+ invocationsRecorder.put(ConfigMappingMethods.USE_BLOCKING_DNS_LOOKUP, true);
+ return false;
+ }
+
+ @Override
+ public OptionalInt maxPoolSize() {
+ invocationsRecorder.put(ConfigMappingMethods.MAX_POOL_SIZE, true);
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public boolean followRedirects() {
+ invocationsRecorder.put(ConfigMappingMethods.FOLLOW_REDIRECTS, true);
+ return false;
+ }
+
+ @Override
+ public Proxy proxy() {
+ invocationsRecorder.put(ConfigMappingMethods.PROXY, true);
+ return new Proxy() {
+ @Override
+ public Optional host() {
+ invocationsRecorder.put(ConfigMappingMethods.PROXY_HOST, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public int port() {
+ invocationsRecorder.put(ConfigMappingMethods.PROXY_PORT, true);
+ return 0;
+ }
+
+ @Override
+ public Optional username() {
+ invocationsRecorder.put(ConfigMappingMethods.PROXY_USERNAME, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional password() {
+ invocationsRecorder.put(ConfigMappingMethods.PROXY_PASSWORD, true);
+ return Optional.empty();
+ }
+ };
+ }
+
+ @Override
+ public Tls tls() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS, true);
+ return new Tls() {
+ @Override
+ public Optional tlsConfigurationName() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_CONFIGURATION, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional verification() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_VERIFICATION, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreFile() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_FILE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreFileType() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_FILE_TYPE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreProvider() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_PROVIDER, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStorePassword() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_PASSWORD, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreKeyAlias() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_KEY_ALIAS, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreKeyPassword() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_KEY_PASSWORD, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional trustStoreFile() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_TRUSTSTORE_FILE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional trustStorePassword() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_TRUSTSTORE_PASSWORD, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional trustStoreCertAlias() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_TRUSTSTORE_CERT_ALIAS, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional trustStoreFileType() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_TRUSTSTORE_FILE_TYPE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional trustStoreProvider() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_TRUSTSTORE_PROVIDER, true);
+ return Optional.empty();
+ }
+ };
+ }
+}
diff --git a/extensions/oidc-client-registration/runtime/src/test/java/io/quarkus/oidc/client/registration/OidcClientRegistrationConfigTest.java b/extensions/oidc-client-registration/runtime/src/test/java/io/quarkus/oidc/client/registration/OidcClientRegistrationConfigTest.java
new file mode 100644
index 0000000000000..d23dfcd678ae7
--- /dev/null
+++ b/extensions/oidc-client-registration/runtime/src/test/java/io/quarkus/oidc/client/registration/OidcClientRegistrationConfigTest.java
@@ -0,0 +1,23 @@
+package io.quarkus.oidc.client.registration;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.EnumSet;
+
+import org.junit.jupiter.api.Test;
+
+public class OidcClientRegistrationConfigTest {
+
+ @Test
+ public void testCopyBetweenConfigMappingAndClass() {
+ var configMappingGroup = new OidcClientRegistrationConfigImpl();
+ new OidcClientRegistrationConfig(configMappingGroup);
+ for (var configMappingMethod : EnumSet.allOf(OidcClientRegistrationConfigImpl.ConfigMappingMethods.class)) {
+ Boolean invoked = configMappingGroup.invocationsRecorder.get(configMappingMethod);
+ assertTrue(invoked != null && invoked,
+ "OidcClientRegistrationConfig method '%s' return value is not copied from interface to class"
+ .formatted(configMappingMethod));
+ }
+ }
+
+}
diff --git a/extensions/oidc-client/deployment/pom.xml b/extensions/oidc-client/deployment/pom.xml
index 3e96bb92c13c7..4a9351f66e255 100644
--- a/extensions/oidc-client/deployment/pom.xml
+++ b/extensions/oidc-client/deployment/pom.xml
@@ -119,9 +119,6 @@
${project.version}
-
- -AlegacyConfigRoot=true
-
diff --git a/extensions/oidc-client/deployment/src/main/java/io/quarkus/oidc/client/deployment/OidcClientBuildStep.java b/extensions/oidc-client/deployment/src/main/java/io/quarkus/oidc/client/deployment/OidcClientBuildStep.java
index 0dd562bec6fc4..aaf1acc48198a 100644
--- a/extensions/oidc-client/deployment/src/main/java/io/quarkus/oidc/client/deployment/OidcClientBuildStep.java
+++ b/extensions/oidc-client/deployment/src/main/java/io/quarkus/oidc/client/deployment/OidcClientBuildStep.java
@@ -270,7 +270,7 @@ public static class IsEnabled implements BooleanSupplier {
OidcClientBuildTimeConfig config;
public boolean getAsBoolean() {
- return config.enabled;
+ return config.enabled();
}
}
}
diff --git a/extensions/oidc-client/runtime/pom.xml b/extensions/oidc-client/runtime/pom.xml
index cdace1db1d7a4..0091875c7551e 100644
--- a/extensions/oidc-client/runtime/pom.xml
+++ b/extensions/oidc-client/runtime/pom.xml
@@ -60,9 +60,6 @@
${project.version}
-
- -AlegacyConfigRoot=true
-
diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/OidcClientConfig.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/OidcClientConfig.java
index 03acfd1626ede..0d15cb4e9f0c1 100644
--- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/OidcClientConfig.java
+++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/OidcClientConfig.java
@@ -7,30 +7,41 @@
import io.quarkus.oidc.common.runtime.OidcClientCommonConfig;
import io.quarkus.oidc.common.runtime.OidcConstants;
-import io.quarkus.runtime.annotations.ConfigDocMapKey;
-import io.quarkus.runtime.annotations.ConfigGroup;
-import io.quarkus.runtime.annotations.ConfigItem;
-@ConfigGroup
public class OidcClientConfig extends OidcClientCommonConfig {
+ public OidcClientConfig() {
+
+ }
+
+ public OidcClientConfig(io.quarkus.oidc.client.runtime.OidcClientConfig mapping) {
+ super(mapping);
+ id = mapping.id();
+ clientEnabled = mapping.clientEnabled();
+ scopes = mapping.scopes();
+ refreshTokenTimeSkew = mapping.refreshTokenTimeSkew();
+ accessTokenExpiresIn = mapping.accessTokenExpiresIn();
+ absoluteExpiresIn = mapping.absoluteExpiresIn();
+ grant.addConfigMappingValues(mapping.grant());
+ grantOptions = mapping.grantOptions();
+ earlyTokensAcquisition = mapping.earlyTokensAcquisition();
+ headers = mapping.headers();
+ }
+
/**
* A unique OIDC client identifier. It must be set when OIDC clients are created dynamically
* and is optional in all other cases.
*/
- @ConfigItem
public Optional id = Optional.empty();
/**
* If this client configuration is enabled.
*/
- @ConfigItem(defaultValue = "true")
public boolean clientEnabled = true;
/**
* List of access token scopes
*/
- @ConfigItem
public Optional> scopes = Optional.empty();
/**
@@ -39,7 +50,6 @@ public class OidcClientConfig extends OidcClientCommonConfig {
* when checking whether the access token should be refreshed. If the sum is greater than this access token's
* expiration time then a refresh is going to happen.
*/
- @ConfigItem
public Optional refreshTokenTimeSkew = Optional.empty();
/**
@@ -47,20 +57,18 @@ public class OidcClientConfig extends OidcClientCommonConfig {
* This property is only checked when an access token grant response
* does not include an access token expiration property.
*/
- @ConfigItem
public Optional accessTokenExpiresIn = Optional.empty();
/**
* If the access token 'expires_in' property should be checked as an absolute time value
* as opposed to a duration relative to the current time.
*/
- @ConfigItem(defaultValue = "false")
public boolean absoluteExpiresIn;
public Grant grant = new Grant();
- @ConfigGroup
public static class Grant {
+
public static enum Type {
/**
* 'client_credentials' grant requiring an OIDC client authentication only
@@ -121,31 +129,26 @@ public String getGrantType() {
/**
* Grant type
*/
- @ConfigItem(defaultValue = "client")
public Type type = Type.CLIENT;
/**
* Access token property name in a token grant response
*/
- @ConfigItem(defaultValue = OidcConstants.ACCESS_TOKEN_VALUE)
public String accessTokenProperty = OidcConstants.ACCESS_TOKEN_VALUE;
/**
* Refresh token property name in a token grant response
*/
- @ConfigItem(defaultValue = OidcConstants.REFRESH_TOKEN_VALUE)
public String refreshTokenProperty = OidcConstants.REFRESH_TOKEN_VALUE;
/**
* Access token expiry property name in a token grant response
*/
- @ConfigItem(defaultValue = OidcConstants.EXPIRES_IN)
public String expiresInProperty = OidcConstants.EXPIRES_IN;
/**
* Refresh token expiry property name in a token grant response
*/
- @ConfigItem(defaultValue = OidcConstants.REFRESH_EXPIRES_IN)
public String refreshExpiresInProperty = OidcConstants.REFRESH_EXPIRES_IN;
public Type getType() {
@@ -187,13 +190,19 @@ public String getRefreshExpiresInProperty() {
public void setRefreshExpiresInProperty(String refreshExpiresInProperty) {
this.refreshExpiresInProperty = refreshExpiresInProperty;
}
+
+ private void addConfigMappingValues(io.quarkus.oidc.client.runtime.OidcClientConfig.Grant grant) {
+ this.type = Grant.Type.valueOf(grant.type().toString());
+ this.accessTokenProperty = grant.accessTokenProperty();
+ this.refreshTokenProperty = grant.refreshTokenProperty();
+ this.expiresInProperty = grant.expiresInProperty();
+ this.refreshExpiresInProperty = grant.refreshExpiresInProperty();
+ }
}
/**
* Grant options
*/
- @ConfigItem
- @ConfigDocMapKey("grant-name")
public Map> grantOptions;
/**
@@ -202,13 +211,11 @@ public void setRefreshExpiresInProperty(String refreshExpiresInProperty) {
* This property should be disabled if the access token may expire before it is used for the first time and no refresh token
* is available.
*/
- @ConfigItem(defaultValue = "true")
public boolean earlyTokensAcquisition = true;
/**
* Custom HTTP headers which have to be sent to the token endpoint
*/
- @ConfigItem
public Map headers;
public Optional getId() {
@@ -274,4 +281,5 @@ public void setGrant(Grant grant) {
public Grant getGrant() {
return grant;
}
+
}
diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/AbstractTokensProducer.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/AbstractTokensProducer.java
index 0c7f8d948c57d..7cc57cc16ee17 100644
--- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/AbstractTokensProducer.java
+++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/AbstractTokensProducer.java
@@ -43,10 +43,10 @@ public void init() {
if (clientId.isPresent()) {
// static named OidcClient
oidcClient = Objects.requireNonNull(oidcClients.getClient(clientId.get()), "Unknown client");
- earlyTokenAcquisition = oidcClientsConfig.namedClients.get(clientId.get()).earlyTokensAcquisition;
+ earlyTokenAcquisition = oidcClientsConfig.namedClients().get(clientId.get()).earlyTokensAcquisition();
} else {
// default OidcClient
- earlyTokenAcquisition = oidcClientsConfig.defaultClient.earlyTokensAcquisition;
+ earlyTokenAcquisition = oidcClientsConfig.defaultClient().earlyTokensAcquisition();
oidcClient = oidcClients.getClient();
}
} else {
@@ -57,7 +57,7 @@ public void init() {
}
protected boolean isClientFeatureDisabled() {
- return !oidcClientBuildTimeConfig.enabled;
+ return !oidcClientBuildTimeConfig.enabled();
}
protected void initTokens() {
diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientBuildTimeConfig.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientBuildTimeConfig.java
index a8dc58b35fdfb..0c667f0e6408b 100644
--- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientBuildTimeConfig.java
+++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientBuildTimeConfig.java
@@ -1,17 +1,19 @@
package io.quarkus.oidc.client.runtime;
-import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
+import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.WithDefault;
/**
* Build time configuration for OIDC client.
*/
-@ConfigRoot(name = "oidc-client", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
-public class OidcClientBuildTimeConfig {
+@ConfigMapping(prefix = "quarkus.oidc-client")
+@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
+public interface OidcClientBuildTimeConfig {
/**
* If the OIDC client extension is enabled.
*/
- @ConfigItem(defaultValue = "true")
- public boolean enabled;
+ @WithDefault("true")
+ boolean enabled();
}
diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientConfig.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientConfig.java
new file mode 100644
index 0000000000000..06fd501e92e57
--- /dev/null
+++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientConfig.java
@@ -0,0 +1,168 @@
+package io.quarkus.oidc.client.runtime;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import io.quarkus.oidc.common.runtime.OidcConstants;
+import io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig;
+import io.quarkus.runtime.annotations.ConfigDocMapKey;
+import io.smallrye.config.WithDefault;
+
+public interface OidcClientConfig extends OidcClientCommonConfig {
+
+ /**
+ * A unique OIDC client identifier. It must be set when OIDC clients are created dynamically
+ * and is optional in all other cases.
+ */
+ Optional id();
+
+ /**
+ * If this client configuration is enabled.
+ */
+ @WithDefault("true")
+ boolean clientEnabled();
+
+ /**
+ * List of access token scopes
+ */
+ Optional> scopes();
+
+ /**
+ * Refresh token time skew.
+ * If this property is enabled then the configured duration is converted to seconds and is added to the current time
+ * when checking whether the access token should be refreshed. If the sum is greater than this access token's
+ * expiration time then a refresh is going to happen.
+ */
+ Optional refreshTokenTimeSkew();
+
+ /**
+ * Access token expiration period relative to the current time.
+ * This property is only checked when an access token grant response
+ * does not include an access token expiration property.
+ */
+ Optional accessTokenExpiresIn();
+
+ /**
+ * If the access token 'expires_in' property should be checked as an absolute time value
+ * as opposed to a duration relative to the current time.
+ */
+ @WithDefault("false")
+ boolean absoluteExpiresIn();
+
+ /**
+ * OIDC Client grant config group.
+ */
+ Grant grant();
+
+ interface Grant {
+ enum Type {
+ /**
+ * 'client_credentials' grant requiring an OIDC client authentication only
+ */
+ CLIENT("client_credentials"),
+ /**
+ * 'password' grant requiring both OIDC client and user ('username' and 'password') authentications
+ */
+ PASSWORD("password"),
+ /**
+ * 'authorization_code' grant requiring an OIDC client authentication as well as
+ * at least 'code' and 'redirect_uri' parameters which must be passed to OidcClient at the token request time.
+ */
+ CODE("authorization_code"),
+ /**
+ * 'urn:ietf:params:oauth:grant-type:token-exchange' grant requiring an OIDC client authentication as well as
+ * at least 'subject_token' parameter which must be passed to OidcClient at the token request time.
+ */
+ EXCHANGE("urn:ietf:params:oauth:grant-type:token-exchange"),
+ /**
+ * 'urn:ietf:params:oauth:grant-type:jwt-bearer' grant requiring an OIDC client authentication as well as
+ * at least an 'assertion' parameter which must be passed to OidcClient at the token request time.
+ */
+ JWT("urn:ietf:params:oauth:grant-type:jwt-bearer"),
+ /**
+ * 'refresh_token' grant requiring an OIDC client authentication and a refresh token.
+ * Note, OidcClient supports this grant by default if an access token acquisition response contained a refresh
+ * token.
+ * However, in some cases, the refresh token is provided out of band, for example, it can be shared between
+ * several of the confidential client's services, etc.
+ * If 'quarkus.oidc-client.grant-type' is set to 'refresh' then `OidcClient` will only support refreshing the
+ * tokens.
+ */
+ REFRESH("refresh_token"),
+ /**
+ * 'urn:openid:params:grant-type:ciba' grant requiring an OIDC client authentication as well as 'auth_req_id'
+ * parameter which must be passed to OidcClient at the token request time.
+ */
+ CIBA("urn:openid:params:grant-type:ciba"),
+ /**
+ * 'urn:ietf:params:oauth:grant-type:device_code' grant requiring an OIDC client authentication as well as
+ * 'device_code'
+ * parameter which must be passed to OidcClient at the token request time.
+ */
+ DEVICE("urn:ietf:params:oauth:grant-type:device_code");
+
+ private final String grantType;
+
+ Type(String grantType) {
+ this.grantType = grantType;
+ }
+
+ public String getGrantType() {
+ return grantType;
+ }
+ }
+
+ /**
+ * Grant type
+ */
+ @WithDefault("client")
+ Type type();
+
+ /**
+ * Access token property name in a token grant response
+ */
+ @WithDefault(OidcConstants.ACCESS_TOKEN_VALUE)
+ String accessTokenProperty();
+
+ /**
+ * Refresh token property name in a token grant response
+ */
+ @WithDefault(OidcConstants.REFRESH_TOKEN_VALUE)
+ String refreshTokenProperty();
+
+ /**
+ * Access token expiry property name in a token grant response
+ */
+ @WithDefault(OidcConstants.EXPIRES_IN)
+ String expiresInProperty();
+
+ /**
+ * Refresh token expiry property name in a token grant response
+ */
+ @WithDefault(OidcConstants.REFRESH_EXPIRES_IN)
+ String refreshExpiresInProperty();
+ }
+
+ /**
+ * Grant options
+ */
+ @ConfigDocMapKey("grant-name")
+ Map> grantOptions();
+
+ /**
+ * Requires that all filters which use 'OidcClient' acquire the tokens at the post-construct initialization time,
+ * possibly long before these tokens are used.
+ * This property should be disabled if the access token may expire before it is used for the first time and no refresh token
+ * is available.
+ */
+ @WithDefault("true")
+ boolean earlyTokensAcquisition();
+
+ /**
+ * Custom HTTP headers which have to be sent to the token endpoint
+ */
+ Map headers();
+
+}
diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java
index 7d3f85cd23065..604c7b159622b 100644
--- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java
+++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java
@@ -48,15 +48,17 @@ private static OidcClients setup(OidcClientsConfig oidcClientsConfig, Supplier registrySupplier) {
var tlsSupport = OidcTlsSupport.of(registrySupplier);
- String defaultClientId = oidcClientsConfig.defaultClient.getId().orElse(DEFAULT_OIDC_CLIENT_ID);
- OidcClient defaultClient = createOidcClient(oidcClientsConfig.defaultClient, defaultClientId, vertx, tlsSupport);
+ var defaultClientConfig = new OidcClientConfig(oidcClientsConfig.defaultClient());
+ String defaultClientId = defaultClientConfig.getId().orElse(DEFAULT_OIDC_CLIENT_ID);
+ OidcClient defaultClient = createOidcClient(defaultClientConfig, defaultClientId, vertx, tlsSupport);
Map staticOidcClients = new HashMap<>();
- for (Map.Entry config : oidcClientsConfig.namedClients.entrySet()) {
- OidcCommonUtils.verifyConfigurationId(defaultClientId, config.getKey(), config.getValue().getId());
+ for (var config : oidcClientsConfig.namedClients().entrySet()) {
+ var namedOidcClientConfig = new OidcClientConfig(config.getValue());
+ OidcCommonUtils.verifyConfigurationId(defaultClientId, config.getKey(), namedOidcClientConfig.getId());
staticOidcClients.put(config.getKey(),
- createOidcClient(config.getValue(), config.getKey(), vertx, tlsSupport));
+ createOidcClient(namedOidcClientConfig, config.getKey(), vertx, tlsSupport));
}
return new OidcClientsImpl(defaultClient, staticOidcClients,
diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientsConfig.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientsConfig.java
index abf4db230b5ab..4c76cb46e88d0 100644
--- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientsConfig.java
+++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientsConfig.java
@@ -2,27 +2,28 @@
import java.util.Map;
-import io.quarkus.oidc.client.OidcClientConfig;
import io.quarkus.runtime.annotations.ConfigDocMapKey;
import io.quarkus.runtime.annotations.ConfigDocSection;
-import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
+import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.WithParentName;
-@ConfigRoot(name = "oidc-client", phase = ConfigPhase.RUN_TIME)
-public class OidcClientsConfig {
+@ConfigMapping(prefix = "quarkus.oidc-client")
+@ConfigRoot(phase = ConfigPhase.RUN_TIME)
+public interface OidcClientsConfig {
/**
* The default client.
*/
- @ConfigItem(name = ConfigItem.PARENT)
- public OidcClientConfig defaultClient;
+ @WithParentName
+ OidcClientConfig defaultClient();
/**
* Additional named clients.
*/
@ConfigDocSection
@ConfigDocMapKey("id")
- @ConfigItem(name = ConfigItem.PARENT)
- public Map namedClients;
+ @WithParentName
+ Map namedClients();
}
diff --git a/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigImpl.java b/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigImpl.java
new file mode 100644
index 0000000000000..b786c83e4237a
--- /dev/null
+++ b/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigImpl.java
@@ -0,0 +1,561 @@
+package io.quarkus.oidc.client;
+
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.OptionalInt;
+
+import io.quarkus.oidc.client.runtime.OidcClientConfig;
+
+final class OidcClientConfigImpl implements OidcClientConfig {
+
+ enum ConfigMappingMethods {
+ ID,
+ AUTH_SERVER_URL,
+ DISCOVERY_ENABLED,
+ REGISTRATION_PATH,
+ CONNECTION_DELAY,
+ CONNECTION_RETRY_COUNT,
+ CONNECTION_TIMEOUT,
+ USE_BLOCKING_DNS_LOOKUP,
+ MAX_POOL_SIZE,
+ FOLLOW_REDIRECTS,
+ PROXY,
+ PROXY_HOST,
+ PROXY_PORT,
+ PROXY_USERNAME,
+ PROXY_PASSWORD,
+ TLS,
+ TLS_CONFIGURATION,
+ TLS_VERIFICATION,
+ TLS_KEYSTORE_FILE,
+ TLS_KEYSTORE_FILE_TYPE,
+ TLS_KEYSTORE_PROVIDER,
+ TLS_KEYSTORE_PASSWORD,
+ TLS_KEYSTORE_KEY_ALIAS,
+ TLS_KEYSTORE_KEY_PASSWORD,
+ TLS_TRUSTSTORE_PASSWORD,
+ TLS_TRUSTSTORE_FILE,
+ TLS_TRUSTSTORE_CERT_ALIAS,
+ TLS_TRUSTSTORE_FILE_TYPE,
+ TLS_TRUSTSTORE_PROVIDER,
+ HEADERS,
+ EARLY_TOKENS_ACQUISITION,
+ GRANT_OPTIONS,
+ CLIENT_ENABLED,
+ SCOPES,
+ REFRESH_TOKEN_TIME_SKEW,
+ ACCESS_TOKEN_EXPIRES_IN,
+ ABSOLUTE_EXPIRES_IN,
+ GRANT,
+ GRANT_TYPE,
+ GRANT_ACCESS_TOKEN_PROPERTY,
+ GRANT_REFRESH_TOKEN_PROPERTY,
+ GRANT_EXPIRES_IN_PROPERTY,
+ REFRESH_EXPIRES_IN_PROPERTY,
+ TOKEN_PATH,
+ REVOKE_PATH,
+ CLIENT_ID,
+ CLIENT_NAME,
+ CREDENTIALS,
+ CREDENTIALS_SECRET,
+ CREDENTIALS_CLIENT_SECRET,
+ CREDENTIALS_CLIENT_SECRET_VALUE,
+ CREDENTIALS_CLIENT_SECRET_PROVIDER,
+ CREDENTIALS_CLIENT_SECRET_METHOD,
+ CREDENTIALS_CLIENT_SECRET_PROVIDER_NAME,
+ CREDENTIALS_CLIENT_SECRET_PROVIDER_KEYRING_NAME,
+ CREDENTIALS_CLIENT_SECRET_PROVIDER_KEY,
+ CREDENTIALS_JWT,
+ CREDENTIALS_JWT_SOURCE,
+ CREDENTIALS_JWT_SECRET,
+ CREDENTIALS_JWT_SECRET_PROVIDER,
+ CREDENTIALS_JWT_SECRET_PROVIDER_NAME,
+ CREDENTIALS_JWT_SECRET_PROVIDER_KEYRING_NAME,
+ CREDENTIALS_JWT_SECRET_PROVIDER_KEY,
+ CREDENTIALS_JWT_KEY,
+ CREDENTIALS_JWT_KEY_FILE,
+ CREDENTIALS_JWT_KEY_STORE_FILE,
+ CREDENTIALS_JWT_KEY_STORE_PASSWORD,
+ CREDENTIALS_JWT_KEY_ID,
+ CREDENTIALS_JWT_KEY_PASSWORD,
+ CREDENTIALS_JWT_ISSUER,
+ CREDENTIALS_JWT_SUBJECT,
+ CREDENTIALS_JWT_CLAIMS,
+ CREDENTIALS_JWT_SIGNATURE_ALGORITHM,
+ CREDENTIALS_JWT_LIFESPAN,
+ CREDENTIALS_JWT_ASSERTION,
+ CREDENTIALS_JWT_AUDIENCE,
+ CREDENTIALS_JWT_TOKEN_ID
+ }
+
+ final Map invocationsRecorder = new EnumMap<>(ConfigMappingMethods.class);
+
+ @Override
+ public Optional tokenPath() {
+ invocationsRecorder.put(ConfigMappingMethods.TOKEN_PATH, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional revokePath() {
+ invocationsRecorder.put(ConfigMappingMethods.REVOKE_PATH, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional clientId() {
+ invocationsRecorder.put(ConfigMappingMethods.CLIENT_ID, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional clientName() {
+ invocationsRecorder.put(ConfigMappingMethods.CLIENT_NAME, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Credentials credentials() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS, true);
+ return new Credentials() {
+ @Override
+ public Optional secret() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_SECRET, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Secret clientSecret() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_CLIENT_SECRET, true);
+ return new Secret() {
+
+ @Override
+ public Optional value() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_CLIENT_SECRET_VALUE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Provider provider() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_CLIENT_SECRET_PROVIDER, true);
+ return new Provider() {
+ @Override
+ public Optional name() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_CLIENT_SECRET_PROVIDER_NAME, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyringName() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_CLIENT_SECRET_PROVIDER_KEYRING_NAME,
+ true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional key() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_CLIENT_SECRET_PROVIDER_KEY, true);
+ return Optional.empty();
+ }
+ };
+ }
+
+ @Override
+ public Optional method() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_CLIENT_SECRET_METHOD, true);
+ return Optional.empty();
+ }
+ };
+ }
+
+ @Override
+ public Jwt jwt() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT, true);
+ return new Jwt() {
+ @Override
+ public Source source() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_SOURCE, true);
+ return Source.BEARER;
+ }
+
+ @Override
+ public Optional secret() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_SECRET, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Provider secretProvider() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_SECRET_PROVIDER, true);
+ return new Provider() {
+ @Override
+ public Optional name() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_SECRET_PROVIDER_NAME, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyringName() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_SECRET_PROVIDER_KEYRING_NAME,
+ true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional key() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_SECRET_PROVIDER_KEY, true);
+ return Optional.empty();
+ }
+ };
+ }
+
+ @Override
+ public Optional key() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_KEY, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyFile() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_KEY_FILE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreFile() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_KEY_STORE_FILE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStorePassword() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_KEY_STORE_PASSWORD, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyId() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_KEY_ID, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyPassword() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_KEY_PASSWORD, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional audience() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_AUDIENCE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional tokenKeyId() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_TOKEN_ID, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional issuer() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_ISSUER, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional subject() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_SUBJECT, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Map claims() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_CLAIMS, true);
+ return Map.of();
+ }
+
+ @Override
+ public Optional signatureAlgorithm() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_SIGNATURE_ALGORITHM, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public int lifespan() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_LIFESPAN, true);
+ return 0;
+ }
+
+ @Override
+ public boolean assertion() {
+ invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_ASSERTION, true);
+ return false;
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public Optional id() {
+ invocationsRecorder.put(ConfigMappingMethods.ID, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public boolean clientEnabled() {
+ invocationsRecorder.put(ConfigMappingMethods.CLIENT_ENABLED, true);
+ return false;
+ }
+
+ @Override
+ public Optional> scopes() {
+ invocationsRecorder.put(ConfigMappingMethods.SCOPES, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional refreshTokenTimeSkew() {
+ invocationsRecorder.put(ConfigMappingMethods.REFRESH_TOKEN_TIME_SKEW, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional accessTokenExpiresIn() {
+ invocationsRecorder.put(ConfigMappingMethods.ACCESS_TOKEN_EXPIRES_IN, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public boolean absoluteExpiresIn() {
+ invocationsRecorder.put(ConfigMappingMethods.ABSOLUTE_EXPIRES_IN, true);
+ return false;
+ }
+
+ @Override
+ public Grant grant() {
+ invocationsRecorder.put(ConfigMappingMethods.GRANT, true);
+ return new Grant() {
+ @Override
+ public Type type() {
+ invocationsRecorder.put(ConfigMappingMethods.GRANT_TYPE, true);
+ return Type.CLIENT;
+ }
+
+ @Override
+ public String accessTokenProperty() {
+ invocationsRecorder.put(ConfigMappingMethods.GRANT_ACCESS_TOKEN_PROPERTY, true);
+ return "";
+ }
+
+ @Override
+ public String refreshTokenProperty() {
+ invocationsRecorder.put(ConfigMappingMethods.GRANT_REFRESH_TOKEN_PROPERTY, true);
+ return "";
+ }
+
+ @Override
+ public String expiresInProperty() {
+ invocationsRecorder.put(ConfigMappingMethods.GRANT_EXPIRES_IN_PROPERTY, true);
+ return "";
+ }
+
+ @Override
+ public String refreshExpiresInProperty() {
+ invocationsRecorder.put(ConfigMappingMethods.REFRESH_EXPIRES_IN_PROPERTY, true);
+ return "";
+ }
+ };
+ }
+
+ @Override
+ public Map> grantOptions() {
+ invocationsRecorder.put(ConfigMappingMethods.GRANT_OPTIONS, true);
+ return Map.of();
+ }
+
+ @Override
+ public boolean earlyTokensAcquisition() {
+ invocationsRecorder.put(ConfigMappingMethods.EARLY_TOKENS_ACQUISITION, true);
+ return false;
+ }
+
+ @Override
+ public Map headers() {
+ invocationsRecorder.put(ConfigMappingMethods.HEADERS, true);
+ return Map.of();
+ }
+
+ @Override
+ public Optional authServerUrl() {
+ invocationsRecorder.put(ConfigMappingMethods.AUTH_SERVER_URL, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional discoveryEnabled() {
+ invocationsRecorder.put(ConfigMappingMethods.DISCOVERY_ENABLED, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional registrationPath() {
+ invocationsRecorder.put(ConfigMappingMethods.REGISTRATION_PATH, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional connectionDelay() {
+ invocationsRecorder.put(ConfigMappingMethods.CONNECTION_DELAY, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public int connectionRetryCount() {
+ invocationsRecorder.put(ConfigMappingMethods.CONNECTION_RETRY_COUNT, true);
+ return 0;
+ }
+
+ @Override
+ public Duration connectionTimeout() {
+ invocationsRecorder.put(ConfigMappingMethods.CONNECTION_TIMEOUT, true);
+ return null;
+ }
+
+ @Override
+ public boolean useBlockingDnsLookup() {
+ invocationsRecorder.put(ConfigMappingMethods.USE_BLOCKING_DNS_LOOKUP, true);
+ return false;
+ }
+
+ @Override
+ public OptionalInt maxPoolSize() {
+ invocationsRecorder.put(ConfigMappingMethods.MAX_POOL_SIZE, true);
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public boolean followRedirects() {
+ invocationsRecorder.put(ConfigMappingMethods.FOLLOW_REDIRECTS, true);
+ return false;
+ }
+
+ @Override
+ public Proxy proxy() {
+ invocationsRecorder.put(ConfigMappingMethods.PROXY, true);
+ return new Proxy() {
+ @Override
+ public Optional host() {
+ invocationsRecorder.put(ConfigMappingMethods.PROXY_HOST, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public int port() {
+ invocationsRecorder.put(ConfigMappingMethods.PROXY_PORT, true);
+ return 0;
+ }
+
+ @Override
+ public Optional username() {
+ invocationsRecorder.put(ConfigMappingMethods.PROXY_USERNAME, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional password() {
+ invocationsRecorder.put(ConfigMappingMethods.PROXY_PASSWORD, true);
+ return Optional.empty();
+ }
+ };
+ }
+
+ @Override
+ public Tls tls() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS, true);
+ return new Tls() {
+ @Override
+ public Optional tlsConfigurationName() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_CONFIGURATION, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional verification() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_VERIFICATION, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreFile() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_FILE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreFileType() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_FILE_TYPE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreProvider() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_PROVIDER, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStorePassword() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_PASSWORD, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreKeyAlias() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_KEY_ALIAS, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional keyStoreKeyPassword() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_KEYSTORE_KEY_PASSWORD, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional trustStoreFile() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_TRUSTSTORE_FILE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional trustStorePassword() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_TRUSTSTORE_PASSWORD, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional trustStoreCertAlias() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_TRUSTSTORE_CERT_ALIAS, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional trustStoreFileType() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_TRUSTSTORE_FILE_TYPE, true);
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional trustStoreProvider() {
+ invocationsRecorder.put(ConfigMappingMethods.TLS_TRUSTSTORE_PROVIDER, true);
+ return Optional.empty();
+ }
+ };
+ }
+}
diff --git a/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigTest.java b/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigTest.java
new file mode 100644
index 0000000000000..9850825e21704
--- /dev/null
+++ b/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigTest.java
@@ -0,0 +1,23 @@
+package io.quarkus.oidc.client;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.EnumSet;
+
+import org.junit.jupiter.api.Test;
+
+public class OidcClientConfigTest {
+
+ @Test
+ public void testCopyBetweenConfigMappingAndClass() {
+ var configMappingGroup = new OidcClientConfigImpl();
+ new OidcClientConfig(configMappingGroup);
+ for (var configMappingMethod : EnumSet.allOf(OidcClientConfigImpl.ConfigMappingMethods.class)) {
+ Boolean invoked = configMappingGroup.invocationsRecorder.get(configMappingMethod);
+ assertTrue(invoked != null && invoked,
+ "OidcClientConfig method '%s' return value is not copied from interface to class"
+ .formatted(configMappingMethod));
+ }
+ }
+
+}
diff --git a/extensions/oidc-common/runtime/pom.xml b/extensions/oidc-common/runtime/pom.xml
index 4a8e750382909..ace03eb72f809 100644
--- a/extensions/oidc-common/runtime/pom.xml
+++ b/extensions/oidc-common/runtime/pom.xml
@@ -71,9 +71,6 @@
${project.version}
-
- -AlegacyConfigRoot=true
-
diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java
index 095719e40d8f3..619982e2bf395 100644
--- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java
+++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java
@@ -4,31 +4,37 @@
import java.util.Map;
import java.util.Optional;
-import io.quarkus.runtime.annotations.ConfigDocMapKey;
-import io.quarkus.runtime.annotations.ConfigGroup;
-import io.quarkus.runtime.annotations.ConfigItem;
-
-@ConfigGroup
public class OidcClientCommonConfig extends OidcCommonConfig {
+
+ public OidcClientCommonConfig() {
+
+ }
+
+ protected OidcClientCommonConfig(io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig mapping) {
+ super(mapping);
+ this.tokenPath = mapping.tokenPath();
+ this.revokePath = mapping.revokePath();
+ this.clientId = mapping.clientId();
+ this.clientName = mapping.clientName();
+ this.credentials.addConfigMappingValues(mapping.credentials());
+ }
+
/**
* The OIDC token endpoint that issues access and refresh tokens;
* specified as a relative path or absolute URL.
* Set if {@link #discoveryEnabled} is `false` or a discovered token endpoint path must be customized.
*/
- @ConfigItem
public Optional tokenPath = Optional.empty();
/**
* The relative path or absolute URL of the OIDC token revocation endpoint.
*/
- @ConfigItem
public Optional revokePath = Optional.empty();
/**
* The client id of the application. Each application has a client id that is used to identify the application.
* Setting the client id is not required if {@link #applicationType} is `service` and no token introspection is required.
*/
- @ConfigItem
public Optional clientId = Optional.empty();
/**
@@ -37,16 +43,13 @@ public class OidcClientCommonConfig extends OidcCommonConfig {
* For example, you can set this property to have more informative log messages which record an activity of the given
* client.
*/
- @ConfigItem
public Optional clientName = Optional.empty();
/**
* Credentials the OIDC adapter uses to authenticate to the OIDC server.
*/
- @ConfigItem
public Credentials credentials = new Credentials();
- @ConfigGroup
public static class Credentials {
/**
@@ -54,7 +57,6 @@ public static class Credentials {
* Must be set unless a secret is set in {@link #clientSecret} or {@link #jwt} client authentication is required.
* You can use `client-secret.value` instead, but both properties are mutually exclusive.
*/
- @ConfigItem
public Optional secret = Optional.empty();
/**
@@ -63,13 +65,11 @@ public static class Credentials {
* Note that a `secret.value` property can be used instead to support the `client_secret_basic` method
* but both properties are mutually exclusive.
*/
- @ConfigItem
public Secret clientSecret = new Secret();
/**
* Client JSON Web Token (JWT) authentication methods
*/
- @ConfigItem
public Jwt jwt = new Jwt();
public Optional getSecret() {
@@ -96,13 +96,18 @@ public void setJwt(Jwt jwt) {
this.jwt = jwt;
}
+ private void addConfigMappingValues(io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig.Credentials mapping) {
+ secret = mapping.secret();
+ clientSecret.addConfigMappingValues(mapping.clientSecret());
+ jwt.addConfigMappingValues(mapping.jwt());
+ }
+
/**
* Supports the client authentication methods that involve sending a client secret.
*
* @see https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
*/
- @ConfigGroup
public static class Secret {
public static enum Method {
@@ -136,20 +141,17 @@ public static enum Method {
* The client secret value. This value is ignored if `credentials.secret` is set.
* Must be set unless a secret is set in {@link #clientSecret} or {@link #jwt} client authentication is required.
*/
- @ConfigItem
public Optional value = Optional.empty();
/**
* The Secret CredentialsProvider.
*/
- @ConfigItem
public Provider provider = new Provider();
/**
* The authentication method.
* If the `clientSecret.value` secret is set, this method is `basic` by default.
*/
- @ConfigItem
public Optional method = Optional.empty();
public Optional getValue() {
@@ -175,6 +177,13 @@ public Provider getSecretProvider() {
public void setSecretProvider(Provider secretProvider) {
this.provider = secretProvider;
}
+
+ private void addConfigMappingValues(
+ io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig.Credentials.Secret mapping) {
+ this.value = mapping.value();
+ this.provider.addConfigMappingValues(mapping.provider());
+ this.method = mapping.method().map(Enum::toString).map(Method::valueOf);
+ }
}
/**
@@ -185,7 +194,6 @@ public void setSecretProvider(Provider secretProvider) {
* @see https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
*/
- @ConfigGroup
public static class Jwt {
public static enum Source {
@@ -200,20 +208,17 @@ public static enum Source {
/**
* JWT token source: OIDC provider client or an existing JWT bearer token.
*/
- @ConfigItem(defaultValue = "client")
public Source source = Source.CLIENT;
/**
* If provided, indicates that JWT is signed using a secret key.
* It is mutually exclusive with {@link #key}, {@link #keyFile} and {@link #keyStore} properties.
*/
- @ConfigItem
public Optional secret = Optional.empty();
/**
* If provided, indicates that JWT is signed using a secret key provided by Secret CredentialsProvider.
*/
- @ConfigItem
public Provider secretProvider = new Provider();
/**
@@ -222,7 +227,6 @@ public static enum Source {
* It is mutually exclusive with {@link #secret}, {@link #keyFile} and {@link #keyStore} properties.
* You can use the {@link #signatureAlgorithm} property to override the default key algorithm, `RS256`.
*/
- @ConfigItem
public Optional key = Optional.empty();
/**
@@ -230,64 +234,53 @@ public static enum Source {
* It is mutually exclusive with {@link #secret}, {@link #key} and {@link #keyStore} properties.
* You can use the {@link #signatureAlgorithm} property to override the default key algorithm, `RS256`.
*/
- @ConfigItem
public Optional keyFile = Optional.empty();
/**
* If provided, indicates that JWT is signed using a private key from a keystore.
* It is mutually exclusive with {@link #secret}, {@link #key} and {@link #keyFile} properties.
*/
- @ConfigItem
public Optional keyStoreFile = Optional.empty();
/**
* A parameter to specify the password of the keystore file.
*/
- @ConfigItem
public Optional keyStorePassword;
/**
* The private key id or alias.
*/
- @ConfigItem
public Optional keyId = Optional.empty();
/**
* The private key password.
*/
- @ConfigItem
public Optional keyPassword;
/**
* The JWT audience (`aud`) claim value.
* By default, the audience is set to the address of the OpenId Connect Provider's token endpoint.
*/
- @ConfigItem
public Optional audience = Optional.empty();
/**
* The key identifier of the signing key added as a JWT `kid` header.
*/
- @ConfigItem
public Optional tokenKeyId = Optional.empty();
/**
* The issuer of the signing key added as a JWT `iss` claim. The default value is the client id.
*/
- @ConfigItem
public Optional issuer = Optional.empty();
/**
* Subject of the signing key added as a JWT `sub` claim The default value is the client id.
*/
- @ConfigItem
public Optional subject = Optional.empty();
/**
* Additional claims.
*/
- @ConfigItem
- @ConfigDocMapKey("claim-name")
public Map claims = new HashMap<>();
/**
@@ -295,14 +288,12 @@ public static enum Source {
* Supported values: `RS256` (default), `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `ES256`, `ES384`, `ES512`,
* `HS256`, `HS384`, `HS512`.
*/
- @ConfigItem
public Optional signatureAlgorithm = Optional.empty();
/**
* The JWT lifespan in seconds. This value is added to the time at which the JWT was issued to calculate the
* expiration time.
*/
- @ConfigItem(defaultValue = "10")
public int lifespan = 10;
/**
@@ -311,7 +302,6 @@ public static enum Source {
* and 'client_assertion_type' form properties, only 'assertion' is produced.
* This option is only supported by the OIDC client extension.
*/
- @ConfigItem(defaultValue = "false")
public boolean assertion = false;
public Optional getSecret() {
@@ -402,19 +392,37 @@ public void setAssertion(boolean assertion) {
this.assertion = assertion;
}
+ private void addConfigMappingValues(
+ io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig.Credentials.Jwt mapping) {
+ source = Source.valueOf(mapping.source().toString());
+ secret = mapping.secret();
+ secretProvider.addConfigMappingValues(mapping.secretProvider());
+ key = mapping.key();
+ keyFile = mapping.keyFile();
+ keyStoreFile = mapping.keyStoreFile();
+ keyStorePassword = mapping.keyStorePassword();
+ keyId = mapping.keyId();
+ keyPassword = mapping.keyPassword();
+ audience = mapping.audience();
+ tokenKeyId = mapping.tokenKeyId();
+ issuer = mapping.issuer();
+ subject = mapping.subject();
+ claims = mapping.claims();
+ signatureAlgorithm = mapping.signatureAlgorithm();
+ lifespan = mapping.lifespan();
+ assertion = mapping.assertion();
+ }
}
/**
* CredentialsProvider, which provides a client secret.
*/
- @ConfigGroup
public static class Provider {
/**
* The CredentialsProvider bean name, which should only be set if more than one CredentialsProvider is
* registered
*/
- @ConfigItem
public Optional name = Optional.empty();
/**
@@ -424,13 +432,11 @@ public static class Provider {
* shared by multiple extensions to retrieve credentials from a more dynamic source like a vault instance or secret
* manager
*/
- @ConfigItem
public Optional keyringName = Optional.empty();
/**
* The CredentialsProvider client secret key
*/
- @ConfigItem
public Optional key = Optional.empty();
public Optional getName() {
@@ -456,6 +462,13 @@ public Optional getKey() {
public void setKey(String key) {
this.key = Optional.of(key);
}
+
+ private void addConfigMappingValues(
+ io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig.Credentials.Provider mapping) {
+ name = mapping.name();
+ keyringName = mapping.keyringName();
+ key = mapping.key();
+ }
}
}
@@ -498,4 +511,5 @@ public Credentials getCredentials() {
public void setCredentials(Credentials credentials) {
this.credentials = credentials;
}
+
}
diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonConfig.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonConfig.java
index 9fb2108b6af4e..7662b906611df 100644
--- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonConfig.java
+++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonConfig.java
@@ -5,11 +5,26 @@
import java.util.Optional;
import java.util.OptionalInt;
-import io.quarkus.runtime.annotations.ConfigGroup;
-import io.quarkus.runtime.annotations.ConfigItem;
-
-@ConfigGroup
public class OidcCommonConfig {
+
+ public OidcCommonConfig() {
+
+ }
+
+ protected OidcCommonConfig(io.quarkus.oidc.common.runtime.config.OidcCommonConfig mapping) {
+ this.authServerUrl = mapping.authServerUrl();
+ this.discoveryEnabled = mapping.discoveryEnabled();
+ this.registrationPath = mapping.registrationPath();
+ this.connectionDelay = mapping.connectionDelay();
+ this.connectionRetryCount = mapping.connectionRetryCount();
+ this.connectionTimeout = mapping.connectionTimeout();
+ this.useBlockingDnsLookup = mapping.useBlockingDnsLookup();
+ this.maxPoolSize = mapping.maxPoolSize();
+ this.followRedirects = mapping.followRedirects();
+ this.proxy.addConfigMappingValues(mapping.proxy());
+ this.tls.addConfigMappingValues(mapping.tls());
+ }
+
/**
* The base URL of the OpenID Connect (OIDC) server, for example, `https://host:port/auth`.
* Do not set this property if you use 'quarkus-oidc' and the public key verification ({@link #publicKey})
@@ -17,21 +32,18 @@ public class OidcCommonConfig {
* The OIDC discovery endpoint is called by default by appending a `.well-known/openid-configuration` path to this URL.
* For Keycloak, use `https://host:port/realms/{realm}`, replacing `{realm}` with the Keycloak realm name.
*/
- @ConfigItem
public Optional authServerUrl = Optional.empty();
/**
* Discovery of the OIDC endpoints.
* If not enabled, you must configure the OIDC endpoint URLs individually.
*/
- @ConfigItem(defaultValueDocumentation = "true")
public Optional discoveryEnabled = Optional.empty();
/**
* The relative path or absolute URL of the OIDC dynamic client registration endpoint.
* Set if {@link #discoveryEnabled} is `false` or a discovered token endpoint path must be customized.
*/
- @ConfigItem
public Optional registrationPath = Optional.empty();
/**
@@ -40,7 +52,6 @@ public class OidcCommonConfig {
* This property is only effective when the initial OIDC connection is created.
* For dropped connections, use the `connection-retry-count` property instead.
*/
- @ConfigItem
public Optional connectionDelay = Optional.empty();
/**
@@ -49,26 +60,22 @@ public class OidcCommonConfig {
* For instance, if a request to the OIDC token endpoint fails due to a connection issue, it will be retried as per this
* setting.
*/
- @ConfigItem(defaultValue = "3")
public int connectionRetryCount = 3;
/**
* The number of seconds after which the current OIDC connection request times out.
*/
- @ConfigItem(defaultValue = "10s")
public Duration connectionTimeout = Duration.ofSeconds(10);
/**
* Whether DNS lookup should be performed on the worker thread.
* Use this option when you can see logged warnings about blocked Vert.x event loop by HTTP requests to OIDC server.
*/
- @ConfigItem(defaultValue = "false")
public boolean useBlockingDnsLookup;
/**
* The maximum size of the connection pool used by the WebClient.
*/
- @ConfigItem
public OptionalInt maxPoolSize = OptionalInt.empty();
/**
@@ -76,22 +83,18 @@ public class OidcCommonConfig {
* When this property is disabled only a single redirect to exactly the same original URI
* is allowed but only if one or more cookies were set during the redirect request.
*/
- @ConfigItem(defaultValue = "true")
public boolean followRedirects = true;
/**
* Options to configure the proxy the OIDC adapter uses to talk with the OIDC server.
*/
- @ConfigItem
public Proxy proxy = new Proxy();
/**
* TLS configurations
*/
- @ConfigItem
public Tls tls = new Tls();
- @ConfigGroup
public static class Tls {
/**
@@ -102,9 +105,24 @@ public static class Tls {
*
* The default TLS configuration is not used by default.
*/
- @ConfigItem
Optional tlsConfigurationName = Optional.empty();
+ private void addConfigMappingValues(io.quarkus.oidc.common.runtime.config.OidcCommonConfig.Tls mapping) {
+ this.tlsConfigurationName = mapping.tlsConfigurationName();
+ this.verification = mapping.verification().map(Enum::toString).map(Verification::valueOf);
+ this.keyStoreFile = mapping.keyStoreFile();
+ this.keyStoreFileType = mapping.keyStoreFileType();
+ this.keyStoreProvider = mapping.keyStoreProvider();
+ this.keyStorePassword = mapping.keyStorePassword();
+ this.keyStoreKeyAlias = mapping.keyStoreKeyAlias();
+ this.keyStoreKeyPassword = mapping.keyStoreKeyPassword();
+ this.trustStoreFile = mapping.trustStoreFile();
+ this.trustStorePassword = mapping.trustStorePassword();
+ this.trustStoreCertAlias = mapping.trustStoreCertAlias();
+ this.trustStoreFileType = mapping.trustStoreFileType();
+ this.trustStoreProvider = mapping.trustStoreProvider();
+ }
+
public enum Verification {
/**
* Certificates are validated and hostname verification is enabled. This is the default value.
@@ -129,8 +147,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional verification = Optional.empty();
/**
@@ -138,8 +154,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional keyStoreFile = Optional.empty();
/**
@@ -147,8 +161,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional keyStoreFileType = Optional.empty();
/**
@@ -157,8 +169,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional keyStoreProvider;
/**
@@ -166,8 +176,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional keyStorePassword;
/**
@@ -177,8 +185,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional keyStoreKeyAlias = Optional.empty();
/**
@@ -186,8 +192,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional keyStoreKeyPassword = Optional.empty();
/**
@@ -195,8 +199,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional trustStoreFile = Optional.empty();
/**
@@ -204,8 +206,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional trustStorePassword = Optional.empty();
/**
@@ -213,8 +213,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional trustStoreCertAlias = Optional.empty();
/**
@@ -224,8 +222,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional trustStoreFileType = Optional.empty();
/**
@@ -235,8 +231,6 @@ public enum Verification {
*
* @deprecated Use the TLS registry instead.
*/
- @Deprecated
- @ConfigItem
public Optional trustStoreProvider;
public Optional getVerification() {
@@ -289,7 +283,6 @@ public void setTrustStoreProvider(String trustStoreProvider) {
}
- @ConfigGroup
public static class Proxy {
/**
@@ -297,27 +290,29 @@ public static class Proxy {
* Note: If the OIDC adapter requires a Proxy to talk with the OIDC server (Provider),
* set this value to enable the usage of a Proxy.
*/
- @ConfigItem
public Optional host = Optional.empty();
/**
* The port number of the Proxy. The default value is `80`.
*/
- @ConfigItem(defaultValue = "80")
public int port = 80;
/**
* The username, if the Proxy needs authentication.
*/
- @ConfigItem
public Optional username = Optional.empty();
/**
* The password, if the Proxy needs authentication.
*/
- @ConfigItem
public Optional password = Optional.empty();
+ private void addConfigMappingValues(io.quarkus.oidc.common.runtime.config.OidcCommonConfig.Proxy mapping) {
+ this.host = mapping.host();
+ this.port = mapping.port();
+ this.username = mapping.username();
+ this.password = mapping.password();
+ }
}
public Optional getConnectionDelay() {
@@ -383,4 +378,5 @@ public Optional getDiscoveryEnabled() {
public void setDiscoveryEnabled(Boolean discoveryEnabled) {
this.discoveryEnabled = Optional.of(discoveryEnabled);
}
+
}
diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfig.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfig.java
new file mode 100644
index 0000000000000..8ad80d388a927
--- /dev/null
+++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfig.java
@@ -0,0 +1,269 @@
+package io.quarkus.oidc.common.runtime.config;
+
+import java.util.Map;
+import java.util.Optional;
+
+import io.quarkus.runtime.annotations.ConfigDocMapKey;
+import io.smallrye.config.WithDefault;
+
+public interface OidcClientCommonConfig extends OidcCommonConfig {
+ /**
+ * The OIDC token endpoint that issues access and refresh tokens;
+ * specified as a relative path or absolute URL.
+ * Set if {@link #discoveryEnabled} is `false` or a discovered token endpoint path must be customized.
+ */
+ Optional tokenPath();
+
+ /**
+ * The relative path or absolute URL of the OIDC token revocation endpoint.
+ */
+ Optional revokePath();
+
+ /**
+ * The client id of the application. Each application has a client id that is used to identify the application.
+ * Setting the client id is not required if {@link #applicationType} is `service` and no token introspection is required.
+ */
+ Optional clientId();
+
+ /**
+ * The client name of the application. It is meant to represent a human readable description of the application which you
+ * may provide when an application (client) is registered in an OpenId Connect provider's dashboard.
+ * For example, you can set this property to have more informative log messages which record an activity of the given
+ * client.
+ */
+ Optional clientName();
+
+ /**
+ * Credentials the OIDC adapter uses to authenticate to the OIDC server.
+ */
+ Credentials credentials();
+
+ interface Credentials {
+
+ /**
+ * The client secret used by the `client_secret_basic` authentication method.
+ * Must be set unless a secret is set in {@link #clientSecret} or {@link #jwt} client authentication is required.
+ * You can use `client-secret.value` instead, but both properties are mutually exclusive.
+ */
+ Optional secret();
+
+ /**
+ * The client secret used by the `client_secret_basic` (default), `client_secret_post`, or `client_secret_jwt`
+ * authentication methods.
+ * Note that a `secret.value` property can be used instead to support the `client_secret_basic` method
+ * but both properties are mutually exclusive.
+ */
+ Secret clientSecret();
+
+ /**
+ * Client JSON Web Token (JWT) authentication methods
+ */
+ Jwt jwt();
+
+ /**
+ * Supports the client authentication methods that involve sending a client secret.
+ *
+ * @see https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
+ */
+ interface Secret {
+
+ enum Method {
+ /**
+ * `client_secret_basic` (default): The client id and secret are submitted with the HTTP Authorization Basic
+ * scheme.
+ */
+ BASIC,
+
+ /**
+ * `client_secret_post`: The client id and secret are submitted as the `client_id` and `client_secret`
+ * form parameters.
+ */
+ POST,
+
+ /**
+ * `client_secret_jwt`: The client id and generated JWT secret are submitted as the `client_id` and
+ * `client_secret`
+ * form parameters.
+ */
+ POST_JWT,
+
+ /**
+ * client id and secret are submitted as HTTP query parameters. This option is only supported by the OIDC
+ * extension.
+ */
+ QUERY
+ }
+
+ /**
+ * The client secret value. This value is ignored if `credentials.secret` is set.
+ * Must be set unless a secret is set in {@link #clientSecret} or {@link #jwt} client authentication is required.
+ */
+ Optional value();
+
+ /**
+ * The Secret CredentialsProvider.
+ */
+ Provider provider();
+
+ /**
+ * The authentication method.
+ * If the `clientSecret.value` secret is set, this method is `basic` by default.
+ */
+ Optional method();
+
+ }
+
+ /**
+ * Supports the client authentication `client_secret_jwt` and `private_key_jwt` methods, which involves sending a JWT
+ * token assertion signed with a client secret or private key.
+ * JWT Bearer client authentication is also supported.
+ *
+ * @see https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
+ */
+ interface Jwt {
+
+ enum Source {
+ // JWT token is generated by the OIDC provider client to support
+ // `client_secret_jwt` and `private_key_jwt` authentication methods
+ CLIENT,
+ // JWT bearer token as used as a client assertion: https://www.rfc-editor.org/rfc/rfc7523#section-2.2
+ // This option is only supported by the OIDC client extension.
+ BEARER
+ }
+
+ /**
+ * JWT token source: OIDC provider client or an existing JWT bearer token.
+ */
+ @WithDefault("client")
+ Source source();
+
+ /**
+ * If provided, indicates that JWT is signed using a secret key.
+ * It is mutually exclusive with {@link #key}, {@link #keyFile} and {@link #keyStore} properties.
+ */
+ Optional secret();
+
+ /**
+ * If provided, indicates that JWT is signed using a secret key provided by Secret CredentialsProvider.
+ */
+ Provider secretProvider();
+
+ /**
+ * String representation of a private key. If provided, indicates that JWT is signed using a private key in PEM or
+ * JWK format.
+ * It is mutually exclusive with {@link #secret}, {@link #keyFile} and {@link #keyStore} properties.
+ * You can use the {@link #signatureAlgorithm} property to override the default key algorithm, `RS256`.
+ */
+ Optional key();
+
+ /**
+ * If provided, indicates that JWT is signed using a private key in PEM or JWK format.
+ * It is mutually exclusive with {@link #secret}, {@link #key} and {@link #keyStore} properties.
+ * You can use the {@link #signatureAlgorithm} property to override the default key algorithm, `RS256`.
+ */
+ Optional keyFile();
+
+ /**
+ * If provided, indicates that JWT is signed using a private key from a keystore.
+ * It is mutually exclusive with {@link #secret}, {@link #key} and {@link #keyFile} properties.
+ */
+ Optional keyStoreFile();
+
+ /**
+ * A parameter to specify the password of the keystore file.
+ */
+ Optional keyStorePassword();
+
+ /**
+ * The private key id or alias.
+ */
+ Optional keyId();
+
+ /**
+ * The private key password.
+ */
+ Optional keyPassword();
+
+ /**
+ * The JWT audience (`aud`) claim value.
+ * By default, the audience is set to the address of the OpenId Connect Provider's token endpoint.
+ */
+ Optional audience();
+
+ /**
+ * The key identifier of the signing key added as a JWT `kid` header.
+ */
+ Optional tokenKeyId();
+
+ /**
+ * The issuer of the signing key added as a JWT `iss` claim. The default value is the client id.
+ */
+ Optional issuer();
+
+ /**
+ * Subject of the signing key added as a JWT `sub` claim The default value is the client id.
+ */
+ Optional subject();
+
+ /**
+ * Additional claims.
+ */
+ @ConfigDocMapKey("claim-name")
+ Map claims();
+
+ /**
+ * The signature algorithm used for the {@link #keyFile} property.
+ * Supported values: `RS256` (default), `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `ES256`, `ES384`, `ES512`,
+ * `HS256`, `HS384`, `HS512`.
+ */
+ Optional signatureAlgorithm();
+
+ /**
+ * The JWT lifespan in seconds. This value is added to the time at which the JWT was issued to calculate the
+ * expiration time.
+ */
+ @WithDefault("10")
+ int lifespan();
+
+ /**
+ * If true then the client authentication token is a JWT bearer grant assertion. Instead of producing
+ * 'client_assertion'
+ * and 'client_assertion_type' form properties, only 'assertion' is produced.
+ * This option is only supported by the OIDC client extension.
+ */
+ @WithDefault("false")
+ boolean assertion();
+
+ }
+
+ /**
+ * CredentialsProvider, which provides a client secret.
+ */
+ interface Provider {
+
+ /**
+ * The CredentialsProvider bean name, which should only be set if more than one CredentialsProvider is
+ * registered
+ */
+ Optional name();
+
+ /**
+ * The CredentialsProvider keyring name.
+ * The keyring name is only required when the CredentialsProvider being
+ * used requires the keyring name to look up the secret, which is often the case when a CredentialsProvider is
+ * shared by multiple extensions to retrieve credentials from a more dynamic source like a vault instance or secret
+ * manager
+ */
+ Optional keyringName();
+
+ /**
+ * The CredentialsProvider client secret key
+ */
+ Optional key();
+
+ }
+ }
+
+}
diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcCommonConfig.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcCommonConfig.java
new file mode 100644
index 0000000000000..4edf4be8a9d46
--- /dev/null
+++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcCommonConfig.java
@@ -0,0 +1,249 @@
+package io.quarkus.oidc.common.runtime.config;
+
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.Optional;
+import java.util.OptionalInt;
+
+import io.quarkus.runtime.annotations.ConfigDocDefault;
+import io.smallrye.config.WithDefault;
+
+public interface OidcCommonConfig {
+ /**
+ * The base URL of the OpenID Connect (OIDC) server, for example, `https://host:port/auth`.
+ * Do not set this property if you use 'quarkus-oidc' and the public key verification ({@link #publicKey})
+ * or certificate chain verification only ({@link #certificateChain}) is required.
+ * The OIDC discovery endpoint is called by default by appending a `.well-known/openid-configuration` path to this URL.
+ * For Keycloak, use `https://host:port/realms/{realm}`, replacing `{realm}` with the Keycloak realm name.
+ */
+ Optional authServerUrl();
+
+ /**
+ * Discovery of the OIDC endpoints.
+ * If not enabled, you must configure the OIDC endpoint URLs individually.
+ */
+ @ConfigDocDefault("true")
+ Optional discoveryEnabled();
+
+ /**
+ * The relative path or absolute URL of the OIDC dynamic client registration endpoint.
+ * Set if {@link #discoveryEnabled} is `false` or a discovered token endpoint path must be customized.
+ */
+ Optional registrationPath();
+
+ /**
+ * The duration to attempt the initial connection to an OIDC server.
+ * For example, setting the duration to `20S` allows 10 retries, each 2 seconds apart.
+ * This property is only effective when the initial OIDC connection is created.
+ * For dropped connections, use the `connection-retry-count` property instead.
+ */
+ Optional connectionDelay();
+
+ /**
+ * The number of times to retry re-establishing an existing OIDC connection if it is temporarily lost.
+ * Different from `connection-delay`, which applies only to initial connection attempts.
+ * For instance, if a request to the OIDC token endpoint fails due to a connection issue, it will be retried as per this
+ * setting.
+ */
+ @WithDefault("3")
+ int connectionRetryCount();
+
+ /**
+ * The number of seconds after which the current OIDC connection request times out.
+ */
+ @WithDefault("10s")
+ Duration connectionTimeout();
+
+ /**
+ * Whether DNS lookup should be performed on the worker thread.
+ * Use this option when you can see logged warnings about blocked Vert.x event loop by HTTP requests to OIDC server.
+ */
+ @WithDefault("false")
+ boolean useBlockingDnsLookup();
+
+ /**
+ * The maximum size of the connection pool used by the WebClient.
+ */
+ OptionalInt maxPoolSize();
+
+ /**
+ * Follow redirects automatically when WebClient gets HTTP 302.
+ * When this property is disabled only a single redirect to exactly the same original URI
+ * is allowed but only if one or more cookies were set during the redirect request.
+ */
+ @WithDefault("true")
+ boolean followRedirects();
+
+ /**
+ * Options to configure the proxy the OIDC adapter uses to talk with the OIDC server.
+ */
+ Proxy proxy();
+
+ /**
+ * TLS configurations
+ */
+ Tls tls();
+
+ interface Tls {
+
+ /**
+ * The name of the TLS configuration to use.
+ *
+ * If a name is configured, it uses the configuration from {@code quarkus.tls..*}
+ * If a name is configured, but no TLS configuration is found with that name then an error will be thrown.
+ *
+ * The default TLS configuration is not used by default.
+ */
+ Optional tlsConfigurationName();
+
+ enum Verification {
+ /**
+ * Certificates are validated and hostname verification is enabled. This is the default value.
+ */
+ REQUIRED,
+
+ /**
+ * Certificates are validated but hostname verification is disabled.
+ */
+ CERTIFICATE_VALIDATION,
+
+ /**
+ * All certificates are trusted and hostname verification is disabled.
+ */
+ NONE
+ }
+
+ /**
+ * Certificate validation and hostname verification, which can be one of the following {@link Verification}
+ * values.
+ * Default is `required`.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional verification();
+
+ /**
+ * An optional keystore that holds the certificate information instead of specifying separate files.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional keyStoreFile();
+
+ /**
+ * The type of the keystore file. If not given, the type is automatically detected based on the file name.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional keyStoreFileType();
+
+ /**
+ * The provider of the keystore file. If not given, the provider is automatically detected based on the
+ * keystore file type.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional keyStoreProvider();
+
+ /**
+ * The password of the keystore file. If not given, the default value, `password`, is used.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional keyStorePassword();
+
+ /**
+ * The alias of a specific key in the keystore.
+ * When SNI is disabled, if the keystore contains multiple
+ * keys and no alias is specified, the behavior is undefined.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional keyStoreKeyAlias();
+
+ /**
+ * The password of the key, if it is different from the {@link #keyStorePassword}.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional keyStoreKeyPassword();
+
+ /**
+ * The truststore that holds the certificate information of the certificates to trust.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional trustStoreFile();
+
+ /**
+ * The password of the truststore file.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional trustStorePassword();
+
+ /**
+ * The alias of the truststore certificate.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional trustStoreCertAlias();
+
+ /**
+ * The type of the truststore file.
+ * If not given, the type is automatically detected
+ * based on the file name.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional trustStoreFileType();
+
+ /**
+ * The provider of the truststore file.
+ * If not given, the provider is automatically detected
+ * based on the truststore file type.
+ *
+ * @deprecated Use the TLS registry instead.
+ */
+ @Deprecated
+ Optional trustStoreProvider();
+
+ }
+
+ interface Proxy {
+
+ /**
+ * The host name or IP address of the Proxy.
+ * Note: If the OIDC adapter requires a Proxy to talk with the OIDC server (Provider),
+ * set this value to enable the usage of a Proxy.
+ */
+ Optional host();
+
+ /**
+ * The port number of the Proxy. The default value is `80`.
+ */
+ @WithDefault("80")
+ int port();
+
+ /**
+ * The username, if the Proxy needs authentication.
+ */
+ Optional username();
+
+ /**
+ * The password, if the Proxy needs authentication.
+ */
+ Optional password();
+
+ }
+}
diff --git a/extensions/oidc/deployment/pom.xml b/extensions/oidc/deployment/pom.xml
index 8e45ae8a28f43..8691bf75f1911 100644
--- a/extensions/oidc/deployment/pom.xml
+++ b/extensions/oidc/deployment/pom.xml
@@ -116,9 +116,6 @@
${project.version}
-
- -AlegacyConfigRoot=true
-
diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/DevUiConfig.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/DevUiConfig.java
index aca96f6e25a7d..1a386b660dda2 100644
--- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/DevUiConfig.java
+++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/DevUiConfig.java
@@ -5,11 +5,9 @@
import java.util.Optional;
import io.quarkus.runtime.annotations.ConfigDocMapKey;
-import io.quarkus.runtime.annotations.ConfigGroup;
-import io.quarkus.runtime.annotations.ConfigItem;
+import io.smallrye.config.WithDefault;
-@ConfigGroup
-public class DevUiConfig {
+public interface DevUiConfig {
/**
* Grant type which affects how OpenId Connect Dev UI will facilitate the token acquisition.
@@ -19,11 +17,10 @@ public class DevUiConfig {
* handler to acquire the tokens while a username and password will have to be entered to request a token using a
* 'password' grant.
*/
- public Grant grant = new Grant();
+ Grant grant();
- @ConfigGroup
- public static class Grant {
- public static enum Type {
+ interface Grant {
+ enum Type {
/**
* 'client_credentials' grant
*/
@@ -45,7 +42,7 @@ public static enum Type {
private String grantType;
- private Type(String grantType) {
+ Type(String grantType) {
this.grantType = grantType;
}
@@ -57,22 +54,20 @@ public String getGrantType() {
/**
* Grant type which will be used to acquire a token to test the OIDC 'service' applications
*/
- @ConfigItem
- public Optional type;
+ Optional type();
}
/**
* Grant options
*/
- @ConfigItem
@ConfigDocMapKey("option-name")
- public Map> grantOptions;
+ Map> grantOptions();
/**
* The WebClient timeout.
* Use this property to configure how long an HTTP client used by Dev UI handlers will wait for a response when requesting
* tokens from OpenId Connect Provider and sending them to the service endpoint.
*/
- @ConfigItem(defaultValue = "4S")
- public Duration webClientTimeout;
+ @WithDefault("4S")
+ Duration webClientTimeout();
}
diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildStep.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildStep.java
index d173468d4383f..c64a0382fa0ac 100644
--- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildStep.java
+++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildStep.java
@@ -427,7 +427,7 @@ public static class IsEnabled implements BooleanSupplier {
OidcBuildTimeConfig config;
public boolean getAsBoolean() {
- return config.enabled;
+ return config.enabled();
}
}
@@ -435,7 +435,7 @@ public static class IsCacheEnabled implements BooleanSupplier {
OidcBuildTimeConfig config;
public boolean getAsBoolean() {
- return config.enabled && config.defaultTokenCacheEnabled;
+ return config.enabled() && config.defaultTokenCacheEnabled();
}
}
}
diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildTimeConfig.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildTimeConfig.java
index 2a25611394c30..58cc8d51e3722 100644
--- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildTimeConfig.java
+++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildTimeConfig.java
@@ -1,30 +1,32 @@
package io.quarkus.oidc.deployment;
import io.quarkus.oidc.runtime.OidcConfig;
-import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigRoot;
+import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.WithDefault;
/**
* Build time configuration for OIDC.
*/
+@ConfigMapping(prefix = "quarkus.oidc")
@ConfigRoot
-public class OidcBuildTimeConfig {
+public interface OidcBuildTimeConfig {
/**
* If the OIDC extension is enabled.
*/
- @ConfigItem(defaultValue = "true")
- public boolean enabled;
+ @WithDefault("true")
+ boolean enabled();
/**
* Dev UI configuration.
*/
- @ConfigItem
- public DevUiConfig devui;
+ DevUiConfig devui();
+
/**
* Enable the registration of the Default TokenIntrospection and UserInfo Cache implementation bean.
* Note: This only enables the default implementation. It requires configuration to be activated.
* See {@link OidcConfig#tokenCache}.
*/
- @ConfigItem(defaultValue = "true")
- public boolean defaultTokenCacheEnabled;
+ @WithDefault("true")
+ boolean defaultTokenCacheEnabled();
}
diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/OidcDevUIProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/OidcDevUIProcessor.java
index 7e094aeccf6c6..f76c97c96b782 100644
--- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/OidcDevUIProcessor.java
+++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/OidcDevUIProcessor.java
@@ -112,7 +112,8 @@ public void run() {
capabilities,
providerName,
getApplicationType(providerConfig),
- oidcConfig.devui.grant.type.isPresent() ? oidcConfig.devui.grant.type.get().getGrantType() : "code",
+ oidcConfig.devui().grant().type().isPresent() ? oidcConfig.devui().grant().type().get().getGrantType()
+ : "code",
metadataNotNull ? metadata.getString("authorization_endpoint") : null,
metadataNotNull ? metadata.getString("token_endpoint") : null,
metadataNotNull ? metadata.getString("end_session_endpoint") : null,
@@ -120,8 +121,8 @@ public void run() {
? (metadata.containsKey("introspection_endpoint") || metadata.containsKey("userinfo_endpoint"))
: checkProviderUserInfoRequired(providerConfig),
syntheticBeanBuildItemBuildProducer,
- oidcConfig.devui.webClientTimeout,
- oidcConfig.devui.grantOptions,
+ oidcConfig.devui().webClientTimeout(),
+ oidcConfig.devui().grantOptions(),
nonApplicationRootPathBuildItem,
configurationBuildItem,
keycloakAdminUrl,
diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevUIProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevUIProcessor.java
index 2cd325f68eadb..0dfb647905a4f 100644
--- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevUIProcessor.java
+++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevUIProcessor.java
@@ -54,14 +54,14 @@ void produceProviderComponent(Optional confi
capabilities,
"Keycloak",
configProps.get().getConfig().get("quarkus.oidc.application-type"),
- oidcConfig.devui.grant.type.orElse(DevUiConfig.Grant.Type.CODE).getGrantType(),
+ oidcConfig.devui().grant().type().orElse(DevUiConfig.Grant.Type.CODE).getGrantType(),
realmUrl + "/protocol/openid-connect/auth",
realmUrl + "/protocol/openid-connect/token",
realmUrl + "/protocol/openid-connect/logout",
true,
syntheticBeanBuildItemBuildProducer,
- oidcConfig.devui.webClientTimeout,
- oidcConfig.devui.grantOptions,
+ oidcConfig.devui().webClientTimeout(),
+ oidcConfig.devui().grantOptions(),
nonApplicationRootPathBuildItem,
configurationBuildItem,
keycloakAdminUrl,
diff --git a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResource.java b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResource.java
index 33ea63f1f53ab..b4dd761333862 100644
--- a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResource.java
+++ b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResource.java
@@ -45,7 +45,7 @@ public void logout() {
@Path("access-token-name")
@GET
public String accessTokenName() {
- if (!config.defaultTenant.authentication.verifyAccessToken) {
+ if (!config.defaultTenant().authentication().verifyAccessToken()) {
throw new IllegalStateException("Access token verification should be enabled");
}
return accessToken.getName();
diff --git a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResourceWithJwtAccessToken.java b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResourceWithJwtAccessToken.java
index dc82b0c8ce510..59d17dd128ab7 100644
--- a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResourceWithJwtAccessToken.java
+++ b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResourceWithJwtAccessToken.java
@@ -26,6 +26,6 @@ public class ProtectedResourceWithJwtAccessToken {
@GET
public String getName() {
- return idToken.getName() + ":" + config.defaultTenant.authentication.verifyAccessToken;
+ return idToken.getName() + ":" + config.defaultTenant().authentication().verifyAccessToken();
}
}
diff --git a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResourceWithoutJwtAccessToken.java b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResourceWithoutJwtAccessToken.java
index d11ae1b9fdb02..3305810d605be 100644
--- a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResourceWithoutJwtAccessToken.java
+++ b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/ProtectedResourceWithoutJwtAccessToken.java
@@ -23,6 +23,6 @@ public class ProtectedResourceWithoutJwtAccessToken {
@GET
public String getName() {
- return idToken.getName() + ":" + config.defaultTenant.authentication.verifyAccessToken;
+ return idToken.getName() + ":" + config.defaultTenant().authentication().verifyAccessToken();
}
}
diff --git a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/UserInfoRequiredDetectionTest.java b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/UserInfoRequiredDetectionTest.java
index 73633f3bbb4a1..b809ea73d3822 100644
--- a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/UserInfoRequiredDetectionTest.java
+++ b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/UserInfoRequiredDetectionTest.java
@@ -12,8 +12,9 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
+import io.quarkus.oidc.OidcTenantConfig;
import io.quarkus.oidc.UserInfo;
-import io.quarkus.oidc.runtime.OidcConfig;
+import io.quarkus.oidc.runtime.TenantConfigBean;
import io.quarkus.security.PermissionsAllowed;
import io.quarkus.test.QuarkusDevModeTest;
import io.quarkus.test.common.QuarkusTestResource;
@@ -92,16 +93,16 @@ void observe(@Observes Router router) {
public static class UserInfoResource {
@Inject
- OidcConfig config;
+ UserInfo userInfo;
@Inject
- UserInfo userInfo;
+ TenantConfigBean tenantConfigBean;
@PermissionsAllowed("openid")
@Path("default-tenant")
@GET
public String getDefaultTenantName() {
- if (!config.defaultTenant.authentication.userInfoRequired.orElse(false)) {
+ if (!tenantConfigBean.getDefaultTenant().oidcConfig().authentication.userInfoRequired.orElse(false)) {
throw new IllegalStateException("Default tenant user info should be required");
}
return userInfo.getPreferredUserName();
@@ -111,7 +112,7 @@ public String getDefaultTenantName() {
@Path("named-tenant")
@GET
public String getNamedTenantName() {
- if (!config.namedTenants.get("named").authentication.userInfoRequired.orElse(false)) {
+ if (!getNamedTenantConfig("named").authentication.userInfoRequired.orElse(false)) {
throw new IllegalStateException("Named tenant user info should be required");
}
return userInfo.getPreferredUserName();
@@ -121,14 +122,18 @@ public String getNamedTenantName() {
@Path("named-tenant-2")
@GET
public boolean getNamed2TenantUserInfoRequired() {
- return config.namedTenants.get("named-2").authentication.userInfoRequired.orElse(false);
+ return getNamedTenantConfig("named-2").authentication.userInfoRequired.orElse(false);
}
@PermissionsAllowed("openid")
@Path("named-tenant-3")
@GET
public boolean getNamed3TenantUserInfoRequired() {
- return config.namedTenants.get("named-3").authentication.userInfoRequired.orElse(false);
+ return getNamedTenantConfig("named-3").authentication.userInfoRequired.orElse(false);
+ }
+
+ private OidcTenantConfig getNamedTenantConfig(String configName) {
+ return tenantConfigBean.getStaticTenant(configName).oidcConfig();
}
}
diff --git a/extensions/oidc/runtime/pom.xml b/extensions/oidc/runtime/pom.xml
index 25bb4a266db35..9e16adde7705b 100644
--- a/extensions/oidc/runtime/pom.xml
+++ b/extensions/oidc/runtime/pom.xml
@@ -81,9 +81,6 @@
${project.version}
-
- -AlegacyConfigRoot=true
-
diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java
index abc3b0a0627e9..252501412a6ff 100644
--- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java
+++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java
@@ -13,21 +13,49 @@
import io.quarkus.oidc.common.runtime.OidcCommonConfig;
import io.quarkus.oidc.common.runtime.OidcConstants;
import io.quarkus.oidc.runtime.OidcConfig;
-import io.quarkus.runtime.annotations.ConfigDocMapKey;
-import io.quarkus.runtime.annotations.ConfigGroup;
-import io.quarkus.runtime.annotations.ConfigItem;
-import io.quarkus.runtime.annotations.ConvertWith;
-import io.quarkus.runtime.configuration.TrimmedStringConverter;
import io.quarkus.security.identity.SecurityIdentityAugmentor;
-@ConfigGroup
public class OidcTenantConfig extends OidcClientCommonConfig {
+ public OidcTenantConfig() {
+
+ }
+
+ public OidcTenantConfig(io.quarkus.oidc.runtime.OidcTenantConfig mapping, String fallbackTenantId) {
+ super(mapping);
+ if (mapping.tenantId().isPresent()) {
+ tenantId = mapping.tenantId();
+ } else {
+ tenantId = Optional.ofNullable(fallbackTenantId);
+ }
+ tenantEnabled = mapping.tenantEnabled();
+ applicationType = mapping.applicationType().map(Enum::toString).map(ApplicationType::valueOf);
+ authorizationPath = mapping.authorizationPath();
+ userInfoPath = mapping.userInfoPath();
+ introspectionPath = mapping.introspectionPath();
+ jwksPath = mapping.jwksPath();
+ endSessionPath = mapping.endSessionPath();
+ tenantPaths = mapping.tenantPaths();
+ publicKey = mapping.publicKey();
+ introspectionCredentials.addConfigMappingValues(mapping.introspectionCredentials());
+ roles.addConfigMappingValues(mapping.roles());
+ token.addConfigMappingValues(mapping.token());
+ logout.addConfigMappingValues(mapping.logout());
+ certificateChain.addConfigMappingValues(mapping.certificateChain());
+ authentication.addConfigMappingValues(mapping.authentication());
+ codeGrant.addConfigMappingValues(mapping.codeGrant());
+ tokenStateManager.addConfigMappingValues(mapping.tokenStateManager());
+ allowTokenIntrospectionCache = mapping.allowTokenIntrospectionCache();
+ allowUserInfoCache = mapping.allowUserInfoCache();
+ cacheUserInfoInIdtoken = mapping.cacheUserInfoInIdtoken();
+ jwks.addConfigMappingValues(mapping.jwks());
+ provider = mapping.provider().map(Enum::toString).map(Provider::valueOf);
+ }
+
/**
* A unique tenant identifier. It can be set by {@code TenantConfigResolver} providers, which
* resolve the tenant configuration dynamically.
*/
- @ConfigItem
public Optional tenantId = Optional.empty();
/**
@@ -38,13 +66,11 @@ public class OidcTenantConfig extends OidcClientCommonConfig {
* or named tenants are configured.
* In this case, you do not need to disable the default tenant.
*/
- @ConfigItem(defaultValue = "true")
public boolean tenantEnabled = true;
/**
* The application type, which can be one of the following {@link ApplicationType} values.
*/
- @ConfigItem(defaultValueDocumentation = "service")
public Optional applicationType = Optional.empty();
/**
@@ -53,7 +79,6 @@ public class OidcTenantConfig extends OidcClientCommonConfig {
* You must set this property for `web-app` applications if OIDC discovery is disabled.
* This property is ignored if OIDC discovery is enabled.
*/
- @ConfigItem
public Optional authorizationPath = Optional.empty();
/**
@@ -62,7 +87,6 @@ public class OidcTenantConfig extends OidcClientCommonConfig {
* and the `authentication.user-info-required` property is enabled.
* This property is ignored if OIDC discovery is enabled.
*/
- @ConfigItem
public Optional userInfoPath = Optional.empty();
/**
@@ -72,7 +96,6 @@ public class OidcTenantConfig extends OidcClientCommonConfig {
* or 2) JWT tokens must be verified while the cached JWK verification set with no matching JWK is being refreshed.
* This property is ignored if the discovery is enabled.
*/
- @ConfigItem
public Optional introspectionPath = Optional.empty();
/**
@@ -81,7 +104,6 @@ public class OidcTenantConfig extends OidcClientCommonConfig {
* This property should be set if OIDC discovery is disabled and the local JWT verification is required.
* This property is ignored if the discovery is enabled.
*/
- @ConfigItem
public Optional jwksPath = Optional.empty();
/**
@@ -90,7 +112,6 @@ public class OidcTenantConfig extends OidcClientCommonConfig {
* required.
* This property is ignored if the discovery is enabled.
*/
- @ConfigItem
public Optional endSessionPath = Optional.empty();
/**
@@ -100,14 +121,12 @@ public class OidcTenantConfig extends OidcClientCommonConfig {
*
* @asciidoclet
*/
- @ConfigItem
public Optional> tenantPaths = Optional.empty();
/**
* The public key for the local JWT token verification.
* OIDC server connection is not created when this property is set.
*/
- @ConfigItem
public Optional publicKey = Optional.empty();
/**
@@ -115,30 +134,25 @@ public class OidcTenantConfig extends OidcClientCommonConfig {
* and OpenId Connect Provider does not support the OIDC client authentication configured with
* {@link OidcCommonConfig#credentials} for its introspection endpoint.
*/
- @ConfigItem
public IntrospectionCredentials introspectionCredentials = new IntrospectionCredentials();
/**
* Introspection Basic Authentication configuration
*/
- @ConfigGroup
public static class IntrospectionCredentials {
/**
* Name
*/
- @ConfigItem
public Optional name = Optional.empty();
/**
* Secret
*/
- @ConfigItem
public Optional secret = Optional.empty();
/**
* Include OpenId Connect Client ID configured with `quarkus.oidc.client-id`.
*/
- @ConfigItem(defaultValue = "true")
public boolean includeClientId = true;
public Optional getName() {
@@ -165,24 +179,26 @@ public void setIncludeClientId(boolean includeClientId) {
this.includeClientId = includeClientId;
}
+ private void addConfigMappingValues(io.quarkus.oidc.runtime.OidcTenantConfig.IntrospectionCredentials mapping) {
+ name = mapping.name();
+ secret = mapping.secret();
+ includeClientId = mapping.includeClientId();
+ }
}
/**
* Configuration to find and parse a custom claim containing the roles information.
*/
- @ConfigItem
public Roles roles = new Roles();
/**
* Configuration how to validate the token claims.
*/
- @ConfigItem
public Token token = new Token();
/**
* RP Initiated, BackChannel and FrontChannel Logout configuration
*/
- @ConfigItem
public Logout logout = new Logout();
/**
@@ -200,35 +216,29 @@ public void setIncludeClientId(boolean includeClientId) {
* If the truststore does not have the leaf certificate imported, then the leaf certificate must be identified by its Common
* Name.
*/
- @ConfigItem
public CertificateChain certificateChain = new CertificateChain();
- @ConfigGroup
public static class CertificateChain {
/**
* Common name of the leaf certificate. It must be set if the {@link #trustStoreFile} does not have
* this certificate imported.
*
*/
- @ConfigItem
public Optional leafCertificateName = Optional.empty();
/**
* Truststore file which keeps thumbprints of the trusted certificates.
*/
- @ConfigItem
public Optional trustStoreFile = Optional.empty();
/**
* A parameter to specify the password of the truststore file if it is configured with {@link #trustStoreFile}.
*/
- @ConfigItem
public Optional trustStorePassword = Optional.empty();
/**
* A parameter to specify the alias of the truststore certificate.
*/
- @ConfigItem
public Optional trustStoreCertAlias = Optional.empty();
/**
@@ -236,7 +246,6 @@ public static class CertificateChain {
* detected
* based on the file name.
*/
- @ConfigItem
public Optional trustStoreFileType = Optional.empty();
public Optional getTrustStoreFile() {
@@ -278,6 +287,14 @@ public Optional getTrustStorePassword() {
public void setTrustStorePassword(String trustStorePassword) {
this.trustStorePassword = Optional.ofNullable(trustStorePassword);
}
+
+ private void addConfigMappingValues(io.quarkus.oidc.runtime.OidcTenantConfig.CertificateChain mapping) {
+ leafCertificateName = mapping.leafCertificateName();
+ trustStoreFile = mapping.trustStoreFile();
+ trustStorePassword = mapping.trustStorePassword();
+ trustStoreCertAlias = mapping.trustStoreCertAlias();
+ trustStoreFileType = mapping.trustStoreFileType();
+ }
}
/**
@@ -293,7 +310,6 @@ public void setTrustStorePassword(String trustStorePassword) {
/**
* Default token state manager configuration
*/
- @ConfigItem
public TokenStateManager tokenStateManager = new TokenStateManager();
/**
@@ -302,7 +318,6 @@ public void setTrustStorePassword(String trustStorePassword) {
* for a given tenant. If the default token cache can be used, see {@link OidcConfig.TokenCache} to enable
* it.
*/
- @ConfigItem(defaultValue = "true")
public boolean allowTokenIntrospectionCache = true;
/**
@@ -311,7 +326,6 @@ public void setTrustStorePassword(String trustStorePassword) {
* for a given tenant. If the default token cache can be used, see {@link OidcConfig.TokenCache} to enable
* it.
*/
- @ConfigItem(defaultValue = "true")
public boolean allowUserInfoCache = true;
/**
@@ -324,10 +338,8 @@ public void setTrustStorePassword(String trustStorePassword) {
* and the UserInfo cache is not enabled or caching UserInfo is disabled for the current tenant
* with the {@link #allowUserInfoCache} property set to `false`.
*/
- @ConfigItem
public Optional cacheUserInfoInIdtoken = Optional.empty();
- @ConfigGroup
public static class Logout {
/**
@@ -335,7 +347,6 @@ public static class Logout {
* initiate the
* logout through this endpoint in conformance with the OpenID Connect RP-Initiated Logout specification.
*/
- @ConfigItem
public Optional path = Optional.empty();
/**
@@ -344,32 +355,26 @@ public static class Logout {
* Connect Provider.
* This endpoint URI must be properly registered at the OpenID Connect Provider as a valid redirect URI.
*/
- @ConfigItem
public Optional postLogoutPath = Optional.empty();
/**
* Name of the post logout URI parameter which is added as a query parameter to the logout redirect URI.
*/
- @ConfigItem(defaultValue = OidcConstants.POST_LOGOUT_REDIRECT_URI)
public String postLogoutUriParam;
/**
* Additional properties which is added as the query parameters to the logout redirect URI.
*/
- @ConfigItem
- @ConfigDocMapKey("query-parameter-name")
public Map extraParams;
/**
* Back-Channel Logout configuration
*/
- @ConfigItem
public Backchannel backchannel = new Backchannel();
/**
* Front-Channel Logout configuration
*/
- @ConfigItem
public Frontchannel frontchannel = new Frontchannel();
public void setPath(Optional path) {
@@ -419,36 +424,40 @@ public Frontchannel getFrontchannel() {
public void setFrontchannel(Frontchannel frontchannel) {
this.frontchannel = frontchannel;
}
+
+ private void addConfigMappingValues(io.quarkus.oidc.runtime.OidcTenantConfig.Logout mapping) {
+ path = mapping.path();
+ postLogoutPath = mapping.postLogoutPath();
+ postLogoutUriParam = mapping.postLogoutUriParam();
+ extraParams = mapping.extraParams();
+ backchannel.addConfigMappingValues(mapping.backchannel());
+ frontchannel.addConfigMappingValues(mapping.frontchannel());
+ }
}
- @ConfigGroup
public static class Backchannel {
/**
* The relative path of the Back-Channel Logout endpoint at the application.
* It must start with the forward slash '/', for example, '/back-channel-logout'.
* This value is always resolved relative to 'quarkus.http.root-path'.
*/
- @ConfigItem
public Optional path = Optional.empty();
/**
* Maximum number of logout tokens that can be cached before they are matched against ID tokens stored in session
* cookies.
*/
- @ConfigItem(defaultValue = "10")
public int tokenCacheSize = 10;
/**
* Number of minutes a logout token can be cached for.
*/
- @ConfigItem(defaultValue = "10M")
public Duration tokenCacheTimeToLive = Duration.ofMinutes(10);
/**
* Token cache timer interval.
* If this property is set, a timer checks and removes the stale entries periodically.
*/
- @ConfigItem
public Optional cleanUpTimerInterval = Optional.empty();
/**
@@ -456,7 +465,6 @@ public static class Backchannel {
* Only `sub` (subject) and `sid` (session id) claims can be used as keys.
* Set it to `sid` only if ID tokens issued by the OIDC provider have no `sub` but have `sid` claim.
*/
- @ConfigItem(defaultValue = "sub")
public String logoutTokenKey = "sub";
public void setPath(Optional path) {
@@ -498,15 +506,21 @@ public Optional getCleanUpTimerInterval() {
public void setCleanUpTimerInterval(Duration cleanUpTimerInterval) {
this.cleanUpTimerInterval = Optional.of(cleanUpTimerInterval);
}
+
+ private void addConfigMappingValues(io.quarkus.oidc.runtime.OidcTenantConfig.Backchannel mapping) {
+ path = mapping.path();
+ tokenCacheSize = mapping.tokenCacheSize();
+ tokenCacheTimeToLive = mapping.tokenCacheTimeToLive();
+ cleanUpTimerInterval = mapping.cleanUpTimerInterval();
+ logoutTokenKey = mapping.logoutTokenKey();
+ }
}
/**
* Configuration for controlling how JsonWebKeySet containing verification keys should be acquired and managed.
*/
- @ConfigItem
public Jwks jwks = new Jwks();
- @ConfigGroup
public static class Jwks {
/**
* If JWK verification keys should be fetched at the moment a connection to the OIDC provider
@@ -516,21 +530,18 @@ public static class Jwks {
* has to be verified. Typically it can only be necessary if the token or other telated request properties
* provide an additional context which is required to resolve the keys correctly.
*/
- @ConfigItem(defaultValue = "true")
public boolean resolveEarly = true;
/**
* Maximum number of JWK keys that can be cached.
* This property is ignored if the {@link #resolveEarly} property is set to true.
*/
- @ConfigItem(defaultValue = "10")
public int cacheSize = 10;
/**
* Number of minutes a JWK key can be cached for.
* This property is ignored if the {@link #resolveEarly} property is set to true.
*/
- @ConfigItem(defaultValue = "10M")
public Duration cacheTimeToLive = Duration.ofMinutes(10);
/**
@@ -538,14 +549,12 @@ public static class Jwks {
* If this property is set, a timer checks and removes the stale entries periodically.
* This property is ignored if the {@link #resolveEarly} property is set to true.
*/
- @ConfigItem
public Optional cleanUpTimerInterval = Optional.empty();
/**
* In case there is no key identifier ('kid') or certificate thumbprints ('x5t', 'x5t#S256') specified in the JOSE
* header and no key could be determined, check all available keys matching the token algorithm ('alg') header value.
*/
- @ConfigItem(defaultValue = "false")
public boolean tryAll = false;
public int getCacheSize() {
@@ -587,14 +596,20 @@ public boolean isTryAll() {
public void setTryAll(boolean fallbackToTryAll) {
this.tryAll = fallbackToTryAll;
}
+
+ private void addConfigMappingValues(io.quarkus.oidc.runtime.OidcTenantConfig.Jwks mapping) {
+ resolveEarly = mapping.resolveEarly();
+ cacheSize = mapping.cacheSize();
+ cacheTimeToLive = mapping.cacheTimeToLive();
+ cleanUpTimerInterval = mapping.cleanUpTimerInterval();
+ tryAll = mapping.tryAll();
+ }
}
- @ConfigGroup
public static class Frontchannel {
/**
* The relative path of the Front-Channel Logout endpoint at the application.
*/
- @ConfigItem
public Optional path = Optional.empty();
public void setPath(Optional path) {
@@ -604,12 +619,15 @@ public void setPath(Optional path) {
public Optional getPath() {
return path;
}
+
+ private void addConfigMappingValues(io.quarkus.oidc.runtime.OidcTenantConfig.Frontchannel mapping) {
+ path = mapping.path();
+ }
}
/**
* Default Authorization Code token state manager configuration
*/
- @ConfigGroup
public static class TokenStateManager {
public enum Strategy {
@@ -632,7 +650,6 @@ public enum Strategy {
/**
* Default TokenStateManager strategy.
*/
- @ConfigItem(defaultValue = "keep_all_tokens")
public Strategy strategy = Strategy.KEEP_ALL_TOKENS;
/**
@@ -641,13 +658,11 @@ public enum Strategy {
*
* Enable this property to minimize a session cookie size
*/
- @ConfigItem(defaultValue = "false")
public boolean splitTokens;
/**
* Mandates that the Default TokenStateManager encrypt the session cookie that stores the tokens.
*/
- @ConfigItem(defaultValue = "true")
public boolean encryptionRequired = true;
/**
@@ -666,7 +681,6 @@ public enum Strategy {
* The length of the secret used to encrypt the tokens should be at least 32 characters long.
* A warning is logged if the secret length is less than 16 characters.
*/
- @ConfigItem
public Optional encryptionSecret = Optional.empty();
/**
@@ -693,7 +707,6 @@ public static enum EncryptionAlgorithm {
/**
* Session cookie key encryption algorithm
*/
- @ConfigItem(defaultValue = "A256GCMKW")
public EncryptionAlgorithm encryptionAlgorithm = EncryptionAlgorithm.A256GCMKW;
public boolean isEncryptionRequired() {
@@ -735,6 +748,14 @@ public EncryptionAlgorithm getEncryptionAlgorithm() {
public void setEncryptionAlgorithm(EncryptionAlgorithm encryptionAlgorithm) {
this.encryptionAlgorithm = encryptionAlgorithm;
}
+
+ private void addConfigMappingValues(io.quarkus.oidc.runtime.OidcTenantConfig.TokenStateManager mapping) {
+ strategy = Strategy.valueOf(mapping.strategy().toString());
+ splitTokens = mapping.splitTokens();
+ encryptionRequired = mapping.encryptionRequired();
+ encryptionSecret = mapping.encryptionSecret();
+ encryptionAlgorithm = EncryptionAlgorithm.valueOf(mapping.encryptionAlgorithm().toString());
+ }
}
public Optional getAuthorizationPath() {
@@ -833,7 +854,6 @@ public Logout getLogout() {
return logout;
}
- @ConfigGroup
public static class Roles {
public static Roles fromClaimPath(List path) {
@@ -855,20 +875,17 @@ public static Roles fromClaimPathAndSeparator(List path, String sep) {
* Use double quotes with the namespace-qualified claim names.
* This property can be used if a token has no `groups` claim but has the groups set in one or more different claims.
*/
- @ConfigItem
public Optional> roleClaimPath = Optional.empty();
/**
* The separator for splitting strings that contain multiple group values.
* It is only used if the "role-claim-path" property points to one or more custom claims whose values are strings.
* A single space is used by default because the standard `scope` claim can contain a space-separated sequence.
*/
- @ConfigItem
public Optional roleClaimSeparator = Optional.empty();
/**
* Source of the principal roles.
*/
- @ConfigItem
public Optional