Skip to content

Commit

Permalink
NIFI-7407 Replaced SSLContextFactory references to "TLS" with "TLSv1.…
Browse files Browse the repository at this point in the history
…2" (in shared constant).

Changed JettyServer default SSL initialization and updated unit test.
Removed SecurityStoreTypes (unused).
Added StringUtils inverted blank and empty checks.
Added TlsConfiguration container object.
Enhanced KeystoreType enum.
Added clean #createSSLContext() method to serve as base method for special cases/other method signatures.
Added utility methods in KeyStoreUtils.
Added generic TlsException for callers that cannot resolve TLS-specific exceptions.
Added utility methods for component object debugging.
Enforced TLS protocol version on cluster comms socket creation.
Added utility method for SSL server socket creation.
Refactored (Server)SocketConfigurationFactoryBean to store relevant NiFiProperties in TlsConfiguration instead of stateful SSLContextFactory (Cluster comms now enforce modern TLS protocol version).
Removed duplicate SSLContextFactory.
Switched duplicate SslContextFactory to wrap shared SSLContextFactory.
Refactored SslContextFactoryTest for clarity (will move any unique tests to nifi-security-utils class test).
Added further validation & boundary checking in uses of TlsConfiguration.
Provided SSLSocketFactory accessor in SslContextFactory.
Refactored OkHttpReplicationClient tuple method.
Refactored OcspCertificateValidator TLS logic.
Added utility method to apply TLS configs to OkHttpClientBuilder.
Removed references to duplicate SslContextFactory.
Removed unnecessary SslContextFactory.
Moved OkHttpClientUtils to nifi-web-util module.
Updated module dependencies.
Removed now empty nifi-security module.
Enforced TLS protocol selection on LB server socket.
Enforced TLS protocol selection on S2S server socket.
Applied specified TLS protocol versions to S2S socket creation.
Completed removal of legacy SSLContext creation methods from only remaining SslContextFactory.
Replaced references to creation methods throughout codebase.
Replaced references to unnecessary NiFiProperties file reads throughout tests.
Removed duplicate ClientAuth enum from SSLContextService and changed all references to SslContextFactory.ClientAuth.
Suppressed repeated TLS exceptions in cluster, S2S, and load balance socket listeners.
Cleaned up legacy code.
Added external timing check to timing test assertion.
Made RestrictedSSLContextService TLS protocol versions allowable values explicit.
Enabled TLSv1.3 on Java 11.
Added explanations of TLS protocol versions in StandardSSLContextService and StandardRestrictedSSLContextService.
Resolved additional Java 11 test failures for NiFi internal classes that don't support TLSv1.3. Filed NIFI-7468 as follow on task.

This closes #4263.

Signed-off-by: Nathan Gough <thenatog@gmail.com>
Signed-off-by: Mark Payne <markap14@hotmail.com>
  • Loading branch information
alopresto committed May 19, 2020
1 parent 5826a09 commit 441781c
Show file tree
Hide file tree
Showing 165 changed files with 4,793 additions and 3,774 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
*/
package org.apache.nifi.bootstrap.notification.http;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
Expand All @@ -32,18 +39,7 @@
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.util.Tuple;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import org.apache.nifi.security.util.TlsConfiguration;

