Skip to content

Commit

Permalink
Merge pull request #26380 from sberyozkin/vertx_http_credentials_prov…
Browse files Browse the repository at this point in the history
…ider

Integrate Vertx HTTP with CredentialsProvider
  • Loading branch information
sberyozkin authored Jul 6, 2022
2 parents 660b90c + 8f2f633 commit 20964b6
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 10 deletions.
4 changes: 4 additions & 0 deletions extensions/vertx-http/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-runtime-spi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-credentials</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mutiny</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConvertWith;
import io.quarkus.runtime.configuration.TrimmedStringConverter;

/**
* A certificate configuration. Either the certificate and key files must be given, or a key store must be given.
Expand All @@ -14,6 +16,30 @@
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class CertificateConfig {

/**
* The {@linkplain CredentialsProvider}}.
* If this property is configured then a matching 'CredentialsProvider' will be used
* to get the keystore, keystore key and truststore passwords unless these passwords have already been configured.
*
* Please note that using MicroProfile {@linkplain ConfigSource} which is directly supported by Quarkus Configuration
* should be preferred unless using `CredentialsProvider` provides for some additional security and dynamism.
*/
@ConfigItem
@ConvertWith(TrimmedStringConverter.class)
public Optional<String> credentialsProvider = Optional.empty();

/**
* The credentials provider bean name.
* <p>
* It is the {@code &#64;Named} value of the credentials provider bean. It is used to discriminate if multiple
* CredentialsProvider beans are available.
* It is recommended to set this property even if there is only one credentials provider currently available
* to ensure the same provider is always found in deployments where more than one provider may be available.
*/
@ConfigItem
@ConvertWith(TrimmedStringConverter.class)
public Optional<String> credentialsProviderName = Optional.empty();

/**
* The file path to a server certificate or certificate chain in PEM format.
*
Expand Down Expand Up @@ -69,10 +95,23 @@ public class CertificateConfig {
public Optional<String> keyStoreProvider;

/**
* A parameter to specify the password of the key store file. If not given, the default ("password") is used.
* A parameter to specify the password of the key store file. If not given, and if it can not be retrieved from
* {@linkplain CredentialsProvider}, then the default ("password") is used.
*
* @see {@link #credentialsProvider}
*/
@ConfigItem(defaultValue = "password")
public String keyStorePassword;
@ConfigItem(defaultValueDocumentation = "password")
public Optional<String> keyStorePassword;

/**
* A parameter to specify a {@linkplain CredentialsProvider} property key which can be used to get the password of the key
* store file
* from {@linkplain CredentialsProvider}.
*
* @see {@link #credentialsProvider}
*/
@ConfigItem
public Optional<String> keyStorePasswordKey;

/**
* An optional parameter to select a specific key in the key store. When SNI is disabled, if the key store contains multiple
Expand All @@ -82,11 +121,23 @@ public class CertificateConfig {
public Optional<String> keyStoreKeyAlias;

/**
* An optional parameter to define the password for the key, in case it's different from {@link #keyStorePassword}.
* An optional parameter to define the password for the key, in case it's different from {@link #keyStorePassword}
* If not given then it may be retrieved from {@linkplain CredentialsProvider}.
*
* @see {@link #credentialsProvider}.
*/
@ConfigItem
public Optional<String> keyStoreKeyPassword;

/**
* A parameter to specify a {@linkplain CredentialsProvider} property key which can be used to get the password for the key
* from {@linkplain CredentialsProvider}.
*
* @see {@link #credentialsProvider}
*/
@ConfigItem
public Optional<String> keyStoreKeyPasswordKey;

