diff --git a/bom/application/pom.xml b/bom/application/pom.xml index ca0b6f350defb..fa5b8f84e5554 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -832,6 +832,17 @@ ${project.version} + + io.quarkus + quarkus-proxy-registry + ${project.version} + + + io.quarkus + quarkus-proxy-registry-deployment + ${project.version} + + diff --git a/devtools/bom-descriptor-json/pom.xml b/devtools/bom-descriptor-json/pom.xml index ea454f643dc07..e7b60b409fe58 100644 --- a/devtools/bom-descriptor-json/pom.xml +++ b/devtools/bom-descriptor-json/pom.xml @@ -2039,6 +2039,19 @@ + + io.quarkus + quarkus-proxy-registry + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-quartz diff --git a/docs/pom.xml b/docs/pom.xml index 57ed700052209..eb989537c03ad 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -2003,6 +2003,19 @@ + + io.quarkus + quarkus-proxy-registry-deployment + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-quartz-deployment diff --git a/extensions/pom.xml b/extensions/pom.xml index 81883feb794da..7a30eb04922cd 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -16,6 +16,7 @@ virtual-threads tls-registry + proxy-registry arc diff --git a/extensions/proxy-registry/deployment/pom.xml b/extensions/proxy-registry/deployment/pom.xml new file mode 100644 index 0000000000000..0f5c2e145a1c4 --- /dev/null +++ b/extensions/proxy-registry/deployment/pom.xml @@ -0,0 +1,55 @@ + + + + quarkus-proxy-registry-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-proxy-registry-deployment + Quarkus - Proxy Registry - Deployment + + + + io.quarkus + quarkus-arc-deployment + + + io.quarkus + quarkus-proxy-registry + + + io.quarkus + quarkus-core-deployment + + + io.quarkus + quarkus-credentials-deployment + + + + + + + maven-compiler-plugin + + + default-compile + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + + + diff --git a/extensions/proxy-registry/deployment/src/main/java/io/quarkus/proxy/config/deployment/ProxyConfigProcessor.java b/extensions/proxy-registry/deployment/src/main/java/io/quarkus/proxy/config/deployment/ProxyConfigProcessor.java new file mode 100644 index 0000000000000..004d2b1c9f755 --- /dev/null +++ b/extensions/proxy-registry/deployment/src/main/java/io/quarkus/proxy/config/deployment/ProxyConfigProcessor.java @@ -0,0 +1,32 @@ +package io.quarkus.proxy.config.deployment; + +import jakarta.inject.Singleton; + +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.ExecutionTime; +import io.quarkus.deployment.annotations.Record; +import io.quarkus.proxy.config.ProxyConfig; +import io.quarkus.proxy.config.ProxyConfigurationRegistry; + +public class ProxyConfigProcessor { + + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + void initializeProxyConfigurationRegistry( + ProxyConfigurationRegistry recorder, + ProxyConfig proxyConfig, + BuildProducer syntheticBeans) { + + recorder.init(proxyConfig); + syntheticBeans.produce(SyntheticBeanBuildItem + .configure(ProxyConfigurationRegistry.class) + .supplier(recorder.getSupplier()) + .scope(Singleton.class) + .unremovable() + .setRuntimeInit() + .done()); + + } +} diff --git a/extensions/proxy-registry/pom.xml b/extensions/proxy-registry/pom.xml new file mode 100644 index 0000000000000..5a560c2f086c2 --- /dev/null +++ b/extensions/proxy-registry/pom.xml @@ -0,0 +1,20 @@ + + + + quarkus-extensions-parent + io.quarkus + 999-SNAPSHOT + ../pom.xml + + 4.0.0 + + quarkus-proxy-registry-parent + Quarkus - Proxy Registry + pom + + deployment + runtime + + diff --git a/extensions/proxy-registry/runtime/pom.xml b/extensions/proxy-registry/runtime/pom.xml new file mode 100644 index 0000000000000..7f55758c5ad1e --- /dev/null +++ b/extensions/proxy-registry/runtime/pom.xml @@ -0,0 +1,55 @@ + + + + quarkus-proxy-registry-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-proxy-registry + Quarkus - Proxy Registry - Runtime + Proxy Configuration used by other Quarkus extensions + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-core + + + io.quarkus + quarkus-credentials + + + + + + + io.quarkus + quarkus-extension-maven-plugin + + + maven-compiler-plugin + + + default-compile + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + + + diff --git a/extensions/proxy-registry/runtime/src/main/java/io/quarkus/proxy/config/ProxyConfig.java b/extensions/proxy-registry/runtime/src/main/java/io/quarkus/proxy/config/ProxyConfig.java new file mode 100644 index 0000000000000..059869bc8923b --- /dev/null +++ b/extensions/proxy-registry/runtime/src/main/java/io/quarkus/proxy/config/ProxyConfig.java @@ -0,0 +1,142 @@ +package io.quarkus.proxy.config; + +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalInt; + +import io.quarkus.credentials.CredentialsProvider; +import io.quarkus.proxy.config.ProxyConfig.NamedProxyConfig; +import io.quarkus.runtime.annotations.ConfigDocDefault; +import io.quarkus.runtime.annotations.ConfigGroup; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; +import io.smallrye.config.WithParentName; + +@ConfigMapping(prefix = "quarkus.proxy") +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +public interface ProxyConfig { + + static final String NO_PROXY = "none"; + + @WithParentName + NamedProxyConfig defaultProxyConfig(); + + @WithParentName + Map namedProxyConfigs(); + + @ConfigGroup + public interface NamedProxyConfig { + + /** + * Proxy host. + */ + Optional host(); + + /** + * Proxy port + */ + OptionalInt port(); + + /** + * The credential provider configuration for the proxy. + * A credential provider offers a way to retrieve the proxy password. + * Note that the credential provider is only used if the password is not set in the configuration. + */ + ProxyCredentialProviderConfig credentialsProvider(); + + /** + * Proxy username. + *

+ * See also {@code credentials-provider} + */ + Optional username(); + + /** + * Proxy password + *

+ * See also {@code credentials-provider} + */ + Optional password(); + + /** + * Hostnames or IP addresses to exclude from proxying + */ + Optional> nonProxyHosts(); + + /** + * Proxy connection timeout. + */ + @ConfigDocDefault("10s") + Optional proxyConnectTimeout(); + + /** + * The proxy type. Possible values are: {@code HTTP} (default), {@code SOCKS4} and {@code SOCKS5}. + */ + @WithDefault("http") + ProxyType type(); + + /** + * @return this {@link NamedProxyConfig} if {@link #type()} returns {@link ProxyType#HTTP}; otherwise throws an + * {@link IllegalStateException} + * @throws IllegalStateException if {@link #type()} does not return {@link ProxyType#HTTP} + */ + default NamedProxyConfig assertHttpType() { + if (type() != ProxyType.HTTP) { + throw new IllegalStateException("Proxy type HTTP is required"); + } + return this; + } + + static enum ProxyType { + HTTP, + SOCKS4, + SOCKS5; + } + + } + + @ConfigGroup + interface ProxyCredentialProviderConfig { + + /** + * The name of the "credential" bucket (map key -> passwords) to retrieve from the + * {@link io.quarkus.credentials.CredentialsProvider}. If not set, the credential provider will not be used. + *

+ * A credential provider offers a way to retrieve the key store password as well as alias password. + * Note that the credential provider is only used if the passwords are not set in the configuration. + */ + Optional name(); + + /** + * The name of the bean providing the credential provider. + *

+ * The name is used to select the credential provider to use. + * The credential provider must be exposed as a CDI bean and with the {@code @Named} annotation set to the + * configured name to be selected. + *

+ * If not set, the default credential provider is used. + */ + Optional beanName(); + + /** + * The key used to retrieve the username from the "credential" bucket. + *

+ * If username, password or both cannot be retrieved from the credential provider, then a RuntimeException is thrown. + */ + @WithDefault(CredentialsProvider.USER_PROPERTY_NAME) + String usernameKey(); + + /** + * The key used to retrieve the password from the "credential" bucket. + *

+ * If username, password or both cannot be retrieved from the credential provider, then a RuntimeException is thrown. + */ + @WithDefault(CredentialsProvider.PASSWORD_PROPERTY_NAME) + String passwordKey(); + + } +} diff --git a/extensions/proxy-registry/runtime/src/main/java/io/quarkus/proxy/config/ProxyConfigurationRegistry.java b/extensions/proxy-registry/runtime/src/main/java/io/quarkus/proxy/config/ProxyConfigurationRegistry.java new file mode 100644 index 0000000000000..502f10bb40f1b --- /dev/null +++ b/extensions/proxy-registry/runtime/src/main/java/io/quarkus/proxy/config/ProxyConfigurationRegistry.java @@ -0,0 +1,251 @@ +package io.quarkus.proxy.config; + +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import jakarta.enterprise.inject.literal.NamedLiteral; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; +import io.quarkus.arc.InstanceHandle; +import io.quarkus.credentials.CredentialsProvider; +import io.quarkus.proxy.config.ProxyConfig.NamedProxyConfig; +import io.quarkus.proxy.config.ProxyConfig.ProxyCredentialProviderConfig; +import io.quarkus.runtime.annotations.Recorder; + +@Recorder +public class ProxyConfigurationRegistry { + + private Map> namedProxyConfigs; + private Optional defaultProxyConfig; + + public Optional getProxyConfig(Optional name, NoneReturnValue noneBehavior) { + if (name.isEmpty()) { + return defaultProxyConfig; + } + final String plainName = name.get(); + if (ProxyConfig.NO_PROXY.equals(plainName)) { + switch (noneBehavior) { + case NONE_INSTANCE: { + return None.INSTANCE; + } + case EMPTY: { + return Optional.empty(); + } + default: + throw new IllegalArgumentException("Unexpected value: " + noneBehavior); + } + } + final Optional namedProxyConfig = namedProxyConfigs.getOrDefault(plainName, Optional.empty()); + if (namedProxyConfig == null) { + throw new IllegalStateException("Proxy configuration with name " + plainName + " was requested but " + + "quarkus.proxy.\"" + plainName + "\".host is not defined"); + } + return namedProxyConfig; + } + + public static Optional getUsernamePassword(NamedProxyConfig config) { + if (config.username().isPresent() && config.password().isPresent()) { + return Optional.of(new UsernamePassword(config.username().get(), config.password().get())); + } else { + final ProxyCredentialProviderConfig cpConfig = config.credentialsProvider(); + if (cpConfig.name().isPresent()) { + CredentialsProvider provider = lookupCredentialsProvider(cpConfig.beanName().orElse(null)); + Map creds = provider.getCredentialsAsync(cpConfig.name().get()).await().indefinitely(); + String username = creds.get(cpConfig.usernameKey()); + String password = creds.get(cpConfig.passwordKey()); + if (username == null || password == null) { + final String badKeys = Map.of(cpConfig.usernameKey(), username, cpConfig.passwordKey(), password).entrySet() + .stream() + .filter(en -> en.getValue() == null) + .map(Entry::getKey) + .collect(Collectors.joining(" and ")); + throw new IllegalStateException( + "Could not retrieve " + badKeys + " from credential bucket " + cpConfig.name().get()); + } + return Optional.of(new UsernamePassword(username, password)); + } + } + return Optional.empty(); + } + + static CredentialsProvider lookupCredentialsProvider(String name) { + ArcContainer container = Arc.container(); + InstanceHandle instance; + if (name == null) { + instance = container.instance(CredentialsProvider.class); + } else { + instance = container.instance(CredentialsProvider.class, NamedLiteral.of(name)); + } + + if (!instance.isAvailable()) { + if (name == null) { + throw new RuntimeException("Unable to find the default credentials provider"); + } else { + throw new RuntimeException("Unable to find the credentials provider named '" + name + "'"); + } + } + return instance.get(); + } + + static Optional assertValid(String prefix, NamedProxyConfig config) { + if (config.host().isEmpty()) { + String badValues = Map.> of( + "port", config.port().isPresent() ? Optional.of(config.port().getAsInt()) : Optional.empty(), + "username", config.username(), + "password", config.password(), + "nonProxyHosts", config.nonProxyHosts(), + "proxyConnectTimeout", config.proxyConnectTimeout()) + .entrySet().stream() + .filter(en -> en.getValue().isPresent()) + .map(en -> prefix + en.getKey()) + .collect(Collectors.joining(", ")); + if (!badValues.isEmpty()) { + throw new IllegalStateException( + "If " + prefix + ".host is not set, then all of " + badValues + " must not be set too"); + } + return Optional.empty(); + } else { + /* host is present */ + if (config.port().isEmpty()) { + throw new IllegalStateException("If " + prefix + ".host is set then " + prefix + ".port must be set too"); + } + + if (config.username().isPresent() != config.password().isPresent()) { + throw new IllegalStateException( + prefix + ".username and " + prefix + ".password must be both set or both left unset"); + } + return Optional.of(config); + } + } + + public void init(ProxyConfig proxyConfig) { + final HashMap> m = new HashMap<>(); + for (Entry en : proxyConfig.namedProxyConfigs().entrySet()) { + final String name = en.getKey(); + if (ProxyConfig.NO_PROXY.equals(name)) { + throw new IllegalStateException( + "Proxy configuration name `none` has a special meaning and configuring it via quarkus.proxy.\"none\".* options is not possible. Remove all quarkus.proxy.\"none\".* keys from your configuration."); + } + Optional validated = assertValid("quarkus.proxy.\"" + name + "\".", en.getValue()); + if (validated.isPresent()) { + m.put(name, validated); + } + } + this.namedProxyConfigs = m; + this.defaultProxyConfig = assertValid("quarkus.proxy.", + proxyConfig.defaultProxyConfig()); + + } + + public Supplier getSupplier() { + return new Supplier() { + @Override + public ProxyConfigurationRegistry get() { + return ProxyConfigurationRegistry.this; + } + }; + } + + public enum NoneReturnValue { + EMPTY, + NONE_INSTANCE; + } + + public static class UsernamePassword { + private final String username; + private final String password; + + public UsernamePassword(String username, String password) { + this.username = username; + this.password = password; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + } + + static class None implements NamedProxyConfig { + static final Optional INSTANCE = Optional.of(new None()); + static final OptionalInt ZERO_OPTIONAL = OptionalInt.of(0); + static final Optional NO_PROXY_OPTIONAL = Optional.of(ProxyConfig.NO_PROXY); + + @Override + public Optional host() { + return NO_PROXY_OPTIONAL; + } + + @Override + public OptionalInt port() { + return ZERO_OPTIONAL; + } + + @Override + public Optional username() { + return Optional.empty(); + } + + @Override + public Optional password() { + return Optional.empty(); + } + + @Override + public Optional> nonProxyHosts() { + return Optional.empty(); + } + + @Override + public Optional proxyConnectTimeout() { + return Optional.empty(); + } + + @Override + public NamedProxyConfig.ProxyType type() { + return NamedProxyConfig.ProxyType.HTTP; + } + + @Override + public ProxyCredentialProviderConfig credentialsProvider() { + return NoProxyCredentialProviderConfig.INSTANCE; + } + + } + + static class NoProxyCredentialProviderConfig implements ProxyCredentialProviderConfig { + static final ProxyCredentialProviderConfig INSTANCE = new NoProxyCredentialProviderConfig(); + + @Override + public Optional name() { + return Optional.empty(); + } + + @Override + public Optional beanName() { + return Optional.empty(); + } + + @Override + public String usernameKey() { + return CredentialsProvider.USER_PROPERTY_NAME; + } + + @Override + public String passwordKey() { + return CredentialsProvider.PASSWORD_PROPERTY_NAME; + } + + } +} diff --git a/extensions/proxy-registry/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/proxy-registry/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..d94550e279625 --- /dev/null +++ b/extensions/proxy-registry/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,10 @@ +--- +artifact: ${project.groupId}:${project.artifactId}:${project.version} +name: "Proxy configuration registry" +metadata: + categories: + - "web" + status: "stable" + unlisted: true + config: + - "quarkus.proxy." diff --git a/extensions/resteasy-classic/rest-client-config/deployment/pom.xml b/extensions/resteasy-classic/rest-client-config/deployment/pom.xml index 22dfdbb1b1356..6e393f01fa3ba 100644 --- a/extensions/resteasy-classic/rest-client-config/deployment/pom.xml +++ b/extensions/resteasy-classic/rest-client-config/deployment/pom.xml @@ -26,6 +26,10 @@ io.quarkus quarkus-arc-deployment + + io.quarkus + quarkus-proxy-registry-deployment + io.quarkus diff --git a/extensions/resteasy-classic/rest-client-config/runtime/pom.xml b/extensions/resteasy-classic/rest-client-config/runtime/pom.xml index 1a31afbc85808..295009715b204 100644 --- a/extensions/resteasy-classic/rest-client-config/runtime/pom.xml +++ b/extensions/resteasy-classic/rest-client-config/runtime/pom.xml @@ -23,6 +23,10 @@ io.quarkus quarkus-arc + + io.quarkus + quarkus-proxy-registry + org.eclipse.microprofile.rest.client microprofile-rest-client-api diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java b/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java index c2359cdcbece3..e3102e27debae 100644 --- a/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java @@ -54,48 +54,78 @@ public interface RestClientsConfig { */ Optional multipartPostEncoderMode(); + /** + * The name of the proxy configuration to use; ignored if {@code quarkus.rest-client.proxy-address} is set. + *

+ * If not set and the default proxy configuration is configured ({@code quarkus.proxy.*}) then that will be used. + * If the proxy configuration name is set, the configuration from {@code quarkus.proxy..*} will be used. + * If the proxy configuration name is set, but no proxy configuration is found with that name, then an error will be thrown + * at runtime. + *

+ * Can be overwritten by client-specific settings. + *

+ * Use the value {@code none} to disable using the default configuration defined via {@code quarkus.proxy.*}. + *

+ * Quarkus RESTEasy client (provided by the quarkus-resteasy-client dependency) does not support this property. + */ + Optional proxyConfigurationName(); + /** * A string value in the form of `:` that specifies the HTTP proxy server hostname * (or IP address) and port for requests of clients to use. *

* Can be overwritten by client-specific settings. + * + * @deprecated use {@code quarkus.rest-client.proxy-configuration-name} instead */ Optional<@WithConverter(TrimmedStringConverter.class) String> proxyAddress(); /** * Proxy username, equivalent to the http.proxy or https.proxy JVM settings. + * Honored only if {@code quarkus.rest-client.proxy-address} is set. *

* Can be overwritten by client-specific settings. *

* This property is not applicable to the RESTEasy Client. + * + * @deprecated use {@code quarkus.rest-client.proxy-configuration-name} instead */ Optional proxyUser(); /** * Proxy password, equivalent to the http.proxyPassword or https.proxyPassword JVM settings. + * Honored only if {@code quarkus.rest-client.proxy-address} is set. *

* Can be overwritten by client-specific settings. *

* This property is not applicable to the RESTEasy Client. + * + * @deprecated use {@code quarkus.rest-client.proxy-configuration-name} instead */ Optional proxyPassword(); /** * Hosts to access without proxy, similar to the http.nonProxyHosts or https.nonProxyHosts JVM settings. * Please note that unlike the JVM settings, this property is empty by default. + * Honored only if {@code quarkus.rest-client.proxy-address} is set. *

* Can be overwritten by client-specific settings. *

* This property is not applicable to the RESTEasy Client. + * + * @deprecated use {@code quarkus.rest-client.proxy-configuration-name} instead */ Optional nonProxyHosts(); /** - * Proxy connection timeout + * Proxy connection timeout. + * Honored only if {@code quarkus.rest-client.proxy-address} is set. *

* Can be overwritten by client-specific settings. *

* This property is not applicable to the RESTEasy Client. + * + * @deprecated use {@code quarkus.rest-client.proxy-configuration-name} instead */ @ConfigDocDefault("10s") Optional proxyConnectTimeout(); @@ -466,39 +496,69 @@ default Optional uriReload() { */ Optional multipartPostEncoderMode(); + /** + * The name of the proxy configuration to use; ignored if {@code quarkus.rest-client."client".proxy-address} is set. + *

+ * If not set and {@code quarkus.rest-client.proxy-configuration-name} or the default proxy configuration + * ({@code quarkus.proxy.*}) is set, then the first valid of them will get effective. + * If the proxy configuration name is set, the configuration from {@code quarkus.proxy..*} will be used. + * If the proxy configuration name is set, but no proxy configuration is found with that name, then an error will be + * thrown at runtime. + *

+ * Use the value {@code none} to disable using the default configuration defined via + * {@code quarkus.rest-client.proxy-configuration-name} or {@code quarkus.proxy.*}. + *

+ * Quarkus RESTEasy client (provided by the quarkus-resteasy-client dependency) does not support this property. + */ + Optional proxyConfigurationName(); + /** * A string value in the form of `:` that specifies the HTTP proxy server hostname * (or IP address) and port for requests of this client to use. *

* Use `none` to disable proxy + * + * @deprecated use {@code quarkus.rest-client."client".proxy-configuration-name} instead */ Optional<@WithConverter(TrimmedStringConverter.class) String> proxyAddress(); /** * Proxy username. + * Honored only if {@code quarkus.rest-client."client".proxy-address} is set. *

* This property is not applicable to the RESTEasy Client. + * + * @deprecated use {@code quarkus.rest-client."client".proxy-configuration-name} instead */ Optional proxyUser(); /** * Proxy password. + * Honored only if {@code quarkus.rest-client."client".proxy-address} is set. *

* This property is not applicable to the RESTEasy Client. + * + * @deprecated use {@code quarkus.rest-client."client".proxy-configuration-name} instead */ Optional proxyPassword(); /** - * Hosts to access without proxy + * Hosts to access without proxy. + * Honored only if {@code quarkus.rest-client."client".proxy-address} is set. *

* This property is not applicable to the RESTEasy Client. + * + * @deprecated use {@code quarkus.rest-client."client".proxy-configuration-name} instead */ Optional nonProxyHosts(); /** - * Proxy connection timeout + * Proxy connection timeout. + * Honored only if {@code quarkus.rest-client."client".proxy-address} is set. *

* This property is not applicable to the RESTEasy Client. + * + * @deprecated use {@code quarkus.rest-client."client".proxy-configuration-name} instead */ @ConfigDocDefault("10s") Optional proxyConnectTimeout(); diff --git a/extensions/resteasy-reactive/rest-client/deployment/pom.xml b/extensions/resteasy-reactive/rest-client/deployment/pom.xml index a793cb435e3ea..54703574421db 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/pom.xml +++ b/extensions/resteasy-reactive/rest-client/deployment/pom.xml @@ -24,6 +24,10 @@ io.quarkus quarkus-rest-client-jaxrs-deployment + + io.quarkus + quarkus-proxy-registry-deployment + io.quarkus quarkus-rest-client-config-deployment diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/GlobalNonProxyTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractGlobalNonProxyTest.java similarity index 60% rename from extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/GlobalNonProxyTest.java rename to extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractGlobalNonProxyTest.java index 36bb44192cbc8..1bce99edaaa55 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/GlobalNonProxyTest.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractGlobalNonProxyTest.java @@ -7,18 +7,18 @@ import org.eclipse.microprofile.rest.client.RestClientBuilder; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.test.QuarkusUnitTest; -public class GlobalNonProxyTest extends ProxyTestBase { +public abstract class AbstractGlobalNonProxyTest extends ProxyTestBase { - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .withApplicationRoot( - jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, Client4.class, Client5.class, - Client6.class, ViaHeaderReturningResource.class)) - .withConfigurationResource("global-non-proxy-test-application.properties"); + protected static QuarkusUnitTest config(String applicationProperties) { + return new QuarkusUnitTest() + .withApplicationRoot( + jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, Client4.class, Client5.class, + Client6.class, ViaHeaderReturningResource.class)) + .withConfigurationResource(applicationProperties); + } @RestClient Client1 client1; diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/GlobalProxyPasswordTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractGlobalProxyPasswordTest.java similarity index 51% rename from extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/GlobalProxyPasswordTest.java rename to extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractGlobalProxyPasswordTest.java index 1dd7135b7707e..947bbda2d644c 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/GlobalProxyPasswordTest.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractGlobalProxyPasswordTest.java @@ -4,16 +4,16 @@ import org.eclipse.microprofile.rest.client.inject.RestClient; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.test.QuarkusUnitTest; -public class GlobalProxyPasswordTest extends ProxyTestBase { - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .withApplicationRoot( - jar -> jar.addClasses(Client1.class, ViaHeaderReturningResource.class)) - .withConfigurationResource("global-proxy-password-test-application.properties"); +public abstract class AbstractGlobalProxyPasswordTest extends ProxyTestBase { + protected static QuarkusUnitTest config(String applicationProperties) { + return new QuarkusUnitTest() + .withApplicationRoot( + jar -> jar.addClasses(Client1.class, ViaHeaderReturningResource.class)) + .withConfigurationResource(applicationProperties); + } @RestClient Client1 client1; diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractProxyTest.java similarity index 85% rename from extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTest.java rename to extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractProxyTest.java index 546f22d7b181b..a5fed866ee00f 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTest.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractProxyTest.java @@ -7,7 +7,6 @@ import org.eclipse.microprofile.rest.client.RestClientBuilder; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.rest.client.reactive.runtime.RestClientBuilderImpl; import io.quarkus.test.QuarkusUnitTest; @@ -15,14 +14,15 @@ /** * client1 and client2 are configured to use 8181 as a proxy, global configuration says to use 8182 */ -public class ProxyTest extends ProxyTestBase { +public abstract class AbstractProxyTest extends ProxyTestBase { - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .withApplicationRoot( - jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, Client4.class, Client5.class, - Client6.class, ViaHeaderReturningResource.class)) - .withConfigurationResource("proxy-test-application.properties"); + protected static QuarkusUnitTest config(String applicationProperties) { + return new QuarkusUnitTest() + .withApplicationRoot( + jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, Client4.class, Client5.class, + Client6.class, ViaHeaderReturningResource.class)) + .withConfigurationResource(applicationProperties); + } @RestClient Client1 client1; diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractSystemPropertyProxyTest.java similarity index 81% rename from extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyTest.java rename to extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractSystemPropertyProxyTest.java index 97fec49f4c1c1..42fff57e7d426 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyTest.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractSystemPropertyProxyTest.java @@ -7,18 +7,18 @@ import org.eclipse.microprofile.rest.client.RestClientBuilder; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import org.junitpioneer.jupiter.SetSystemProperty; import io.quarkus.rest.client.reactive.runtime.RestClientBuilderImpl; import io.quarkus.test.QuarkusUnitTest; -public class SystemPropertyProxyTest extends ProxyTestBase { - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .withApplicationRoot( - jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, ViaHeaderReturningResource.class)) - .withConfigurationResource("system-props-proxy-test-application.properties"); +public abstract class AbstractSystemPropertyProxyTest extends ProxyTestBase { + protected static QuarkusUnitTest config(String applicationProperties) { + return new QuarkusUnitTest() + .withApplicationRoot( + jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, ViaHeaderReturningResource.class)) + .withConfigurationResource(applicationProperties); + } @RestClient Client1 client1; diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyWithAuthTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractSystemPropertyProxyWithAuthTest.java similarity index 77% rename from extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyWithAuthTest.java rename to extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractSystemPropertyProxyWithAuthTest.java index aba42f0ed6930..67f67af353b50 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyWithAuthTest.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/AbstractSystemPropertyProxyWithAuthTest.java @@ -7,17 +7,17 @@ import org.eclipse.microprofile.rest.client.RestClientBuilder; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import org.junitpioneer.jupiter.SetSystemProperty; import io.quarkus.test.QuarkusUnitTest; -public class SystemPropertyProxyWithAuthTest extends ProxyTestBase { - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .withApplicationRoot( - jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, ViaHeaderReturningResource.class)) - .withConfigurationResource("system-props-proxy-test-application.properties"); +public abstract class AbstractSystemPropertyProxyWithAuthTest extends ProxyTestBase { + protected static QuarkusUnitTest config(String applicationProperties) { + return new QuarkusUnitTest() + .withApplicationRoot( + jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, ViaHeaderReturningResource.class)) + .withConfigurationResource("system-props-proxy-test-application.properties"); + } @RestClient Client1 client1; diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/GlobalNonProxyTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/GlobalNonProxyTest.java new file mode 100644 index 0000000000000..6194e70a84331 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/GlobalNonProxyTest.java @@ -0,0 +1,13 @@ +package io.quarkus.rest.client.reactive.proxy.config.legacy; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.rest.client.reactive.proxy.AbstractGlobalNonProxyTest; +import io.quarkus.test.QuarkusUnitTest; + +public class GlobalNonProxyTest extends AbstractGlobalNonProxyTest { + + @RegisterExtension + static final QuarkusUnitTest config = config("global-non-proxy-test-application.properties"); + +} diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/GlobalProxyPasswordTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/GlobalProxyPasswordTest.java new file mode 100644 index 0000000000000..2b709b892a467 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/GlobalProxyPasswordTest.java @@ -0,0 +1,13 @@ +package io.quarkus.rest.client.reactive.proxy.config.legacy; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.rest.client.reactive.proxy.AbstractGlobalProxyPasswordTest; +import io.quarkus.test.QuarkusUnitTest; + +public class GlobalProxyPasswordTest extends AbstractGlobalProxyPasswordTest { + + @RegisterExtension + static final QuarkusUnitTest config = config("global-proxy-password-test-application.properties"); + +} diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/ProxyTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/ProxyTest.java new file mode 100644 index 0000000000000..e670ccd73e62e --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/ProxyTest.java @@ -0,0 +1,15 @@ +package io.quarkus.rest.client.reactive.proxy.config.legacy; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.rest.client.reactive.proxy.AbstractProxyTest; +import io.quarkus.test.QuarkusUnitTest; + +/** + * client1 and client2 are configured to use 8181 as a proxy, global configuration says to use 8182 + */ +public class ProxyTest extends AbstractProxyTest { + + @RegisterExtension + static final QuarkusUnitTest config = config("proxy-test-application.properties"); +} diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/SystemPropertyProxyTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/SystemPropertyProxyTest.java new file mode 100644 index 0000000000000..e4689afc9232e --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/SystemPropertyProxyTest.java @@ -0,0 +1,11 @@ +package io.quarkus.rest.client.reactive.proxy.config.legacy; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.rest.client.reactive.proxy.AbstractSystemPropertyProxyTest; +import io.quarkus.test.QuarkusUnitTest; + +public class SystemPropertyProxyTest extends AbstractSystemPropertyProxyTest { + @RegisterExtension + static final QuarkusUnitTest config = config("system-props-proxy-test-application.properties"); +} diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/SystemPropertyProxyWithAuthTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/SystemPropertyProxyWithAuthTest.java new file mode 100644 index 0000000000000..525aeb1db884e --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/legacy/SystemPropertyProxyWithAuthTest.java @@ -0,0 +1,12 @@ +package io.quarkus.rest.client.reactive.proxy.config.legacy; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.rest.client.reactive.proxy.AbstractSystemPropertyProxyWithAuthTest; +import io.quarkus.test.QuarkusUnitTest; + +public class SystemPropertyProxyWithAuthTest extends AbstractSystemPropertyProxyWithAuthTest { + @RegisterExtension + static final QuarkusUnitTest config = config("system-props-proxy-test-application.properties"); + +} diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/GlobalNonProxyRegistryTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/GlobalNonProxyRegistryTest.java new file mode 100644 index 0000000000000..f3b3d9feeb7f4 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/GlobalNonProxyRegistryTest.java @@ -0,0 +1,13 @@ +package io.quarkus.rest.client.reactive.proxy.config.registry; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.rest.client.reactive.proxy.AbstractGlobalNonProxyTest; +import io.quarkus.test.QuarkusUnitTest; + +public class GlobalNonProxyRegistryTest extends AbstractGlobalNonProxyTest { + + @RegisterExtension + static final QuarkusUnitTest config = config("global-non-proxy-registry-test-application.properties"); + +} diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/GlobalProxyRegistryPasswordTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/GlobalProxyRegistryPasswordTest.java new file mode 100644 index 0000000000000..348edec8ca39c --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/GlobalProxyRegistryPasswordTest.java @@ -0,0 +1,13 @@ +package io.quarkus.rest.client.reactive.proxy.config.registry; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.rest.client.reactive.proxy.AbstractGlobalProxyPasswordTest; +import io.quarkus.test.QuarkusUnitTest; + +public class GlobalProxyRegistryPasswordTest extends AbstractGlobalProxyPasswordTest { + + @RegisterExtension + static final QuarkusUnitTest config = config("global-proxy-registry-password-test-application.properties"); + +} diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/ProxyRegistryTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/ProxyRegistryTest.java new file mode 100644 index 0000000000000..30c663694b4ac --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/ProxyRegistryTest.java @@ -0,0 +1,15 @@ +package io.quarkus.rest.client.reactive.proxy.config.registry; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.rest.client.reactive.proxy.AbstractProxyTest; +import io.quarkus.test.QuarkusUnitTest; + +/** + * client1 and client2 are configured to use 8181 as a proxy, global configuration says to use 8182 + */ +public class ProxyRegistryTest extends AbstractProxyTest { + + @RegisterExtension + static final QuarkusUnitTest config = config("proxy-registry-test-application.properties"); +} diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/SystemPropertyProxyRegistryTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/SystemPropertyProxyRegistryTest.java new file mode 100644 index 0000000000000..4110bfb40f4ba --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/SystemPropertyProxyRegistryTest.java @@ -0,0 +1,11 @@ +package io.quarkus.rest.client.reactive.proxy.config.registry; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.rest.client.reactive.proxy.AbstractSystemPropertyProxyTest; +import io.quarkus.test.QuarkusUnitTest; + +public class SystemPropertyProxyRegistryTest extends AbstractSystemPropertyProxyTest { + @RegisterExtension + static final QuarkusUnitTest config = config("system-props-proxy-registry-test-application.properties"); +} diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/SystemPropertyProxyRegistryWithAuthTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/SystemPropertyProxyRegistryWithAuthTest.java new file mode 100644 index 0000000000000..f899ba8cd9f36 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/config/registry/SystemPropertyProxyRegistryWithAuthTest.java @@ -0,0 +1,12 @@ +package io.quarkus.rest.client.reactive.proxy.config.registry; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.rest.client.reactive.proxy.AbstractSystemPropertyProxyWithAuthTest; +import io.quarkus.test.QuarkusUnitTest; + +public class SystemPropertyProxyRegistryWithAuthTest extends AbstractSystemPropertyProxyWithAuthTest { + @RegisterExtension + static final QuarkusUnitTest config = config("system-props-proxy-registry-test-application.properties"); + +} diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/global-non-proxy-registry-test-application.properties b/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/global-non-proxy-registry-test-application.properties new file mode 100644 index 0000000000000..3bc3b58474046 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/global-non-proxy-registry-test-application.properties @@ -0,0 +1,5 @@ +quarkus.proxy.host=localhost +quarkus.proxy.port=8182 +quarkus.proxy.non-proxy-hosts=localhost + +quarkus.rest-client.client1.url=http://localhost:${quarkus.http.test-port:8081}/ diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/global-proxy-registry-password-test-application.properties b/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/global-proxy-registry-password-test-application.properties new file mode 100644 index 0000000000000..783d474f732bd --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/global-proxy-registry-password-test-application.properties @@ -0,0 +1,6 @@ +quarkus.rest-client.client1.url=http://localhost:${quarkus.http.test-port:8081}/ + +quarkus.proxy.host=localhost +quarkus.proxy.port=8183 +quarkus.proxy.username=admin +quarkus.proxy.password=r00t diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/proxy-registry-test-application.properties b/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/proxy-registry-test-application.properties new file mode 100644 index 0000000000000..477406c864a3f --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/proxy-registry-test-application.properties @@ -0,0 +1,34 @@ + +quarkus.proxy.client1.host=localhost +quarkus.proxy.client1.port=8181 +quarkus.rest-client.client1.url=http://localhost:${quarkus.http.test-port:8081}/ +quarkus.rest-client.client1.proxy-configuration-name=client1 + +quarkus.proxy.client2.host=localhost +quarkus.proxy.client2.port=8181 +quarkus.rest-client.client2.url=http://localhost:${quarkus.http.test-port:8081}/ +quarkus.rest-client.client2.proxy-configuration-name=client2 +#client2/mp-rest/proxyAddress=localhost:8181 + +client3/mp-rest/url=http://localhost:${quarkus.http.test-port:8081}/ + +quarkus.proxy.client4.host=localhost +quarkus.proxy.client4.port=8183 +quarkus.proxy.client4.username=admin +quarkus.proxy.client4.password=r00t +quarkus.rest-client.client4.url=http://localhost:${quarkus.http.test-port:8081}/ +quarkus.rest-client.client4.proxy-configuration-name=client4 + +quarkus.proxy.client5.host=localhost +quarkus.proxy.client5.port=8183 +quarkus.proxy.client5.username=admin +quarkus.proxy.client5.password=r00t +quarkus.proxy.client5.non-proxy-hosts=localhost +quarkus.rest-client.client5.url=http://localhost:${quarkus.http.test-port:8081}/ +quarkus.rest-client.client5.proxy-configuration-name=client5 + +quarkus.rest-client.client6.proxy-configuration-name=none +quarkus.rest-client.client6.url=http://localhost:${quarkus.http.test-port:8081}/ + +quarkus.proxy.host=localhost +quarkus.proxy.port=8182 diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/system-props-proxy-registry-test-application.properties b/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/system-props-proxy-registry-test-application.properties new file mode 100644 index 0000000000000..559415d04fa69 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/resources/system-props-proxy-registry-test-application.properties @@ -0,0 +1,6 @@ +quarkus.rest-client.client1.url=http://localhost:${quarkus.http.test-port:8081}/ + +quarkus.proxy.client2.host=localhost +quarkus.proxy.client2.port=8181 +quarkus.rest-client.client2.url=http://localhost:${quarkus.http.test-port:8081}/ +quarkus.rest-client.client2.proxy-configuration-name=client2 diff --git a/extensions/resteasy-reactive/rest-client/runtime/pom.xml b/extensions/resteasy-reactive/rest-client/runtime/pom.xml index 531aa0c4d327a..744bcbb6d0f0c 100644 --- a/extensions/resteasy-reactive/rest-client/runtime/pom.xml +++ b/extensions/resteasy-reactive/rest-client/runtime/pom.xml @@ -22,6 +22,10 @@ io.quarkus quarkus-rest-client-config + + io.quarkus + quarkus-proxy-registry + io.quarkus quarkus-tls-registry diff --git a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java index 96301d255cada..0cc418b48ac0d 100644 --- a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java +++ b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java @@ -20,6 +20,7 @@ import org.jboss.resteasy.reactive.client.api.ClientLogger; import org.jboss.resteasy.reactive.client.api.LoggingScope; +import io.quarkus.proxy.config.ProxyConfig.NamedProxyConfig.ProxyType; import io.quarkus.rest.client.reactive.runtime.QuarkusRestClientBuilderImpl; import io.quarkus.rest.client.reactive.runtime.RestClientBuilderImpl; import io.quarkus.tls.TlsConfiguration; @@ -235,6 +236,14 @@ static QuarkusRestClientBuilder newBuilder() { */ QuarkusRestClientBuilder proxyConnectTimeout(Duration connectTimeout); + /** + * Specifies the proxy type for the proxy connection. + * + * @param proxyType proxy type + * @return the current builder + */ + QuarkusRestClientBuilder proxyType(ProxyType proxyType); + /** * Specifies the URI formatting style to use when multiple query parameter values are passed to the client. * diff --git a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java index edd376d760f2e..0efb577b81c3e 100644 --- a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java +++ b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java @@ -18,6 +18,7 @@ import org.jboss.resteasy.reactive.client.api.ClientLogger; import org.jboss.resteasy.reactive.client.api.LoggingScope; +import io.quarkus.proxy.config.ProxyConfig.NamedProxyConfig.ProxyType; import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder; import io.quarkus.rest.client.reactive.runtime.context.ClientHeadersFactoryContextResolver; import io.quarkus.rest.client.reactive.runtime.context.HttpClientOptionsContextResolver; @@ -134,6 +135,12 @@ public QuarkusRestClientBuilder proxyConnectTimeout(Duration connectTimeout) { return this; } + @Override + public QuarkusRestClientBuilder proxyType(ProxyType proxyType) { + delegate.proxyType(proxyType); + return this; + } + @Override public QuarkusRestClientBuilder multipartPostEncoderMode(String mode) { delegate.multipartPostEncoderMode(mode); diff --git a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java index a7f613d6190f0..9ee30c18db9ad 100644 --- a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java +++ b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java @@ -17,6 +17,7 @@ import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; @@ -48,11 +49,16 @@ import io.quarkus.arc.Arc; import io.quarkus.arc.ArcContainer; import io.quarkus.arc.InstanceHandle; +import io.quarkus.proxy.config.ProxyConfig.NamedProxyConfig; +import io.quarkus.proxy.config.ProxyConfigurationRegistry; +import io.quarkus.proxy.config.ProxyConfigurationRegistry.NoneReturnValue; +import io.quarkus.proxy.config.ProxyConfigurationRegistry.UsernamePassword; import io.quarkus.rest.client.reactive.runtime.ProxyAddressUtil.HostAndPort; import io.quarkus.restclient.config.RestClientsConfig; import io.quarkus.tls.TlsConfiguration; import io.smallrye.config.SmallRyeConfig; import io.vertx.core.net.KeyCertOptions; +import io.vertx.core.net.ProxyType; import io.vertx.core.net.SSLOptions; import io.vertx.core.net.TrustOptions; @@ -83,6 +89,7 @@ public class RestClientBuilderImpl implements RestClientBuilder { private String proxyPassword; private String nonProxyHosts; private Duration proxyConnectTimeout; + private ProxyType proxyType; private ClientLogger clientLogger; private LoggingScope loggingScope; @@ -244,6 +251,27 @@ public RestClientBuilderImpl proxyConnectTimeout(Duration proxyConnectTimeout) { return this; } + public RestClientBuilderImpl proxyType(io.quarkus.proxy.config.ProxyConfig.NamedProxyConfig.ProxyType proxyType) { + this.proxyType = toVertxProxyType(proxyType); + return this; + } + + static ProxyType toVertxProxyType(io.quarkus.proxy.config.ProxyConfig.NamedProxyConfig.ProxyType type) { + switch (type) { + case HTTP: { + return ProxyType.HTTP; + } + case SOCKS4: { + return ProxyType.SOCKS4; + } + case SOCKS5: { + return ProxyType.SOCKS5; + } + default: + throw new IllegalArgumentException("Unexpected ProxyType " + type); + } + } + public RestClientBuilderImpl multipartPostEncoderMode(String mode) { this.multipartPostEncoderMode = mode; return this; @@ -575,7 +603,7 @@ public T build(Class aClass) throws IllegalStateException, RestClientDefi } if (proxyHost != null) { - configureProxy(proxyHost, proxyPort, proxyUser, proxyPassword, nonProxyHosts, proxyConnectTimeout); + configureProxy(proxyHost, proxyPort, proxyUser, proxyPassword, nonProxyHosts, proxyConnectTimeout, proxyType); } else if (restClients.proxyAddress().isPresent()) { HostAndPort globalProxy = ProxyAddressUtil.parseAddress(restClients.proxyAddress().get()); configureProxy( @@ -584,7 +612,25 @@ public T build(Class aClass) throws IllegalStateException, RestClientDefi restClients.proxyUser().orElse(null), restClients.proxyPassword().orElse(null), restClients.nonProxyHosts().orElse(null), - restClients.proxyConnectTimeout().orElse(null)); + restClients.proxyConnectTimeout().orElse(null), + null); + } else { + /* Check the named proxy configuration on the rest-client extension level or fallback to global proxy settings */ + final ProxyConfigurationRegistry registry = Arc.container().select(ProxyConfigurationRegistry.class).get(); + registry.getProxyConfig(restClients.proxyConfigurationName(), NoneReturnValue.NONE_INSTANCE) + .map(NamedProxyConfig::assertHttpType) + .ifPresent(proxyConfig -> { + Optional creds = registry.getUsernamePassword(proxyConfig); + configureProxy( + proxyConfig.host().get(), + proxyConfig.port().getAsInt(), + creds.map(UsernamePassword::getUsername).orElse(null), + creds.map(UsernamePassword::getPassword).orElse(null), + proxyConfig.nonProxyHosts().map(nph -> nph.stream().collect(Collectors.joining(","))) + .orElse(null), + proxyConfig.proxyConnectTimeout().orElse(null), + toVertxProxyType(proxyConfig.type())); + }); } if (!clientBuilder.getConfiguration().hasProperty(QuarkusRestClientProperties.MULTIPART_ENCODER_MODE)) { @@ -616,7 +662,7 @@ public T build(Class aClass) throws IllegalStateException, RestClientDefi } private void configureProxy(String proxyHost, Integer proxyPort, String proxyUser, String proxyPassword, - String nonProxyHosts, Duration proxyConnectTimeout) { + String nonProxyHosts, Duration proxyConnectTimeout, io.vertx.core.net.ProxyType proxyType) { if (proxyHost != null) { clientBuilder.proxy(proxyHost, proxyPort); if (proxyUser != null && proxyPassword != null) { @@ -631,6 +677,9 @@ private void configureProxy(String proxyHost, Integer proxyPort, String proxyUse if (proxyConnectTimeout != null) { clientBuilder.proxyConnectTimeout(proxyConnectTimeout); } + if (proxyType != null) { + clientBuilder.proxyType(proxyType); + } } } diff --git a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java index 5eb4e5b8d6a8e..980c7103c5e9a 100644 --- a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java +++ b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java @@ -20,6 +20,7 @@ import java.util.OptionalInt; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.stream.Collectors; import javax.net.ssl.HostnameVerifier; @@ -30,6 +31,9 @@ import org.jboss.resteasy.reactive.client.impl.multipart.PausableHttpPostRequestEncoder; import io.quarkus.arc.Arc; +import io.quarkus.proxy.config.ProxyConfig.NamedProxyConfig; +import io.quarkus.proxy.config.ProxyConfigurationRegistry; +import io.quarkus.proxy.config.ProxyConfigurationRegistry.NoneReturnValue; import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder; import io.quarkus.restclient.config.RestClientsConfig; import io.quarkus.restclient.config.RestClientsConfig.RestClientConfig; @@ -180,24 +184,44 @@ private static Function intChunkSize() { } private void configureProxy(QuarkusRestClientBuilder builder) { - Optional maybeProxy = oneOf(restClientConfig.proxyAddress(), configRoot.proxyAddress()); - if (maybeProxy.isEmpty()) { - return; - } - String proxyAddress = maybeProxy.get(); - if (proxyAddress.equals("none")) { - builder.proxyAddress("none", 0); + final Optional legacyProxy = oneOf(restClientConfig.proxyAddress(), configRoot.proxyAddress()); + if (legacyProxy.isPresent()) { + String proxyAddress = legacyProxy.get(); + if (proxyAddress.equals("none")) { + builder.proxyAddress("none", 0); + } else { + ProxyAddressUtil.HostAndPort hostAndPort = ProxyAddressUtil.parseAddress(proxyAddress); + builder.proxyAddress(hostAndPort.host, hostAndPort.port); + + oneOf(restClientConfig.proxyUser(), configRoot.proxyUser()).ifPresent(builder::proxyUser); + oneOf(restClientConfig.proxyPassword(), configRoot.proxyPassword()).ifPresent(builder::proxyPassword); + oneOf(restClientConfig.nonProxyHosts(), configRoot.nonProxyHosts()).ifPresent(builder::nonProxyHosts); + oneOf(restClientConfig.proxyConnectTimeout(), configRoot.proxyConnectTimeout()) + .ifPresent(builder::proxyConnectTimeout); + } } else { - ProxyAddressUtil.HostAndPort hostAndPort = ProxyAddressUtil.parseAddress(proxyAddress); - builder.proxyAddress(hostAndPort.host, hostAndPort.port); - - oneOf(restClientConfig.proxyUser(), configRoot.proxyUser()).ifPresent(builder::proxyUser); - oneOf(restClientConfig.proxyPassword(), configRoot.proxyPassword()).ifPresent(builder::proxyPassword); - oneOf(restClientConfig.nonProxyHosts(), configRoot.nonProxyHosts()).ifPresent(builder::nonProxyHosts); - oneOf(restClientConfig.proxyConnectTimeout(), configRoot.proxyConnectTimeout()) - .ifPresent(builder::proxyConnectTimeout); + /* Check the named proxy configurations */ + final ProxyConfigurationRegistry registry = Arc.container().select(ProxyConfigurationRegistry.class).get(); + final Optional proxyConfigurationName = restClientConfig.proxyConfigurationName() + .or(() -> configRoot.proxyConfigurationName()); + registry.getProxyConfig(proxyConfigurationName, NoneReturnValue.NONE_INSTANCE) + .map(NamedProxyConfig::assertHttpType) + .ifPresent(proxyConfig -> { + builder.proxyAddress(proxyConfig.host().get(), proxyConfig.port().getAsInt()); + registry.getUsernamePassword(proxyConfig).ifPresent(creds -> { + builder.proxyUser(creds.getUsername()); + builder.proxyPassword(creds.getPassword()); + }); + proxyConfig.nonProxyHosts().ifPresent(nonProxyHosts -> { + if (!nonProxyHosts.isEmpty()) { + builder.nonProxyHosts(nonProxyHosts.stream().collect(Collectors.joining(","))); + } + }); + proxyConfig.proxyConnectTimeout().ifPresent(builder::proxyConnectTimeout); + }); } + } private void configureQueryParamStyle(QuarkusRestClientBuilder builder) { diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientBuilderImpl.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientBuilderImpl.java index 2bb90f63c0a36..fbfdcd5e56122 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientBuilderImpl.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientBuilderImpl.java @@ -41,6 +41,7 @@ import io.vertx.core.http.HttpVersion; import io.vertx.core.net.JksOptions; import io.vertx.core.net.ProxyOptions; +import io.vertx.core.net.ProxyType; import io.vertx.core.net.SSLOptions; public class ClientBuilderImpl extends ClientBuilder { @@ -58,6 +59,7 @@ public class ClientBuilderImpl extends ClientBuilder { private String proxyUser; private String nonProxyHosts; private Duration proxyConnectTimeout; + private ProxyType proxyType; private boolean followRedirects; @@ -260,6 +262,9 @@ public ClientImpl build() { if (proxyConnectTimeout != null) { proxyOptions.setConnectTimeout(proxyConnectTimeout); } + if (proxyType != null) { + proxyOptions.setType(proxyType); + } options.setProxyOptions(proxyOptions); configureNonProxyHosts(options, nonProxyHosts); } @@ -501,4 +506,9 @@ public ClientBuilderImpl proxyConnectTimeout(Duration proxyConnectTimeout) { this.proxyConnectTimeout = proxyConnectTimeout; return this; } + + public ClientBuilderImpl proxyType(ProxyType proxyType) { + this.proxyType = proxyType; + return this; + } }