NIFI-1163: Providing handling of SSLContext creation in GetHTTP in case of only performing a one-way SSL request and accompanying test to verify the configuration/usage.

Reviewed by Tony Kurc (tkurc@apache.org)
This commit is contained in:
Aldrin Piri 2015-11-14 18:43:49 -05:00 committed by Tony Kurc
parent 90f6830003
commit 01539ed323
2 changed files with 92 additions and 40 deletions

View File

@ -49,6 +49,7 @@ import java.util.regex.Pattern;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
@ -64,11 +65,11 @@ import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.nifi.annotation.behavior.InputRequirement; import org.apache.nifi.annotation.behavior.InputRequirement;
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement; import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
import org.apache.nifi.annotation.behavior.WritesAttribute; import org.apache.nifi.annotation.behavior.WritesAttribute;
@ -320,19 +321,26 @@ public class GetHTTP extends AbstractSessionFactoryProcessor {
private SSLContext createSSLContext(final SSLContextService service) private SSLContext createSSLContext(final SSLContextService service)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, KeyManagementException, UnrecoverableKeyException { throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, KeyManagementException, UnrecoverableKeyException {
final SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
if (StringUtils.isNotBlank(service.getTrustStoreFile())) {
final KeyStore truststore = KeyStore.getInstance(service.getTrustStoreType()); final KeyStore truststore = KeyStore.getInstance(service.getTrustStoreType());
try (final InputStream in = new FileInputStream(new File(service.getTrustStoreFile()))) { try (final InputStream in = new FileInputStream(new File(service.getTrustStoreFile()))) {
truststore.load(in, service.getTrustStorePassword().toCharArray()); truststore.load(in, service.getTrustStorePassword().toCharArray());
} }
sslContextBuilder.loadTrustMaterial(truststore, new TrustSelfSignedStrategy());
}
if (StringUtils.isNotBlank(service.getKeyStoreFile())){
final KeyStore keystore = KeyStore.getInstance(service.getKeyStoreType()); final KeyStore keystore = KeyStore.getInstance(service.getKeyStoreType());
try (final InputStream in = new FileInputStream(new File(service.getKeyStoreFile()))) { try (final InputStream in = new FileInputStream(new File(service.getKeyStoreFile()))) {
keystore.load(in, service.getKeyStorePassword().toCharArray()); keystore.load(in, service.getKeyStorePassword().toCharArray());
} }
sslContextBuilder.loadKeyMaterial(keystore, service.getKeyStorePassword().toCharArray());
}
final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(truststore, new TrustSelfSignedStrategy()).loadKeyMaterial(keystore, service.getKeyStorePassword().toCharArray()).build(); return sslContextBuilder.build();
return sslContext;
} }
@Override @Override

View File

@ -317,48 +317,27 @@ public class TestGetHTTP {
} }
} }
private Map<String, String> getSslProperties() {
Map<String, String> props = new HashMap<String, String>();
props.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
props.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
props.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
props.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
props.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "localtest");
props.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
return props;
}
private void useSSLContextService() {
final SSLContextService service = new StandardSSLContextService();
try {
controller.addControllerService("ssl-service", service, getSslProperties());
controller.enableControllerService(service);
} catch (InitializationException ex) {
ex.printStackTrace();
Assert.fail("Could not create SSL Context Service");
}
controller.setProperty(GetHTTP.SSL_CONTEXT_SERVICE, "ssl-service");
}
@Test @Test
public final void testSecure() throws Exception { public final void testSecure_oneWaySsl() throws Exception {
// set up web service // set up web service
ServletHandler handler = new ServletHandler(); final ServletHandler handler = new ServletHandler();
handler.addServletWithMapping(HelloWorldServlet.class, "/*"); handler.addServletWithMapping(HelloWorldServlet.class, "/*");
// create the service // create the service, disabling the need for client auth
TestServer server = new TestServer(getSslProperties()); final Map<String, String> serverSslProperties = getKeystoreProperties();
serverSslProperties.put(TestServer.NEED_CLIENT_AUTH, Boolean.toString(false));
final TestServer server = new TestServer(serverSslProperties);
server.addHandler(handler); server.addHandler(handler);
try { try {
server.startServer(); server.startServer();
String destination = server.getSecureUrl(); final String destination = server.getSecureUrl();
// set up NiFi mock controller // set up NiFi mock controller
controller = TestRunners.newTestRunner(GetHTTP.class); controller = TestRunners.newTestRunner(GetHTTP.class);
useSSLContextService(); // Use context service with only a truststore
useSSLContextService(getTruststoreProperties());
controller.setProperty(GetHTTP.CONNECTION_TIMEOUT, "5 secs"); controller.setProperty(GetHTTP.CONNECTION_TIMEOUT, "5 secs");
controller.setProperty(GetHTTP.URL, destination); controller.setProperty(GetHTTP.URL, destination);
@ -374,4 +353,69 @@ public class TestGetHTTP {
} }
} }
@Test
public final void testSecure_twoWaySsl() throws Exception {
// set up web service
final ServletHandler handler = new ServletHandler();
handler.addServletWithMapping(HelloWorldServlet.class, "/*");
// create the service, providing both truststore and keystore properties, requiring client auth (default)
final Map<String, String> twoWaySslProperties = getKeystoreProperties();
twoWaySslProperties.putAll(getTruststoreProperties());
final TestServer server = new TestServer(twoWaySslProperties);
server.addHandler(handler);
try {
server.startServer();
final String destination = server.getSecureUrl();
// set up NiFi mock controller
controller = TestRunners.newTestRunner(GetHTTP.class);
// Use context service with a keystore and a truststore
useSSLContextService(twoWaySslProperties);
controller.setProperty(GetHTTP.CONNECTION_TIMEOUT, "5 secs");
controller.setProperty(GetHTTP.URL, destination);
controller.setProperty(GetHTTP.FILENAME, "testFile");
controller.setProperty(GetHTTP.ACCEPT_CONTENT_TYPE, "application/json");
controller.run();
controller.assertAllFlowFilesTransferred(GetHTTP.REL_SUCCESS, 1);
final MockFlowFile mff = controller.getFlowFilesForRelationship(GetHTTP.REL_SUCCESS).get(0);
mff.assertContentEquals("Hello, World!");
} finally {
server.shutdownServer();
}
}
private static Map<String, String> getTruststoreProperties() {
final Map<String, String> props = new HashMap<>();
props.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
props.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "localtest");
props.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
return props;
}
private static Map<String, String> getKeystoreProperties() {
final Map<String, String> properties = new HashMap<>();
properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
return properties;
}
private void useSSLContextService(final Map<String, String> sslProperties) {
final SSLContextService service = new StandardSSLContextService();
try {
controller.addControllerService("ssl-service", service, sslProperties);
controller.enableControllerService(service);
} catch (InitializationException ex) {
ex.printStackTrace();
Assert.fail("Could not create SSL Context Service");
}
controller.setProperty(GetHTTP.SSL_CONTEXT_SERVICE, "ssl-service");
}
} }