Skip to content

Commit

Permalink
NIFI-14027 Added SSLContextProvider Controller Service Interface
Browse files Browse the repository at this point in the history
- Updated SSLContextService to extend SSLContextProvider
- Updated Processors and Controller Services to use SSLContextProvider where supported

Signed-off-by: Pierre Villard <[email protected]>

This closes apache#9537.
  • Loading branch information
exceptionfactory authored and pvillard31 committed Nov 21, 2024
1 parent aa3a7c0 commit d07b363
Show file tree
Hide file tree
Showing 63 changed files with 628 additions and 803 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.ssl.SSLContextProvider;


/**
Expand Down Expand Up @@ -127,7 +127,7 @@ abstract class AbstractAMQPProcessor<T extends AMQPWorker> extends AbstractProce
.displayName("SSL Context Service")
.description("The SSL Context Service used to provide client certificate information for TLS/SSL connections.")
.required(false)
.identifiesControllerService(SSLContextService.class)
.identifiesControllerService(SSLContextProvider.class)
.build();
public static final PropertyDescriptor USE_CERT_AUTHENTICATION = new PropertyDescriptor.Builder()
.name("cert-authentication")
Expand Down Expand Up @@ -314,11 +314,11 @@ protected Connection createConnection(ProcessContext context, ExecutorService ex
}

// handles TLS/SSL aspects
final SSLContextService sslService = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class);
final SSLContextProvider sslContextProvider = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
final Boolean useCertAuthentication = context.getProperty(USE_CERT_AUTHENTICATION).asBoolean();

if (sslService != null) {
final SSLContext sslContext = sslService.createContext();
if (sslContextProvider != null) {
final SSLContext sslContext = sslContextProvider.createContext();
cf.useSslProtocol(sslContext);

if (useCertAuthentication) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package org.apache.nifi.amqp.processors;

import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.ssl.SSLContextProvider;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -90,10 +90,10 @@ public void testNotValidClientCertAuthButNoSSLContextService() throws Exception
}

private void configureSSLContextService() throws InitializationException {
SSLContextService sslService = mock(SSLContextService.class);
when(sslService.getIdentifier()).thenReturn("ssl-context");
testRunner.addControllerService("ssl-context", sslService);
testRunner.enableControllerService(sslService);
SSLContextProvider sslContextProvider = mock(SSLContextProvider.class);
when(sslContextProvider.getIdentifier()).thenReturn("ssl-context");
testRunner.addControllerService("ssl-context", sslContextProvider);
testRunner.enableControllerService(sslContextProvider);

testRunner.setProperty(AbstractAMQPProcessor.SSL_CONTEXT_SERVICE, "ssl-context");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
import org.apache.nifi.processors.aws.credentials.provider.service.AWSCredentialsProviderService;
import org.apache.nifi.proxy.ProxyConfiguration;
import org.apache.nifi.proxy.ProxySpec;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.ssl.SSLContextProvider;

import javax.net.ssl.SSLContext;
import java.net.Proxy;
Expand Down Expand Up @@ -98,7 +98,7 @@ public abstract class AbstractAWSCredentialsProviderProcessor<ClientType extends
.name("SSL Context Service")
.description("Specifies an optional SSL Context Service that, if provided, will be used to create connections")
.required(false)
.identifiesControllerService(SSLContextService.class)
.identifiesControllerService(SSLContextProvider.class)
.build();

public static final PropertyDescriptor ENDPOINT_OVERRIDE = new PropertyDescriptor.Builder()
Expand Down Expand Up @@ -204,9 +204,9 @@ protected ClientConfiguration createConfiguration(final PropertyContext context,
config.setSocketTimeout(commsTimeout);

if (this.getSupportedPropertyDescriptors().contains(SSL_CONTEXT_SERVICE)) {
final SSLContextService sslContextService = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class);
if (sslContextService != null) {
final SSLContext sslContext = sslContextService.createContext();
final SSLContextProvider sslContextProvider = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
if (sslContextProvider != null) {
final SSLContext sslContext = sslContextProvider.createContext();
// NIFI-3788: Changed hostnameVerifier from null to DHV (BrowserCompatibleHostnameVerifier is deprecated)
SdkTLSSocketFactory sdkTLSSocketFactory = new SdkTLSSocketFactory(sslContext, new DefaultHostnameVerifier());
config.getApacheHttpClientConfig().setSslSocketFactory(sdkTLSSocketFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,28 @@
import org.apache.nifi.processors.aws.credentials.provider.service.AWSCredentialsProviderService;
import org.apache.nifi.proxy.ProxyConfiguration;
import org.apache.nifi.proxy.ProxySpec;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.ssl.SSLContextProvider;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
import software.amazon.awssdk.core.SdkClient;
import software.amazon.awssdk.core.client.builder.SdkClientBuilder;
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
import software.amazon.awssdk.core.retry.RetryPolicy;
import software.amazon.awssdk.http.FileStoreTlsKeyManagersProvider;
import software.amazon.awssdk.http.TlsKeyManagersProvider;
import software.amazon.awssdk.http.TlsTrustManagersProvider;
import software.amazon.awssdk.regions.Region;

import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509TrustManager;
import java.net.Proxy;
import java.net.URI;
import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -118,7 +120,7 @@ public abstract class AbstractAwsProcessor<T extends SdkClient> extends Abstract
.name("SSL Context Service")
.description("Specifies an optional SSL Context Service that, if provided, will be used to create connections")
.required(false)
.identifiesControllerService(SSLContextService.class)
.identifiesControllerService(SSLContextProvider.class)
.build();

public static final PropertyDescriptor ENDPOINT_OVERRIDE = new PropertyDescriptor.Builder()
Expand Down Expand Up @@ -283,17 +285,22 @@ protected void configureSdkHttpClient(final ProcessContext context, final AwsHtt
httpClientConfigurer.configureBasicSettings(Duration.ofMillis(communicationsTimeout), context.getMaxConcurrentTasks());

if (this.getSupportedPropertyDescriptors().contains(SSL_CONTEXT_SERVICE)) {
final SSLContextService sslContextService = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class);
if (sslContextService != null) {
TlsTrustManagersProvider trustManagersProvider = null;
TlsKeyManagersProvider keyManagersProvider = null;
if (sslContextService.isTrustStoreConfigured()) {
trustManagersProvider = () -> new TrustManager[]{sslContextService.createTrustManager()};
}
if (sslContextService.isKeyStoreConfigured()) {
keyManagersProvider = FileStoreTlsKeyManagersProvider
.create(Path.of(sslContextService.getKeyStoreFile()), sslContextService.getKeyStoreType(), sslContextService.getKeyStorePassword());
final SSLContextProvider sslContextProvider = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
if (sslContextProvider != null) {
final X509TrustManager trustManager = sslContextProvider.createTrustManager();
final TrustManager[] trustManagers = new TrustManager[]{trustManager};
final TlsTrustManagersProvider trustManagersProvider = () -> trustManagers;

final TlsKeyManagersProvider keyManagersProvider;
final Optional<X509ExtendedKeyManager> keyManagerFound = sslContextProvider.createKeyManager();
if (keyManagerFound.isPresent()) {
final X509ExtendedKeyManager keyManager = keyManagerFound.get();
final KeyManager[] keyManagers = new KeyManager[]{keyManager};
keyManagersProvider = () -> keyManagers;
} else {
keyManagersProvider = null;
}

httpClientConfigurer.configureTls(trustManagersProvider, keyManagersProvider);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
import org.apache.nifi.parameter.VerifiableParameterProvider;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.processors.aws.credentials.provider.service.AWSCredentialsProviderService;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.ssl.SSLContextProvider;

import javax.net.ssl.SSLContext;
import java.util.ArrayList;
Expand Down Expand Up @@ -160,7 +160,7 @@ public String getDescription() {
.displayName("SSL Context Service")
.description("Specifies an optional SSL Context Service that, if provided, will be used to create connections")
.required(false)
.identifiesControllerService(SSLContextService.class)
.identifiesControllerService(SSLContextProvider.class)
.build();

private static final String DEFAULT_USER_AGENT = "NiFi";
Expand Down Expand Up @@ -311,9 +311,9 @@ protected ClientConfiguration createConfiguration(final ConfigurationContext con
config.setConnectionTimeout(commsTimeout);
config.setSocketTimeout(commsTimeout);

final SSLContextService sslContextService = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class);
if (sslContextService != null) {
final SSLContext sslContext = sslContextService.createContext();
final SSLContextProvider sslContextProvider = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
if (sslContextProvider != null) {
final SSLContext sslContext = sslContextProvider.createContext();
SdkTLSSocketFactory sdkTLSSocketFactory = new SdkTLSSocketFactory(sslContext, new DefaultHostnameVerifier());
config.getApacheHttpClientConfig().setSslSocketFactory(sdkTLSSocketFactory);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import org.apache.nifi.processors.aws.signer.AwsSignerType;
import org.apache.nifi.proxy.ProxyConfiguration;
import org.apache.nifi.proxy.ProxyConfigurationService;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.ssl.SSLContextProvider;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.regions.Region;
Expand Down Expand Up @@ -131,13 +131,13 @@ public AWSCredentialsProvider getDerivedCredentialsProvider(final PropertyContex
final String assumeRoleSTSRegion = propertyContext.getProperty(ASSUME_ROLE_STS_REGION).getValue();
final String assumeRoleSTSEndpoint = propertyContext.getProperty(ASSUME_ROLE_STS_ENDPOINT).getValue();
final String assumeRoleSTSSigner = propertyContext.getProperty(ASSUME_ROLE_STS_SIGNER_OVERRIDE).getValue();
final SSLContextService sslContextService = propertyContext.getProperty(ASSUME_ROLE_SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class);
final SSLContextProvider sslContextProvider = propertyContext.getProperty(ASSUME_ROLE_SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
final ProxyConfigurationService proxyConfigurationService = propertyContext.getProperty(ASSUME_ROLE_PROXY_CONFIGURATION_SERVICE).asControllerService(ProxyConfigurationService.class);

final ClientConfiguration config = new ClientConfiguration();

if (sslContextService != null) {
final SSLContext sslContext = sslContextService.createContext();
if (sslContextProvider != null) {
final SSLContext sslContext = sslContextProvider.createContext();
config.getApacheHttpClientConfig().setSslSocketFactory(new SSLConnectionSocketFactory(sslContext));
}

Expand Down Expand Up @@ -199,15 +199,15 @@ public AwsCredentialsProvider getDerivedAwsCredentialsProvider(final PropertyCon
final String assumeRoleExternalId = propertyContext.getProperty(ASSUME_ROLE_EXTERNAL_ID).getValue();
final String assumeRoleSTSEndpoint = propertyContext.getProperty(ASSUME_ROLE_STS_ENDPOINT).getValue();
final String stsRegion = propertyContext.getProperty(ASSUME_ROLE_STS_REGION).getValue();
final SSLContextService sslContextService = propertyContext.getProperty(ASSUME_ROLE_SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class);
final SSLContextProvider sslContextProvider = propertyContext.getProperty(ASSUME_ROLE_SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
final ProxyConfigurationService proxyConfigurationService = propertyContext.getProperty(ASSUME_ROLE_PROXY_CONFIGURATION_SERVICE).asControllerService(ProxyConfigurationService.class);

final StsAssumeRoleCredentialsProvider.Builder builder = StsAssumeRoleCredentialsProvider.builder();

final ApacheHttpClient.Builder httpClientBuilder = ApacheHttpClient.builder();

if (sslContextService != null) {
final SSLContext sslContext = sslContextService.createContext();
if (sslContextProvider != null) {
final SSLContext sslContext = sslContextProvider.createContext();
httpClientBuilder.socketFactory(new SSLConnectionSocketFactory(sslContext));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
import org.apache.nifi.processors.aws.credentials.provider.factory.strategies.ImplicitDefaultCredentialsStrategy;
import org.apache.nifi.processors.aws.credentials.provider.factory.strategies.NamedProfileCredentialsStrategy;
import org.apache.nifi.proxy.ProxyConfigurationService;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.ssl.SSLContextProvider;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.regions.Region;

Expand Down Expand Up @@ -191,7 +191,7 @@ public class AWSCredentialsProviderControllerService extends AbstractControllerS
.name("assume-role-ssl-context-service")
.displayName("Assume Role SSL Context Service")
.description("SSL Context Service used when connecting to the STS Endpoint.")
.identifiesControllerService(SSLContextService.class)
.identifiesControllerService(SSLContextProvider.class)
.required(false)
.dependsOn(ASSUME_ROLE_ARN)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,28 @@
import org.apache.nifi.schemaregistry.services.SchemaRegistry;
import org.apache.nifi.serialization.record.RecordSchema;
import org.apache.nifi.serialization.record.SchemaIdentifier;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.ssl.SSLContextProvider;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.http.FileStoreTlsKeyManagersProvider;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.TlsKeyManagersProvider;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.glue.GlueClient;
import software.amazon.awssdk.services.glue.GlueClientBuilder;

import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.Proxy;
import java.net.URI;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -129,7 +130,7 @@ public class AmazonGlueSchemaRegistry extends AbstractControllerService implemen
.displayName("SSL Context Service")
.description("Specifies an optional SSL Context Service that, if provided, will be used to create connections")
.required(false)
.identifiesControllerService(SSLContextService.class)
.identifiesControllerService(SSLContextProvider.class)
.build();

private static final ProxySpec[] PROXY_SPECS = {ProxySpec.HTTP_AUTH};
Expand Down Expand Up @@ -218,16 +219,17 @@ private SdkHttpClient createSdkHttpClient(final ConfigurationContext context) {
builder.socketTimeout(Duration.ofMillis(communicationsTimeout));

if (this.getSupportedPropertyDescriptors().contains(SSL_CONTEXT_SERVICE)) {
final SSLContextService sslContextService = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class);
if (sslContextService != null) {
if (sslContextService.isTrustStoreConfigured()) {
final TrustManager[] trustManagers = new TrustManager[]{sslContextService.createTrustManager()};
builder.tlsTrustManagersProvider(() -> trustManagers);
}
if (sslContextService.isKeyStoreConfigured()) {
final TlsKeyManagersProvider keyManagersProvider = FileStoreTlsKeyManagersProvider
.create(Paths.get(sslContextService.getKeyStoreFile()), sslContextService.getKeyStoreType(), sslContextService.getKeyStorePassword());
builder.tlsKeyManagersProvider(keyManagersProvider);
final SSLContextProvider sslContextProvider = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
if (sslContextProvider != null) {
final X509TrustManager trustManager = sslContextProvider.createTrustManager();
final TrustManager[] trustManagers = new TrustManager[]{trustManager};
builder.tlsTrustManagersProvider(() -> trustManagers);

final Optional<X509ExtendedKeyManager> keyManagerFound = sslContextProvider.createKeyManager();
if (keyManagerFound.isPresent()) {
final X509ExtendedKeyManager keyManager = keyManagerFound.get();
final KeyManager[] keyManagers = new KeyManager[]{keyManager};
builder.tlsKeyManagersProvider(() -> keyManagers);
}
}
}
Expand Down
Loading

0 comments on commit d07b363

Please sign in to comment.