mirror of
https://github.com/apache/nifi.git
synced 2025-02-28 14:39:10 +00:00
NIFI-9228 Refactored tests to use generated KeyStores
- Refactored multiple tests using KeyStoreUtils - Removed static KeyStore and TrustStore files Signed-off-by: Matthew Burgess <mattyb149@apache.org> This closes #5401
This commit is contained in:
parent
2e998839eb
commit
ba775d28de
@ -96,11 +96,6 @@
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.esotericsoftware.kryo</groupId>
|
||||
<artifactId>kryo</artifactId>
|
||||
|
@ -22,6 +22,7 @@ import static org.apache.nifi.remote.protocol.http.HttpHeaders.LOCATION_URI_INTE
|
||||
import static org.apache.nifi.remote.protocol.http.HttpHeaders.LOCATION_URI_INTENT_VALUE;
|
||||
import static org.apache.nifi.remote.protocol.http.HttpHeaders.PROTOCOL_VERSION;
|
||||
import static org.apache.nifi.remote.protocol.http.HttpHeaders.SERVER_SIDE_TRANSACTION_TTL;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@ -31,12 +32,14 @@ import static org.junit.Assume.assumeFalse;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URI;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
@ -65,6 +68,7 @@ import org.apache.nifi.remote.protocol.SiteToSiteTransportProtocol;
|
||||
import org.apache.nifi.remote.protocol.http.HttpHeaders;
|
||||
import org.apache.nifi.remote.protocol.http.HttpProxy;
|
||||
import org.apache.nifi.remote.util.StandardDataPacket;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.TlsConfiguration;
|
||||
import org.apache.nifi.stream.io.StreamUtils;
|
||||
import org.apache.nifi.web.api.dto.ControllerDTO;
|
||||
@ -116,6 +120,8 @@ public class TestHttpClient {
|
||||
private static Set<PeerDTO> peersSecure;
|
||||
private static String serverChecksum;
|
||||
|
||||
private static TlsConfiguration tlsConfiguration;
|
||||
|
||||
public static class SiteInfoServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
@ -181,7 +187,7 @@ public class TestHttpClient {
|
||||
public static class PortTransactionsServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
|
||||
final int reqProtocolVersion = getReqProtocolVersion(req);
|
||||
|
||||
@ -201,7 +207,7 @@ public class TestHttpClient {
|
||||
public static class PortTransactionsAccessDeniedServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
|
||||
respondWithText(resp, "Unable to perform the desired action" +
|
||||
" due to insufficient permissions. Contact the system administrator.", 403);
|
||||
@ -213,7 +219,7 @@ public class TestHttpClient {
|
||||
public static class InputPortTransactionServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
final int reqProtocolVersion = getReqProtocolVersion(req);
|
||||
|
||||
final TransactionResultEntity entity = new TransactionResultEntity();
|
||||
@ -226,7 +232,7 @@ public class TestHttpClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
|
||||
final int reqProtocolVersion = getReqProtocolVersion(req);
|
||||
|
||||
@ -244,7 +250,7 @@ public class TestHttpClient {
|
||||
public static class OutputPortTransactionServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
final int reqProtocolVersion = getReqProtocolVersion(req);
|
||||
|
||||
final TransactionResultEntity entity = new TransactionResultEntity();
|
||||
@ -257,7 +263,7 @@ public class TestHttpClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
|
||||
final int reqProtocolVersion = getReqProtocolVersion(req);
|
||||
|
||||
@ -332,7 +338,7 @@ public class TestHttpClient {
|
||||
public static class FlowFilesTimeoutAfterDataExchangeServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
|
||||
final int reqProtocolVersion = getReqProtocolVersion(req);
|
||||
|
||||
@ -398,7 +404,7 @@ public class TestHttpClient {
|
||||
|
||||
private static int getReqProtocolVersion(HttpServletRequest req) {
|
||||
final String reqProtocolVersionStr = req.getHeader(PROTOCOL_VERSION);
|
||||
assertTrue(!isEmpty(reqProtocolVersionStr));
|
||||
assertFalse(isEmpty(reqProtocolVersionStr));
|
||||
return Integer.parseInt(reqProtocolVersionStr);
|
||||
}
|
||||
|
||||
@ -454,11 +460,12 @@ public class TestHttpClient {
|
||||
wrongPathContextHandler.insertHandler(wrongPathServletHandler);
|
||||
|
||||
final SslContextFactory sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/certs/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("passwordpassword");
|
||||
sslContextFactory.setKeyStoreType("JKS");
|
||||
|
||||
setTlsConfiguration();
|
||||
sslContextFactory.setKeyStorePath(tlsConfiguration.getKeystorePath());
|
||||
sslContextFactory.setKeyStorePassword(tlsConfiguration.getKeystorePassword());
|
||||
sslContextFactory.setKeyStoreType(tlsConfiguration.getKeystoreType().getType());
|
||||
sslContextFactory.setProtocol(TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
|
||||
sslContextFactory.setExcludeProtocols("TLS", "TLSv1", "TLSv1.1");
|
||||
|
||||
httpConnector = new ServerConnector(server);
|
||||
|
||||
@ -597,10 +604,6 @@ public class TestHttpClient {
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
|
||||
System.setProperty("org.slf4j.simpleLogger.log.org.apache.nifi.remote", "TRACE");
|
||||
System.setProperty("org.slf4j.simpleLogger.log.org.apache.nifi.remote.protocol.http.HttpClientTransaction", "DEBUG");
|
||||
|
||||
testCaseFinished = new CountDownLatch(1);
|
||||
|
||||
final PeerDTO peer = new PeerDTO();
|
||||
@ -693,13 +696,12 @@ public class TestHttpClient {
|
||||
return new SiteToSiteClient.Builder().transportProtocol(SiteToSiteTransportProtocol.HTTP)
|
||||
.url("https://localhost:" + sslConnector.getLocalPort() + "/nifi")
|
||||
.timeout(3, TimeUnit.MINUTES)
|
||||
.keystoreFilename("src/test/resources/certs/keystore.jks")
|
||||
.keystorePass("passwordpassword")
|
||||
.keystoreType(KeystoreType.JKS)
|
||||
.truststoreFilename("src/test/resources/certs/truststore.jks")
|
||||
.truststorePass("passwordpassword")
|
||||
.truststoreType(KeystoreType.JKS)
|
||||
;
|
||||
.keystoreFilename(tlsConfiguration.getKeystorePath())
|
||||
.keystorePass(tlsConfiguration.getKeystorePassword())
|
||||
.keystoreType(KeystoreType.valueOf(tlsConfiguration.getKeystoreType().getType()))
|
||||
.truststoreFilename(tlsConfiguration.getTruststorePath())
|
||||
.truststorePass(tlsConfiguration.getTruststorePassword())
|
||||
.truststoreType(KeystoreType.valueOf(tlsConfiguration.getTruststoreType().getType()));
|
||||
}
|
||||
|
||||
private static void consumeDataPacket(DataPacket packet) throws IOException {
|
||||
@ -1400,4 +1402,9 @@ public class TestHttpClient {
|
||||
}
|
||||
}
|
||||
|
||||
private static void setTlsConfiguration() throws GeneralSecurityException, IOException {
|
||||
tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
|
||||
new File(tlsConfiguration.getKeystorePath()).deleteOnExit();
|
||||
new File(tlsConfiguration.getTruststorePath()).deleteOnExit();
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>%-4r [%t] %-5p %c{3} - %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>./target/log</file>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>%date %level [%thread] %logger{40} %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="org.apache.nifi" level="INFO"/>
|
||||
<logger name="org.apache.nifi.remote.client" level="INFO"/>
|
||||
<logger name="org.apache.nifi.remote.client.PeerSelectorTest" level="DEBUG"/>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
@ -1,318 +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.elasticsearch.integration
|
||||
|
||||
import org.apache.nifi.elasticsearch.DeleteOperationResponse
|
||||
import org.apache.nifi.elasticsearch.ElasticSearchClientService
|
||||
import org.apache.nifi.elasticsearch.ElasticSearchClientServiceImpl
|
||||
import org.apache.nifi.elasticsearch.IndexOperationRequest
|
||||
import org.apache.nifi.elasticsearch.IndexOperationResponse
|
||||
import org.apache.nifi.elasticsearch.SearchResponse
|
||||
import org.apache.nifi.security.util.KeystoreType
|
||||
import org.apache.nifi.ssl.StandardSSLContextService
|
||||
import org.apache.nifi.util.StringUtils
|
||||
import org.apache.nifi.util.TestRunner
|
||||
import org.apache.nifi.util.TestRunners
|
||||
import org.junit.After
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
import static groovy.json.JsonOutput.prettyPrint
|
||||
import static groovy.json.JsonOutput.toJson
|
||||
|
||||
class ElasticSearch5ClientService_IT {
|
||||
|
||||
private TestRunner runner
|
||||
private ElasticSearchClientServiceImpl service
|
||||
|
||||
static String INDEX = "messages"
|
||||
static String TYPE = StringUtils.isNotBlank(System.getProperty("type_name")) ? System.getProperty("type_name") : null;
|
||||
|
||||
@Before
|
||||
void before() throws Exception {
|
||||
runner = TestRunners.newTestRunner(TestControllerServiceProcessor.class)
|
||||
service = new ElasticSearchClientServiceImpl()
|
||||
runner.addControllerService("Client Service", service)
|
||||
runner.setProperty(service, ElasticSearchClientService.HTTP_HOSTS, "http://localhost:9400")
|
||||
runner.setProperty(service, ElasticSearchClientService.CONNECT_TIMEOUT, "10000")
|
||||
runner.setProperty(service, ElasticSearchClientService.SOCKET_TIMEOUT, "60000")
|
||||
runner.setProperty(service, ElasticSearchClientService.RETRY_TIMEOUT, "60000")
|
||||
runner.setProperty(service, ElasticSearchClientService.SUPPRESS_NULLS, ElasticSearchClientService.ALWAYS_SUPPRESS.getValue())
|
||||
try {
|
||||
runner.enableControllerService(service)
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace()
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
void after() throws Exception {
|
||||
service.onDisabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBasicSearch() throws Exception {
|
||||
String query = prettyPrint(toJson([
|
||||
size: 10,
|
||||
query: [
|
||||
match_all: [:]
|
||||
],
|
||||
aggs: [
|
||||
term_counts: [
|
||||
terms: [
|
||||
field: "msg",
|
||||
size: 5
|
||||
]
|
||||
]
|
||||
]
|
||||
]))
|
||||
|
||||
|
||||
SearchResponse response = service.search(query, "messages", TYPE)
|
||||
Assert.assertNotNull("Response was null", response)
|
||||
|
||||
Assert.assertEquals("Wrong count", 15, response.numberOfHits)
|
||||
Assert.assertFalse("Timed out", response.isTimedOut())
|
||||
Assert.assertNotNull("Hits was null", response.getHits())
|
||||
Assert.assertEquals("Wrong number of hits", 10, response.hits.size())
|
||||
Assert.assertNotNull("Aggregations are missing", response.aggregations)
|
||||
Assert.assertEquals("Aggregation count is wrong", 1, response.aggregations.size())
|
||||
|
||||
Map termCounts = response.aggregations.get("term_counts")
|
||||
Assert.assertNotNull("Term counts was missing", termCounts)
|
||||
def buckets = termCounts.get("buckets")
|
||||
Assert.assertNotNull("Buckets branch was empty", buckets)
|
||||
def expected = [
|
||||
"one": 1,
|
||||
"two": 2,
|
||||
"three": 3,
|
||||
"four": 4,
|
||||
"five": 5
|
||||
]
|
||||
|
||||
buckets.each { aggRes ->
|
||||
def key = aggRes["key"]
|
||||
def docCount = aggRes["doc_count"]
|
||||
Assert.assertEquals("${key} did not match.", expected[key], docCount)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteByQuery() throws Exception {
|
||||
String query = prettyPrint(toJson([
|
||||
query: [
|
||||
match: [
|
||||
msg: "five"
|
||||
]
|
||||
]
|
||||
]))
|
||||
DeleteOperationResponse response = service.deleteByQuery(query, INDEX, TYPE)
|
||||
Assert.assertNotNull(response)
|
||||
Assert.assertTrue(response.getTook() > 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteById() throws Exception {
|
||||
final String ID = "1"
|
||||
DeleteOperationResponse response = service.deleteById(INDEX, TYPE, ID)
|
||||
Assert.assertNotNull(response)
|
||||
Assert.assertTrue(response.getTook() > 0)
|
||||
def doc = service.get(INDEX, TYPE, ID)
|
||||
Assert.assertNull(doc)
|
||||
doc = service.get(INDEX, TYPE, "2")
|
||||
Assert.assertNotNull(doc)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGet() throws IOException {
|
||||
Map old
|
||||
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "TYPE: " + TYPE + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
|
||||
1.upto(15) { index ->
|
||||
String id = String.valueOf(index)
|
||||
def doc = service.get(INDEX, TYPE, id)
|
||||
Assert.assertNotNull("Doc was null", doc)
|
||||
Assert.assertNotNull("${doc.toString()}\t${doc.keySet().toString()}", doc.get("msg"))
|
||||
old = doc
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSSL() {
|
||||
def sslContext = new StandardSSLContextService()
|
||||
runner.setProperty(TestControllerServiceProcessor.CLIENT_SERVICE, "Client Service")
|
||||
runner.disableControllerService(service)
|
||||
runner.addControllerService("sslContext", sslContext)
|
||||
runner.setProperty(sslContext, StandardSSLContextService.TRUSTSTORE, "src/test/resources/truststore.jks")
|
||||
runner.setProperty(sslContext, StandardSSLContextService.TRUSTSTORE_PASSWORD, "2DZ5i7yvbG2GA3Ld4yiAsH62QDqAjWt4ToCU0yHajwM")
|
||||
runner.setProperty(sslContext, StandardSSLContextService.TRUSTSTORE_TYPE, KeystoreType.JKS.getType())
|
||||
runner.setProperty(service, ElasticSearchClientService.PROP_SSL_CONTEXT_SERVICE, "sslContext")
|
||||
runner.enableControllerService(sslContext)
|
||||
runner.enableControllerService(service)
|
||||
runner.assertValid()
|
||||
|
||||
runner.disableControllerService(service)
|
||||
runner.disableControllerService(sslContext)
|
||||
runner.setProperty(sslContext, StandardSSLContextService.KEYSTORE, "src/test/resources/keystore.jks")
|
||||
runner.setProperty(sslContext, StandardSSLContextService.KEYSTORE_PASSWORD, "pben4DTOUhLDI8mZiCHNX1dGEAWrpGnSYX38FTvmaeU")
|
||||
runner.setProperty(sslContext, StandardSSLContextService.KEYSTORE_TYPE, KeystoreType.JKS.getType())
|
||||
runner.enableControllerService(sslContext)
|
||||
runner.enableControllerService(service)
|
||||
|
||||
runner.assertValid()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNullSuppression() {
|
||||
Map<String, Object> doc = new HashMap<String, Object>(){{
|
||||
put("msg", "test")
|
||||
put("is_null", null)
|
||||
put("is_empty", "")
|
||||
put("is_blank", " ")
|
||||
put("empty_nested", Collections.emptyMap())
|
||||
put("empty_array", Collections.emptyList())
|
||||
}}
|
||||
|
||||
// index with nulls
|
||||
suppressNulls(false)
|
||||
IndexOperationResponse response = service.bulk([new IndexOperationRequest("nulls", TYPE, "1", doc, IndexOperationRequest.Operation.Index)])
|
||||
Assert.assertNotNull(response)
|
||||
Assert.assertTrue(response.getTook() > 0)
|
||||
Thread.sleep(2000)
|
||||
|
||||
Map<String, Object> result = service.get("nulls", TYPE, "1")
|
||||
Assert.assertEquals(doc, result)
|
||||
|
||||
// suppress nulls
|
||||
suppressNulls(true)
|
||||
response = service.bulk([new IndexOperationRequest("nulls", TYPE, "2", doc, IndexOperationRequest.Operation.Index)])
|
||||
Assert.assertNotNull(response)
|
||||
Assert.assertTrue(response.getTook() > 0)
|
||||
Thread.sleep(2000)
|
||||
|
||||
result = service.get("nulls", TYPE, "2")
|
||||
Assert.assertTrue("Non-nulls (present): " + result.toString(), result.keySet().containsAll(["msg", "is_blank"]))
|
||||
Assert.assertFalse("is_null (should be omitted): " + result.toString(), result.keySet().contains("is_null"))
|
||||
Assert.assertFalse("is_empty (should be omitted): " + result.toString(), result.keySet().contains("is_empty"))
|
||||
Assert.assertFalse("empty_nested (should be omitted): " + result.toString(), result.keySet().contains("empty_nested"))
|
||||
Assert.assertFalse("empty_array (should be omitted): " + result.toString(), result.keySet().contains("empty_array"))
|
||||
}
|
||||
|
||||
private void suppressNulls(final boolean suppressNulls) {
|
||||
runner.setProperty(TestControllerServiceProcessor.CLIENT_SERVICE, "Client Service")
|
||||
runner.disableControllerService(service)
|
||||
runner.setProperty(service, ElasticSearchClientService.SUPPRESS_NULLS, suppressNulls ? ElasticSearchClientService.ALWAYS_SUPPRESS.getValue() : ElasticSearchClientService.NEVER_SUPPRESS.getValue())
|
||||
runner.enableControllerService(service)
|
||||
runner.assertValid()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBulkAddTwoIndexes() throws Exception {
|
||||
List<IndexOperationRequest> payload = new ArrayList<>()
|
||||
for (int x = 0; x < 20; x++) {
|
||||
String index = x % 2 == 0 ? "bulk_a": "bulk_b"
|
||||
payload.add(new IndexOperationRequest(index, TYPE, String.valueOf(x), new HashMap<String, Object>(){{
|
||||
put("msg", "test")
|
||||
}}, IndexOperationRequest.Operation.Index))
|
||||
}
|
||||
for (int x = 0; x < 5; x++) {
|
||||
payload.add(new IndexOperationRequest("bulk_c", TYPE, String.valueOf(x), new HashMap<String, Object>(){{
|
||||
put("msg", "test")
|
||||
}}, IndexOperationRequest.Operation.Index))
|
||||
}
|
||||
IndexOperationResponse response = service.bulk(payload)
|
||||
Assert.assertNotNull(response)
|
||||
Assert.assertTrue(response.getTook() > 0)
|
||||
Thread.sleep(2000)
|
||||
|
||||
/*
|
||||
* Now, check to ensure that both indexes got populated appropriately.
|
||||
*/
|
||||
String query = "{ \"query\": { \"match_all\": {}}}"
|
||||
Long indexA = service.count(query, "bulk_a", TYPE)
|
||||
Long indexB = service.count(query, "bulk_b", TYPE)
|
||||
Long indexC = service.count(query, "bulk_c", TYPE)
|
||||
|
||||
Assert.assertNotNull(indexA)
|
||||
Assert.assertNotNull(indexB)
|
||||
Assert.assertNotNull(indexC)
|
||||
Assert.assertEquals(indexA, indexB)
|
||||
Assert.assertEquals(10, indexA.intValue())
|
||||
Assert.assertEquals(10, indexB.intValue())
|
||||
Assert.assertEquals(5, indexC.intValue())
|
||||
|
||||
Long total = service.count(query, "bulk_*", TYPE)
|
||||
Assert.assertNotNull(total)
|
||||
Assert.assertEquals(25, total.intValue())
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateAndUpsert() {
|
||||
final String TEST_ID = "update-test"
|
||||
Map<String, Object> doc = new HashMap<>()
|
||||
doc.put("msg", "Buongiorno, mondo")
|
||||
service.add(new IndexOperationRequest(INDEX, TYPE, TEST_ID, doc, IndexOperationRequest.Operation.Index))
|
||||
Map<String, Object> result = service.get(INDEX, TYPE, TEST_ID)
|
||||
Assert.assertEquals("Not the same", doc, result)
|
||||
|
||||
Map<String, Object> updates = new HashMap<>()
|
||||
updates.put("from", "john.smith")
|
||||
Map<String, Object> merged = new HashMap<>()
|
||||
merged.putAll(updates)
|
||||
merged.putAll(doc)
|
||||
IndexOperationRequest request = new IndexOperationRequest(INDEX, TYPE, TEST_ID, updates, IndexOperationRequest.Operation.Update)
|
||||
service.add(request)
|
||||
result = service.get(INDEX, TYPE, TEST_ID)
|
||||
Assert.assertTrue(result.containsKey("from"))
|
||||
Assert.assertTrue(result.containsKey("msg"))
|
||||
Assert.assertEquals("Not the same after update.", merged, result)
|
||||
|
||||
final String UPSERTED_ID = "upsert-ftw"
|
||||
Map<String, Object> upsertItems = new HashMap<>()
|
||||
upsertItems.put("upsert_1", "hello")
|
||||
upsertItems.put("upsert_2", 1)
|
||||
upsertItems.put("upsert_3", true)
|
||||
request = new IndexOperationRequest(INDEX, TYPE, UPSERTED_ID, upsertItems, IndexOperationRequest.Operation.Upsert)
|
||||
service.add(request)
|
||||
result = service.get(INDEX, TYPE, UPSERTED_ID)
|
||||
Assert.assertEquals(upsertItems, result)
|
||||
|
||||
List<IndexOperationRequest> deletes = new ArrayList<>()
|
||||
deletes.add(new IndexOperationRequest(INDEX, TYPE, TEST_ID, null, IndexOperationRequest.Operation.Delete))
|
||||
deletes.add(new IndexOperationRequest(INDEX, TYPE, UPSERTED_ID, null, IndexOperationRequest.Operation.Delete))
|
||||
service.bulk(deletes)
|
||||
Assert.assertNull(service.get(INDEX, TYPE, TEST_ID))
|
||||
Assert.assertNull(service.get(INDEX, TYPE, UPSERTED_ID))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBulkResponsesWithErrors() {
|
||||
def ops = [
|
||||
new IndexOperationRequest(INDEX, TYPE, "1", [ "msg": "one", intField: 1], IndexOperationRequest.Operation.Index), // OK
|
||||
new IndexOperationRequest(INDEX, TYPE, "2", [ "msg": "two", intField: 1], IndexOperationRequest.Operation.Create), // already exists
|
||||
new IndexOperationRequest(INDEX, TYPE, "1", [ "msg": "one", intField: "notaninteger"], IndexOperationRequest.Operation.Index) // can't parse int field
|
||||
]
|
||||
def response = service.bulk(ops)
|
||||
assert response.hasErrors()
|
||||
assert response.items.findAll {
|
||||
def key = it.keySet().stream().findFirst().get()
|
||||
it[key].containsKey("error")
|
||||
}.size() == 2
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
@ -104,11 +104,6 @@
|
||||
<artifactId>poi-scratchpad</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-ssl-context-service</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-mock</artifactId>
|
||||
|
@ -19,7 +19,12 @@ package org.apache.nifi.processors.email;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Properties;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
@ -27,20 +32,57 @@ import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.nifi.remote.io.socket.NetworkUtils;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.security.util.ClientAuth;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.SslContextFactory;
|
||||
import org.apache.nifi.security.util.StandardTlsConfiguration;
|
||||
import org.apache.nifi.security.util.TlsConfiguration;
|
||||
import org.apache.nifi.ssl.RestrictedSSLContextService;
|
||||
import org.apache.nifi.ssl.SSLContextService;
|
||||
import org.apache.nifi.ssl.StandardRestrictedSSLContextService;
|
||||
import org.apache.nifi.ssl.StandardSSLContextService;
|
||||
import org.apache.nifi.util.TestRunner;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestListenSMTP {
|
||||
private static final String SSL_SERVICE_IDENTIFIER = "ssl-context";
|
||||
|
||||
private static TlsConfiguration tlsConfiguration;
|
||||
|
||||
private static SSLContextService sslContextService;
|
||||
|
||||
private static final int MESSAGES = 2;
|
||||
|
||||
@BeforeClass
|
||||
public static void setTlsConfiguration() throws IOException, GeneralSecurityException {
|
||||
final TlsConfiguration testTlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
|
||||
new File(testTlsConfiguration.getKeystorePath()).deleteOnExit();
|
||||
new File(testTlsConfiguration.getTruststorePath()).deleteOnExit();
|
||||
|
||||
tlsConfiguration = new StandardTlsConfiguration(
|
||||
testTlsConfiguration.getKeystorePath(),
|
||||
testTlsConfiguration.getKeystorePassword(),
|
||||
testTlsConfiguration.getKeyPassword(),
|
||||
testTlsConfiguration.getKeystoreType(),
|
||||
testTlsConfiguration.getTruststorePath(),
|
||||
testTlsConfiguration.getTruststorePassword(),
|
||||
testTlsConfiguration.getTruststoreType(),
|
||||
TlsConfiguration.TLS_1_2_PROTOCOL
|
||||
);
|
||||
|
||||
final SSLContext sslContext = SslContextFactory.createSslContext(tlsConfiguration);
|
||||
sslContextService = mock(RestrictedSSLContextService.class);
|
||||
when(sslContextService.getIdentifier()).thenReturn(SSL_SERVICE_IDENTIFIER);
|
||||
when(sslContextService.createContext()).thenReturn(sslContext);
|
||||
|
||||
|
||||
when(sslContextService.createTlsConfiguration()).thenReturn(tlsConfiguration);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenSMTP() throws Exception {
|
||||
final int port = NetworkUtils.availablePort();
|
||||
@ -50,13 +92,12 @@ public class TestListenSMTP {
|
||||
assertPortListening(port);
|
||||
|
||||
final Session session = getSession(port);
|
||||
final int numMessages = 5;
|
||||
for (int i = 0; i < numMessages; i++) {
|
||||
for (int i = 0; i < MESSAGES; i++) {
|
||||
sendMessage(session, i);
|
||||
}
|
||||
|
||||
runner.shutdown();
|
||||
runner.assertAllFlowFilesTransferred(ListenSMTP.REL_SUCCESS, numMessages);
|
||||
runner.assertAllFlowFilesTransferred(ListenSMTP.REL_SUCCESS, MESSAGES);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -64,23 +105,21 @@ public class TestListenSMTP {
|
||||
final int port = NetworkUtils.availablePort();
|
||||
final TestRunner runner = newTestRunner(port);
|
||||
|
||||
final String tlsProtocol = TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion();
|
||||
configureSslContextService(runner, tlsProtocol);
|
||||
configureSslContextService(runner);
|
||||
runner.setProperty(ListenSMTP.SSL_CONTEXT_SERVICE, SSL_SERVICE_IDENTIFIER);
|
||||
runner.setProperty(ListenSMTP.CLIENT_AUTH, ClientAuth.NONE.name());
|
||||
runner.assertValid();
|
||||
|
||||
runner.run(1, false);
|
||||
assertPortListening(port);
|
||||
final Session session = getSessionTls(port, tlsProtocol);
|
||||
final Session session = getSessionTls(port, tlsConfiguration.getProtocol());
|
||||
|
||||
final int numMessages = 5;
|
||||
for (int i = 0; i < numMessages; i++) {
|
||||
for (int i = 0; i < MESSAGES; i++) {
|
||||
sendMessage(session, i);
|
||||
}
|
||||
|
||||
runner.shutdown();
|
||||
runner.assertAllFlowFilesTransferred(ListenSMTP.REL_SUCCESS, numMessages);
|
||||
runner.assertAllFlowFilesTransferred(ListenSMTP.REL_SUCCESS, MESSAGES);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -88,7 +127,7 @@ public class TestListenSMTP {
|
||||
final int port = NetworkUtils.availablePort();
|
||||
final TestRunner runner = newTestRunner(port);
|
||||
|
||||
configureSslContextService(runner, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
|
||||
configureSslContextService(runner);
|
||||
runner.setProperty(ListenSMTP.SSL_CONTEXT_SERVICE, SSL_SERVICE_IDENTIFIER);
|
||||
runner.setProperty(ListenSMTP.CLIENT_AUTH, ClientAuth.NONE.name());
|
||||
runner.assertValid();
|
||||
@ -105,7 +144,7 @@ public class TestListenSMTP {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenSMTPwithTooLargeMessage() throws Exception {
|
||||
public void testListenSMTPwithTooLargeMessage() {
|
||||
final int port = NetworkUtils.availablePort();
|
||||
final TestRunner runner = newTestRunner(port);
|
||||
runner.setProperty(ListenSMTP.SMTP_MAXIMUM_MSG_SIZE, "10 B");
|
||||
@ -172,16 +211,8 @@ public class TestListenSMTP {
|
||||
Transport.send(email);
|
||||
}
|
||||
|
||||
private void configureSslContextService(final TestRunner runner, final String tlsProtocol) throws InitializationException {
|
||||
final SSLContextService sslContextService = new StandardRestrictedSSLContextService();
|
||||
private void configureSslContextService(final TestRunner runner) throws InitializationException {
|
||||
runner.addControllerService(SSL_SERVICE_IDENTIFIER, sslContextService);
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, "src/test/resources/truststore.jks");
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_PASSWORD, "passwordpassword");
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, "JKS");
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE, "src/test/resources/keystore.jks");
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_PASSWORD, "passwordpassword");
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_TYPE, "JKS");
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.SSL_ALGORITHM, tlsProtocol);
|
||||
runner.enableControllerService(sslContextService);
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -18,33 +18,27 @@
|
||||
|
||||
package org.apache.nifi.cluster.coordination.http.replication.okhttp
|
||||
|
||||
|
||||
import org.apache.nifi.security.util.KeyStoreUtils
|
||||
import org.apache.nifi.security.util.TlsConfiguration
|
||||
import org.apache.nifi.util.NiFiProperties
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
private static final Logger logger = LoggerFactory.getLogger(OkHttpReplicationClientTest.class)
|
||||
private static TlsConfiguration tlsConfiguration
|
||||
|
||||
@BeforeClass
|
||||
static void setUpOnce() throws Exception {
|
||||
logger.metaClass.methodMissing = { String name, args ->
|
||||
logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
|
||||
}
|
||||
tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore()
|
||||
new File(tlsConfiguration.keystorePath).deleteOnExit()
|
||||
new File(tlsConfiguration.truststorePath).deleteOnExit()
|
||||
}
|
||||
|
||||
private static NiFiProperties mockNiFiProperties() {
|
||||
[getClusterNodeConnectionTimeout: { -> "10 ms" },
|
||||
getClusterNodeReadTimeout : { -> "10 ms" },
|
||||
getProperty : { String prop ->
|
||||
logger.mock("Requested getProperty(${prop}) -> \"\"")
|
||||
""
|
||||
}] as NiFiProperties
|
||||
return NiFiProperties.createBasicNiFiProperties(null)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -52,7 +46,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
// Arrange
|
||||
def headers = ["Content-Length": "123", "Other-Header": "arbitrary value"]
|
||||
String method = "DELETE"
|
||||
logger.info("Original headers: ${headers}")
|
||||
|
||||
NiFiProperties mockProperties = mockNiFiProperties()
|
||||
|
||||
@ -60,7 +53,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
|
||||
// Act
|
||||
client.checkContentLengthHeader(method, headers)
|
||||
logger.info("Checked headers: ${headers}")
|
||||
|
||||
// Assert
|
||||
assert headers.size() == 2
|
||||
@ -72,7 +64,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
// Arrange
|
||||
def headers = ["Content-Length": "123", "Other-Header": "arbitrary value"]
|
||||
String method = "delete"
|
||||
logger.info("Original headers: ${headers}")
|
||||
|
||||
NiFiProperties mockProperties = mockNiFiProperties()
|
||||
|
||||
@ -80,7 +71,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
|
||||
// Act
|
||||
client.checkContentLengthHeader(method, headers)
|
||||
logger.info("Checked headers: ${headers}")
|
||||
|
||||
// Assert
|
||||
assert headers.size() == 2
|
||||
@ -100,11 +90,7 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
// Act
|
||||
zeroOrNullContentLengths.each { String contentLength ->
|
||||
def headers = ["Content-Length": contentLength, "Other-Header": "arbitrary value"]
|
||||
logger.info("Original headers: ${headers}")
|
||||
|
||||
logger.info("Trying method ${method}")
|
||||
client.checkContentLengthHeader(method, headers)
|
||||
logger.info("Checked headers: ${headers}")
|
||||
|
||||
// Assert
|
||||
assert headers.size() == 2
|
||||
@ -116,7 +102,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
void testShouldNotReplaceNonZeroContentLengthHeaderOnOtherMethod() {
|
||||
// Arrange
|
||||
def headers = ["Content-Length": "123", "Other-Header": "arbitrary value"]
|
||||
logger.info("Original headers: ${headers}")
|
||||
|
||||
NiFiProperties mockProperties = mockNiFiProperties()
|
||||
|
||||
@ -126,9 +111,7 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
|
||||
// Act
|
||||
nonDeleteMethods.each { String method ->
|
||||
logger.info("Trying method ${method}")
|
||||
client.checkContentLengthHeader(method, headers)
|
||||
logger.info("Checked headers: ${headers}")
|
||||
|
||||
// Assert
|
||||
assert headers.size() == 2
|
||||
@ -140,12 +123,12 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
void testShouldUseKeystorePasswordIfKeyPasswordIsBlank() {
|
||||
// Arrange
|
||||
Map propsMap = [
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : "./src/test/resources/conf/truststore.jks",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): "passwordpassword",
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : "./src/test/resources/conf/keystore.jks",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : "passwordpassword",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : tlsConfiguration.truststorePath,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : tlsConfiguration.truststoreType.type,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): tlsConfiguration.truststorePassword,
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : tlsConfiguration.keystorePath,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : tlsConfiguration.keystoreType.type,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : tlsConfiguration.keystorePassword,
|
||||
(NiFiProperties.SECURITY_KEY_PASSWD) : "",
|
||||
(NiFiProperties.WEB_HTTPS_HOST) : "localhost",
|
||||
(NiFiProperties.WEB_HTTPS_PORT) : "51552",
|
||||
@ -154,7 +137,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
|
||||
// Act
|
||||
OkHttpReplicationClient client = new OkHttpReplicationClient(mockNiFiProperties)
|
||||
logger.info("Created secure HTTPS client with TLS configured: ${client.isTLSConfigured()}")
|
||||
|
||||
// Assert
|
||||
assert client.isTLSConfigured()
|
||||
@ -164,12 +146,12 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
void testShouldUseKeystorePasswordIfKeyPasswordIsNull() {
|
||||
// Arrange
|
||||
Map flowfileEncryptionProps = [
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : "./src/test/resources/conf/truststore.jks",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): "passwordpassword",
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : "./src/test/resources/conf/keystore.jks",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : "passwordpassword",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : tlsConfiguration.truststorePath,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : tlsConfiguration.truststoreType.type,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): tlsConfiguration.truststorePassword,
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : tlsConfiguration.keystorePath,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : tlsConfiguration.keystoreType.type,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : tlsConfiguration.keystorePassword,
|
||||
(NiFiProperties.WEB_HTTPS_HOST) : "localhost",
|
||||
(NiFiProperties.WEB_HTTPS_PORT) : "51552",
|
||||
]
|
||||
@ -177,7 +159,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
|
||||
// Act
|
||||
OkHttpReplicationClient client = new OkHttpReplicationClient(mockNiFiProperties)
|
||||
logger.info("Created secure HTTPS client with TLS configured: ${client.isTLSConfigured()}")
|
||||
|
||||
// Assert
|
||||
assert client.isTLSConfigured()
|
||||
@ -187,13 +168,13 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
void testShouldFailIfKeyPasswordIsSetButKeystorePasswordIsBlank() {
|
||||
// Arrange
|
||||
Map propsMap = [
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : "./src/test/resources/conf/truststore.jks",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): "passwordpassword",
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : "./src/test/resources/conf/keystore.jks",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : tlsConfiguration.truststorePath,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : tlsConfiguration.truststoreType.type,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): tlsConfiguration.truststorePassword,
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : tlsConfiguration.keystorePath,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : tlsConfiguration.keystoreType.type,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : tlsConfiguration.keystorePassword,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : "",
|
||||
(NiFiProperties.SECURITY_KEY_PASSWD) : "passwordpassword",
|
||||
(NiFiProperties.WEB_HTTPS_HOST) : "localhost",
|
||||
(NiFiProperties.WEB_HTTPS_PORT) : "51552",
|
||||
]
|
||||
@ -201,7 +182,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
|
||||
// Act
|
||||
OkHttpReplicationClient client = new OkHttpReplicationClient(mockNiFiProperties)
|
||||
logger.info("Created (invalid) secure HTTPS client with TLS configured: ${client.isTLSConfigured()}")
|
||||
|
||||
// Assert
|
||||
assert !client.isTLSConfigured()
|
||||
@ -211,11 +191,11 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
void testShouldFailIfKeyPasswordAndKeystorePasswordAreBlank() {
|
||||
// Arrange
|
||||
Map propsMap = [
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : "./src/test/resources/conf/truststore.jks",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): "passwordpassword",
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : "./src/test/resources/conf/keystore.jks",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : tlsConfiguration.truststorePath,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : tlsConfiguration.truststoreType.type,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): tlsConfiguration.truststorePassword,
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : tlsConfiguration.keystorePath,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : tlsConfiguration.keystoreType.type,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : "",
|
||||
(NiFiProperties.SECURITY_KEY_PASSWD) : "",
|
||||
(NiFiProperties.WEB_HTTPS_HOST) : "localhost",
|
||||
@ -225,7 +205,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
|
||||
// Act
|
||||
OkHttpReplicationClient client = new OkHttpReplicationClient(mockNiFiProperties)
|
||||
logger.info("Created (invalid) secure HTTPS client with TLS configured: ${client.isTLSConfigured()}")
|
||||
|
||||
// Assert
|
||||
assert !client.isTLSConfigured()
|
||||
@ -238,13 +217,12 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
(NiFiProperties.WEB_HTTPS_PORT): "51552",]
|
||||
|
||||
Map tlsPropsMap = [
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : "./src/test/resources/conf/keystore.jks",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : "passwordpassword",
|
||||
(NiFiProperties.SECURITY_KEY_PASSWD) : "",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : "./src/test/resources/conf/truststore.jks",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): "passwordpassword",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : "JKS",
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : tlsConfiguration.truststorePath,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : tlsConfiguration.truststoreType.type,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): tlsConfiguration.truststorePassword,
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : tlsConfiguration.keystorePath,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : tlsConfiguration.keystoreType.type,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : tlsConfiguration.keystorePassword
|
||||
] + propsMap
|
||||
|
||||
|
||||
@ -258,14 +236,8 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
|
||||
|
||||
// Act
|
||||
OkHttpReplicationClient client = new OkHttpReplicationClient(mockNiFiProperties)
|
||||
logger.info("Created plaintext HTTP client with TLS configured: ${client.isTLSConfigured()}")
|
||||
|
||||
OkHttpReplicationClient invalidTlsClient = new OkHttpReplicationClient(mockInvalidTLSNiFiProperties)
|
||||
logger.info("Created (invalid) secure HTTPS client with TLS configured: ${invalidTlsClient.isTLSConfigured()}")
|
||||
|
||||
OkHttpReplicationClient tlsClient = new OkHttpReplicationClient(mockTLSNiFiProperties)
|
||||
logger.info("Created secure HTTPS client with TLS configured: ${tlsClient.isTLSConfigured()}")
|
||||
|
||||
|
||||
// Assert
|
||||
assert !client.isTLSConfigured()
|
||||
|
Binary file not shown.
Binary file not shown.
@ -1,52 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<configuration scan="true" scanPeriod="30 seconds">
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>%-4r [%t] %-5p %c - %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- valid logging levels: TRACE, DEBUG, INFO, WARN, ERROR -->
|
||||
<logger name="org.apache.nifi" level="INFO"/>
|
||||
<logger name="org.apache.nifi.security.util" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.cluster.coordination.http.replication.okhttp" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.engine.FlowEngine" level="OFF" />
|
||||
<logger name="org.apache.nifi.cluster.coordination.node" level="DEBUG" />
|
||||
<logger name="org.apache.curator.framework.recipes.leader.LeaderSelector" level="OFF" />
|
||||
<logger name="org.apache.zookeeper.ClientCnxn" level="ERROR" />
|
||||
<logger name="org.apache.curator.framework.imps.CuratorFrameworkImpl" level="OFF" />
|
||||
|
||||
<!-- Logger for managing logging statements for nifi clusters. -->
|
||||
<logger name="org.apache.nifi.cluster" level="INFO"/>
|
||||
|
||||
<!--
|
||||
Logger for logging HTTP requests received by the web server. Setting
|
||||
log level to 'debug' activates HTTP request logging.
|
||||
-->
|
||||
<logger name="org.apache.nifi.server.JettyServer" level="INFO"/>
|
||||
|
||||
<!-- Logger for managing logging statements for jetty -->
|
||||
<logger name="org.mortbay" level="INFO"/>
|
||||
|
||||
<logger name="org.apache.nifi.processors.standard" level="DEBUG"/>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
@ -275,8 +275,6 @@
|
||||
<exclude>src/test/resources/old-swap-file.swap</exclude>
|
||||
<exclude>src/test/resources/xxe_template.xml</exclude>
|
||||
<exclude>src/test/resources/swap/444-old-swap-file.swap</exclude>
|
||||
<exclude>src/test/resources/ZooKeeperStateServerConfigurationsTest/keystore.jks</exclude>
|
||||
<exclude>src/test/resources/ZooKeeperStateServerConfigurationsTest/truststore.jks</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
@ -19,38 +19,21 @@ package org.apache.nifi.controller.queue.clustered.server
|
||||
import org.apache.nifi.events.EventReporter
|
||||
import org.apache.nifi.reporting.Severity
|
||||
import org.apache.nifi.security.util.KeyStoreUtils
|
||||
import org.apache.nifi.security.util.KeystoreType
|
||||
import org.apache.nifi.security.util.SslContextFactory
|
||||
import org.apache.nifi.security.util.StandardTlsConfiguration
|
||||
import org.apache.nifi.security.util.TlsConfiguration
|
||||
import org.apache.nifi.security.util.TlsPlatform
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLPeerUnverifiedException
|
||||
import javax.net.ssl.SSLServerSocket
|
||||
import java.security.Security
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
class ConnectionLoadBalanceServerTest extends GroovyTestCase {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConnectionLoadBalanceServerTest.class)
|
||||
|
||||
private static final String KEYSTORE_PATH = "src/test/resources/localhost-ks.jks"
|
||||
private static final String KEYSTORE_PASSWORD = "OI7kMpWzzVNVx/JGhTL/0uO4+PWpGJ46uZ/pfepbkwI"
|
||||
private static final KeystoreType KEYSTORE_TYPE = KeystoreType.JKS
|
||||
|
||||
private static final String TRUSTSTORE_PATH = "src/test/resources/localhost-ts.jks"
|
||||
private static final String TRUSTSTORE_PASSWORD = "wAOR0nQJ2EXvOP0JZ2EaqA/n7W69ILS4sWAHghmIWCc"
|
||||
private static final KeystoreType TRUSTSTORE_TYPE = KeystoreType.JKS
|
||||
|
||||
private static final String HOSTNAME = "localhost"
|
||||
private static final int PORT = 54321
|
||||
private static final int NUM_THREADS = 1
|
||||
@ -63,13 +46,9 @@ class ConnectionLoadBalanceServerTest extends GroovyTestCase {
|
||||
|
||||
@BeforeClass
|
||||
static void setUpOnce() throws Exception {
|
||||
Security.addProvider(new BouncyCastleProvider())
|
||||
|
||||
logger.metaClass.methodMissing = { String name, args ->
|
||||
logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
|
||||
}
|
||||
|
||||
tlsConfiguration = new StandardTlsConfiguration(KEYSTORE_PATH, KEYSTORE_PASSWORD, KEYSTORE_TYPE, TRUSTSTORE_PATH, TRUSTSTORE_PASSWORD, TRUSTSTORE_TYPE)
|
||||
tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore()
|
||||
new File(tlsConfiguration.keystorePath).deleteOnExit()
|
||||
new File(tlsConfiguration.truststorePath).deleteOnExit()
|
||||
sslContext = SslContextFactory.createSslContext(tlsConfiguration)
|
||||
}
|
||||
|
||||
@ -87,9 +66,7 @@ class ConnectionLoadBalanceServerTest extends GroovyTestCase {
|
||||
@Test
|
||||
void testRequestPeerListShouldUseTLS() {
|
||||
// Arrange
|
||||
logger.info("Creating SSL Context from TLS Configuration: ${tlsConfiguration}")
|
||||
SSLContext sslContext = SslContextFactory.createSslContext(tlsConfiguration)
|
||||
logger.info("Created SSL Context: ${KeyStoreUtils.sslContextToString(sslContext)}")
|
||||
|
||||
def mockLBP = [
|
||||
receiveFlowFiles: { Socket s, InputStream i, OutputStream o -> null }
|
||||
@ -132,7 +109,7 @@ class ConnectionLoadBalanceServerTest extends GroovyTestCase {
|
||||
receiveFlowFiles: { Socket s, InputStream i, OutputStream o -> null }
|
||||
] as LoadBalanceProtocol
|
||||
EventReporter mockER = [
|
||||
reportEvent: { Severity s, String c, String m -> logger.mock("${s}: ${c} | ${m}") }
|
||||
reportEvent: { Severity s, String c, String m -> }
|
||||
] as EventReporter
|
||||
|
||||
def output = [debug: 0, error: 0]
|
||||
@ -142,12 +119,8 @@ class ConnectionLoadBalanceServerTest extends GroovyTestCase {
|
||||
// Override the threshold to 100 ms
|
||||
communicateAction.EXCEPTION_THRESHOLD_MILLIS = 100
|
||||
|
||||
long listenerStart = System.currentTimeMillis()
|
||||
|
||||
// Act
|
||||
CONNECTION_ATTEMPTS.times { int i ->
|
||||
long now = System.currentTimeMillis()
|
||||
logger.debug("Attempting connection ${i + 1} at ${now} [${now - listenerStart}]")
|
||||
boolean printedError = communicateAction.handleTlsError(peerDescription, e)
|
||||
if (printedError) {
|
||||
output.error++
|
||||
@ -156,17 +129,11 @@ class ConnectionLoadBalanceServerTest extends GroovyTestCase {
|
||||
}
|
||||
sleep(10)
|
||||
}
|
||||
logger.info("After ${CONNECTION_ATTEMPTS} attempts, debug: ${output.debug}, error: ${output.error}")
|
||||
|
||||
// Assert
|
||||
logger.info("output.debug (${output.debug}) > output.error (${output.error}): ${output.debug > output.error}")
|
||||
|
||||
// Only enforce if the test completed in a reasonable amount of time (i.e. external delays did not influence the timing)
|
||||
long testStopMillis = System.currentTimeMillis()
|
||||
long testDurationMillis = testStopMillis - testStartMillis
|
||||
if (testDurationMillis > MAX_TEST_DURATION_MILLIS) {
|
||||
logger.warn("The test took ${testDurationMillis} ms, which is longer than the max duration ${MAX_TEST_DURATION_MILLIS} ms, so the timing may be suspect and the assertion will not be enforced")
|
||||
} else {
|
||||
if (testDurationMillis <= MAX_TEST_DURATION_MILLIS) {
|
||||
assert output.debug > output.error
|
||||
}
|
||||
|
||||
|
@ -56,11 +56,9 @@ import org.apache.nifi.controller.repository.claim.ResourceClaimManager;
|
||||
import org.apache.nifi.controller.repository.claim.StandardResourceClaimManager;
|
||||
import org.apache.nifi.events.EventReporter;
|
||||
import org.apache.nifi.provenance.ProvenanceRepository;
|
||||
import org.apache.nifi.security.util.KeystoreType;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.SslContextFactory;
|
||||
import org.apache.nifi.security.util.StandardTlsConfiguration;
|
||||
import org.apache.nifi.security.util.TlsConfiguration;
|
||||
import org.apache.nifi.security.util.TlsException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
@ -70,9 +68,11 @@ import org.mockito.stubbing.Answer;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@ -141,7 +141,7 @@ public class LoadBalancedQueueIT {
|
||||
private final AtomicReference<LoadBalanceCompression> compressionReference = new AtomicReference<>();
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, TlsException {
|
||||
public void setup() throws IOException, GeneralSecurityException {
|
||||
compressionReference.set(LoadBalanceCompression.DO_NOT_COMPRESS);
|
||||
|
||||
nodeIdentifiers = new HashSet<>();
|
||||
@ -190,13 +190,9 @@ public class LoadBalancedQueueIT {
|
||||
clientRepoRecords = Collections.synchronizedList(new ArrayList<>());
|
||||
clientFlowFileRepo = createFlowFileRepository(clientRepoRecords);
|
||||
|
||||
final String keystore = "src/test/resources/localhost-ks.jks";
|
||||
final String keystorePass = "OI7kMpWzzVNVx/JGhTL/0uO4+PWpGJ46uZ/pfepbkwI";
|
||||
final String keyPass = keystorePass;
|
||||
final String truststore = "src/test/resources/localhost-ts.jks";
|
||||
final String truststorePass = "wAOR0nQJ2EXvOP0JZ2EaqA/n7W69ILS4sWAHghmIWCc";
|
||||
TlsConfiguration tlsConfiguration = new StandardTlsConfiguration(keystore, keystorePass, keyPass, KeystoreType.JKS,
|
||||
truststore, truststorePass, KeystoreType.JKS, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
|
||||
TlsConfiguration tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
|
||||
new File(tlsConfiguration.getKeystorePath()).deleteOnExit();
|
||||
new File(tlsConfiguration.getTruststorePath()).deleteOnExit();
|
||||
sslContext = SslContextFactory.createSslContext(tlsConfiguration);
|
||||
}
|
||||
|
||||
|
@ -28,11 +28,14 @@ import org.apache.nifi.controller.state.providers.AbstractTestStateProvider;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
import org.apache.nifi.mock.MockComponentLogger;
|
||||
import org.apache.nifi.parameter.ParameterLookup;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.TlsConfiguration;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.zookeeper.server.ServerCnxnFactory;
|
||||
import org.apache.zookeeper.server.ZooKeeperServer;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -44,6 +47,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
@ -64,14 +68,14 @@ public class ITZooKeeperStateProvider extends AbstractTestStateProvider {
|
||||
private static ServerCnxnFactory serverConnectionFactory;
|
||||
private static NiFiProperties nifiProperties;
|
||||
|
||||
private static final String CLIENT_KEYSTORE = "src/test/resources/localhost-ks.jks";
|
||||
private static final String CLIENT_TRUSTSTORE = "src/test/resources/localhost-ts.jks";
|
||||
private static final String CLIENT_KEYSTORE_TYPE = "JKS";
|
||||
private static final String CLIENT_TRUSTSTORE_TYPE = "JKS";
|
||||
private static final String SERVER_KEYSTORE = "src/test/resources/localhost-ks.jks";
|
||||
private static final String SERVER_TRUSTSTORE = "src/test/resources/localhost-ts.jks";
|
||||
private static final String KEYSTORE_PASSWORD = "OI7kMpWzzVNVx/JGhTL/0uO4+PWpGJ46uZ/pfepbkwI";
|
||||
private static final String TRUSTSTORE_PASSWORD = "wAOR0nQJ2EXvOP0JZ2EaqA/n7W69ILS4sWAHghmIWCc";
|
||||
private static TlsConfiguration tlsConfiguration;
|
||||
|
||||
@BeforeClass
|
||||
public static void setTlsConfiguration() throws GeneralSecurityException, IOException {
|
||||
tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
|
||||
new File(tlsConfiguration.getTruststorePath()).deleteOnExit();
|
||||
new File(tlsConfiguration.getKeystorePath()).deleteOnExit();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
@ -86,22 +90,22 @@ public class ITZooKeeperStateProvider extends AbstractTestStateProvider {
|
||||
dataDir,
|
||||
tempDir,
|
||||
clientPort,
|
||||
Paths.get(SERVER_KEYSTORE),
|
||||
KEYSTORE_PASSWORD,
|
||||
Paths.get(SERVER_TRUSTSTORE),
|
||||
TRUSTSTORE_PASSWORD
|
||||
Paths.get(tlsConfiguration.getKeystorePath()),
|
||||
tlsConfiguration.getKeystorePassword(),
|
||||
Paths.get(tlsConfiguration.getTruststorePath()),
|
||||
tlsConfiguration.getTruststorePassword()
|
||||
);
|
||||
zkServer = serverConnectionFactory.getZooKeeperServer();
|
||||
|
||||
// Set up state provider (client) TLS properties, normally injected through StateProviderContext annotation
|
||||
nifiProperties = createSecureClientProperties(
|
||||
clientPort,
|
||||
Paths.get(CLIENT_KEYSTORE),
|
||||
CLIENT_KEYSTORE_TYPE,
|
||||
KEYSTORE_PASSWORD,
|
||||
Paths.get(CLIENT_TRUSTSTORE),
|
||||
CLIENT_TRUSTSTORE_TYPE,
|
||||
TRUSTSTORE_PASSWORD
|
||||
Paths.get(tlsConfiguration.getKeystorePath()),
|
||||
tlsConfiguration.getKeystoreType().getType(),
|
||||
tlsConfiguration.getKeystorePassword(),
|
||||
Paths.get(tlsConfiguration.getTruststorePath()),
|
||||
tlsConfiguration.getTruststoreType().getType(),
|
||||
tlsConfiguration.getTruststorePassword()
|
||||
);
|
||||
|
||||
// Set up state provider properties
|
||||
@ -138,12 +142,12 @@ public class ITZooKeeperStateProvider extends AbstractTestStateProvider {
|
||||
}
|
||||
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_CLIENT_SECURE, Boolean.TRUE.toString());
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE, CLIENT_KEYSTORE);
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE_PASSWD, KEYSTORE_PASSWORD);
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE_TYPE, CLIENT_KEYSTORE_TYPE);
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE, CLIENT_TRUSTSTORE);
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE_PASSWD, TRUSTSTORE_PASSWORD);
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE_TYPE, CLIENT_TRUSTSTORE_TYPE);
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE, tlsConfiguration.getKeystorePath());
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE_PASSWD, tlsConfiguration.getKeystorePassword());
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE_TYPE, tlsConfiguration.getKeystoreType().getType());
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE, tlsConfiguration.getTruststorePath());
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE_PASSWD, tlsConfiguration.getTruststorePassword());
|
||||
propValueMap.put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE_TYPE, tlsConfiguration.getTruststoreType().getType());
|
||||
|
||||
return propValueMap;
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ import org.apache.curator.utils.DefaultZookeeperFactory;
|
||||
import org.apache.curator.utils.ZookeeperFactory;
|
||||
import org.apache.nifi.controller.cluster.SecureClientZooKeeperFactory;
|
||||
import org.apache.nifi.controller.cluster.ZooKeeperClientConfig;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.TlsConfiguration;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.zookeeper.KeeperException;
|
||||
import org.apache.zookeeper.data.Stat;
|
||||
@ -32,6 +34,7 @@ import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
@ -39,6 +42,7 @@ import org.junit.rules.ExpectedException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -50,9 +54,6 @@ import static org.junit.Assert.assertNotNull;
|
||||
|
||||
// Testing setting up a ZooKeeperStateServer with TLS
|
||||
public class ITZooKeeperStateServerTLS {
|
||||
private static final String KEY_STORE = getPath("keystore.jks");
|
||||
private static final String TRUST_STORE = getPath("truststore.jks");
|
||||
private static final String STORE_TYPE = "JKS";
|
||||
private static final String INSECURE_ZOOKEEPER_PROPS = getPath("insecure.zookeeper.properties");
|
||||
private static final String PARTIAL_ZOOKEEPER_PROPS = getPath("partial.zookeeper.properties");
|
||||
private static final String SECURE_ZOOKEEPER_PROPS = getPath("secure.zookeeper.properties");
|
||||
@ -60,9 +61,41 @@ public class ITZooKeeperStateServerTLS {
|
||||
private static final String ZOOKEEPER_CNXN_FACTORY = "org.apache.zookeeper.server.NettyServerCnxnFactory";
|
||||
private static final String QUORUM_CONNECT_STRING = "node0.apache.org:2281,node1.apache.org:2281";
|
||||
|
||||
private static final Map<String, String> SECURE_NIFI_PROPS = new HashMap<>();
|
||||
private static final Map<String, String> SECURE_ZOOKEEPER_NIFI_PROPS = new HashMap<>();
|
||||
|
||||
private static TlsConfiguration tlsConfiguration;
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@BeforeClass
|
||||
public static void setTlsConfiguration() throws GeneralSecurityException, IOException {
|
||||
tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
|
||||
new File(tlsConfiguration.getTruststorePath()).deleteOnExit();
|
||||
new File(tlsConfiguration.getKeystorePath()).deleteOnExit();
|
||||
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.STATE_MANAGEMENT_ZOOKEEPER_PROPERTIES, SECURE_ZOOKEEPER_PROPS);
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.WEB_HTTPS_PORT, "8443");
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_KEYSTORE, tlsConfiguration.getKeystorePath());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_KEYSTORE_TYPE, tlsConfiguration.getKeystoreType().getType());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_KEYSTORE_PASSWD, tlsConfiguration.getKeystorePassword());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_TRUSTSTORE, tlsConfiguration.getTruststorePath());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_TRUSTSTORE_TYPE, tlsConfiguration.getTruststoreType().getType());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD, tlsConfiguration.getTruststorePassword());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.ZOOKEEPER_CLIENT_SECURE, "true");
|
||||
|
||||
SECURE_ZOOKEEPER_NIFI_PROPS.put(NiFiProperties.STATE_MANAGEMENT_ZOOKEEPER_PROPERTIES, SECURE_ZOOKEEPER_PROPS);
|
||||
SECURE_ZOOKEEPER_NIFI_PROPS.put(NiFiProperties.WEB_HTTPS_PORT, "8443");
|
||||
SECURE_ZOOKEEPER_NIFI_PROPS.put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE, tlsConfiguration.getKeystorePath());
|
||||
SECURE_ZOOKEEPER_NIFI_PROPS.put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE_TYPE, tlsConfiguration.getKeystoreType().getType());
|
||||
SECURE_ZOOKEEPER_NIFI_PROPS.put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE_PASSWD, tlsConfiguration.getKeystorePassword());
|
||||
SECURE_ZOOKEEPER_NIFI_PROPS.put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE, tlsConfiguration.getTruststorePath());
|
||||
SECURE_ZOOKEEPER_NIFI_PROPS.put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE_TYPE, tlsConfiguration.getTruststoreType().getType());
|
||||
SECURE_ZOOKEEPER_NIFI_PROPS.put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE_PASSWD, tlsConfiguration.getTruststorePassword());
|
||||
SECURE_ZOOKEEPER_NIFI_PROPS.put(NiFiProperties.ZOOKEEPER_CLIENT_SECURE, "true");
|
||||
}
|
||||
|
||||
private static final Map<String, String> INSECURE_NIFI_PROPS = new HashMap<String, String>() {{
|
||||
put(ZOOKEEPER_PROPERTIES_FILE_KEY, INSECURE_ZOOKEEPER_PROPS);
|
||||
put(NiFiProperties.WEB_HTTP_HOST, "localhost");
|
||||
@ -70,32 +103,6 @@ public class ITZooKeeperStateServerTLS {
|
||||
put(NiFiProperties.ZOOKEEPER_CLIENT_SECURE, "false");
|
||||
}};
|
||||
|
||||
private static final String TEST_PASSWORD = "passwordpassword";
|
||||
|
||||
private static final Map<String, String> SECURE_NIFI_PROPS = new HashMap<String, String>() {{
|
||||
put(NiFiProperties.STATE_MANAGEMENT_ZOOKEEPER_PROPERTIES, SECURE_ZOOKEEPER_PROPS);
|
||||
put(NiFiProperties.WEB_HTTPS_PORT, "8443");
|
||||
put(NiFiProperties.SECURITY_KEYSTORE, KEY_STORE);
|
||||
put(NiFiProperties.SECURITY_KEYSTORE_TYPE, STORE_TYPE);
|
||||
put(NiFiProperties.SECURITY_KEYSTORE_PASSWD, TEST_PASSWORD);
|
||||
put(NiFiProperties.SECURITY_TRUSTSTORE, TRUST_STORE);
|
||||
put(NiFiProperties.SECURITY_TRUSTSTORE_TYPE, STORE_TYPE);
|
||||
put(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD, TEST_PASSWORD);
|
||||
put(NiFiProperties.ZOOKEEPER_CLIENT_SECURE, "true");
|
||||
}};
|
||||
|
||||
private static final Map<String, String> SECURE_ZOOKEEPER_NIFI_PROPS = new HashMap<String, String>() {{
|
||||
put(NiFiProperties.STATE_MANAGEMENT_ZOOKEEPER_PROPERTIES, SECURE_ZOOKEEPER_PROPS);
|
||||
put(NiFiProperties.WEB_HTTPS_PORT, "8443");
|
||||
put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE, KEY_STORE);
|
||||
put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE_TYPE, STORE_TYPE);
|
||||
put(NiFiProperties.ZOOKEEPER_SECURITY_KEYSTORE_PASSWD, TEST_PASSWORD);
|
||||
put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE, TRUST_STORE);
|
||||
put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE_TYPE, STORE_TYPE);
|
||||
put(NiFiProperties.ZOOKEEPER_SECURITY_TRUSTSTORE_PASSWD, TEST_PASSWORD);
|
||||
put(NiFiProperties.ZOOKEEPER_CLIENT_SECURE, "true");
|
||||
}};
|
||||
|
||||
private NiFiProperties niFiProps;
|
||||
private static NiFiProperties clientProperties;
|
||||
private QuorumPeerConfig quorumPeerConfig;
|
||||
@ -245,7 +252,6 @@ public class ITZooKeeperStateServerTLS {
|
||||
@Test
|
||||
public void testSecureClientQuorumConnectString() throws Exception {
|
||||
final int actualPort = Integer.parseInt(secureZooKeeperProps.getProperty("secureClientPort", "0"));
|
||||
final String connect = "localhost:" + actualPort;
|
||||
final NiFiProperties validZkClientProps = NiFiProperties.createBasicNiFiProperties(null, new HashMap<String, String>() {{
|
||||
putAll(SECURE_NIFI_PROPS);
|
||||
put(ZOOKEEPER_PROPERTIES_FILE_KEY, SECURE_ZOOKEEPER_PROPS);
|
||||
@ -271,7 +277,6 @@ public class ITZooKeeperStateServerTLS {
|
||||
// Connect to an insecure ZooKeeperStateServer with an insecure client (ensure insecure setup still works)
|
||||
@Test
|
||||
public void testInsecureZooKeeperWithInsecureClient() throws Exception {
|
||||
final int actualPort = Integer.parseInt(insecureZooKeeperProps.getProperty("clientPort", "0"));
|
||||
final String connect = "localhost:" + 2381;
|
||||
final NiFiProperties validZkClientProps = NiFiProperties.createBasicNiFiProperties(null, new HashMap<String, String>() {{
|
||||
putAll(INSECURE_NIFI_PROPS);
|
||||
@ -281,8 +286,6 @@ public class ITZooKeeperStateServerTLS {
|
||||
|
||||
server = ZooKeeperStateServer.create(validZkClientProps);
|
||||
assertNotNull(server);
|
||||
final int serverPort = server.getQuorumPeerConfig().getClientPortAddress().getPort();
|
||||
//assertEquals(actualPort, 2381);
|
||||
server.start();
|
||||
|
||||
// Set up a ZK client
|
||||
@ -318,7 +321,7 @@ public class ITZooKeeperStateServerTLS {
|
||||
final String testPath = "/test";
|
||||
|
||||
// Expect this to fail with ConnectionLossException
|
||||
final String createResult = client.create().forPath(testPath, new byte[0]);
|
||||
client.create().forPath(testPath, new byte[0]);
|
||||
}
|
||||
|
||||
// Fail to connect to a secure ZooKeeperStateServer with missing client configuration
|
||||
@ -516,12 +519,12 @@ public class ITZooKeeperStateServerTLS {
|
||||
// TODO: port being set needs to be based on port set in nifi.properties, should create client in the same
|
||||
clientProperties = createSecureClientProperties(
|
||||
port,
|
||||
Paths.get(KEY_STORE),
|
||||
STORE_TYPE,
|
||||
TEST_PASSWORD,
|
||||
Paths.get(TRUST_STORE),
|
||||
STORE_TYPE,
|
||||
TEST_PASSWORD
|
||||
Paths.get(tlsConfiguration.getKeystorePath()),
|
||||
tlsConfiguration.getKeystoreType().getType(),
|
||||
tlsConfiguration.getKeystorePassword(),
|
||||
Paths.get(tlsConfiguration.getTruststorePath()),
|
||||
tlsConfiguration.getTruststoreType().getType(),
|
||||
tlsConfiguration.getTruststorePassword()
|
||||
);
|
||||
|
||||
final ZooKeeperClientConfig zkClientConfig =
|
||||
|
@ -17,16 +17,20 @@
|
||||
package org.apache.nifi.controller.state.server;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.TlsConfiguration;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.zookeeper.server.ServerCnxnFactory;
|
||||
import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -35,38 +39,23 @@ import java.util.Properties;
|
||||
// This class tests the behaviors involved with the ZooKeeperStateServer::create method. The servers are not started,
|
||||
// and TLS connections are not used.
|
||||
public class TestZooKeeperStateServerConfigurations {
|
||||
private static final String KEY_STORE = getPath("keystore.jks");
|
||||
private static final String TRUST_STORE = getPath("truststore.jks");
|
||||
private static final String INSECURE_ZOOKEEPER_PROPS = getPath("insecure.zookeeper.properties");
|
||||
private static final String SECURE_ZOOKEEPER_PROPS = getPath("secure.zookeeper.properties");
|
||||
private static final String ZOOKEEPER_PROPERTIES_FILE_KEY = "nifi.state.management.embedded.zookeeper.properties";
|
||||
private static final String ZOOKEEPER_CNXN_FACTORY = "org.apache.zookeeper.server.NettyServerCnxnFactory";
|
||||
private static final String KEYSTORE_PASSWORD = "passwordpassword";
|
||||
private static final String TRUSTSTORE_PASSWORD = "passwordpassword";
|
||||
private static final String STORE_TYPE = "JKS";
|
||||
|
||||
private static final Map<String, String> INSECURE_PROPS = new HashMap<String, String>() {{
|
||||
put(ZOOKEEPER_PROPERTIES_FILE_KEY, INSECURE_ZOOKEEPER_PROPS);
|
||||
}};
|
||||
|
||||
private static final Map<String, String> SECURE_NIFI_PROPS = new HashMap<>();
|
||||
|
||||
private static final Map<String, String> INSECURE_NIFI_PROPS = new HashMap<String, String>() {{
|
||||
putAll(INSECURE_PROPS);
|
||||
put(NiFiProperties.WEB_HTTP_PORT, "8080");
|
||||
put(NiFiProperties.ZOOKEEPER_CLIENT_SECURE, "false");
|
||||
}};
|
||||
|
||||
private static final Map<String, String> SECURE_NIFI_PROPS = new HashMap<String, String>() {{
|
||||
put(ZOOKEEPER_PROPERTIES_FILE_KEY, SECURE_ZOOKEEPER_PROPS);
|
||||
put(NiFiProperties.WEB_HTTPS_PORT, "8443");
|
||||
put(NiFiProperties.SECURITY_KEYSTORE, KEY_STORE);
|
||||
put(NiFiProperties.SECURITY_KEYSTORE_PASSWD, KEYSTORE_PASSWORD);
|
||||
put(NiFiProperties.SECURITY_KEYSTORE_TYPE, STORE_TYPE);
|
||||
put(NiFiProperties.SECURITY_TRUSTSTORE, TRUST_STORE);
|
||||
put(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD, TRUSTSTORE_PASSWORD);
|
||||
put(NiFiProperties.SECURITY_TRUSTSTORE_TYPE, STORE_TYPE);
|
||||
put(NiFiProperties.ZOOKEEPER_CLIENT_SECURE, "true");
|
||||
}};
|
||||
|
||||
private NiFiProperties secureNiFiProps;
|
||||
private NiFiProperties insecureNiFiProps;
|
||||
private QuorumPeerConfig secureQuorumPeerConfig;
|
||||
@ -74,6 +63,25 @@ public class TestZooKeeperStateServerConfigurations {
|
||||
private Properties secureZooKeeperProps;
|
||||
private Properties insecureZooKeeperProps;
|
||||
|
||||
private static TlsConfiguration tlsConfiguration;
|
||||
|
||||
@BeforeClass
|
||||
public static void setTlsConfiguration() throws GeneralSecurityException, IOException {
|
||||
tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
|
||||
new File(tlsConfiguration.getTruststorePath()).deleteOnExit();
|
||||
new File(tlsConfiguration.getKeystorePath()).deleteOnExit();
|
||||
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.STATE_MANAGEMENT_ZOOKEEPER_PROPERTIES, SECURE_ZOOKEEPER_PROPS);
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.WEB_HTTPS_PORT, "8443");
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_KEYSTORE, tlsConfiguration.getKeystorePath());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_KEYSTORE_TYPE, tlsConfiguration.getKeystoreType().getType());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_KEYSTORE_PASSWD, tlsConfiguration.getKeystorePassword());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_TRUSTSTORE, tlsConfiguration.getTruststorePath());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_TRUSTSTORE_TYPE, tlsConfiguration.getTruststoreType().getType());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD, tlsConfiguration.getTruststorePassword());
|
||||
SECURE_NIFI_PROPS.put(NiFiProperties.ZOOKEEPER_CLIENT_SECURE, "true");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupWithValidProperties() throws IOException, QuorumPeerConfig.ConfigException {
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,22 +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.
|
||||
|
||||
log4j.rootLogger=INFO,console
|
||||
log4j.category.org.apache.nifi=DEBUG
|
||||
|
||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.console.target=System.err
|
||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n
|
@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>%-4r [%t] %-5p %c{3} - %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>./target/log</file>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>%date %level [%thread] %logger{40} %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="org.apache.nifi" level="INFO"/>
|
||||
<logger name="org.apache.nifi.controller.tasks" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.controller.service" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.encrypt" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.security.util.crypto" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.controller.repository.crypto" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.security.repository" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.controller.service.mock" level="ERROR"/>
|
||||
|
||||
<logger name="StandardProcessSession.claims" level="INFO" />
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
@ -25,7 +25,7 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
|
@ -16,14 +16,11 @@
|
||||
*/
|
||||
package org.apache.nifi.web.server
|
||||
|
||||
import org.apache.log4j.AppenderSkeleton
|
||||
import org.apache.log4j.spi.LoggingEvent
|
||||
import org.apache.nifi.bundle.Bundle
|
||||
import org.apache.nifi.nar.ExtensionManagerHolder
|
||||
import org.apache.nifi.nar.ExtensionMapping
|
||||
import org.apache.nifi.nar.SystemBundle
|
||||
import org.apache.nifi.processor.DataUnit
|
||||
import org.apache.nifi.remote.io.socket.NetworkUtils
|
||||
import org.apache.nifi.security.util.KeyStoreUtils
|
||||
import org.apache.nifi.security.util.StandardTlsConfiguration
|
||||
import org.apache.nifi.security.util.TlsConfiguration
|
||||
import org.apache.nifi.security.util.TlsPlatform
|
||||
@ -81,44 +78,41 @@ class JettyServerGroovyTest extends GroovyTestCase {
|
||||
private static final int HTTPS_PORT = NetworkUtils.getAvailableTcpPort()
|
||||
private static final String HTTPS_HOSTNAME = "localhost"
|
||||
|
||||
private static final String KEYSTORE_PATH = "src/test/resources/keystore.jks"
|
||||
private static final String TRUSTSTORE_PATH = "src/test/resources/truststore.jks"
|
||||
private static final String STORE_PASSWORD = "passwordpassword"
|
||||
private static final String STORE_TYPE = "JKS"
|
||||
|
||||
private static final String TLS_1_3_PROTOCOL = "TLSv1.3"
|
||||
private static final List<String> TLS_1_3_CIPHER_SUITES = ["TLS_AES_128_GCM_SHA256"]
|
||||
|
||||
private static final TlsConfiguration TLS_CONFIGURATION = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore()
|
||||
|
||||
// These protocol versions should not ever be supported
|
||||
static private final List<String> LEGACY_TLS_PROTOCOLS = ["TLS", "TLSv1", "TLSv1.1", "SSL", "SSLv2", "SSLv2Hello", "SSLv3"]
|
||||
|
||||
NiFiProperties httpsProps = new NiFiProperties(new Properties([
|
||||
(NiFiProperties.WEB_HTTPS_PORT) : HTTPS_PORT as String,
|
||||
(NiFiProperties.WEB_HTTPS_HOST) : HTTPS_HOSTNAME,
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : KEYSTORE_PATH,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : STORE_PASSWORD,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : STORE_TYPE,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : TRUSTSTORE_PATH,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): STORE_PASSWORD,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : STORE_TYPE,
|
||||
(NiFiProperties.SECURITY_KEYSTORE) : TLS_CONFIGURATION.keystorePath,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD) : TLS_CONFIGURATION.keystorePassword,
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE) : TLS_CONFIGURATION.keystoreType.type,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE) : TLS_CONFIGURATION.truststorePath,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD): TLS_CONFIGURATION.truststorePassword,
|
||||
(NiFiProperties.SECURITY_TRUSTSTORE_TYPE) : TLS_CONFIGURATION.truststoreType.type,
|
||||
]))
|
||||
|
||||
@BeforeClass
|
||||
static void setUpOnce() throws Exception {
|
||||
new File(TLS_CONFIGURATION.keystorePath).deleteOnExit()
|
||||
new File(TLS_CONFIGURATION.truststorePath).deleteOnExit()
|
||||
|
||||
Security.addProvider(new BouncyCastleProvider())
|
||||
|
||||
logger.metaClass.methodMissing = { String name, args ->
|
||||
logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
|
||||
}
|
||||
|
||||
TestAppender.reset()
|
||||
}
|
||||
|
||||
@After
|
||||
void tearDown() throws Exception {
|
||||
// Cleans up the EMH so it can be reinitialized when a new Jetty server starts
|
||||
ExtensionManagerHolder.INSTANCE = null
|
||||
TestAppender.reset()
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -143,12 +137,9 @@ class JettyServerGroovyTest extends GroovyTestCase {
|
||||
// Act
|
||||
boolean bothConfigsPresent = JettyServer.bothHttpAndHttpsConnectorsConfigured(mockProps)
|
||||
logger.info("Both configs present: ${bothConfigsPresent}")
|
||||
def log = TestAppender.getLogLines()
|
||||
|
||||
// Assert
|
||||
assert bothConfigsPresent
|
||||
assert !log.isEmpty()
|
||||
assert log.first() =~ "Both the HTTP and HTTPS connectors are configured in nifi.properties. Only one of these connectors should be configured. See the NiFi Admin Guide for more details"
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -163,7 +154,6 @@ class JettyServerGroovyTest extends GroovyTestCase {
|
||||
getSslPort : { -> null },
|
||||
getProperty: { String prop ->
|
||||
String value = httpMap[prop] ?: "no_value"
|
||||
logger.mock("getProperty(${prop}) -> ${value}")
|
||||
value
|
||||
},
|
||||
] as NiFiProperties
|
||||
@ -177,7 +167,6 @@ class JettyServerGroovyTest extends GroovyTestCase {
|
||||
getSslPort : { -> DEFAULT_HTTPS_PORT },
|
||||
getProperty: { String prop ->
|
||||
String value = httpsMap[prop] ?: "no_value"
|
||||
logger.mock("getProperty(${prop}) -> ${value}")
|
||||
value
|
||||
},
|
||||
] as NiFiProperties
|
||||
@ -188,15 +177,10 @@ class JettyServerGroovyTest extends GroovyTestCase {
|
||||
|
||||
boolean bothConfigsPresentForHttps = JettyServer.bothHttpAndHttpsConnectorsConfigured(httpsProps)
|
||||
logger.info("Both configs present for HTTPS properties: ${bothConfigsPresentForHttps}")
|
||||
def log = TestAppender.getLogLines()
|
||||
|
||||
// Assert
|
||||
assert !bothConfigsPresentForHttp
|
||||
assert !bothConfigsPresentForHttps
|
||||
|
||||
// Verifies that the warning was not logged (messages are duplicated because of log4j.properties settings)
|
||||
assert log.size() == 4
|
||||
assert log.every { it =~ "Both configs present for HTTPS? properties: false" }
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -240,80 +224,6 @@ class JettyServerGroovyTest extends GroovyTestCase {
|
||||
// Assertions defined above
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression test added after NiFi 1.12.0 because Jetty upgrade to 9.4.26 no longer works
|
||||
* with multiple certificate keystores.
|
||||
*/
|
||||
@Test
|
||||
void testShouldStartWithMultipleCertificatePKCS12Keystore() {
|
||||
// Arrange
|
||||
final String externalHostname = "localhost"
|
||||
|
||||
NiFiProperties httpsProps = new NiFiProperties(new Properties([
|
||||
(NiFiProperties.WEB_HTTPS_PORT): HTTPS_PORT as String,
|
||||
(NiFiProperties.WEB_HTTPS_HOST): externalHostname,
|
||||
(NiFiProperties.SECURITY_KEYSTORE): "src/test/resources/multiple_cert_keystore.p12",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD): "passwordpassword",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE): "PKCS12",
|
||||
(NiFiProperties.NAR_LIBRARY_DIRECTORY): "target/"
|
||||
]))
|
||||
|
||||
JettyServer jetty = createJettyServer(httpsProps)
|
||||
Server internalServer = jetty.server
|
||||
List<Connector> connectors = Arrays.asList(internalServer.connectors)
|
||||
|
||||
// Act
|
||||
jetty.start()
|
||||
|
||||
// Assert
|
||||
assertServerConnector(connectors, externalHostname, HTTPS_PORT)
|
||||
|
||||
// Clean up
|
||||
jetty.stop()
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression test added after NiFi 1.12.0 because Jetty upgrade to 9.4.26 no longer works
|
||||
* with multiple certificate keystores.
|
||||
*/
|
||||
@Test
|
||||
void testShouldStartWithMultipleCertificateJKSKeystore() {
|
||||
// Arrange
|
||||
final String externalHostname = "localhost"
|
||||
|
||||
NiFiProperties httpsProps = new NiFiProperties(new Properties([
|
||||
(NiFiProperties.WEB_HTTPS_PORT): HTTPS_PORT as String,
|
||||
(NiFiProperties.WEB_HTTPS_HOST): externalHostname,
|
||||
(NiFiProperties.SECURITY_KEYSTORE): "src/test/resources/multiple_cert_keystore.jks",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_PASSWD): "passwordpassword",
|
||||
(NiFiProperties.SECURITY_KEYSTORE_TYPE): "JKS",
|
||||
(NiFiProperties.NAR_LIBRARY_DIRECTORY): "target/"
|
||||
]))
|
||||
|
||||
JettyServer jetty = createJettyServer(httpsProps)
|
||||
Server internalServer = jetty.server
|
||||
List<Connector> connectors = Arrays.asList(internalServer.connectors)
|
||||
|
||||
// Act
|
||||
jetty.start()
|
||||
|
||||
// Assert
|
||||
assertServerConnector(connectors, externalHostname, HTTPS_PORT)
|
||||
|
||||
// Clean up
|
||||
jetty.stop()
|
||||
}
|
||||
|
||||
private static JettyServer createJettyServer(NiFiProperties httpsProps) {
|
||||
Server internalServer = new Server()
|
||||
JettyServer jetty = new JettyServer(internalServer, httpsProps)
|
||||
jetty.systemBundle = SystemBundle.create(httpsProps)
|
||||
jetty.bundles = [] as Set<Bundle>
|
||||
jetty.extensionMapping = [size: { -> 0 }] as ExtensionMapping
|
||||
jetty.configureHttpsConnector(internalServer, new HttpConfiguration())
|
||||
jetty
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldConfigureHTTPSConnector() {
|
||||
// Arrange
|
||||
@ -523,35 +433,3 @@ class JettyServerGroovyTest extends GroovyTestCase {
|
||||
assert !filterNames.contains("ContentLengthFilter")
|
||||
}
|
||||
}
|
||||
|
||||
class TestAppender extends AppenderSkeleton {
|
||||
static final List<LoggingEvent> events = new ArrayList<>()
|
||||
|
||||
@Override
|
||||
protected void append(LoggingEvent e) {
|
||||
synchronized (events) {
|
||||
events.add(e)
|
||||
}
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
synchronized (events) {
|
||||
events.clear()
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean requiresLayout() {
|
||||
return false
|
||||
}
|
||||
|
||||
static List<String> getLogLines() {
|
||||
synchronized (events) {
|
||||
events.collect { LoggingEvent le -> le.getRenderedMessage() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
@ -1,28 +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.
|
||||
#
|
||||
|
||||
log4j.rootLogger=INFO,console,test
|
||||
log4j.logger.org.apache.nifi.web=DEBUG,console,test
|
||||
|
||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.console.Target=System.err
|
||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n
|
||||
|
||||
log4j.appender.test=org.apache.nifi.web.server.TestAppender
|
||||
log4j.appender.test.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.test.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n
|
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>%-4r [%t] %-5p %c - %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>./target/log</file>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>%date %level [%thread] %logger{40} %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="org.apache.nifi" level="INFO"/>
|
||||
<logger name="org.apache.nifi.web.server" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.web.util" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.web.filter" level="DEBUG"/>
|
||||
<logger name="org.eclipse.jetty.server" level="DEBUG"/>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</root>
|
||||
</configuration>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -17,6 +17,8 @@
|
||||
package org.apache.nifi.web.security.saml.impl;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.TlsConfiguration;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.nifi.web.security.saml.SAMLConfigurationFactory;
|
||||
import org.apache.nifi.web.security.saml.SAMLService;
|
||||
@ -28,12 +30,14 @@ import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ -43,7 +47,6 @@ public class TestStandardSAMLService {
|
||||
private SAMLConfigurationFactory samlConfigurationFactory;
|
||||
private SAMLService samlService;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpSuite() {
|
||||
Assume.assumeTrue("Test only runs on *nix", !SystemUtils.IS_OS_WINDOWS);
|
||||
@ -62,18 +65,22 @@ public class TestStandardSAMLService {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSamlEnabledWithFileBasedIdpMetadata() {
|
||||
public void testSamlEnabledWithFileBasedIdpMetadata() throws GeneralSecurityException, IOException {
|
||||
final String spEntityId = "org:apache:nifi";
|
||||
final File idpMetadataFile = new File("src/test/resources/saml/sso-circle-meta.xml");
|
||||
final String baseUrl = "https://localhost:8443/nifi-api";
|
||||
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_KEYSTORE)).thenReturn("src/test/resources/saml/keystore.jks");
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD)).thenReturn("passwordpassword");
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD)).thenReturn("passwordpassword");
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_TYPE)).thenReturn("JKS");
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE)).thenReturn("src/test/resources/saml/truststore.jks");
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD)).thenReturn("passwordpassword");
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_TYPE)).thenReturn("JKS");
|
||||
final TlsConfiguration tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
|
||||
new File(tlsConfiguration.getKeystorePath()).deleteOnExit();
|
||||
new File(tlsConfiguration.getTruststorePath()).deleteOnExit();
|
||||
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_KEYSTORE)).thenReturn(tlsConfiguration.getKeystorePath());
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD)).thenReturn(tlsConfiguration.getKeystorePassword());
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD)).thenReturn(tlsConfiguration.getKeyPassword());
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_TYPE)).thenReturn(tlsConfiguration.getKeystoreType().getType());
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE)).thenReturn(tlsConfiguration.getTruststorePath());
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD)).thenReturn(tlsConfiguration.getTruststorePassword());
|
||||
when(properties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_TYPE)).thenReturn(tlsConfiguration.getTruststoreType().getType());
|
||||
when(properties.getPropertyKeys()).thenReturn(new HashSet<>(Arrays.asList(
|
||||
NiFiProperties.SECURITY_KEYSTORE,
|
||||
NiFiProperties.SECURITY_KEYSTORE_PASSWD,
|
||||
@ -110,25 +117,9 @@ public class TestStandardSAMLService {
|
||||
@Test
|
||||
public void testInitializeWhenSamlNotEnabled() {
|
||||
when(properties.isSamlEnabled()).thenReturn(false);
|
||||
|
||||
// initialize the saml service
|
||||
samlService.initialize();
|
||||
assertFalse(samlService.isSamlEnabled());
|
||||
|
||||
// methods should throw IllegalStateException...
|
||||
|
||||
try {
|
||||
samlService.initializeServiceProvider("https://localhost:8443/nifi-api");
|
||||
fail("Should have thrown exception");
|
||||
} catch (IllegalStateException e) {
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
samlService.getServiceProviderMetadata();
|
||||
fail("Should have thrown exception");
|
||||
} catch (IllegalStateException e) {
|
||||
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> samlService.initializeServiceProvider("https://localhost:8443/nifi-api"));
|
||||
assertThrows(IllegalStateException.class, () -> samlService.getServiceProviderMetadata());
|
||||
}
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>%-4r [%t] %-5p %c - %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>./target/log</file>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>%date %level [%thread] %logger{40} %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="org.apache.nifi" level="INFO"/>
|
||||
<logger name="org.apache.nifi.web.api" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.web.server" level="DEBUG"/>
|
||||
<logger name="org.apache.nifi.web.security.requests" level="DEBUG"/>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</root>
|
||||
</configuration>
|
Binary file not shown.
Binary file not shown.
@ -22,18 +22,12 @@ import io.grpc.ManagedChannel;
|
||||
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSessionFactory;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.ssl.SSLContextService;
|
||||
import org.apache.nifi.ssl.StandardSSLContextService;
|
||||
import org.apache.nifi.util.MockFlowFile;
|
||||
import org.apache.nifi.util.TestRunner;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@ -43,38 +37,8 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
public class ITListenGRPC {
|
||||
private static final String HOST = "localhost";
|
||||
private static final String CERT_DN = "CN=localhost, OU=NIFI";
|
||||
private static final String SOURCE_SYSTEM_UUID = "FAKE_UUID";
|
||||
|
||||
private static Map<String, String> getTruststoreProperties() {
|
||||
final Map<String, String> props = new HashMap<>();
|
||||
props.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/truststore.jks");
|
||||
props.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "passwordpassword");
|
||||
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/keystore.jks");
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "passwordpassword");
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
|
||||
return properties;
|
||||
}
|
||||
|
||||
private static void useSSLContextService(final TestRunner controller, 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(InvokeGRPC.PROP_SSL_CONTEXT_SERVICE, "ssl-service");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulRoundTrip() throws Exception {
|
||||
final int randPort = TestGRPCClient.randomPort();
|
||||
@ -200,195 +164,4 @@ public class ITListenGRPC {
|
||||
channel.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecureTwoWaySSL() throws Exception {
|
||||
final int randPort = TestGRPCClient.randomPort();
|
||||
final Map<String, String> sslProperties = getKeystoreProperties();
|
||||
sslProperties.putAll(getTruststoreProperties());
|
||||
final ManagedChannel channel = TestGRPCClient.buildChannel(HOST, randPort, sslProperties);
|
||||
final FlowFileServiceGrpc.FlowFileServiceBlockingStub stub = FlowFileServiceGrpc.newBlockingStub(channel);
|
||||
|
||||
final ListenGRPC listenGRPC = new ListenGRPC();
|
||||
final TestRunner runner = TestRunners.newTestRunner(listenGRPC);
|
||||
runner.setProperty(ListenGRPC.PROP_SERVICE_PORT, String.valueOf(randPort));
|
||||
runner.setProperty(ListenGRPC.PROP_USE_SECURE, "true");
|
||||
useSSLContextService(runner, sslProperties);
|
||||
|
||||
final ProcessContext processContext = runner.getProcessContext();
|
||||
final ProcessSessionFactory processSessionFactory = runner.getProcessSessionFactory();
|
||||
|
||||
try {
|
||||
// start the server. The order of the following statements shouldn't matter, because the
|
||||
// startServer() method waits for a processSessionFactory to be available to it.
|
||||
listenGRPC.startServer(processContext);
|
||||
listenGRPC.onTrigger(processContext, processSessionFactory);
|
||||
|
||||
|
||||
final FlowFileRequest ingestFile = FlowFileRequest.newBuilder()
|
||||
.putAttributes("FOO", "BAR")
|
||||
.setContent(ByteString.copyFrom("content".getBytes()))
|
||||
.build();
|
||||
final FlowFileReply reply = stub.send(ingestFile);
|
||||
assertThat(reply.getResponseCode(), equalTo(FlowFileReply.ResponseCode.SUCCESS));
|
||||
assertThat(reply.getBody(), equalTo("FlowFile successfully received."));
|
||||
|
||||
runner.assertTransferCount(ListenGRPC.REL_SUCCESS, 1);
|
||||
final List<MockFlowFile> successFiles = runner.getFlowFilesForRelationship(ListenGRPC.REL_SUCCESS);
|
||||
assertThat(successFiles.size(), equalTo(1));
|
||||
final MockFlowFile mockFlowFile = successFiles.get(0);
|
||||
assertThat(mockFlowFile.getAttribute("FOO"), equalTo("BAR"));
|
||||
assertThat(mockFlowFile.getAttribute(ListenGRPC.REMOTE_HOST), equalTo("127.0.0.1"));
|
||||
assertThat(mockFlowFile.getAttribute(ListenGRPC.REMOTE_USER_DN), equalTo(CERT_DN));
|
||||
|
||||
} finally {
|
||||
// stop the server
|
||||
listenGRPC.stopServer(processContext);
|
||||
channel.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecureOneWaySSL() throws Exception {
|
||||
final int randPort = TestGRPCClient.randomPort();
|
||||
final Map<String, String> sslProperties = getTruststoreProperties();
|
||||
final ManagedChannel channel = TestGRPCClient.buildChannel(HOST, randPort, sslProperties);
|
||||
final FlowFileServiceGrpc.FlowFileServiceBlockingStub stub = FlowFileServiceGrpc.newBlockingStub(channel);
|
||||
|
||||
final ListenGRPC listenGRPC = new ListenGRPC();
|
||||
final TestRunner runner = TestRunners.newTestRunner(listenGRPC);
|
||||
runner.setProperty(ListenGRPC.PROP_SERVICE_PORT, String.valueOf(randPort));
|
||||
runner.setProperty(ListenGRPC.PROP_USE_SECURE, "true");
|
||||
useSSLContextService(runner, getKeystoreProperties());
|
||||
|
||||
final ProcessContext processContext = runner.getProcessContext();
|
||||
final ProcessSessionFactory processSessionFactory = runner.getProcessSessionFactory();
|
||||
|
||||
try {
|
||||
// start the server. The order of the following statements shouldn't matter, because the
|
||||
// startServer() method waits for a processSessionFactory to be available to it.
|
||||
listenGRPC.startServer(processContext);
|
||||
listenGRPC.onTrigger(processContext, processSessionFactory);
|
||||
|
||||
|
||||
final FlowFileRequest ingestFile = FlowFileRequest.newBuilder()
|
||||
.putAttributes("FOO", "BAR")
|
||||
.setContent(ByteString.copyFrom("content".getBytes()))
|
||||
.build();
|
||||
final FlowFileReply reply = stub.send(ingestFile);
|
||||
assertThat(reply.getResponseCode(), equalTo(FlowFileReply.ResponseCode.SUCCESS));
|
||||
assertThat(reply.getBody(), equalTo("FlowFile successfully received."));
|
||||
|
||||
// known race condition spot: grpc reply vs flowfile transfer
|
||||
Thread.sleep(10);
|
||||
runner.assertTransferCount(ListenGRPC.REL_SUCCESS, 1);
|
||||
final List<MockFlowFile> successFiles = runner.getFlowFilesForRelationship(ListenGRPC.REL_SUCCESS);
|
||||
assertThat(successFiles.size(), equalTo(1));
|
||||
final MockFlowFile mockFlowFile = successFiles.get(0);
|
||||
assertThat(mockFlowFile.getAttribute("FOO"), equalTo("BAR"));
|
||||
assertThat(mockFlowFile.getAttribute(ListenGRPC.REMOTE_HOST), equalTo("127.0.0.1"));
|
||||
assertThat(mockFlowFile.getAttribute(ListenGRPC.REMOTE_USER_DN), equalTo(FlowFileIngestServiceInterceptor.DEFAULT_FOUND_SUBJECT));
|
||||
|
||||
} finally {
|
||||
// stop the server
|
||||
listenGRPC.stopServer(processContext);
|
||||
channel.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = io.grpc.StatusRuntimeException.class)
|
||||
public void testSecureTwoWaySSLFailAuthorizedDNCheck() throws Exception {
|
||||
final int randPort = TestGRPCClient.randomPort();
|
||||
final Map<String, String> sslProperties = getKeystoreProperties();
|
||||
sslProperties.putAll(getTruststoreProperties());
|
||||
final ManagedChannel channel = TestGRPCClient.buildChannel(HOST, randPort, sslProperties);
|
||||
final FlowFileServiceGrpc.FlowFileServiceBlockingStub stub = FlowFileServiceGrpc.newBlockingStub(channel);
|
||||
|
||||
final ListenGRPC listenGRPC = new ListenGRPC();
|
||||
final TestRunner runner = TestRunners.newTestRunner(listenGRPC);
|
||||
runner.setProperty(ListenGRPC.PROP_SERVICE_PORT, String.valueOf(randPort));
|
||||
runner.setProperty(ListenGRPC.PROP_USE_SECURE, "true");
|
||||
runner.setProperty(ListenGRPC.PROP_AUTHORIZED_DN_PATTERN, "CN=FAKE.*");
|
||||
useSSLContextService(runner, sslProperties);
|
||||
|
||||
final ProcessContext processContext = runner.getProcessContext();
|
||||
final ProcessSessionFactory processSessionFactory = runner.getProcessSessionFactory();
|
||||
|
||||
try {
|
||||
// start the server. The order of the following statements shouldn't matter, because the
|
||||
// startServer() method waits for a processSessionFactory to be available to it.
|
||||
listenGRPC.startServer(processContext);
|
||||
listenGRPC.onTrigger(processContext, processSessionFactory);
|
||||
|
||||
|
||||
final FlowFileRequest ingestFile = FlowFileRequest.newBuilder()
|
||||
.putAttributes("FOO", "BAR")
|
||||
.setContent(ByteString.copyFrom("content".getBytes()))
|
||||
.build();
|
||||
final FlowFileReply reply = stub.send(ingestFile);
|
||||
assertThat(reply.getResponseCode(), equalTo(FlowFileReply.ResponseCode.SUCCESS));
|
||||
assertThat(reply.getBody(), equalTo("FlowFile successfully received."));
|
||||
|
||||
runner.assertTransferCount(ListenGRPC.REL_SUCCESS, 1);
|
||||
final List<MockFlowFile> successFiles = runner.getFlowFilesForRelationship(ListenGRPC.REL_SUCCESS);
|
||||
assertThat(successFiles.size(), equalTo(1));
|
||||
final MockFlowFile mockFlowFile = successFiles.get(0);
|
||||
assertThat(mockFlowFile.getAttribute("FOO"), equalTo("BAR"));
|
||||
assertThat(mockFlowFile.getAttribute(ListenGRPC.REMOTE_HOST), equalTo("127.0.0.1"));
|
||||
assertThat(mockFlowFile.getAttribute(ListenGRPC.REMOTE_USER_DN), equalTo(CERT_DN));
|
||||
|
||||
} finally {
|
||||
// stop the server
|
||||
listenGRPC.stopServer(processContext);
|
||||
channel.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecureTwoWaySSLPassAuthorizedDNCheck() throws Exception {
|
||||
final int randPort = TestGRPCClient.randomPort();
|
||||
final Map<String, String> sslProperties = getKeystoreProperties();
|
||||
sslProperties.putAll(getTruststoreProperties());
|
||||
final ManagedChannel channel = TestGRPCClient.buildChannel(HOST, randPort, sslProperties);
|
||||
final FlowFileServiceGrpc.FlowFileServiceBlockingStub stub = FlowFileServiceGrpc.newBlockingStub(channel);
|
||||
|
||||
final ListenGRPC listenGRPC = new ListenGRPC();
|
||||
final TestRunner runner = TestRunners.newTestRunner(listenGRPC);
|
||||
runner.setProperty(ListenGRPC.PROP_SERVICE_PORT, String.valueOf(randPort));
|
||||
runner.setProperty(ListenGRPC.PROP_USE_SECURE, "true");
|
||||
runner.setProperty(ListenGRPC.PROP_AUTHORIZED_DN_PATTERN, "CN=localhost.*");
|
||||
useSSLContextService(runner, sslProperties);
|
||||
|
||||
final ProcessContext processContext = runner.getProcessContext();
|
||||
final ProcessSessionFactory processSessionFactory = runner.getProcessSessionFactory();
|
||||
|
||||
try {
|
||||
// start the server. The order of the following statements shouldn't matter, because the
|
||||
// startServer() method waits for a processSessionFactory to be available to it.
|
||||
listenGRPC.startServer(processContext);
|
||||
listenGRPC.onTrigger(processContext, processSessionFactory);
|
||||
|
||||
|
||||
final FlowFileRequest ingestFile = FlowFileRequest.newBuilder()
|
||||
.putAttributes("FOO", "BAR")
|
||||
.setContent(ByteString.copyFrom("content".getBytes()))
|
||||
.build();
|
||||
final FlowFileReply reply = stub.send(ingestFile);
|
||||
assertThat(reply.getResponseCode(), equalTo(FlowFileReply.ResponseCode.SUCCESS));
|
||||
assertThat(reply.getBody(), equalTo("FlowFile successfully received."));
|
||||
|
||||
runner.assertTransferCount(ListenGRPC.REL_SUCCESS, 1);
|
||||
final List<MockFlowFile> successFiles = runner.getFlowFilesForRelationship(ListenGRPC.REL_SUCCESS);
|
||||
assertThat(successFiles.size(), equalTo(1));
|
||||
final MockFlowFile mockFlowFile = successFiles.get(0);
|
||||
assertThat(mockFlowFile.getAttribute("FOO"), equalTo("BAR"));
|
||||
assertThat(mockFlowFile.getAttribute(ListenGRPC.REMOTE_HOST), equalTo("127.0.0.1"));
|
||||
assertThat(mockFlowFile.getAttribute(ListenGRPC.REMOTE_USER_DN), equalTo(CERT_DN));
|
||||
|
||||
} finally {
|
||||
// stop the server
|
||||
listenGRPC.stopServer(processContext);
|
||||
channel.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,21 +16,14 @@
|
||||
*/
|
||||
package org.apache.nifi.processors.grpc;
|
||||
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.ssl.SSLContextService;
|
||||
import org.apache.nifi.ssl.StandardSSLContextService;
|
||||
import org.apache.nifi.util.MockFlowFile;
|
||||
import org.apache.nifi.util.TestRunner;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.grpc.stub.StreamObserver;
|
||||
import io.netty.handler.ssl.ClientAuth;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@ -394,121 +387,6 @@ public class TestInvokeGRPC {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecureTwoWaySsl() throws Exception {
|
||||
final Map<String, String> sslProperties = getKeystoreProperties();
|
||||
sslProperties.putAll(getTruststoreProperties());
|
||||
final TestGRPCServer<DummyFlowFileService> server = new TestGRPCServer<>(DummyFlowFileService.class, sslProperties);
|
||||
|
||||
try {
|
||||
final TestRunner runner = TestRunners.newTestRunner(InvokeGRPC.class);
|
||||
runner.setProperty(InvokeGRPC.PROP_SERVICE_HOST, TestGRPCServer.HOST);
|
||||
useSSLContextService(runner, sslProperties);
|
||||
final int port = server.start(0);
|
||||
runner.setProperty(InvokeGRPC.PROP_SERVICE_PORT, String.valueOf(port));
|
||||
runner.setProperty(InvokeGRPC.PROP_USE_SECURE, "true");
|
||||
|
||||
final MockFlowFile mockFlowFile = new MockFlowFile(SUCCESS);
|
||||
runner.enqueue(mockFlowFile);
|
||||
runner.run();
|
||||
runner.assertTransferCount(InvokeGRPC.REL_RESPONSE, 1);
|
||||
runner.assertTransferCount(InvokeGRPC.REL_SUCCESS_REQ, 1);
|
||||
runner.assertTransferCount(InvokeGRPC.REL_RETRY, 0);
|
||||
runner.assertTransferCount(InvokeGRPC.REL_NO_RETRY, 0);
|
||||
runner.assertTransferCount(InvokeGRPC.REL_FAILURE, 0);
|
||||
|
||||
final List<MockFlowFile> responseFiles = runner.getFlowFilesForRelationship(InvokeGRPC.REL_RESPONSE);
|
||||
assertThat(responseFiles.size(), equalTo(1));
|
||||
final MockFlowFile response = responseFiles.get(0);
|
||||
response.assertAttributeEquals(InvokeGRPC.RESPONSE_CODE, String.valueOf(FlowFileReply.ResponseCode.SUCCESS));
|
||||
response.assertAttributeEquals(InvokeGRPC.RESPONSE_BODY, "success");
|
||||
response.assertAttributeEquals(InvokeGRPC.SERVICE_HOST, TestGRPCServer.HOST);
|
||||
response.assertAttributeEquals(InvokeGRPC.SERVICE_PORT, String.valueOf(port));
|
||||
|
||||
final List<MockFlowFile> successFiles = runner.getFlowFilesForRelationship(InvokeGRPC.REL_SUCCESS_REQ);
|
||||
assertThat(successFiles.size(), equalTo(1));
|
||||
final MockFlowFile successFile = successFiles.get(0);
|
||||
successFile.assertAttributeEquals(InvokeGRPC.RESPONSE_CODE, String.valueOf(FlowFileReply.ResponseCode.SUCCESS));
|
||||
successFile.assertAttributeEquals(InvokeGRPC.RESPONSE_BODY, "success");
|
||||
successFile.assertAttributeEquals(InvokeGRPC.SERVICE_HOST, TestGRPCServer.HOST);
|
||||
successFile.assertAttributeEquals(InvokeGRPC.SERVICE_PORT, String.valueOf(port));
|
||||
} finally {
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecureOneWaySsl() throws Exception {
|
||||
final Map<String, String> sslProperties = getKeystoreProperties();
|
||||
sslProperties.put(TestGRPCServer.NEED_CLIENT_AUTH, ClientAuth.NONE.name());
|
||||
final TestGRPCServer<DummyFlowFileService> server = new TestGRPCServer<>(DummyFlowFileService.class, sslProperties);
|
||||
|
||||
try {
|
||||
final TestRunner runner = TestRunners.newTestRunner(InvokeGRPC.class);
|
||||
runner.setProperty(InvokeGRPC.PROP_SERVICE_HOST, TestGRPCServer.HOST);
|
||||
useSSLContextService(runner, getTruststoreProperties());
|
||||
final int port = server.start(0);
|
||||
runner.setProperty(InvokeGRPC.PROP_SERVICE_PORT, String.valueOf(port));
|
||||
runner.setProperty(InvokeGRPC.PROP_USE_SECURE, "true");
|
||||
|
||||
final MockFlowFile mockFlowFile = new MockFlowFile(SUCCESS);
|
||||
runner.enqueue(mockFlowFile);
|
||||
runner.run();
|
||||
runner.assertTransferCount(InvokeGRPC.REL_RESPONSE, 1);
|
||||
runner.assertTransferCount(InvokeGRPC.REL_SUCCESS_REQ, 1);
|
||||
runner.assertTransferCount(InvokeGRPC.REL_RETRY, 0);
|
||||
runner.assertTransferCount(InvokeGRPC.REL_NO_RETRY, 0);
|
||||
runner.assertTransferCount(InvokeGRPC.REL_FAILURE, 0);
|
||||
|
||||
final List<MockFlowFile> responseFiles = runner.getFlowFilesForRelationship(InvokeGRPC.REL_RESPONSE);
|
||||
assertThat(responseFiles.size(), equalTo(1));
|
||||
final MockFlowFile response = responseFiles.get(0);
|
||||
response.assertAttributeEquals(InvokeGRPC.RESPONSE_CODE, String.valueOf(FlowFileReply.ResponseCode.SUCCESS));
|
||||
response.assertAttributeEquals(InvokeGRPC.RESPONSE_BODY, "success");
|
||||
response.assertAttributeEquals(InvokeGRPC.SERVICE_HOST, TestGRPCServer.HOST);
|
||||
response.assertAttributeEquals(InvokeGRPC.SERVICE_PORT, String.valueOf(port));
|
||||
|
||||
final List<MockFlowFile> successFiles = runner.getFlowFilesForRelationship(InvokeGRPC.REL_SUCCESS_REQ);
|
||||
assertThat(successFiles.size(), equalTo(1));
|
||||
final MockFlowFile successFile = successFiles.get(0);
|
||||
successFile.assertAttributeEquals(InvokeGRPC.RESPONSE_CODE, String.valueOf(FlowFileReply.ResponseCode.SUCCESS));
|
||||
successFile.assertAttributeEquals(InvokeGRPC.RESPONSE_BODY, "success");
|
||||
successFile.assertAttributeEquals(InvokeGRPC.SERVICE_HOST, TestGRPCServer.HOST);
|
||||
successFile.assertAttributeEquals(InvokeGRPC.SERVICE_PORT, String.valueOf(port));
|
||||
} finally {
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> getTruststoreProperties() {
|
||||
final Map<String, String> props = new HashMap<>();
|
||||
props.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/truststore.jks");
|
||||
props.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "passwordpassword");
|
||||
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/keystore.jks");
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "passwordpassword");
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
|
||||
return properties;
|
||||
}
|
||||
|
||||
private void useSSLContextService(final TestRunner controller, 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(InvokeGRPC.PROP_SSL_CONTEXT_SERVICE, "ssl-service");
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy gRPC service whose responses are dictated by the IDs on the messages it receives
|
||||
*/
|
||||
|
Binary file not shown.
Binary file not shown.
@ -54,11 +54,12 @@
|
||||
<artifactId>moquette-broker</artifactId>
|
||||
<version>0.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-ssl-context-service</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
|
@ -21,10 +21,13 @@ import io.moquette.proto.messages.PublishMessage;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
import org.apache.nifi.processors.mqtt.common.MQTTQueueMessage;
|
||||
import org.apache.nifi.processors.mqtt.common.MqttTestClient;
|
||||
import org.apache.nifi.processors.mqtt.common.MqttTestUtils;
|
||||
import org.apache.nifi.processors.mqtt.common.TestConsumeMqttCommon;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.ssl.StandardSSLContextService;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.SslContextFactory;
|
||||
import org.apache.nifi.security.util.TlsConfiguration;
|
||||
import org.apache.nifi.security.util.TlsException;
|
||||
import org.apache.nifi.ssl.SSLContextService;
|
||||
import org.apache.nifi.util.TestRunner;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttClient;
|
||||
@ -33,14 +36,16 @@ import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@ -50,6 +55,8 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
public class TestConsumeMQTT extends TestConsumeMqttCommon {
|
||||
private static TlsConfiguration tlsConfiguration;
|
||||
|
||||
public MqttTestClient mqttTestClient;
|
||||
|
||||
public class UnitTestableConsumeMqtt extends ConsumeMQTT {
|
||||
@ -65,8 +72,15 @@ public class TestConsumeMQTT extends TestConsumeMqttCommon {
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setTlsConfiguration() throws IOException, GeneralSecurityException {
|
||||
tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
|
||||
new File(tlsConfiguration.getKeystorePath()).deleteOnExit();
|
||||
new File(tlsConfiguration.getTruststorePath()).deleteOnExit();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init() throws IOException {
|
||||
public void init() {
|
||||
PUBLISH_WAIT_MS = 0;
|
||||
|
||||
broker = "tcp://localhost:1883";
|
||||
@ -79,7 +93,7 @@ public class TestConsumeMQTT extends TestConsumeMqttCommon {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSSLContextServiceTruststoreOnly() throws InitializationException {
|
||||
public void testSslContextService() throws InitializationException, TlsException {
|
||||
String brokerURI = "ssl://localhost:8883";
|
||||
TestRunner runner = TestRunners.newTestRunner(ConsumeMQTT.class);
|
||||
runner.setVariable("brokerURI", brokerURI);
|
||||
@ -88,26 +102,25 @@ public class TestConsumeMQTT extends TestConsumeMqttCommon {
|
||||
runner.setProperty(ConsumeMQTT.PROP_TOPIC_FILTER, "testTopic");
|
||||
runner.setProperty(ConsumeMQTT.PROP_MAX_QUEUE_SIZE, "100");
|
||||
|
||||
final StandardSSLContextService sslService = new StandardSSLContextService();
|
||||
Map<String, String> sslProperties = MqttTestUtils.createSslPropertiesTruststoreOnly();
|
||||
runner.addControllerService("ssl-context", sslService, sslProperties);
|
||||
runner.enableControllerService(sslService);
|
||||
runner.setProperty(ConsumeMQTT.PROP_SSL_CONTEXT_SERVICE, "ssl-context");
|
||||
final SSLContextService sslContextService = mock(SSLContextService.class);
|
||||
final String identifier = SSLContextService.class.getSimpleName();
|
||||
when(sslContextService.getIdentifier()).thenReturn(identifier);
|
||||
final SSLContext sslContext = SslContextFactory.createSslContext(tlsConfiguration);
|
||||
when(sslContextService.createContext()).thenReturn(sslContext);
|
||||
|
||||
try {
|
||||
ConsumeMQTT processor = (ConsumeMQTT) runner.getProcessor();
|
||||
processor.onScheduled(runner.getProcessContext());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail("Unexpected error");
|
||||
}
|
||||
runner.addControllerService(identifier, sslContextService);
|
||||
runner.enableControllerService(sslContextService);
|
||||
runner.setProperty(ConsumeMQTT.PROP_SSL_CONTEXT_SERVICE, identifier);
|
||||
|
||||
ConsumeMQTT processor = (ConsumeMQTT) runner.getProcessor();
|
||||
processor.onScheduled(runner.getProcessContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the session.commit() fails, we should not remove the unprocessed message
|
||||
*/
|
||||
@Test
|
||||
public void testMessageNotConsumedOnCommitFail() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
|
||||
public void testMessageNotConsumedOnCommitFail() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException {
|
||||
testRunner.run(1, false);
|
||||
ConsumeMQTT processor = (ConsumeMQTT) testRunner.getProcessor();
|
||||
MQTTQueueMessage mock = mock(MQTTQueueMessage.class);
|
||||
@ -133,7 +146,7 @@ public class TestConsumeMQTT extends TestConsumeMqttCommon {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
public void tearDown() {
|
||||
if (MQTT_server != null) {
|
||||
MQTT_server.stopServer();
|
||||
}
|
||||
|
@ -1,46 +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.processors.mqtt.common;
|
||||
|
||||
import org.apache.nifi.ssl.StandardSSLContextService;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MqttTestUtils {
|
||||
|
||||
public static Map<String, String> createSslProperties() {
|
||||
final Map<String, String> map = new HashMap<>();
|
||||
map.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/keystore.jks");
|
||||
map.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "passwordpassword");
|
||||
map.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
|
||||
map.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/truststore.jks");
|
||||
map.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "passwordpassword");
|
||||
map.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
|
||||
return map;
|
||||
}
|
||||
|
||||
public static Map<String, String> createSslPropertiesTruststoreOnly() {
|
||||
final Map<String, String> map = new HashMap<>();
|
||||
map.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/truststore.jks");
|
||||
map.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "passwordpassword");
|
||||
map.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
@ -1,148 +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.processors.mqtt.integration;
|
||||
|
||||
import io.moquette.BrokerConstants;
|
||||
import io.moquette.proto.messages.AbstractMessage;
|
||||
import io.moquette.proto.messages.PublishMessage;
|
||||
import io.moquette.server.Server;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.moquette.server.config.MemoryConfig;
|
||||
import org.apache.nifi.processors.mqtt.ConsumeMQTT;
|
||||
import org.apache.nifi.processors.mqtt.common.TestConsumeMqttCommon;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.ssl.StandardSSLContextService;
|
||||
import org.apache.nifi.util.MockFlowFile;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static io.moquette.BrokerConstants.PERSISTENT_STORE_PROPERTY_NAME;
|
||||
import static org.apache.nifi.processors.mqtt.ConsumeMQTT.BROKER_ATTRIBUTE_KEY;
|
||||
import static org.apache.nifi.processors.mqtt.ConsumeMQTT.IS_DUPLICATE_ATTRIBUTE_KEY;
|
||||
import static org.apache.nifi.processors.mqtt.ConsumeMQTT.IS_RETAINED_ATTRIBUTE_KEY;
|
||||
import static org.apache.nifi.processors.mqtt.ConsumeMQTT.QOS_ATTRIBUTE_KEY;
|
||||
import static org.apache.nifi.processors.mqtt.ConsumeMQTT.TOPIC_ATTRIBUTE_KEY;
|
||||
import static org.apache.nifi.processors.mqtt.common.MqttTestUtils.createSslProperties;
|
||||
|
||||
|
||||
public class TestConsumeMqttSSL extends TestConsumeMqttCommon {
|
||||
|
||||
|
||||
private void startServer() throws IOException {
|
||||
MQTT_server = new Server();
|
||||
final Properties configProps = new Properties();
|
||||
|
||||
configProps.put(BrokerConstants.WEB_SOCKET_PORT_PROPERTY_NAME, "1884");
|
||||
configProps.put(BrokerConstants.SSL_PORT_PROPERTY_NAME, "8883");
|
||||
configProps.put(BrokerConstants.JKS_PATH_PROPERTY_NAME, "src/test/resources/keystore.jks");
|
||||
configProps.put(BrokerConstants.KEY_STORE_PASSWORD_PROPERTY_NAME, "passwordpassword");
|
||||
configProps.put(BrokerConstants.KEY_MANAGER_PASSWORD_PROPERTY_NAME, "passwordpassword");
|
||||
configProps.setProperty(PERSISTENT_STORE_PROPERTY_NAME,"./target/moquette_store.mapdb");
|
||||
IConfig server_config = new MemoryConfig(configProps);
|
||||
MQTT_server.startServer(server_config);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init() throws IOException, InitializationException {
|
||||
startServer();
|
||||
|
||||
broker = "ssl://localhost:8883";
|
||||
testRunner = TestRunners.newTestRunner(ConsumeMQTT.class);
|
||||
testRunner.setProperty(ConsumeMQTT.PROP_BROKER_URI, broker);
|
||||
testRunner.setProperty(ConsumeMQTT.PROP_CLIENTID, "TestClient");
|
||||
testRunner.setProperty(ConsumeMQTT.PROP_TOPIC_FILTER, "testTopic");
|
||||
testRunner.setProperty(ConsumeMQTT.PROP_MAX_QUEUE_SIZE, "100");
|
||||
|
||||
final StandardSSLContextService sslService = new StandardSSLContextService();
|
||||
Map<String, String> sslProperties = createSslProperties();
|
||||
testRunner.addControllerService("ssl-context", sslService, sslProperties);
|
||||
testRunner.enableControllerService(sslService);
|
||||
testRunner.setProperty(ConsumeMQTT.PROP_SSL_CONTEXT_SERVICE, "ssl-context");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (MQTT_server != null) {
|
||||
MQTT_server.stopServer();
|
||||
}
|
||||
final File folder = new File("./target");
|
||||
final File[] files = folder.listFiles( new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept( final File dir,
|
||||
final String name ) {
|
||||
return name.matches( "moquette_store.mapdb.*" );
|
||||
}
|
||||
} );
|
||||
for ( final File file : files ) {
|
||||
if ( !file.delete() ) {
|
||||
System.err.println( "Can't remove " + file.getAbsolutePath() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetainedQoS2() throws Exception {
|
||||
testRunner.setProperty(ConsumeMQTT.PROP_QOS, "2");
|
||||
|
||||
testRunner.assertValid();
|
||||
|
||||
PublishMessage testMessage = new PublishMessage();
|
||||
testMessage.setPayload(ByteBuffer.wrap("testMessage".getBytes()));
|
||||
testMessage.setTopicName("testTopic");
|
||||
testMessage.setDupFlag(false);
|
||||
testMessage.setQos(AbstractMessage.QOSType.EXACTLY_ONCE);
|
||||
testMessage.setRetainFlag(true);
|
||||
|
||||
internalPublish(testMessage);
|
||||
|
||||
ConsumeMQTT consumeMQTT = (ConsumeMQTT) testRunner.getProcessor();
|
||||
consumeMQTT.onScheduled(testRunner.getProcessContext());
|
||||
reconnect(consumeMQTT, testRunner.getProcessContext());
|
||||
|
||||
Thread.sleep(PUBLISH_WAIT_MS);
|
||||
|
||||
testRunner.run(1, false, false);
|
||||
|
||||
testRunner.assertTransferCount(ConsumeMQTT.REL_MESSAGE, 1);
|
||||
|
||||
List<MockFlowFile> flowFiles = testRunner.getFlowFilesForRelationship(ConsumeMQTT.REL_MESSAGE);
|
||||
MockFlowFile flowFile = flowFiles.get(0);
|
||||
|
||||
flowFile.assertContentEquals("testMessage");
|
||||
flowFile.assertAttributeEquals(BROKER_ATTRIBUTE_KEY, broker);
|
||||
flowFile.assertAttributeEquals(TOPIC_ATTRIBUTE_KEY, "testTopic");
|
||||
flowFile.assertAttributeEquals(QOS_ATTRIBUTE_KEY, "2");
|
||||
flowFile.assertAttributeEquals(IS_DUPLICATE_ATTRIBUTE_KEY, "false");
|
||||
flowFile.assertAttributeEquals(IS_RETAINED_ATTRIBUTE_KEY, "true");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalPublish(PublishMessage publishMessage) {
|
||||
MQTT_server.internalPublish(publishMessage);
|
||||
}
|
||||
}
|
@ -58,7 +58,7 @@ public class TestPublishMQTT extends TestPublishMqttCommon {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
public void tearDown() {
|
||||
if (MQTT_server != null) {
|
||||
MQTT_server.stopServer();
|
||||
}
|
||||
|
@ -1,98 +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.processors.mqtt.integration;
|
||||
|
||||
import io.moquette.BrokerConstants;
|
||||
import io.moquette.server.Server;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.moquette.server.config.MemoryConfig;
|
||||
import org.apache.nifi.processors.mqtt.PublishMQTT;
|
||||
import org.apache.nifi.processors.mqtt.common.TestPublishMqttCommon;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.ssl.StandardSSLContextService;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static io.moquette.BrokerConstants.PERSISTENT_STORE_PROPERTY_NAME;
|
||||
import static org.apache.nifi.processors.mqtt.common.MqttTestUtils.createSslProperties;
|
||||
|
||||
|
||||
public class TestPublishMqttSSL extends TestPublishMqttCommon {
|
||||
|
||||
private void startServer() throws IOException {
|
||||
MQTT_server = new Server();
|
||||
final Properties configProps = new Properties();
|
||||
|
||||
configProps.put(BrokerConstants.WEB_SOCKET_PORT_PROPERTY_NAME, "1884");
|
||||
configProps.put(BrokerConstants.SSL_PORT_PROPERTY_NAME, "8883");
|
||||
configProps.put(BrokerConstants.JKS_PATH_PROPERTY_NAME, "src/test/resources/keystore.jks");
|
||||
configProps.put(BrokerConstants.KEY_STORE_PASSWORD_PROPERTY_NAME, "passwordpassword");
|
||||
configProps.put(BrokerConstants.KEY_MANAGER_PASSWORD_PROPERTY_NAME, "passwordpassword");
|
||||
configProps.setProperty(PERSISTENT_STORE_PROPERTY_NAME,"./target/moquette_store.mapdb");
|
||||
IConfig server_config = new MemoryConfig(configProps);
|
||||
MQTT_server.startServer(server_config);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init() throws IOException, InitializationException {
|
||||
startServer();
|
||||
testRunner = TestRunners.newTestRunner(PublishMQTT.class);
|
||||
testRunner.setProperty(PublishMQTT.PROP_BROKER_URI, "ssl://localhost:8883");
|
||||
testRunner.setProperty(PublishMQTT.PROP_CLIENTID, "TestClient");
|
||||
testRunner.setProperty(PublishMQTT.PROP_RETAIN, "true");
|
||||
testRunner.setProperty(PublishMQTT.PROP_TOPIC, "testTopic");
|
||||
|
||||
final StandardSSLContextService sslService = new StandardSSLContextService();
|
||||
Map<String, String> sslProperties = createSslProperties();
|
||||
testRunner.addControllerService("ssl-context", sslService, sslProperties);
|
||||
testRunner.enableControllerService(sslService);
|
||||
testRunner.setProperty(PublishMQTT.PROP_SSL_CONTEXT_SERVICE, "ssl-context");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (MQTT_server != null) {
|
||||
MQTT_server.stopServer();
|
||||
}
|
||||
final File folder = new File("./target");
|
||||
final File[] files = folder.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(final File dir,
|
||||
final String name) {
|
||||
return name.matches("moquette_store.mapdb.*");
|
||||
}
|
||||
});
|
||||
for (final File file : files) {
|
||||
if (!file.delete()) {
|
||||
System.err.println("Can't remove " + file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyPublishedMessage(byte[] payload, int qos, boolean retain) {
|
||||
//Cannot verify published message without subscribing and consuming it which is outside the scope of this test.
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
@ -1,112 +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.processors.livy;
|
||||
|
||||
import org.apache.nifi.controller.livy.LivySessionController;
|
||||
import org.apache.nifi.ssl.StandardSSLContextService;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.apache.nifi.web.util.TestServer;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TestExecuteSparkInteractiveSSL extends ExecuteSparkInteractiveTestBase {
|
||||
|
||||
private static Map<String, String> sslProperties;
|
||||
|
||||
private static TestServer server;
|
||||
private static String url;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
// useful for verbose logging output
|
||||
// don't commit this with this property enabled, or any 'mvn test' will be really verbose
|
||||
// System.setProperty("org.slf4j.simpleLogger.log.nifi.processors.standard", "debug");
|
||||
|
||||
// create the SSL properties, which basically store keystore / truststore information
|
||||
// this is used by the StandardSSLContextService and the Jetty Server
|
||||
sslProperties = createSslProperties();
|
||||
|
||||
// create a Jetty server on a random port
|
||||
server = createServer();
|
||||
server.startServer();
|
||||
|
||||
// Allow time for the server to start
|
||||
Thread.sleep(1000);
|
||||
|
||||
// this is the base url with the random port
|
||||
url = server.getSecureUrl();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
server.shutdownServer();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
runner = TestRunners.newTestRunner(ExecuteSparkInteractive.class);
|
||||
|
||||
final StandardSSLContextService sslService = new StandardSSLContextService();
|
||||
runner.addControllerService("ssl-context", sslService, sslProperties);
|
||||
runner.enableControllerService(sslService);
|
||||
|
||||
// Allow time for the controller service to fully initialize
|
||||
Thread.sleep(500);
|
||||
|
||||
LivySessionController livyControllerService = new LivySessionController();
|
||||
runner.addControllerService("livyCS", livyControllerService);
|
||||
runner.setProperty(livyControllerService, LivySessionController.LIVY_HOST, url.substring(url.indexOf("://") + 3, url.lastIndexOf(":")));
|
||||
runner.setProperty(livyControllerService, LivySessionController.LIVY_PORT, url.substring(url.lastIndexOf(":") + 1));
|
||||
runner.setProperty(livyControllerService, LivySessionController.SSL_CONTEXT_SERVICE, "ssl-context");
|
||||
runner.enableControllerService(livyControllerService);
|
||||
|
||||
runner.setProperty(ExecuteSparkInteractive.LIVY_CONTROLLER_SERVICE, "livyCS");
|
||||
|
||||
server.clearHandlers();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
runner.shutdown();
|
||||
}
|
||||
|
||||
private static TestServer createServer() {
|
||||
return new TestServer(sslProperties);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSparkSession() throws Exception {
|
||||
testCode(server,"print \"hello world\"");
|
||||
}
|
||||
|
||||
private static Map<String, String> createSslProperties() {
|
||||
final Map<String, String> map = new HashMap<>();
|
||||
map.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/keystore.jks");
|
||||
map.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "passwordpassword");
|
||||
map.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
|
||||
map.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/truststore.jks");
|
||||
map.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "passwordpassword");
|
||||
map.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
|
||||
return map;
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -17,7 +17,7 @@
|
||||
package org.apache.nifi.web.util.ssl;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.security.util.KeystoreType;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.SslContextFactory;
|
||||
import org.apache.nifi.security.util.StandardTlsConfiguration;
|
||||
import org.apache.nifi.security.util.TlsConfiguration;
|
||||
@ -27,33 +27,43 @@ import javax.net.ssl.SSLContext;
|
||||
import java.io.File;
|
||||
|
||||
public class SslContextUtils {
|
||||
private static final String KEYSTORE_PATH = "src/test/resources/keystore.jks";
|
||||
private static final TlsConfiguration TLS_CONFIGURATION;
|
||||
|
||||
private static final String KEYSTORE_AND_TRUSTSTORE_PASSWORD = "passwordpassword";
|
||||
private static final TlsConfiguration KEYSTORE_TLS_CONFIGURATION;
|
||||
|
||||
private static final String TRUSTSTORE_PATH = "src/test/resources/truststore.jks";
|
||||
private static final TlsConfiguration TRUSTSTORE_TLS_CONFIGURATION;
|
||||
|
||||
private static final TlsConfiguration KEYSTORE_TLS_CONFIGURATION = new StandardTlsConfiguration(
|
||||
KEYSTORE_PATH,
|
||||
KEYSTORE_AND_TRUSTSTORE_PASSWORD,
|
||||
KEYSTORE_AND_TRUSTSTORE_PASSWORD,
|
||||
KeystoreType.JKS,
|
||||
TRUSTSTORE_PATH,
|
||||
KEYSTORE_AND_TRUSTSTORE_PASSWORD,
|
||||
KeystoreType.JKS,
|
||||
TlsConfiguration.TLS_1_2_PROTOCOL
|
||||
);
|
||||
static {
|
||||
try {
|
||||
TLS_CONFIGURATION = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
|
||||
new File(TLS_CONFIGURATION.getKeystorePath()).deleteOnExit();
|
||||
new File(TLS_CONFIGURATION.getTruststorePath()).deleteOnExit();
|
||||
|
||||
private static final TlsConfiguration TRUSTSTORE_TLS_CONFIGURATION = new StandardTlsConfiguration(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
TRUSTSTORE_PATH,
|
||||
KEYSTORE_AND_TRUSTSTORE_PASSWORD,
|
||||
KeystoreType.JKS,
|
||||
TlsConfiguration.TLS_1_2_PROTOCOL
|
||||
);
|
||||
KEYSTORE_TLS_CONFIGURATION = new StandardTlsConfiguration(
|
||||
TLS_CONFIGURATION.getKeystorePath(),
|
||||
TLS_CONFIGURATION.getKeystorePassword(),
|
||||
TLS_CONFIGURATION.getKeyPassword(),
|
||||
TLS_CONFIGURATION.getKeystoreType().getType(),
|
||||
TLS_CONFIGURATION.getTruststorePath(),
|
||||
TLS_CONFIGURATION.getTruststorePassword(),
|
||||
TLS_CONFIGURATION.getTruststoreType().getType(),
|
||||
TlsConfiguration.TLS_1_2_PROTOCOL
|
||||
);
|
||||
|
||||
TRUSTSTORE_TLS_CONFIGURATION = new StandardTlsConfiguration(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
TLS_CONFIGURATION.getTruststorePath(),
|
||||
TLS_CONFIGURATION.getTruststorePassword(),
|
||||
TLS_CONFIGURATION.getTruststoreType().getType(),
|
||||
TlsConfiguration.TLS_1_2_PROTOCOL
|
||||
);
|
||||
} catch (final Exception e) {
|
||||
throw new IllegalStateException("Failed to create TLS configuration for testing", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SSLContext with Key Store and Trust Store configured
|
||||
|
@ -1,244 +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.ssl
|
||||
|
||||
|
||||
import org.apache.nifi.security.util.ClientAuth
|
||||
import org.apache.nifi.util.MockProcessContext
|
||||
import org.apache.nifi.util.TestRunner
|
||||
import org.apache.nifi.util.TestRunners
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.junit.*
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import javax.net.ssl.SSLContext
|
||||
import java.security.Security
|
||||
|
||||
import static groovy.test.GroovyAssert.shouldFail
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
class StandardSSLContextServiceTest {
|
||||
private static final Logger logger = LoggerFactory.getLogger(StandardSSLContextServiceTest.class)
|
||||
|
||||
private static final String KEYSTORE_PATH = "src/test/resources/keystore.jks"
|
||||
private static final String TRUSTSTORE_PATH = "src/test/resources/truststore.jks"
|
||||
private static final String NO_PASSWORD_TRUSTSTORE_PATH = "src/test/resources/no-password-truststore.jks"
|
||||
private static final String TRUSTSTORE_PATH_WITH_EL = "\${someAttribute}/truststore.jks"
|
||||
|
||||
private static final String KEYSTORE_PASSWORD = "passwordpassword"
|
||||
private static final String TRUSTSTORE_PASSWORD = "passwordpassword"
|
||||
private static final String TRUSTSTORE_NO_PASSWORD = ""
|
||||
|
||||
private static final String KEYSTORE_TYPE = "JKS"
|
||||
private static final String TRUSTSTORE_TYPE = "JKS"
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder tmp = new TemporaryFolder(new File("src/test/resources"))
|
||||
|
||||
@BeforeClass
|
||||
static void setUpOnce() throws Exception {
|
||||
Security.addProvider(new BouncyCastleProvider())
|
||||
|
||||
logger.metaClass.methodMissing = { String name, args ->
|
||||
logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
static void tearDownOnce() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldValidateSimpleFileValidatorPath() {
|
||||
// Arrange
|
||||
TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
|
||||
String controllerServiceId = "ssl-context"
|
||||
final SSLContextService sslContextService = new StandardSSLContextService()
|
||||
runner.addControllerService(controllerServiceId, sslContextService)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, TRUSTSTORE_PATH)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_PASSWORD, TRUSTSTORE_PASSWORD)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
|
||||
runner.enableControllerService(sslContextService)
|
||||
|
||||
// Act
|
||||
runner.assertValid(sslContextService)
|
||||
|
||||
// Assert
|
||||
final MockProcessContext processContext = (MockProcessContext) runner.getProcessContext()
|
||||
assert processContext.getControllerServiceProperties(sslContextService).get(StandardSSLContextService.TRUSTSTORE, "") == TRUSTSTORE_PATH
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTruststoreWithNoPasswordIsValid() {
|
||||
// Arrange
|
||||
TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
|
||||
String controllerServiceId = "ssl-context"
|
||||
final SSLContextService sslContextService = new StandardSSLContextService()
|
||||
runner.addControllerService(controllerServiceId, sslContextService)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, NO_PASSWORD_TRUSTSTORE_PATH)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_PASSWORD, TRUSTSTORE_NO_PASSWORD)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
|
||||
runner.enableControllerService(sslContextService)
|
||||
|
||||
// Act
|
||||
runner.assertValid(sslContextService)
|
||||
|
||||
// Assert
|
||||
final MockProcessContext processContext = (MockProcessContext) runner.getProcessContext()
|
||||
assert processContext.getControllerServiceProperties(sslContextService).get(StandardSSLContextService.TRUSTSTORE, "") == NO_PASSWORD_TRUSTSTORE_PATH
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTruststoreWithNullPasswordIsValid() {
|
||||
// Arrange
|
||||
TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
|
||||
String controllerServiceId = "ssl-context"
|
||||
final SSLContextService sslContextService = new StandardSSLContextService()
|
||||
runner.addControllerService(controllerServiceId, sslContextService)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, NO_PASSWORD_TRUSTSTORE_PATH)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_PASSWORD, null as String)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
|
||||
runner.enableControllerService(sslContextService)
|
||||
|
||||
// Act
|
||||
runner.assertValid(sslContextService)
|
||||
|
||||
// Assert
|
||||
final MockProcessContext processContext = (MockProcessContext) runner.getProcessContext()
|
||||
assert processContext.getControllerServiceProperties(sslContextService).get(StandardSSLContextService.TRUSTSTORE, "") == NO_PASSWORD_TRUSTSTORE_PATH
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTruststoreWithMissingPasswordIsValid() {
|
||||
// Arrange
|
||||
TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
|
||||
String controllerServiceId = "ssl-context"
|
||||
final SSLContextService sslContextService = new StandardSSLContextService()
|
||||
runner.addControllerService(controllerServiceId, sslContextService)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, NO_PASSWORD_TRUSTSTORE_PATH)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
|
||||
runner.enableControllerService(sslContextService)
|
||||
|
||||
// Act
|
||||
runner.assertValid(sslContextService)
|
||||
|
||||
// Assert
|
||||
final MockProcessContext processContext = (MockProcessContext) runner.getProcessContext()
|
||||
assert processContext.getControllerServiceProperties(sslContextService).get(StandardSSLContextService.TRUSTSTORE, "") == NO_PASSWORD_TRUSTSTORE_PATH
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldConnectWithPasswordlessTruststore() {
|
||||
// Arrange
|
||||
TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
|
||||
String controllerServiceId = "ssl-context"
|
||||
final SSLContextService sslContextService = new StandardSSLContextService()
|
||||
runner.addControllerService(controllerServiceId, sslContextService)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, NO_PASSWORD_TRUSTSTORE_PATH)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
|
||||
runner.enableControllerService(sslContextService)
|
||||
runner.assertValid(sslContextService)
|
||||
|
||||
// Act
|
||||
SSLContext sslContext = sslContextService.createContext();
|
||||
|
||||
// Assert
|
||||
assert sslContext
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldConnectWithPasswordlessTruststoreWhenKeystorePresent() {
|
||||
// Arrange
|
||||
TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
|
||||
String controllerServiceId = "ssl-context"
|
||||
final SSLContextService sslContextService = new StandardSSLContextService()
|
||||
runner.addControllerService(controllerServiceId, sslContextService)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE, KEYSTORE_PATH)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_PASSWORD, KEYSTORE_PASSWORD)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_TYPE, KEYSTORE_TYPE)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, NO_PASSWORD_TRUSTSTORE_PATH)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
|
||||
runner.enableControllerService(sslContextService)
|
||||
runner.assertValid(sslContextService)
|
||||
|
||||
// Act
|
||||
SSLContext sslContext = sslContextService.createContext();
|
||||
|
||||
// Assert
|
||||
assert sslContext
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldNotValidateExpressionLanguageInFileValidator() {
|
||||
// Arrange
|
||||
TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
|
||||
String controllerServiceId = "ssl-context"
|
||||
final SSLContextService sslContextService = new StandardSSLContextService()
|
||||
runner.addControllerService(controllerServiceId, sslContextService)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, TRUSTSTORE_PATH_WITH_EL)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_PASSWORD, TRUSTSTORE_PASSWORD)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
|
||||
|
||||
// Act
|
||||
def msg = shouldFail {
|
||||
runner.enableControllerService(sslContextService)
|
||||
}
|
||||
|
||||
// Assert
|
||||
runner.assertNotValid(sslContextService)
|
||||
}
|
||||
|
||||
/**
|
||||
* This test ensures that the deprecated ClientAuth enum is correctly mapped to the canonical enum.
|
||||
*/
|
||||
@Test
|
||||
void testShouldTranslateValidDeprecatedClientAuths() {
|
||||
// Arrange
|
||||
TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
|
||||
String controllerServiceId = "ssl-context"
|
||||
final SSLContextService sslContextService = new StandardSSLContextService()
|
||||
runner.addControllerService(controllerServiceId, sslContextService)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, NO_PASSWORD_TRUSTSTORE_PATH)
|
||||
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
|
||||
runner.enableControllerService(sslContextService)
|
||||
runner.assertValid(sslContextService)
|
||||
|
||||
// Act
|
||||
Map<SSLContextService.ClientAuth, SSLContext> sslContexts = SSLContextService.ClientAuth.values().collectEntries { ca ->
|
||||
[ca, sslContextService.createSSLContext(ca)]
|
||||
}
|
||||
|
||||
// Assert
|
||||
assert sslContexts.size() == ClientAuth.values().size()
|
||||
sslContexts.every { clientAuth, sslContext ->
|
||||
assert ClientAuth.isValidClientAuthType(clientAuth.name())
|
||||
assert sslContext
|
||||
}
|
||||
}
|
||||
}
|
@ -23,33 +23,32 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.TlsConfiguration;
|
||||
import org.apache.nifi.util.MockProcessContext;
|
||||
import org.apache.nifi.util.MockValidationContext;
|
||||
import org.apache.nifi.util.TestRunner;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SSLContextServiceTest {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SSLContextServiceTest.class);
|
||||
private final String KEYSTORE_PATH = "src/test/resources/keystore.jks";
|
||||
private final String KEYSTORE_AND_TRUSTSTORE_PASSWORD = "passwordpassword";
|
||||
private final String JKS_TYPE = "JKS";
|
||||
private final String TRUSTSTORE_PATH = "src/test/resources/truststore.jks";
|
||||
private static final String KEYSTORE_WITH_KEY_PASSWORD_PATH = "src/test/resources/keystore-with-key-password.jks";
|
||||
private static TlsConfiguration tlsConfiguration;
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder tmp = new TemporaryFolder(new File("src/test/resources"));
|
||||
@BeforeClass
|
||||
public static void setTlsConfiguration() throws GeneralSecurityException, IOException {
|
||||
tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
|
||||
new File(tlsConfiguration.getKeystorePath()).deleteOnExit();
|
||||
new File(tlsConfiguration.getTruststorePath()).deleteOnExit();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldFailToAddControllerServiceWithNoProperties() throws InitializationException {
|
||||
@ -65,8 +64,8 @@ public class SSLContextServiceTest {
|
||||
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
final SSLContextService service = new StandardSSLContextService();
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), KEYSTORE_PATH);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), tlsConfiguration.getKeystorePath());
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), tlsConfiguration.getKeystorePassword());
|
||||
runner.addControllerService("test-no-keystore-type", service, properties);
|
||||
runner.assertNotValid(service);
|
||||
}
|
||||
@ -76,10 +75,10 @@ public class SSLContextServiceTest {
|
||||
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
final SSLContextService service = new StandardSSLContextService();
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), KEYSTORE_PATH);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), JKS_TYPE);
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE.getName(), TRUSTSTORE_PATH);
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), tlsConfiguration.getKeystorePath());
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), tlsConfiguration.getKeystorePassword());
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), tlsConfiguration.getKeystoreType().getType());
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE.getName(), tlsConfiguration.getTruststorePath());
|
||||
runner.addControllerService("test-no-truststore-password-or-type", service, properties);
|
||||
runner.assertNotValid(service);
|
||||
}
|
||||
@ -89,12 +88,12 @@ public class SSLContextServiceTest {
|
||||
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
final SSLContextService service = new StandardSSLContextService();
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), KEYSTORE_PATH);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "wrongpassword");
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "PKCS12");
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE.getName(), TRUSTSTORE_PATH);
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "wrongpassword");
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), JKS_TYPE);
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), tlsConfiguration.getKeystorePath());
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), String.class.getSimpleName());
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), tlsConfiguration.getKeystoreType().getType());
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE.getName(), tlsConfiguration.getTruststorePath());
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), String.class.getSimpleName());
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), tlsConfiguration.getTruststoreType().getType());
|
||||
runner.addControllerService("test-wrong-passwords", service, properties);
|
||||
|
||||
runner.assertNotValid(service);
|
||||
@ -106,11 +105,11 @@ public class SSLContextServiceTest {
|
||||
final SSLContextService service = new StandardSSLContextService();
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/DOES-NOT-EXIST.jks");
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "PKCS12");
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE.getName(), TRUSTSTORE_PATH);
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), JKS_TYPE);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), tlsConfiguration.getTruststorePassword());
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), tlsConfiguration.getKeystoreType().getType());
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE.getName(), tlsConfiguration.getTruststorePath());
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), tlsConfiguration.getTruststorePassword());
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), tlsConfiguration.getTruststoreType().getType());
|
||||
runner.addControllerService("test-keystore-file-does-not-exist", service, properties);
|
||||
runner.assertNotValid(service);
|
||||
}
|
||||
@ -120,12 +119,12 @@ public class SSLContextServiceTest {
|
||||
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
SSLContextService service = new StandardSSLContextService();
|
||||
runner.addControllerService("test-good1", service);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE.getName(), KEYSTORE_PATH);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_TYPE.getName(), JKS_TYPE);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE.getName(), TRUSTSTORE_PATH);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_TYPE.getName(), JKS_TYPE);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE.getName(), tlsConfiguration.getKeystorePath());
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_PASSWORD.getName(), tlsConfiguration.getKeystorePassword());
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_TYPE.getName(), tlsConfiguration.getKeystoreType().getType());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE.getName(), tlsConfiguration.getTruststorePath());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), tlsConfiguration.getTruststorePassword());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_TYPE.getName(), tlsConfiguration.getTruststoreType().getType());
|
||||
runner.enableControllerService(service);
|
||||
|
||||
runner.setProperty("SSL Context Svc ID", "test-good1");
|
||||
@ -141,14 +140,14 @@ public class SSLContextServiceTest {
|
||||
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
SSLContextService service = new StandardSSLContextService();
|
||||
runner.addControllerService("test-good1", service);
|
||||
runner.setVariable("keystore", KEYSTORE_PATH);
|
||||
runner.setVariable("truststore", TRUSTSTORE_PATH);
|
||||
runner.setVariable("keystore", tlsConfiguration.getKeystorePath());
|
||||
runner.setVariable("truststore", tlsConfiguration.getTruststorePath());
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE.getName(), "${keystore}");
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_TYPE.getName(), JKS_TYPE);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_PASSWORD.getName(), tlsConfiguration.getKeystorePassword());
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_TYPE.getName(), tlsConfiguration.getKeystoreType().getType());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE.getName(), "${truststore}");
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_TYPE.getName(), JKS_TYPE);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), tlsConfiguration.getTruststorePassword());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_TYPE.getName(), tlsConfiguration.getTruststoreType().getType());
|
||||
runner.enableControllerService(service);
|
||||
|
||||
runner.setProperty("SSL Context Svc ID", "test-good1");
|
||||
@ -164,12 +163,12 @@ public class SSLContextServiceTest {
|
||||
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
SSLContextService service = new StandardSSLContextService();
|
||||
runner.addControllerService("test-good1", service);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE.getName(), KEYSTORE_PATH);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_TYPE.getName(), JKS_TYPE);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE.getName(), TRUSTSTORE_PATH);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_TYPE.getName(), JKS_TYPE);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE.getName(), tlsConfiguration.getKeystorePath());
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_PASSWORD.getName(), tlsConfiguration.getKeystorePassword());
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_TYPE.getName(), tlsConfiguration.getKeystoreType().getType());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE.getName(), tlsConfiguration.getTruststorePath());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), tlsConfiguration.getTruststorePassword());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_TYPE.getName(), tlsConfiguration.getTruststoreType().getType());
|
||||
runner.enableControllerService(service);
|
||||
|
||||
runner.setProperty("SSL Context Svc ID", "test-good1");
|
||||
@ -179,25 +178,23 @@ public class SSLContextServiceTest {
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/DOES-NOT-EXIST.jks");
|
||||
runner.assertNotValid(service);
|
||||
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE.getName(), KEYSTORE_PATH);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "badpassword");
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE.getName(), tlsConfiguration.getKeystorePath());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), String.class.getSimpleName());
|
||||
runner.assertNotValid(service);
|
||||
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), tlsConfiguration.getTruststorePassword());
|
||||
runner.enableControllerService(service);
|
||||
runner.assertValid(service);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidationResultsCacheShouldExpire() throws InitializationException, IOException {
|
||||
// Arrange
|
||||
|
||||
// Copy the keystore and truststore to a tmp directory so the originals are not modified
|
||||
File originalKeystore = new File(KEYSTORE_PATH);
|
||||
File originalTruststore = new File(TRUSTSTORE_PATH);
|
||||
File originalKeystore = new File(tlsConfiguration.getKeystorePath());
|
||||
File originalTruststore = new File(tlsConfiguration.getTruststorePath());
|
||||
|
||||
File tmpKeystore = tmp.newFile("keystore-tmp.jks");
|
||||
File tmpTruststore = tmp.newFile("truststore-tmp.jks");
|
||||
File tmpKeystore = File.createTempFile(getClass().getSimpleName(), ".keystore.p12");
|
||||
File tmpTruststore = File.createTempFile(getClass().getSimpleName(), ".truststore.p12");
|
||||
|
||||
Files.copy(originalKeystore.toPath(), tmpKeystore.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
Files.copy(originalTruststore.toPath(), tmpTruststore.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
@ -207,11 +204,11 @@ public class SSLContextServiceTest {
|
||||
final String serviceIdentifier = "test-should-expire";
|
||||
runner.addControllerService(serviceIdentifier, service);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE.getName(), tmpKeystore.getAbsolutePath());
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_TYPE.getName(), JKS_TYPE);
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_PASSWORD.getName(), tlsConfiguration.getKeystorePassword());
|
||||
runner.setProperty(service, StandardSSLContextService.KEYSTORE_TYPE.getName(), tlsConfiguration.getKeystoreType().getType());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE.getName(), tmpTruststore.getAbsolutePath());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_TYPE.getName(), JKS_TYPE);
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), tlsConfiguration.getTruststorePassword());
|
||||
runner.setProperty(service, StandardSSLContextService.TRUSTSTORE_TYPE.getName(), tlsConfiguration.getTruststoreType().getType());
|
||||
runner.enableControllerService(service);
|
||||
|
||||
runner.setProperty("SSL Context Svc ID", serviceIdentifier);
|
||||
@ -221,7 +218,6 @@ public class SSLContextServiceTest {
|
||||
boolean isDeleted = tmpKeystore.delete();
|
||||
assert isDeleted;
|
||||
assert !tmpKeystore.exists();
|
||||
logger.info("Deleted keystore file");
|
||||
|
||||
// Manually validate the service (expecting cached result to be returned)
|
||||
final MockProcessContext processContext = (MockProcessContext) runner.getProcessContext();
|
||||
@ -231,7 +227,6 @@ public class SSLContextServiceTest {
|
||||
// Even though the keystore file is no longer present, because no property changed, the cached result is still valid
|
||||
Collection<ValidationResult> validationResults = service.customValidate(validationContext);
|
||||
assertTrue("validation results is not empty", validationResults.isEmpty());
|
||||
logger.info("(1) StandardSSLContextService#customValidate() returned true even though the keystore file is no longer available");
|
||||
|
||||
// Assert
|
||||
|
||||
@ -239,12 +234,10 @@ public class SSLContextServiceTest {
|
||||
for (int i = 2; i < service.getValidationCacheExpiration(); i++) {
|
||||
validationResults = service.customValidate(validationContext);
|
||||
assertTrue("validation results is not empty", validationResults.isEmpty());
|
||||
logger.info("(" + i + ") StandardSSLContextService#customValidate() returned true even though the keystore file is no longer available");
|
||||
}
|
||||
|
||||
validationResults = service.customValidate(validationContext);
|
||||
assertFalse("validation results is empty", validationResults.isEmpty());
|
||||
logger.info("(" + service.getValidationCacheExpiration() + ") StandardSSLContextService#customValidate() returned false because the cache expired");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -252,9 +245,9 @@ public class SSLContextServiceTest {
|
||||
TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
SSLContextService service = new StandardSSLContextService();
|
||||
HashMap<String, String> properties = new HashMap<>();
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE.getName(), TRUSTSTORE_PATH);
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), JKS_TYPE);
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE.getName(), tlsConfiguration.getTruststorePath());
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), tlsConfiguration.getTruststorePassword());
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), tlsConfiguration.getTruststoreType().getType());
|
||||
runner.addControllerService("test-good2", service, properties);
|
||||
runner.enableControllerService(service);
|
||||
|
||||
@ -270,9 +263,9 @@ public class SSLContextServiceTest {
|
||||
TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
SSLContextService service = new StandardSSLContextService();
|
||||
HashMap<String, String> properties = new HashMap<>();
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), KEYSTORE_PATH);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), JKS_TYPE);
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), tlsConfiguration.getKeystorePath());
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), tlsConfiguration.getKeystorePassword());
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), tlsConfiguration.getKeystoreType().getType());
|
||||
runner.addControllerService("test-good3", service, properties);
|
||||
runner.enableControllerService(service);
|
||||
|
||||
@ -281,49 +274,4 @@ public class SSLContextServiceTest {
|
||||
Assert.assertNotNull(service);
|
||||
service.createContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test asserts that the keystore password and key password are different. This is only
|
||||
* true because they were explicitly set that way. Normal keystores that do not have passwords
|
||||
* set on individual keys will fail this test.
|
||||
*/
|
||||
@Test
|
||||
public void testDifferentKeyPassword() throws Exception {
|
||||
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
final SSLContextService service = new StandardSSLContextService();
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), KEYSTORE_WITH_KEY_PASSWORD_PATH);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
properties.put(StandardSSLContextService.KEY_PASSWORD.getName(), "keypassword");
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), JKS_TYPE);
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE.getName(), TRUSTSTORE_PATH);
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), JKS_TYPE);
|
||||
runner.addControllerService("test-diff-keys", service, properties);
|
||||
runner.enableControllerService(service);
|
||||
|
||||
runner.setProperty("SSL Context Svc ID", "test-diff-keys");
|
||||
runner.assertValid();
|
||||
Assert.assertNotNull(service);
|
||||
service.createContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test asserts that the keystore password and key password are different. This is only
|
||||
* true because they were explicitly set that way. Normal keystores that do not have passwords
|
||||
* set on individual keys will fail this test.
|
||||
*/
|
||||
@Test
|
||||
public void testDifferentKeyPasswordWithoutSpecifyingKeyPassword() throws Exception {
|
||||
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
final SSLContextService service = new StandardSSLContextService();
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
properties.put(StandardSSLContextService.KEYSTORE.getName(), KEYSTORE_WITH_KEY_PASSWORD_PATH);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), KEYSTORE_AND_TRUSTSTORE_PASSWORD);
|
||||
properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), JKS_TYPE);
|
||||
runner.addControllerService("test-diff-keys", service, properties);
|
||||
|
||||
// Assert the service is not valid due to an internal "cannot recover key" because the key password is missing
|
||||
runner.assertNotValid(service);
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,100 +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.websocket.example;
|
||||
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* This is a WebSocket client example testcase.
|
||||
*/
|
||||
@Ignore
|
||||
public class WebSocketClientExample {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(WebSocketClientExample.class);
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String destUri = "wss://localhost:50010/test";
|
||||
|
||||
final CountDownLatch replyLatch = new CountDownLatch(1);
|
||||
final SslContextFactory sslContextFactory = new SslContextFactory.Client();
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/certs/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("passwordpassword");
|
||||
sslContextFactory.setKeyStoreType("JKS");
|
||||
sslContextFactory.setTrustStorePath("src/test/resources/certs/truststore.jks");
|
||||
sslContextFactory.setTrustStorePassword("passwordpassword");
|
||||
sslContextFactory.setTrustStoreType("JKS");
|
||||
|
||||
WebSocketClient client = new WebSocketClient(sslContextFactory);
|
||||
WebSocketAdapter socket = new WebSocketAdapter() {
|
||||
@Override
|
||||
public void onWebSocketConnect(Session session) {
|
||||
super.onWebSocketConnect(session);
|
||||
|
||||
try {
|
||||
session.getRemote().sendString("Hello, this is Jetty ws client.");
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to send a message due to " + e, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketText(String message) {
|
||||
logger.info("Received a reply: {}", message);
|
||||
replyLatch.countDown();
|
||||
}
|
||||
};
|
||||
try {
|
||||
client.start();
|
||||
|
||||
URI echoUri = new URI(destUri);
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
final Future<Session> connect = client.connect(socket, echoUri, request);
|
||||
logger.info("Connecting to : {}", echoUri);
|
||||
|
||||
final Session session = connect.get(3, TimeUnit.SECONDS);
|
||||
logger.info("Connected, session={}", session);
|
||||
|
||||
session.close(StatusCode.NORMAL, "Bye");
|
||||
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
client.stop();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,195 +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.websocket.example;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.SslConnectionFactory;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketListener;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This is a WebSocket server example testcase.
|
||||
*/
|
||||
@Ignore
|
||||
public class WebSocketServerExample {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(WebSocketServerExample.class);
|
||||
private static Server server;
|
||||
private static ServletHandler servletHandler;
|
||||
private static ServletHolder servletHolder;
|
||||
private static ServerConnector httpConnector;
|
||||
private static ServerConnector sslConnector;
|
||||
|
||||
private static final Map<Integer, WebSocketServerExample> portToController = new HashMap<>();
|
||||
|
||||
private Map<String, WebSocketListener> listeners = new HashMap<>();
|
||||
|
||||
public class SocketListener extends WebSocketAdapter {
|
||||
|
||||
public SocketListener() {
|
||||
logger.info("New instance is created: {}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(Session session) {
|
||||
logger.info("Connected, {}, {}", session.getLocalAddress(), session.getRemoteAddress());
|
||||
super.onWebSocketConnect(session);
|
||||
|
||||
session.getUpgradeRequest().getRequestURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketText(String message) {
|
||||
logger.info("Received: {}", message);
|
||||
|
||||
final String resultMessage;
|
||||
if (message.startsWith("add-servlet")) {
|
||||
// Is it possible to add servlet mapping??
|
||||
final String path = message.split(":")[1].trim();
|
||||
servletHandler.addServletWithMapping(servletHolder, path);
|
||||
|
||||
resultMessage = "Deployed new servlet under: " + path;
|
||||
} else {
|
||||
resultMessage = "Got message: " + message;
|
||||
}
|
||||
|
||||
try {
|
||||
getSession().getRemote().sendString(resultMessage);
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to send a message back to remote.", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public WebSocketServerExample() {
|
||||
this.listeners.put("/test", new SocketListener());
|
||||
portToController.put(httpConnector.getPort(), this);
|
||||
portToController.put(sslConnector.getPort(), this);
|
||||
}
|
||||
|
||||
public static class WSServlet extends WebSocketServlet implements WebSocketCreator {
|
||||
@Override
|
||||
public void configure(WebSocketServletFactory webSocketServletFactory) {
|
||||
webSocketServletFactory.setCreator(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createWebSocket(ServletUpgradeRequest servletUpgradeRequest, ServletUpgradeResponse servletUpgradeResponse) {
|
||||
final WebSocketServerExample testWebSocket = portToController.get(servletUpgradeRequest.getLocalPort());
|
||||
return testWebSocket.listeners.get(servletUpgradeRequest.getRequestURI().getPath());
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConnectionCheckServlet extends HttpServlet {
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.setContentType("text/plain");
|
||||
resp.setStatus(HttpServletResponse.SC_OK);
|
||||
resp.getWriter().println("Ok :)");
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws Exception {
|
||||
server = new Server(0);
|
||||
|
||||
final ContextHandlerCollection handlerCollection = new ContextHandlerCollection();
|
||||
|
||||
final ServletContextHandler contextHandler = new ServletContextHandler();
|
||||
servletHandler = new ServletHandler();
|
||||
contextHandler.insertHandler(servletHandler);
|
||||
|
||||
handlerCollection.setHandlers(new Handler[]{contextHandler});
|
||||
|
||||
server.setHandler(handlerCollection);
|
||||
|
||||
httpConnector = new ServerConnector(server);
|
||||
httpConnector.setPort(50010);
|
||||
|
||||
final SslContextFactory sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/certs/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("passwordpassword");
|
||||
sslContextFactory.setKeyStoreType("JKS");
|
||||
|
||||
final HttpConfiguration https = new HttpConfiguration();
|
||||
https.addCustomizer(new SecureRequestCustomizer());
|
||||
sslConnector = new ServerConnector(server,
|
||||
new SslConnectionFactory(sslContextFactory, "http/1.1"),
|
||||
new HttpConnectionFactory(https));
|
||||
sslConnector.setPort(50011);
|
||||
|
||||
|
||||
server.setConnectors(new Connector[]{httpConnector, sslConnector});
|
||||
|
||||
servletHolder = servletHandler.addServletWithMapping(WSServlet.class, "/test");
|
||||
servletHolder = servletHandler.addServletWithMapping(ConnectionCheckServlet.class, "/check");
|
||||
|
||||
server.start();
|
||||
|
||||
logger.info("Starting server on port {} for HTTP, and {} for HTTPS", httpConnector.getLocalPort(), sslConnector.getLocalPort());
|
||||
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void teardown() throws Exception {
|
||||
logger.info("Stopping server.");
|
||||
try {
|
||||
server.stop();
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to stop Jetty server due to " + e, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
logger.info("Waiting for a while...");
|
||||
Thread.sleep(1000_000);
|
||||
}
|
||||
}
|
@ -1,68 +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.websocket.jetty;
|
||||
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.ssl.StandardSSLContextService;
|
||||
import org.apache.nifi.websocket.WebSocketService;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class ITJettyWebSocketSecureCommunication extends ITJettyWebSocketCommunication{
|
||||
|
||||
private final StandardSSLContextService sslContextService = new StandardSSLContextService();
|
||||
private final ControllerServiceTestContext sslTestContext = new ControllerServiceTestContext(sslContextService, "SSLContextService");
|
||||
|
||||
public ITJettyWebSocketSecureCommunication() {
|
||||
try {
|
||||
sslTestContext.setCustomValue(StandardSSLContextService.KEYSTORE, "src/test/resources/certs/keystore.jks");
|
||||
sslTestContext.setCustomValue(StandardSSLContextService.KEYSTORE_PASSWORD, "passwordpassword");
|
||||
sslTestContext.setCustomValue(StandardSSLContextService.KEYSTORE_TYPE, "JKS");
|
||||
sslTestContext.setCustomValue(StandardSSLContextService.TRUSTSTORE, "src/test/resources/certs/truststore.jks");
|
||||
sslTestContext.setCustomValue(StandardSSLContextService.TRUSTSTORE_PASSWORD, "passwordpassword");
|
||||
sslTestContext.setCustomValue(StandardSSLContextService.TRUSTSTORE_TYPE, "JKS");
|
||||
|
||||
sslContextService.initialize(sslTestContext.getInitializationContext());
|
||||
sslContextService.onConfigured(sslTestContext.getConfigurationContext());
|
||||
} catch (InitializationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSecure() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeServer() {
|
||||
serverServiceContext.getInitializationContext().addControllerService(sslContextService);
|
||||
serverServiceContext.setCustomValue(WebSocketService.SSL_CONTEXT, sslContextService.getIdentifier());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeClient() {
|
||||
clientServiceContext.getInitializationContext().addControllerService(sslContextService);
|
||||
clientServiceContext.setCustomValue(WebSocketService.SSL_CONTEXT, sslContextService.getIdentifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientServerCommunication() throws Exception {
|
||||
super.testClientServerCommunication();
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user