Skip to content

Commit

Permalink
TLS Registry support quarkiverse#1486
Browse files Browse the repository at this point in the history
  • Loading branch information
ppalaga committed Sep 19, 2024
1 parent 7665ed6 commit 7cb473c
Show file tree
Hide file tree
Showing 20 changed files with 412 additions and 530 deletions.
6 changes: 6 additions & 0 deletions bom-test/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@
<type>exe</type>
<version>${quarkus-cxf.version}</version>
</dependency>
<dependency>
<groupId>io.smallrye.certs</groupId>
<artifactId>smallrye-certificate-generator-junit5</artifactId>
<version>${smallrye-certificate-generator.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-netty-server</artifactId>
Expand Down
43 changes: 29 additions & 14 deletions docs/modules/ROOT/examples/mtls/application.properties
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# pkcs12 and p12 are replaced by maven-resource-plugin filtering based on Maven profile
keystore.type = pkcs12
keystore.type.short = p12

# tag::mtls[]
# Server keystore for Simple TLS
quarkus.tls.localhost-pkcs12.key-store.p12.path = localhost-keystore.pkcs12
quarkus.tls.localhost-pkcs12.key-store.p12.password = localhost-keystore-password
quarkus.tls.localhost-pkcs12.key-store.p12.path = localhost-keystore.p12
quarkus.tls.localhost-pkcs12.key-store.p12.password = secret
quarkus.tls.localhost-pkcs12.key-store.p12.alias = localhost
quarkus.tls.localhost-pkcs12.key-store.p12.alias-password = localhost-keystore-password
quarkus.tls.localhost-pkcs12.key-store.p12.alias-password = secret
# Server truststore for Mutual TLS
quarkus.tls.localhost-pkcs12.trust-store.p12.path = localhost-truststore.pkcs12
quarkus.tls.localhost-pkcs12.trust-store.p12.password = localhost-truststore-password
quarkus.tls.localhost-pkcs12.trust-store.p12.path = localhost-server-truststore.p12
quarkus.tls.localhost-pkcs12.trust-store.p12.password = secret
# Select localhost-pkcs12 as the TLS configuration for the HTTP server
quarkus.http.tls-configuration-name = localhost-pkcs12

Expand All @@ -22,21 +23,35 @@ quarkus.cxf.endpoint."/mTls".implementor = io.quarkiverse.cxf.it.auth.mtls.MTlsH
# CXF client with a properly set certificate for mTLS
quarkus.cxf.client.mTls.client-endpoint-url = https://localhost:${quarkus.http.test-ssl-port}/services/mTls
quarkus.cxf.client.mTls.service-interface = io.quarkiverse.cxf.it.security.policy.HelloService
quarkus.cxf.client.mTls.key-store = target/classes/client-keystore.pkcs12
quarkus.cxf.client.mTls.key-store-type = pkcs12
quarkus.cxf.client.mTls.key-store-password = client-keystore-password
quarkus.cxf.client.mTls.key-password = client-keystore-password
quarkus.cxf.client.mTls.trust-store = target/classes/client-truststore.pkcs12
quarkus.cxf.client.mTls.trust-store-type = pkcs12
quarkus.cxf.client.mTls.trust-store-password = client-truststore-password
# Set client-pkcs12 as the TLS configuration for the this client
quarkus.cxf.client.mTls.tls-configuration-name = client-pkcs12
# Named TLS configuration for the client
quarkus.tls.client-pkcs12.key-store.p12.path = target/classes/localhost-client-keystore.p12
quarkus.tls.client-pkcs12.key-store.p12.password = secret
quarkus.tls.client-pkcs12.key-store.p12.alias = client
quarkus.tls.client-pkcs12.key-store.p12.alias-password = secret
quarkus.tls.client-pkcs12.trust-store.p12.path = target/classes/localhost-truststore.p12
quarkus.tls.client-pkcs12.trust-store.p12.password = secret

# Include the keystores in the native executable
quarkus.native.resources.includes = *.pkcs12,*.jks
# end::mtls[]

# CXF client configured for mTLS in the old way
quarkus.cxf.client.mTlsOld.client-endpoint-url = https://localhost:${quarkus.http.test-ssl-port}/services/mTls
quarkus.cxf.client.mTlsOld.service-interface = io.quarkiverse.cxf.it.security.policy.HelloService
quarkus.cxf.client.mTlsOld.key-store = target/classes/localhost-client-keystore.p12
quarkus.cxf.client.mTlsOld.key-store-type = pkcs12
quarkus.cxf.client.mTlsOld.key-store-password = secret
quarkus.cxf.client.mTlsOld.key-password = secret
quarkus.cxf.client.mTlsOld.trust-store = target/classes/localhost-truststore.p12
quarkus.cxf.client.mTlsOld.trust-store-type = pkcs12
quarkus.cxf.client.mTlsOld.trust-store-password = secret


# CXF client without keystore (to test the failing case)
quarkus.cxf.client.noKeystore.client-endpoint-url = https://localhost:${quarkus.http.test-ssl-port}/services/mTls
quarkus.cxf.client.noKeystore.service-interface = io.quarkiverse.cxf.it.security.policy.HelloService
quarkus.cxf.client.noKeystore.trust-store = client-truststore.pkcs12
quarkus.cxf.client.noKeystore.trust-store = localhost-truststore.p12
quarkus.cxf.client.noKeystore.trust-store-type = pkcs12
quarkus.cxf.client.noKeystore.trust-store-password = client-truststore-password
quarkus.cxf.client.noKeystore.trust-store-password = secret
14 changes: 14 additions & 0 deletions docs/modules/ROOT/pages/reference/extensions/quarkus-cxf.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1888,6 +1888,20 @@ underlying HTTP client.
*Environment variable*: `+++QUARKUS_CXF_CLIENT__CLIENT_NAME__HTTP_CONDUIT_FACTORY+++` +
*Since Quarkus CXF*: 2.3.0

.<| [[quarkus-cxf_quarkus-cxf-client-client-name-tls-configuration-name]]`link:#quarkus-cxf_quarkus-cxf-client-client-name-tls-configuration-name[quarkus.cxf.client."client-name".tls-configuration-name]`
.<| `string`
.<|

3+a|The name of the TLS configuration to use for setting up trust store and keystore for this SOAP client.
<p>
If not set and `.trust-store` or `.key-store` is configured then that the configuration from `.trust-store*`
and `.key-store*` family of options will be used.
If a name is configured, it uses the configuration from `quarkus.tls.<name>.*`
If a name is configured, but no TLS configuration is found with that name then an error will be thrown at runtime.

*Environment variable*: `+++QUARKUS_CXF_CLIENT__CLIENT_NAME__TLS_CONFIGURATION_NAME+++` +
*Since Quarkus CXF*: 3.15.0

.<| [[quarkus-cxf_quarkus-cxf-client-client-name-key-store]]`link:#quarkus-cxf_quarkus-cxf-client-client-name-key-store[quarkus.cxf.client."client-name".key-store]`
.<| `string`
.<|
Expand Down
4 changes: 4 additions & 0 deletions extensions/core/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-tls-registry-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.cxf</groupId>
<artifactId>quarkus-cxf</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions extensions/core/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-tls-registry</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus.vertx.utils</groupId>
<artifactId>quarkus-vertx-utils</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
package io.quarkiverse.cxf;

import java.net.URL;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;

import org.apache.cxf.annotations.SchemaValidation.SchemaValidationType;
import org.apache.cxf.transports.http.configuration.ConnectionType;
import org.apache.cxf.transports.http.configuration.ProxyServerType;

import io.quarkiverse.cxf.CxfClientConfig.HTTPConduitImpl;
import io.quarkus.arc.Arc;
import io.quarkus.arc.Unremovable;
import io.quarkus.tls.TlsConfiguration;
import io.quarkus.tls.TlsConfigurationRegistry;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.JksOptions;
import io.vertx.core.net.KeyStoreOptionsBase;
import io.vertx.core.net.PfxOptions;

/**
* CXF client metadata - the complete set as known at runtime.
Expand Down Expand Up @@ -172,40 +184,8 @@ public class CXFClientInfo {
*/
private final String proxyPassword;

/**
* The key store location. Can point to either a classpath resource or a file.
*/
private final String keyStore;

/**
* The key store password.
*/
private final String keyStorePassword;

/**
* The type of the trust store. Defaults to "JKS".
*/
private final String keyStoreType;

/**
* The key password.
*/
private final String keyPassword;

/**
* The trust store location. Can point to either a classpath resource or a file.
*/
private final String trustStore;
private final TlsConfiguration tlsConfiguration;

/**
* The trust store password.
*/
private final String trustStorePassword;

/**
* The type of the trust store. Defaults to "JKS".
*/
private final String trustStoreType;
private final String hostnameVerifier;

private final HTTPConduitImpl httpConduitImpl;
Expand All @@ -216,7 +196,7 @@ public class CXFClientInfo {

private final boolean secureWsdlAccess;

public CXFClientInfo(CXFClientData other, CxfConfig cxfConfig, CxfClientConfig config, String configKey) {
public CXFClientInfo(CXFClientData other, CxfConfig cxfConfig, CxfClientConfig config, String configKey, Vertx vertx) {
Objects.requireNonNull(config);
this.sei = other.getSei();
this.soapBinding = config.soapBinding().orElse(other.getSoapBinding());
Expand Down Expand Up @@ -259,13 +239,7 @@ public CXFClientInfo(CXFClientData other, CxfConfig cxfConfig, CxfClientConfig c
this.proxyUsername = config.proxyUsername().orElse(null);
this.proxyPassword = config.proxyPassword().orElse(null);

this.keyStore = config.keyStore().orElse(null);
this.keyStorePassword = config.keyStorePassword().orElse(null);
this.keyStoreType = Objects.requireNonNull(config.keyStoreType(), "keyStoreType cannot be null");
this.keyPassword = config.keyPassword().orElse(null);
this.trustStore = config.trustStore().orElse(null);
this.trustStorePassword = config.trustStorePassword().orElse(null);
this.trustStoreType = Objects.requireNonNull(config.trustStoreType(), "trustStoreType cannot be null");
this.tlsConfiguration = tlsConfiguration(vertx, config, configKey);
this.hostnameVerifier = config.hostnameVerifier().orElse(null);
this.schemaValidationEnabledFor = config.schemaValidationEnabledFor().orElse(null);

Expand All @@ -278,6 +252,88 @@ public CXFClientInfo(CXFClientData other, CxfConfig cxfConfig, CxfClientConfig c
this.configKey = configKey;
}

static TlsConfiguration tlsConfiguration(Vertx vertx, CxfClientConfig config, String configKey) {
final TlsConfigurationRegistry tlsRegistry = Arc.container().select(TlsConfigurationRegistry.class).get();
final Optional<String> maybeTlsConfigName = config.tlsConfigurationName();
if (maybeTlsConfigName.isEmpty()) {
if (config.keyStore().isPresent() || config.trustStore().isPresent()) {
final String registryKey = "quarkus-cxf-client-" + configKey;
final Optional<TlsConfiguration> cachedTlsConfiguration = tlsRegistry.get(registryKey);
if (cachedTlsConfiguration.isPresent()) {
return cachedTlsConfiguration.get();
}

final KeyStoreOptionsBase keyStoreOptions;
final KeyStore keyStore;
if (config.keyStore().isPresent()) {
keyStoreOptions = keyStoreOptions(config.keyStoreType(),
"quarkus.cxf.client." + configKey + ".key-store-type");
keyStoreOptions
.setPassword(config.keyStorePassword().orElse(null))
.setValue(Buffer.buffer(CXFRuntimeUtils.read(config.keyStore().get())))
.setPath(config.keyStore().orElse(null));
if (config.keyPassword().isPresent()) {
keyStoreOptions.setAliasPassword(config.keyPassword().get());
}
try {
keyStore = keyStoreOptions.loadKeyStore(vertx);
} catch (Exception e) {
throw new RuntimeException("Could not load key store from " + config.keyStore().get(), e);
}
} else {
keyStore = null;
keyStoreOptions = null;
}

final KeyStoreOptionsBase trustOptions;
final KeyStore trustStore;
if (config.trustStore().isPresent()) {
trustOptions = keyStoreOptions(config.trustStoreType(),
"quarkus.cxf.client." + configKey + ".trust-store-type");
trustOptions
.setPassword(config.trustStorePassword().orElse(null))
.setValue(Buffer.buffer(CXFRuntimeUtils.read(config.trustStore().get())))
.setPath(config.trustStore().orElse(null));
try {
trustStore = trustOptions.loadKeyStore(vertx);
} catch (Exception e) {
throw new RuntimeException("Could not load trust store from " + config.trustStore().get(), e);
}
} else {
trustOptions = null;
trustStore = null;
}
final CxfTlsConfiguration cxfTlsConfiguration = new CxfTlsConfiguration(keyStoreOptions, keyStore, trustOptions,
trustStore);
tlsRegistry.register(registryKey, cxfTlsConfiguration);
return cxfTlsConfiguration;
}

/* No TLS config - that's fine too */
return null;
} else {
Optional<TlsConfiguration> maybeTlsConfig = tlsRegistry.get(maybeTlsConfigName.get());
if (maybeTlsConfig.isPresent()) {
return maybeTlsConfig.get();
} else {
throw new IllegalStateException("No such TLS configuration quarkus.tls." + maybeTlsConfigName.get());
}
}
}

private static KeyStoreOptionsBase keyStoreOptions(String type, String configKey) {
return switch (type.toUpperCase(Locale.ROOT)) {
case "JKS": {
yield new JksOptions();
}
case "PKCS12": {
yield new PfxOptions();
}
default:
throw new IllegalArgumentException("Unexpected key store type " + type + " for " + configKey);
};
}

public String getHostnameVerifier() {
return hostnameVerifier;
}
Expand Down Expand Up @@ -484,32 +540,8 @@ public HTTPConduitImpl getHttpConduitImpl() {
return httpConduitImpl;
}

public String getKeyStore() {
return keyStore;
}

public String getKeyStorePassword() {
return keyStorePassword;
}

public String getKeyStoreType() {
return keyStoreType;
}

public String getKeyPassword() {
return keyPassword;
}

public String getTrustStore() {
return trustStore;
}

public String getTrustStorePassword() {
return trustStorePassword;
}

public String getTrustStoreType() {
return trustStoreType;
public TlsConfiguration getTlsConfiguration() {
return tlsConfiguration;
}

public String getConfigKey() {
Expand Down
Loading

0 comments on commit 7cb473c

Please sign in to comment.