public class HttpNotificationService extends AbstractNotificationService {

Expand Down Expand Up @@ -139,6 +135,7 @@ public class HttpNotificationService extends AbstractNotificationService {
private final AtomicReference<String> urlReference = new AtomicReference<>();

private static final List<PropertyDescriptor> supportedProperties;

static {
supportedProperties = new ArrayList<>();
supportedProperties.add(PROP_URL);
Expand All @@ -160,7 +157,7 @@ protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
}

@Override
protected PropertyDescriptor getSupportedDynamicPropertyDescriptor(final String propertyDescriptorName){
protected PropertyDescriptor getSupportedDynamicPropertyDescriptor(final String propertyDescriptorName) {
return new PropertyDescriptor.Builder()
.required(false)
.name(propertyDescriptorName)
Expand Down Expand Up @@ -193,25 +190,15 @@ protected void init(final NotificationInitializationContext context) {
// check if the keystore is set and add the factory if so
if (url.toLowerCase().startsWith("https")) {
try {
Tuple<SSLContext, TrustManager[]> sslContextTuple = SslContextFactory.createTrustSslContextWithTrustManagers(
context.getProperty(HttpNotificationService.PROP_KEYSTORE).getValue(),
context.getProperty(HttpNotificationService.PROP_KEYSTORE_PASSWORD).isSet()
? context.getProperty(HttpNotificationService.PROP_KEYSTORE_PASSWORD).getValue().toCharArray() : null,
context.getProperty(HttpNotificationService.PROP_KEY_PASSWORD).isSet()
? context.getProperty(HttpNotificationService.PROP_KEY_PASSWORD).getValue().toCharArray() : null,
context.getProperty(HttpNotificationService.PROP_KEYSTORE_TYPE).getValue(),
context.getProperty(HttpNotificationService.PROP_TRUSTSTORE).getValue(),
context.getProperty(HttpNotificationService.PROP_TRUSTSTORE_PASSWORD).isSet()
? context.getProperty(HttpNotificationService.PROP_TRUSTSTORE_PASSWORD).getValue().toCharArray() : null,
context.getProperty(HttpNotificationService.PROP_TRUSTSTORE_TYPE).getValue(),
SslContextFactory.ClientAuth.REQUIRED,
context.getProperty(HttpNotificationService.SSL_ALGORITHM).getValue()
);
// Find the first X509TrustManager
List<X509TrustManager> x509TrustManagers = Arrays.stream(sslContextTuple.getValue())
.filter(trustManager -> trustManager instanceof X509TrustManager)
.map(trustManager -> (X509TrustManager) trustManager).collect(Collectors.toList());
okHttpClientBuilder.sslSocketFactory(sslContextTuple.getKey().getSocketFactory(), x509TrustManagers.get(0));
TlsConfiguration tlsConfiguration = createTlsConfigurationFromContext(context);
final SSLSocketFactory sslSocketFactory = SslContextFactory.createSSLSocketFactory(tlsConfiguration);
final X509TrustManager x509TrustManager = SslContextFactory.getX509TrustManager(tlsConfiguration);
if (sslSocketFactory != null && x509TrustManager != null) {
okHttpClientBuilder.sslSocketFactory(sslSocketFactory, x509TrustManager);
} else {
// If the TLS config couldn't be parsed, throw an exception
throw new IllegalStateException("The HTTP notification service URL indicates HTTPS but the TLS properties are not valid");
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
Expand All @@ -220,6 +207,17 @@ protected void init(final NotificationInitializationContext context) {
httpClientReference.set(okHttpClientBuilder.build());
}

private static TlsConfiguration createTlsConfigurationFromContext(NotificationInitializationContext context) {
String keystorePath = context.getProperty(HttpNotificationService.PROP_KEYSTORE).getValue();
String keystorePassword = context.getProperty(HttpNotificationService.PROP_KEYSTORE_PASSWORD).getValue();
String keyPassword = context.getProperty(HttpNotificationService.PROP_KEY_PASSWORD).getValue();
String keystoreType = context.getProperty(HttpNotificationService.PROP_KEYSTORE_TYPE).getValue();
String truststorePath = context.getProperty(HttpNotificationService.PROP_TRUSTSTORE).getValue();
String truststorePassword = context.getProperty(HttpNotificationService.PROP_TRUSTSTORE_PASSWORD).getValue();
String truststoreType = context.getProperty(HttpNotificationService.PROP_TRUSTSTORE_TYPE).getValue();
return new TlsConfiguration(keystorePath, keystorePassword, keyPassword, keystoreType, truststorePath, truststorePassword, truststoreType);
}

@Override
public void notify(NotificationContext context, NotificationType notificationType, String subject, String message) throws NotificationFailedException {
try {
Expand All @@ -231,7 +229,7 @@ public void notify(NotificationContext context, NotificationType notificationTyp

Map<PropertyDescriptor, String> configuredProperties = context.getProperties();

for(PropertyDescriptor propertyDescriptor: configuredProperties.keySet()) {
for (PropertyDescriptor propertyDescriptor : configuredProperties.keySet()) {
if (propertyDescriptor.isDynamic()) {
String propertyValue = context.getProperty(propertyDescriptor).evaluateAttributeExpressions().getValue();
requestBuilder = requestBuilder.addHeader(propertyDescriptor.getDisplayName(), propertyValue);
Expand All @@ -246,14 +244,14 @@ public void notify(NotificationContext context, NotificationType notificationTyp
final OkHttpClient httpClient = httpClientReference.get();

final Call call = httpClient.newCall(request);
try (final Response response = call.execute()) {

if (!response.isSuccessful()) {
throw new NotificationFailedException("Failed to send Http Notification. Received an unsuccessful status code response '" + response.code() + "'. The message was '" +
response.message() + "'");
}
}
} catch (NotificationFailedException e){
try (final Response response = call.execute()) {

if (!response.isSuccessful()) {
throw new NotificationFailedException("Failed to send Http Notification. Received an unsuccessful status code response '" + response.code() + "'. The message was '" +
response.message() + "'");
}
}
} catch (NotificationFailedException e) {
throw e;
} catch (Exception e) {
throw new NotificationFailedException("Failed to send Http Notification", e);
Expand Down
Loading

0 comments on commit 441781c

Please sign in to comment.