mirror of https://github.com/apache/nifi.git
NIFI-6927 Consolidate SSL context and trust managers for OkHttp on JDK9.
Fixes name conflicts. This closes #4047. Signed-off-by: Andy LoPresto <alopresto@apache.org>
This commit is contained in:
parent
4098404596
commit
0de89452f1
|
@ -28,16 +28,13 @@ import org.apache.nifi.bootstrap.notification.NotificationFailedException;
|
|||
import org.apache.nifi.bootstrap.notification.NotificationInitializationContext;
|
||||
import org.apache.nifi.bootstrap.notification.NotificationType;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.PropertyValue;
|
||||
import org.apache.nifi.expression.AttributeExpression;
|
||||
import org.apache.nifi.expression.ExpressionLanguageScope;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
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.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.util.ArrayList;
|
||||
|
@ -196,12 +193,25 @@ public class HttpNotificationService extends AbstractNotificationService {
|
|||
// check if the keystore is set and add the factory if so
|
||||
if (url.toLowerCase().startsWith("https")) {
|
||||
try {
|
||||
Tuple<SSLSocketFactory, TrustManager[]> sslSocketFactoryWithTrustManagers = getSslSocketFactory(context);
|
||||
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(sslSocketFactoryWithTrustManagers.getValue())
|
||||
List<X509TrustManager> x509TrustManagers = Arrays.stream(sslContextTuple.getValue())
|
||||
.filter(trustManager -> trustManager instanceof X509TrustManager)
|
||||
.map(trustManager -> (X509TrustManager) trustManager).collect(Collectors.toList());
|
||||
okHttpClientBuilder.sslSocketFactory(sslSocketFactoryWithTrustManagers.getKey(), x509TrustManagers.get(0));
|
||||
okHttpClientBuilder.sslSocketFactory(sslContextTuple.getKey().getSocketFactory(), x509TrustManagers.get(0));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
@ -249,51 +259,4 @@ public class HttpNotificationService extends AbstractNotificationService {
|
|||
throw new NotificationFailedException("Failed to send Http Notification", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Tuple<SSLSocketFactory, TrustManager[]> getSslSocketFactory(NotificationInitializationContext context) {
|
||||
|
||||
final String protocol = context.getProperty(SSL_ALGORITHM).getValue();
|
||||
try {
|
||||
final PropertyValue keyPasswdProp = context.getProperty(PROP_KEY_PASSWORD);
|
||||
final char[] keyPassword = keyPasswdProp.isSet() ? keyPasswdProp.getValue().toCharArray() : null;
|
||||
|
||||
final Tuple<SSLContext, TrustManager[]> sslContextWithTrustManagers;
|
||||
final String truststoreFile = context.getProperty(PROP_TRUSTSTORE).getValue();
|
||||
final String keystoreFile = context.getProperty(PROP_KEYSTORE).getValue();
|
||||
|
||||
if (keystoreFile == null) {
|
||||
// If keystore not specified, create SSL Context based only on trust store.
|
||||
sslContextWithTrustManagers = SslContextFactory.createTrustSslContextWithTrustManagers(
|
||||
context.getProperty(PROP_TRUSTSTORE).getValue(),
|
||||
context.getProperty(PROP_TRUSTSTORE_PASSWORD).getValue().toCharArray(),
|
||||
context.getProperty(PROP_TRUSTSTORE_TYPE).getValue(),
|
||||
protocol);
|
||||
|
||||
} else if (truststoreFile == null) {
|
||||
// If truststore not specified, create SSL Context based only on key store.
|
||||
sslContextWithTrustManagers = SslContextFactory.createSslContextWithTrustManagers(
|
||||
context.getProperty(PROP_KEYSTORE).getValue(),
|
||||
context.getProperty(PROP_KEYSTORE_PASSWORD).getValue().toCharArray(),
|
||||
keyPassword,
|
||||
context.getProperty(PROP_KEYSTORE_TYPE).getValue(),
|
||||
protocol);
|
||||
|
||||
} else {
|
||||
sslContextWithTrustManagers = SslContextFactory.createSslContextWithTrustManagers(
|
||||
context.getProperty(PROP_KEYSTORE).getValue(),
|
||||
context.getProperty(PROP_KEYSTORE_PASSWORD).getValue().toCharArray(),
|
||||
keyPassword,
|
||||
context.getProperty(PROP_KEYSTORE_TYPE).getValue(),
|
||||
context.getProperty(PROP_TRUSTSTORE).getValue(),
|
||||
context.getProperty(PROP_TRUSTSTORE_PASSWORD).getValue().toCharArray(),
|
||||
context.getProperty(PROP_TRUSTSTORE_TYPE).getValue(),
|
||||
SslContextFactory.ClientAuth.REQUIRED,
|
||||
protocol);
|
||||
}
|
||||
|
||||
return new Tuple<>(sslContextWithTrustManagers.getKey().getSocketFactory(), sslContextWithTrustManagers.getValue());
|
||||
} catch (final Exception e) {
|
||||
throw new ProcessException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public final class SslContextFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a SSLContext instance using the given information. The password for the key is assumed to be the same
|
||||
* Creates an SSLContext instance using the given information. The password for the key is assumed to be the same
|
||||
* as the password for the keystore. If this is not the case, the {@link #createSslContext(String, char[], char[], String, String, char[], String, ClientAuth, String)}
|
||||
* method should be used instead
|
||||
*
|
||||
|
@ -63,7 +63,7 @@ public final class SslContextFactory {
|
|||
* @param clientAuth the type of client authentication
|
||||
* @param protocol the protocol to use for the SSL connection
|
||||
*
|
||||
* @return a SSLContext instance
|
||||
* @return an SSLContext instance
|
||||
* @throws java.security.KeyStoreException if any issues accessing the keystore
|
||||
* @throws java.io.IOException for any problems loading the keystores
|
||||
* @throws java.security.NoSuchAlgorithmException if an algorithm is found to be used but is unknown
|
||||
|
@ -83,10 +83,11 @@ public final class SslContextFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a SSLContext instance using the given information.
|
||||
* Creates an SSLContext instance using the given information.
|
||||
*
|
||||
* @param keystore the full path to the keystore
|
||||
* @param keystorePasswd the keystore password
|
||||
* @param keyPasswd the password for the key within the keystore
|
||||
* @param keystoreType the type of keystore (e.g., PKCS12, JKS)
|
||||
* @param truststore the full path to the truststore
|
||||
* @param truststorePasswd the truststore password
|
||||
|
@ -94,7 +95,7 @@ public final class SslContextFactory {
|
|||
* @param clientAuth the type of client authentication
|
||||
* @param protocol the protocol to use for the SSL connection
|
||||
*
|
||||
* @return a SSLContext instance
|
||||
* @return an SSLContext instance
|
||||
* @throws java.security.KeyStoreException if any issues accessing the keystore
|
||||
* @throws java.io.IOException for any problems loading the keystores
|
||||
* @throws java.security.NoSuchAlgorithmException if an algorithm is found to be used but is unknown
|
||||
|
@ -113,10 +114,11 @@ public final class SslContextFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a SSLContext instance paired with its TrustManager instances using the given information.
|
||||
* Creates an SSLContext instance paired with its TrustManager instances using the given information.
|
||||
*
|
||||
* @param keystore the full path to the keystore
|
||||
* @param keystorePasswd the keystore password
|
||||
* @param keyPasswd the password for the key within the keystore
|
||||
* @param keystoreType the type of keystore (e.g., PKCS12, JKS)
|
||||
* @param truststore the full path to the truststore
|
||||
* @param truststorePasswd the truststore password
|
||||
|
@ -124,7 +126,7 @@ public final class SslContextFactory {
|
|||
* @param clientAuth the type of client authentication
|
||||
* @param protocol the protocol to use for the SSL connection
|
||||
*
|
||||
* @return a {@link Tuple} pairing a SSLContext instance with its TrustManagers
|
||||
* @return a {@link Tuple} pairing an SSLContext instance with its TrustManagers
|
||||
* @throws java.security.KeyStoreException if any issues accessing the keystore
|
||||
* @throws java.io.IOException for any problems loading the keystores
|
||||
* @throws java.security.NoSuchAlgorithmException if an algorithm is found to be used but is unknown
|
||||
|
@ -174,7 +176,7 @@ public final class SslContextFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a SSLContext instance using the given information. This method assumes that the key password is
|
||||
* Creates an SSLContext instance using the given information. This method assumes that the key password is
|
||||
* the same as the keystore password. If this is not the case, use the {@link #createSslContext(String, char[], char[], String, String)}
|
||||
* method instead.
|
||||
*
|
||||
|
@ -183,7 +185,7 @@ public final class SslContextFactory {
|
|||
* @param keystoreType the type of keystore (e.g., PKCS12, JKS)
|
||||
* @param protocol the protocol to use for the SSL connection
|
||||
*
|
||||
* @return a SSLContext instance
|
||||
* @return an SSLContext instance
|
||||
* @throws java.security.KeyStoreException if any issues accessing the keystore
|
||||
* @throws java.io.IOException for any problems loading the keystores
|
||||
* @throws java.security.NoSuchAlgorithmException if an algorithm is found to be used but is unknown
|
||||
|
@ -201,14 +203,15 @@ public final class SslContextFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a SSLContext instance using the given information.
|
||||
* Creates an SSLContext instance using the given information.
|
||||
*
|
||||
* @param keystore the full path to the keystore
|
||||
* @param keystorePasswd the keystore password
|
||||
* @param keyPasswd the password for the key within the keystore
|
||||
* @param keystoreType the type of keystore (e.g., PKCS12, JKS)
|
||||
* @param protocol the protocol to use for the SSL connection
|
||||
*
|
||||
* @return a SSLContext instance
|
||||
* @return an SSLContext instance
|
||||
* @throws java.security.KeyStoreException if any issues accessing the keystore
|
||||
* @throws java.io.IOException for any problems loading the keystores
|
||||
* @throws java.security.NoSuchAlgorithmException if an algorithm is found to be used but is unknown
|
||||
|
@ -224,14 +227,15 @@ public final class SslContextFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a SSLContext instance paired with its TrustManager instances using the given information.
|
||||
* Creates an SSLContext instance paired with its TrustManager instances using the given information.
|
||||
*
|
||||
* @param keystore the full path to the keystore
|
||||
* @param keystorePasswd the keystore password
|
||||
* @param keyPasswd the password for the key within the keystore
|
||||
* @param keystoreType the type of keystore (e.g., PKCS12, JKS)
|
||||
* @param protocol the protocol to use for the SSL connection
|
||||
*
|
||||
* @return a {@link Tuple} pairing a SSLContext instance paired with its TrustManager instances
|
||||
* @return a {@link Tuple} pairing an SSLContext instance paired with its TrustManager instances
|
||||
* @throws java.security.KeyStoreException if any issues accessing the keystore
|
||||
* @throws java.io.IOException for any problems loading the keystores
|
||||
* @throws java.security.NoSuchAlgorithmException if an algorithm is found to be used but is unknown
|
||||
|
@ -265,14 +269,14 @@ public final class SslContextFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a SSLContext instance using the given information.
|
||||
* Creates an SSLContext instance using the given information.
|
||||
*
|
||||
* @param truststore the full path to the truststore
|
||||
* @param truststorePasswd the truststore password
|
||||
* @param truststoreType the type of truststore (e.g., PKCS12, JKS)
|
||||
* @param protocol the protocol to use for the SSL connection
|
||||
*
|
||||
* @return a SSLContext instance
|
||||
* @return an SSLContext instance
|
||||
* @throws java.security.KeyStoreException if any issues accessing the keystore
|
||||
* @throws java.io.IOException for any problems loading the keystores
|
||||
* @throws java.security.NoSuchAlgorithmException if an algorithm is found to be used but is unknown
|
||||
|
@ -290,14 +294,14 @@ public final class SslContextFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a SSLContext instance paired with its TrustManager instances using the given information.
|
||||
* Creates an SSLContext instance paired with its TrustManager instances using the given information.
|
||||
*
|
||||
* @param truststore the full path to the truststore
|
||||
* @param truststorePasswd the truststore password
|
||||
* @param truststoreType the type of truststore (e.g., PKCS12, JKS)
|
||||
* @param protocol the protocol to use for the SSL connection
|
||||
*
|
||||
* @return a {@link Tuple} pairing a SSLContext instance paired with its TrustManager instances
|
||||
* @return a {@link Tuple} pairing an SSLContext instance paired with its TrustManager instances
|
||||
* @throws KeyStoreException if any issues accessing the keystore
|
||||
* @throws IOException for any problems loading the keystores
|
||||
* @throws NoSuchAlgorithmException if an algorithm is found to be used but is unknown
|
||||
|
@ -324,4 +328,39 @@ public final class SslContextFactory {
|
|||
|
||||
return new Tuple<>(ctx, trustManagers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an SSLContext instance paired with its TrustManager instances using the given information.
|
||||
*
|
||||
* @param keystore the full path to the keystore
|
||||
* @param keystorePasswd the keystore password
|
||||
* @param keyPasswd the password for the key within the keystore
|
||||
* @param keystoreType the type of keystore (e.g., PKCS12, JKS)
|
||||
* @param truststore the full path to the truststore
|
||||
* @param truststorePasswd the truststore password
|
||||
* @param truststoreType the type of truststore (e.g., PKCS12, JKS)
|
||||
* @param clientAuth the type of client authentication
|
||||
* @param protocol the protocol to use for the SSL connection
|
||||
*
|
||||
* @return a {@link Tuple} pairing an SSLSocketFactory instance with its TrustManagers
|
||||
*
|
||||
*/
|
||||
public static Tuple<SSLContext, TrustManager[]> createTrustSslContextWithTrustManagers(
|
||||
final String keystore, final char[] keystorePasswd, final char[] keyPasswd, final String keystoreType,
|
||||
final String truststore, final char[] truststorePasswd, final String truststoreType,
|
||||
final ClientAuth clientAuth, final String protocol) throws CertificateException, UnrecoverableKeyException,
|
||||
NoSuchAlgorithmException, KeyStoreException, KeyManagementException, IOException {
|
||||
|
||||
final Tuple<SSLContext, TrustManager[]> sslContextWithTrustManagers;
|
||||
if (keystore == null) {
|
||||
sslContextWithTrustManagers = createTrustSslContextWithTrustManagers(truststore, truststorePasswd, truststoreType, protocol);
|
||||
} else if (truststore == null) {
|
||||
sslContextWithTrustManagers = createSslContextWithTrustManagers(keystore, keystorePasswd, keyPasswd, keystoreType, protocol);
|
||||
} else {
|
||||
sslContextWithTrustManagers = createSslContextWithTrustManagers(keystore, keystorePasswd, keyPasswd, keystoreType, truststore,
|
||||
truststorePasswd, truststoreType, clientAuth, protocol);
|
||||
}
|
||||
return new Tuple<>(sslContextWithTrustManagers.getKey(), sslContextWithTrustManagers.getValue());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ language governing permissions and limitations under the License. -->
|
|||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<version>3.14.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
|
|
|
@ -36,20 +36,31 @@ import org.apache.nifi.processor.exception.ProcessException;
|
|||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.proxy.ProxyConfiguration;
|
||||
import org.apache.nifi.proxy.ProxySpec;
|
||||
import org.apache.nifi.security.util.SslContextFactory;
|
||||
import org.apache.nifi.ssl.SSLContextService;
|
||||
import org.apache.nifi.util.StringUtils;
|
||||
import org.apache.nifi.util.Tuple;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A base class for Elasticsearch processors that use the HTTP API
|
||||
|
@ -212,7 +223,25 @@ public abstract class AbstractElasticsearchHttpProcessor extends AbstractElastic
|
|||
|
||||
// check if the ssl context is set and add the factory if so
|
||||
if (sslContext != null) {
|
||||
okHttpClient.sslSocketFactory(sslContext.getSocketFactory());
|
||||
try {
|
||||
Tuple<SSLContext, TrustManager[]> sslContextTuple = SslContextFactory.createTrustSslContextWithTrustManagers(
|
||||
sslService.getKeyStoreFile(),
|
||||
sslService.getKeyStorePassword() != null ? sslService.getKeyStorePassword().toCharArray() : null,
|
||||
sslService.getKeyPassword() != null ? sslService.getKeyPassword().toCharArray() : null,
|
||||
sslService.getKeyStoreType(),
|
||||
sslService.getTrustStoreFile(),
|
||||
sslService.getTrustStorePassword() != null ? sslService.getTrustStorePassword().toCharArray() : null,
|
||||
sslService.getTrustStoreType(),
|
||||
SslContextFactory.ClientAuth.WANT,
|
||||
sslService.getSslAlgorithm()
|
||||
);
|
||||
List<X509TrustManager> x509TrustManagers = Arrays.stream(sslContextTuple.getValue())
|
||||
.filter(trustManager -> trustManager instanceof X509TrustManager)
|
||||
.map(trustManager -> (X509TrustManager) trustManager).collect(Collectors.toList());
|
||||
okHttpClient.sslSocketFactory(sslContextTuple.getKey().getSocketFactory(), x509TrustManagers.get(0));
|
||||
} catch (CertificateException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException | IOException e) {
|
||||
throw new ProcessException(e);
|
||||
}
|
||||
}
|
||||
|
||||
okHttpClientAtomicReference.set(okHttpClient.build());
|
||||
|
|
|
@ -257,7 +257,7 @@ public class TestQueryElasticsearchHttpNoHits {
|
|||
if (expectHitCountOnQueryInfo) {
|
||||
out.assertAttributeEquals("es.query.hitcount", String.valueOf(expectedHits));
|
||||
}
|
||||
Assert.assertTrue(out.getAttribute("es.query.url").startsWith("http://127.0.0.1:9200/doc/status/_search?q=source:Twitter%20AND%20identifier:%22%22&size=2"));
|
||||
Assert.assertTrue(out.getAttribute("es.query.url").startsWith("http://127.0.0.1:9200/doc/status/_search?q=source%3ATwitter%20AND%20identifier%3A%22%22&size=2"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,16 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -39,12 +43,9 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.core.MultivaluedHashMap;
|
||||
|
@ -70,6 +71,9 @@ import org.apache.nifi.util.Tuple;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StreamUtils;
|
||||
// Using static imports because of the name conflict:
|
||||
import static org.apache.nifi.security.util.SslContextFactory.ClientAuth.WANT;
|
||||
import static org.apache.nifi.security.util.SslContextFactory.createTrustSslContextWithTrustManagers;
|
||||
|
||||
public class OkHttpReplicationClient implements HttpReplicationClient {
|
||||
private static final Logger logger = LoggerFactory.getLogger(OkHttpReplicationClient.class);
|
||||
|
@ -103,7 +107,8 @@ public class OkHttpReplicationClient implements HttpReplicationClient {
|
|||
|
||||
/**
|
||||
* Checks the content length header on DELETE requests to ensure it is set to '0', avoiding request timeouts on replicated requests.
|
||||
* @param method the HTTP method of the request
|
||||
*
|
||||
* @param method the HTTP method of the request
|
||||
* @param headers the header keys and values
|
||||
*/
|
||||
private void checkContentLengthHeader(String method, Map<String, String> headers) {
|
||||
|
@ -327,57 +332,22 @@ public class OkHttpReplicationClient implements HttpReplicationClient {
|
|||
}
|
||||
|
||||
try {
|
||||
final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
|
||||
|
||||
// initialize the KeyManager array to null and we will overwrite later if a keystore is loaded
|
||||
KeyManager[] keyManagers = null;
|
||||
|
||||
// we will only initialize the keystore if properties have been supplied by the SSLContextService
|
||||
final String keystoreLocation = properties.getProperty(NiFiProperties.SECURITY_KEYSTORE);
|
||||
final String keystorePass = properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD);
|
||||
final String keystoreType = properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_TYPE);
|
||||
|
||||
// prepare the keystore
|
||||
final KeyStore keyStore = KeyStore.getInstance(keystoreType);
|
||||
|
||||
try (FileInputStream keyStoreStream = new FileInputStream(keystoreLocation)) {
|
||||
keyStore.load(keyStoreStream, keystorePass.toCharArray());
|
||||
}
|
||||
|
||||
keyManagerFactory.init(keyStore, keystorePass.toCharArray());
|
||||
keyManagers = keyManagerFactory.getKeyManagers();
|
||||
|
||||
// we will only initialize the truststure if properties have been supplied by the SSLContextService
|
||||
// load truststore
|
||||
final String truststoreLocation = properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE);
|
||||
final String truststorePass = properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD);
|
||||
final String truststoreType = properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_TYPE);
|
||||
|
||||
KeyStore truststore = KeyStore.getInstance(truststoreType);
|
||||
truststore.load(new FileInputStream(truststoreLocation), truststorePass.toCharArray());
|
||||
trustManagerFactory.init(truststore);
|
||||
|
||||
// TrustManagerFactory.getTrustManagers returns a trust manager for each type of trust material. Since we are getting a trust manager factory that uses "X509"
|
||||
// as it's trust management algorithm, we are able to grab the first (and thus the most preferred) and use it as our x509 Trust Manager
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/TrustManagerFactory.html#getTrustManagers--
|
||||
final X509TrustManager x509TrustManager;
|
||||
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
|
||||
if (trustManagers[0] != null) {
|
||||
x509TrustManager = (X509TrustManager) trustManagers[0];
|
||||
} else {
|
||||
throw new IllegalStateException("List of trust managers is null");
|
||||
}
|
||||
|
||||
// if keystore properties were not supplied, the keyManagers array will be null
|
||||
sslContext.init(keyManagers, trustManagerFactory.getTrustManagers(), null);
|
||||
|
||||
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
||||
return new Tuple<>(sslSocketFactory, x509TrustManager);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Failed to create SSL Socket Factory for replicating requests across the cluster");
|
||||
Tuple<SSLContext, TrustManager[]> sslContextTuple = createTrustSslContextWithTrustManagers(
|
||||
properties.getProperty(NiFiProperties.SECURITY_KEYSTORE),
|
||||
properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD) != null ? properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD).toCharArray() : null,
|
||||
properties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD) != null ? properties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD).toCharArray() : null,
|
||||
properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_TYPE),
|
||||
properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE),
|
||||
properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD) != null ? properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD).toCharArray() : null,
|
||||
properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_TYPE),
|
||||
WANT,
|
||||
sslContext.getProtocol());
|
||||
List<X509TrustManager> x509TrustManagers = Arrays.stream(sslContextTuple.getValue())
|
||||
.filter(trustManager -> trustManager instanceof X509TrustManager)
|
||||
.map(trustManager -> (X509TrustManager) trustManager).collect(Collectors.toList());
|
||||
return new Tuple<>(sslContextTuple.getKey().getSocketFactory(), x509TrustManagers.get(0));
|
||||
} catch (CertificateException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException | IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.framework.security.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
|
||||
/**
|
||||
* Implements a server socket factory for creating secure server sockets based
|
||||
* on the application's configuration properties. If the properties are
|
||||
* configured for SSL (one-way or two-way), then a SSLServerSocketFactory is
|
||||
* created and used based on those properties. Otherwise, Java's default
|
||||
* SSLServerSocketFactory is used. Specifically,
|
||||
* SSLContext.getDefault().getServerSocketFactory().
|
||||
*/
|
||||
public class SslServerSocketFactory extends SSLServerSocketFactory {
|
||||
|
||||
private SSLServerSocketFactory sslServerSocketFactory;
|
||||
|
||||
public SslServerSocketFactory(final NiFiProperties nifiProperties) {
|
||||
final SSLContext sslCtx = SslContextFactory.createSslContext(nifiProperties);
|
||||
if (sslCtx == null) {
|
||||
try {
|
||||
sslServerSocketFactory = SSLContext.getDefault().getServerSocketFactory();
|
||||
} catch (final NoSuchAlgorithmException nsae) {
|
||||
throw new SslServerSocketFactoryCreationException(nsae);
|
||||
}
|
||||
} else {
|
||||
sslServerSocketFactory = sslCtx.getServerSocketFactory();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSocket createServerSocket(int i, int i1, InetAddress ia) throws IOException {
|
||||
return sslServerSocketFactory.createServerSocket(i, i1, ia);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSocket createServerSocket(int i, int i1) throws IOException {
|
||||
return sslServerSocketFactory.createServerSocket(i, i1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSocket createServerSocket(int i) throws IOException {
|
||||
return sslServerSocketFactory.createServerSocket(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSocket createServerSocket() throws IOException {
|
||||
return sslServerSocketFactory.createServerSocket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedCipherSuites() {
|
||||
return sslServerSocketFactory.getSupportedCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDefaultCipherSuites() {
|
||||
return sslServerSocketFactory.getDefaultCipherSuites();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.framework.security.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
|
||||
/**
|
||||
* Implements a socket factory for creating secure sockets based on the
|
||||
* application's configuration properties. If the properties are configured for
|
||||
* SSL (one-way or two-way), then a SSLSocketFactory is created and used based
|
||||
* on those properties. Otherwise, Java's default SSLSocketFactory is used.
|
||||
* Specifically, SSLContext.getDefault().getSocketFactory().
|
||||
*/
|
||||
public class SslSocketFactory extends SSLSocketFactory {
|
||||
|
||||
private final SSLSocketFactory sslSocketFactory;
|
||||
|
||||
public SslSocketFactory(final NiFiProperties nifiProperties) {
|
||||
final SSLContext sslCtx = SslContextFactory.createSslContext(nifiProperties);
|
||||
if (sslCtx == null) {
|
||||
try {
|
||||
sslSocketFactory = SSLContext.getDefault().getSocketFactory();
|
||||
} catch (final NoSuchAlgorithmException nsae) {
|
||||
throw new SslSocketFactoryCreationException(nsae);
|
||||
}
|
||||
} else {
|
||||
sslSocketFactory = sslCtx.getSocketFactory();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedCipherSuites() {
|
||||
return sslSocketFactory.getSupportedCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDefaultCipherSuites() {
|
||||
return sslSocketFactory.getDefaultCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException {
|
||||
return sslSocketFactory.createSocket(socket, string, i, bln);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException {
|
||||
return sslSocketFactory.createSocket(ia, i, ia1, i1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress ia, int i) throws IOException {
|
||||
return sslSocketFactory.createSocket(ia, i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException, UnknownHostException {
|
||||
return sslSocketFactory.createSocket(string, i, ia, i1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String string, int i) throws IOException, UnknownHostException {
|
||||
return sslSocketFactory.createSocket(string, i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket() throws IOException {
|
||||
return sslSocketFactory.createSocket();
|
||||
}
|
||||
|
||||
}
|
|
@ -55,6 +55,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
|
@ -104,9 +105,11 @@ import org.apache.nifi.processors.standard.util.ProxyAuthenticator;
|
|||
import org.apache.nifi.processors.standard.util.SoftLimitBoundedByteArrayOutputStream;
|
||||
import org.apache.nifi.proxy.ProxyConfiguration;
|
||||
import org.apache.nifi.proxy.ProxySpec;
|
||||
import org.apache.nifi.security.util.SslContextFactory;
|
||||
import org.apache.nifi.ssl.SSLContextService;
|
||||
import org.apache.nifi.ssl.SSLContextService.ClientAuth;
|
||||
import org.apache.nifi.stream.io.StreamUtils;
|
||||
import org.apache.nifi.util.Tuple;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
|
@ -634,8 +637,21 @@ public final class InvokeHTTP extends AbstractProcessor {
|
|||
|
||||
// check if the ssl context is set and add the factory if so
|
||||
if (sslContext != null) {
|
||||
setSslSocketFactory(okHttpClientBuilder, sslService, sslContext, isHttpsProxy);
|
||||
}
|
||||
Tuple<SSLContext, TrustManager[]> sslContextTuple =SslContextFactory.createTrustSslContextWithTrustManagers(
|
||||
sslService.getKeyStoreFile(),
|
||||
sslService.getKeyStorePassword() != null ? sslService.getKeyStorePassword().toCharArray() : null,
|
||||
sslService.getKeyPassword() != null ? sslService.getKeyPassword().toCharArray() : null,
|
||||
sslService.getKeyStoreType(),
|
||||
sslService.getTrustStoreFile(),
|
||||
sslService.getTrustStorePassword() != null ? sslService.getTrustStorePassword().toCharArray() : null,
|
||||
sslService.getTrustStoreType(),
|
||||
SslContextFactory.ClientAuth.NONE,
|
||||
sslService.getSslAlgorithm());
|
||||
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));
|
||||
}
|
||||
|
||||
setAuthenticator(okHttpClientBuilder, context);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.apache.nifi.components.Validator;
|
|||
import org.apache.nifi.controller.AbstractControllerService;
|
||||
import org.apache.nifi.controller.ConfigurationContext;
|
||||
import org.apache.nifi.expression.ExpressionLanguageScope;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.proxy.ProxyConfiguration;
|
||||
import org.apache.nifi.proxy.ProxyConfigurationService;
|
||||
|
@ -48,6 +49,7 @@ import org.apache.nifi.record.path.FieldValue;
|
|||
import org.apache.nifi.record.path.RecordPath;
|
||||
import org.apache.nifi.record.path.validation.RecordPathValidator;
|
||||
import org.apache.nifi.schema.access.SchemaNotFoundException;
|
||||
import org.apache.nifi.security.util.SslContextFactory;
|
||||
import org.apache.nifi.serialization.MalformedRecordException;
|
||||
import org.apache.nifi.serialization.RecordReader;
|
||||
import org.apache.nifi.serialization.RecordReaderFactory;
|
||||
|
@ -57,12 +59,20 @@ import org.apache.nifi.serialization.record.Record;
|
|||
import org.apache.nifi.serialization.record.RecordSchema;
|
||||
import org.apache.nifi.ssl.SSLContextService;
|
||||
import org.apache.nifi.util.StringUtils;
|
||||
import org.apache.nifi.util.Tuple;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Proxy;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -231,9 +241,33 @@ public class RestLookupService extends AbstractControllerService implements Reco
|
|||
}
|
||||
|
||||
final SSLContextService sslService = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class);
|
||||
final SSLContext sslContext = sslService == null ? null : sslService.createSSLContext(SSLContextService.ClientAuth.WANT);
|
||||
if (sslService != null) {
|
||||
builder.sslSocketFactory(sslContext.getSocketFactory());
|
||||
Tuple<SSLContext, TrustManager[]> sslContextTuple = null;
|
||||
try {
|
||||
sslContextTuple = SslContextFactory.createTrustSslContextWithTrustManagers(
|
||||
sslService.getKeyStoreFile(),
|
||||
sslService.getKeyStorePassword() != null ? sslService.getKeyStorePassword().toCharArray() : null,
|
||||
sslService.getKeyPassword() != null ? sslService.getKeyPassword().toCharArray() : null,
|
||||
sslService.getKeyStoreType(),
|
||||
sslService.getTrustStoreFile(),
|
||||
sslService.getTrustStorePassword() != null ? sslService.getTrustStorePassword().toCharArray() : null,
|
||||
sslService.getTrustStoreType(),
|
||||
SslContextFactory.ClientAuth.WANT,
|
||||
sslService.getSslAlgorithm()
|
||||
);
|
||||
} catch (CertificateException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException | IOException e) {
|
||||
throw new ProcessException(e);
|
||||
}
|
||||
List<X509TrustManager> x509TrustManagers = Arrays.stream(sslContextTuple.getValue())
|
||||
.filter(trustManager -> trustManager instanceof X509TrustManager)
|
||||
.map(trustManager -> (X509TrustManager) trustManager).collect(Collectors.toList());
|
||||
builder.sslSocketFactory(sslContextTuple.getKey().getSocketFactory(), x509TrustManagers.get(0));
|
||||
|
||||
if (sslContextTuple.getValue().length > 0) {
|
||||
builder.sslSocketFactory(sslContextTuple.getKey().getSocketFactory(), (X509TrustManager) sslContextTuple.getValue()[0]);
|
||||
} else {
|
||||
throw new ProcessException("Failed to create SSL socket factory with trust manager.");
|
||||
}
|
||||
}
|
||||
|
||||
client = builder.build();
|
||||
|
|
Loading…
Reference in New Issue