/**
* An optional trust store which holds the certificate information of the certificates to trust.
*/
Expand All @@ -109,10 +160,23 @@ public class CertificateConfig {

/**
* A parameter to specify the password of the trust store file.
* If not given then it may be retrieved from {@linkplain CredentialsProvider}.
*
* @see {@link #credentialsProvider}.
*/
@ConfigItem
public Optional<String> trustStorePassword;

/**
* A parameter to specify a {@linkplain CredentialsProvider} property key which can be used to get the password of the trust
* store file
* from {@linkplain CredentialsProvider}.
*
* @see {@link #credentialsProvider}
*/
@ConfigItem
public Optional<String> trustStorePasswordKey;

/**
* An optional parameter to trust only one specific certificate in the trust store (instead of trusting all certificates in
* the store).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
import io.quarkus.arc.Arc;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.bootstrap.runner.Timing;
import io.quarkus.credentials.CredentialsProvider;
import io.quarkus.credentials.runtime.CredentialsProviderFinder;
import io.quarkus.dev.spi.DevModeType;
import io.quarkus.dev.spi.HotReplacementContext;
import io.quarkus.netty.runtime.virtual.VirtualAddress;
Expand Down Expand Up @@ -781,10 +783,22 @@ private static HttpServerOptions createSslOptions(HttpBuildTimeConfig buildTimeC
certificates.add(certFile.get());
}

// credentials provider
Map<String, String> credentials = Map.of();
if (sslConfig.certificate.credentialsProvider.isPresent()) {
String beanName = sslConfig.certificate.credentialsProviderName.orElse(null);
CredentialsProvider credentialsProvider = CredentialsProviderFinder.find(beanName);
String name = sslConfig.certificate.credentialsProvider.get();
credentials = credentialsProvider.getCredentials(name);
}
final Optional<Path> keyStoreFile = sslConfig.certificate.keyStoreFile;
final String keystorePassword = sslConfig.certificate.keyStorePassword;
final Optional<String> keyStorePassword = getCredential(sslConfig.certificate.keyStorePassword, credentials,
sslConfig.certificate.keyStorePasswordKey);
final Optional<String> keyStoreKeyPassword = getCredential(sslConfig.certificate.keyStoreKeyPassword, credentials,
sslConfig.certificate.keyStoreKeyPasswordKey);
final Optional<Path> trustStoreFile = sslConfig.certificate.trustStoreFile;
final Optional<String> trustStorePassword = sslConfig.certificate.trustStorePassword;
final Optional<String> trustStorePassword = getCredential(sslConfig.certificate.trustStorePassword, credentials,
sslConfig.certificate.trustStorePasswordKey);
final HttpServerOptions serverOptions = new HttpServerOptions();

//ssl
Expand All @@ -801,11 +815,11 @@ private static HttpServerOptions createSslOptions(HttpBuildTimeConfig buildTimeC
} else if (keyStoreFile.isPresent()) {
KeyStoreOptions options = createKeyStoreOptions(
keyStoreFile.get(),
keystorePassword,
keyStorePassword.orElse("password"),
sslConfig.certificate.keyStoreFileType,
sslConfig.certificate.keyStoreProvider,
sslConfig.certificate.keyStoreKeyAlias,
sslConfig.certificate.keyStoreKeyPassword);
keyStoreKeyPassword);
serverOptions.setKeyCertOptions(options);
} else {
return null;
Expand Down Expand Up @@ -846,6 +860,19 @@ private static HttpServerOptions createSslOptions(HttpBuildTimeConfig buildTimeC
return serverOptions;
}

private static Optional<String> getCredential(Optional<String> password, Map<String, String> credentials,
Optional<String> passwordKey) {
if (password.isPresent()) {
return password;
}

if (passwordKey.isPresent()) {
return Optional.ofNullable(credentials.get(passwordKey.get()));
} else {
return Optional.empty();
}
}

private static void applyCommonOptions(HttpServerOptions httpServerOptions,
HttpBuildTimeConfig buildTimeConfig,
HttpConfiguration httpConfiguration,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.quarkus.it.bouncycastle;

import java.util.HashMap;
import java.util.Map;

import javax.enterprise.context.ApplicationScoped;

import io.quarkus.arc.Unremovable;
import io.quarkus.credentials.CredentialsProvider;

@ApplicationScoped
@Unremovable
public class SecretProvider implements CredentialsProvider {

@Override
public Map<String, String> getCredentials(String credentialsProviderName) {
Map<String, String> creds = new HashMap<>();
creds.put("keystore-password", "password");
creds.put("truststore-password", "password");
return creds;
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
quarkus.security.security-providers=BCJSSE

quarkus.http.ssl.certificate.key-store-file=server-keystore.jks
quarkus.http.ssl.certificate.key-store-password=password
quarkus.http.ssl.certificate.key-store-password-key=key-store-password
quarkus.http.ssl.certificate.trust-store-file=server-truststore.jks
quarkus.http.ssl.certificate.trust-store-password=password
quarkus.http.ssl.certificate.trust-store-password-key=truststore-password
quarkus.http.ssl.certificate.credentials-provider=custom

quarkus.http.ssl.client-auth=REQUIRED
quarkus.native.additional-build-args=-H:IncludeResources=.*\\.jks

Expand Down

0 comments on commit 20964b6

Please sign in to comment.