NIFI-5623 Upgraded OkHttp3 to 4.9.1 and updated unit tests

Signed-off-by: Pierre Villard <pierre.villard.fr@gmail.com>

This closes #4826.
This commit is contained in:
exceptionfactory 2021-02-15 15:57:13 -06:00 committed by Pierre Villard
parent aa726040c5
commit f532b3ae1d
No known key found for this signature in database
GPG Key ID: F92A93B30C07C6D5
17 changed files with 270 additions and 465 deletions

View File

@ -53,12 +53,12 @@ language governing permissions and limitations under the License. -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.6.0</version>
<version>${okhttp.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<version>3.6.0</version>
<version>${okhttp.version}</version>
<scope>test</scope>
</dependency>
<!-- This needs to be here because it is relied upon by the nifi-runtime which starts NiFi. It uses this bootstrap module

View File

@ -21,7 +21,9 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.Call;
import okhttp3.MediaType;
@ -189,15 +191,20 @@ public class HttpNotificationService extends AbstractNotificationService {
// check if the keystore is set and add the factory if so
if (url.toLowerCase().startsWith("https")) {
try {
TlsConfiguration tlsConfiguration = createTlsConfigurationFromContext(context);
final SSLSocketFactory sslSocketFactory = SslContextFactory.createSSLSocketFactory(tlsConfiguration);
final TlsConfiguration tlsConfiguration = createTlsConfigurationFromContext(context);
final X509TrustManager x509TrustManager = SslContextFactory.getX509TrustManager(tlsConfiguration);
if (sslSocketFactory != null && x509TrustManager != null) {
okHttpClientBuilder.sslSocketFactory(sslSocketFactory, x509TrustManager);
} else {
// If the TLS config couldn't be parsed, throw an exception
throw new IllegalStateException("The HTTP notification service URL indicates HTTPS but the TLS properties are not valid");
if (x509TrustManager == null) {
throw new IllegalStateException("Unable to get X.509 Trust Manager for HTTP Notification Service configured for TLS");
}
final TrustManager[] trustManagers = new TrustManager[] { x509TrustManager };
final SSLContext sslContext = SslContextFactory.createSslContext(tlsConfiguration, trustManagers);
if (sslContext == null) {
throw new IllegalStateException("Unable to get SSL Context for HTTP Notification Service configured for TLS");
}
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
okHttpClientBuilder.sslSocketFactory(sslSocketFactory, x509TrustManager);
} catch (Exception e) {
throw new IllegalStateException(e);
}
@ -214,13 +221,13 @@ public class HttpNotificationService extends AbstractNotificationService {
String truststorePath = context.getProperty(HttpNotificationService.PROP_TRUSTSTORE).getValue();
String truststorePassword = context.getProperty(HttpNotificationService.PROP_TRUSTSTORE_PASSWORD).getValue();
String truststoreType = context.getProperty(HttpNotificationService.PROP_TRUSTSTORE_TYPE).getValue();
return new StandardTlsConfiguration(keystorePath, keystorePassword, keyPassword, keystoreType, truststorePath, truststorePassword, truststoreType);
return new StandardTlsConfiguration(keystorePath, keystorePassword, keyPassword, keystoreType, truststorePath, truststorePassword, truststoreType, TlsConfiguration.TLS_PROTOCOL);
}
@Override
public void notify(NotificationContext context, NotificationType notificationType, String subject, String message) throws NotificationFailedException {
try {
final RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), message);
final RequestBody requestBody = RequestBody.create(message, MediaType.parse("text/plain"));
Request.Builder requestBuilder = new Request.Builder()
.post(requestBody)

View File

@ -0,0 +1,242 @@
/*
* 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.bootstrap.http;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import okio.Buffer;
import org.apache.nifi.attribute.expression.language.StandardPropertyValue;
import org.apache.nifi.bootstrap.notification.NotificationContext;
import org.apache.nifi.bootstrap.notification.NotificationFailedException;
import org.apache.nifi.bootstrap.notification.NotificationInitializationContext;
import org.apache.nifi.bootstrap.notification.NotificationType;
import org.apache.nifi.bootstrap.notification.http.HttpNotificationService;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.security.util.KeyStoreUtils;
import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.security.util.TlsConfiguration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.PROP_URL;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.PROP_CONNECTION_TIMEOUT;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.PROP_WRITE_TIMEOUT;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.PROP_KEYSTORE;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.PROP_KEYSTORE_PASSWORD;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.PROP_KEYSTORE_TYPE;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.PROP_KEY_PASSWORD;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.PROP_TRUSTSTORE;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.PROP_TRUSTSTORE_PASSWORD;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.PROP_TRUSTSTORE_TYPE;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.NOTIFICATION_SUBJECT_KEY;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.NOTIFICATION_TYPE_KEY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
public class HttpNotificationServiceTest {
private static final long REQUEST_TIMEOUT = 2;
private static final String SUBJECT = "Subject";
private static final String MESSAGE = "Message";
private static final String LOCALHOST = "localhost";
private static final String BASE_PATH = "/";
private static final String TIMEOUT = "10s";
private MockWebServer mockWebServer;
@Before
public void startServer() {
mockWebServer = new MockWebServer();
}
@After
public void shutdownServer() throws IOException {
mockWebServer.shutdown();
}
@Test
public void testStartNotification() throws InterruptedException, NotificationFailedException {
enqueueResponseCode(200);
final Map<PropertyDescriptor, PropertyValue> properties = getProperties();
final HttpNotificationService service = getHttpNotificationService(properties);
service.notify(getNotificationContext(), NotificationType.NIFI_STARTED, SUBJECT, MESSAGE);
assertRequestMatches(NotificationType.NIFI_STARTED);
}
@Test
public void testStopNotification() throws InterruptedException, NotificationFailedException {
enqueueResponseCode(200);
final Map<PropertyDescriptor, PropertyValue> properties = getProperties();
final HttpNotificationService service = getHttpNotificationService(properties);
service.notify(getNotificationContext(), NotificationType.NIFI_STOPPED, SUBJECT, MESSAGE);
assertRequestMatches(NotificationType.NIFI_STOPPED);
}
@Test
public void testDiedNotification() throws InterruptedException, NotificationFailedException {
enqueueResponseCode(200);
final Map<PropertyDescriptor, PropertyValue> properties = getProperties();
final HttpNotificationService service = getHttpNotificationService(properties);
service.notify(getNotificationContext(), NotificationType.NIFI_DIED, SUBJECT, MESSAGE);
assertRequestMatches(NotificationType.NIFI_DIED);
}
@Test
public void testStartNotificationFailure() throws InterruptedException {
enqueueResponseCode(500);
final Map<PropertyDescriptor, PropertyValue> properties = getProperties();
final HttpNotificationService service = getHttpNotificationService(properties);
assertThrows(NotificationFailedException.class, () -> service.notify(getNotificationContext(), NotificationType.NIFI_STARTED, SUBJECT, MESSAGE));
assertRequestMatches(NotificationType.NIFI_STARTED);
}
@Test
public void testStartNotificationHttps() throws GeneralSecurityException, NotificationFailedException, InterruptedException, IOException {
final TlsConfiguration tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
try {
final SSLContext sslContext = SslContextFactory.createSslContext(tlsConfiguration);
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
mockWebServer.useHttps(sslSocketFactory, false);
enqueueResponseCode(200);
final Map<PropertyDescriptor, PropertyValue> properties = getProperties();
properties.put(PROP_KEYSTORE, createPropertyValue(tlsConfiguration.getKeystorePath()));
properties.put(PROP_KEYSTORE_PASSWORD, createPropertyValue(tlsConfiguration.getKeystorePassword()));
properties.put(PROP_KEY_PASSWORD, createPropertyValue(tlsConfiguration.getKeyPassword()));
properties.put(PROP_KEYSTORE_TYPE, createPropertyValue(tlsConfiguration.getKeystoreType().getType()));
properties.put(PROP_TRUSTSTORE, createPropertyValue(tlsConfiguration.getTruststorePath()));
properties.put(PROP_TRUSTSTORE_PASSWORD, createPropertyValue(tlsConfiguration.getTruststorePassword()));
properties.put(PROP_TRUSTSTORE_TYPE, createPropertyValue(tlsConfiguration.getTruststoreType().getType()));
final HttpNotificationService service = getHttpNotificationService(properties);
service.notify(getNotificationContext(), NotificationType.NIFI_STARTED, SUBJECT, MESSAGE);
assertRequestMatches(NotificationType.NIFI_STARTED);
} finally {
Files.deleteIfExists(Paths.get(tlsConfiguration.getKeystorePath()));
Files.deleteIfExists(Paths.get(tlsConfiguration.getTruststorePath()));
}
}
private void assertRequestMatches(final NotificationType notificationType) throws InterruptedException {
final RecordedRequest recordedRequest = mockWebServer.takeRequest(REQUEST_TIMEOUT, TimeUnit.SECONDS);
assertNotNull(recordedRequest);
assertEquals(notificationType.name(), recordedRequest.getHeader(NOTIFICATION_TYPE_KEY));
assertEquals(SUBJECT, recordedRequest.getHeader(NOTIFICATION_SUBJECT_KEY));
final Buffer bodyBuffer = recordedRequest.getBody();
final String bodyString = new String(bodyBuffer.readByteArray(), UTF_8);
assertEquals(MESSAGE, bodyString);
}
private void enqueueResponseCode(final int responseCode) {
mockWebServer.enqueue(new MockResponse().setResponseCode(responseCode));
}
private HttpNotificationService getHttpNotificationService(final Map<PropertyDescriptor, PropertyValue> properties) {
final HttpNotificationService service = new HttpNotificationService();
final NotificationInitializationContext context = new NotificationInitializationContext() {
@Override
public String getIdentifier() {
return NotificationInitializationContext.class.getName();
}
@Override
public PropertyValue getProperty(final PropertyDescriptor descriptor) {
return properties.get(descriptor);
}
@Override
public Map<String, String> getAllProperties() {
final Map<String, String> allProperties = new HashMap<>();
for (final Map.Entry<PropertyDescriptor, PropertyValue> entry : properties.entrySet()) {
allProperties.put(entry.getKey().getName(), entry.getValue().getValue());
}
return allProperties;
}
};
service.initialize(context);
return service;
}
private Map<PropertyDescriptor, PropertyValue> getProperties() {
final Map<PropertyDescriptor, PropertyValue> properties = new HashMap<>();
// Setting localhost is necessary to avoid hostname verification failures on Windows
final String url = mockWebServer.url(BASE_PATH).newBuilder().host(LOCALHOST).build().toString();
properties.put(PROP_URL, createPropertyValue(url));
properties.put(PROP_CONNECTION_TIMEOUT, createPropertyValue(TIMEOUT));
properties.put(PROP_WRITE_TIMEOUT, createPropertyValue(TIMEOUT));
return properties;
}
private PropertyValue createPropertyValue(final String value) {
return new StandardPropertyValue(value, null, null);
}
private NotificationContext getNotificationContext() {
final Map<PropertyDescriptor, PropertyValue> properties = getProperties();
return new NotificationContext() {
@Override
public PropertyValue getProperty(final PropertyDescriptor descriptor) {
return properties.get(descriptor);
}
@Override
public Map<PropertyDescriptor, String> getProperties() {
final Map<PropertyDescriptor, String> propertyValues = new HashMap<>();
for (final Map.Entry<PropertyDescriptor, PropertyValue> entry : properties.entrySet()) {
propertyValues.put(entry.getKey(), entry.getValue().getValue());
}
return propertyValues;
}
};
}
}

View File

@ -1,61 +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.bootstrap.http;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.mockito.internal.util.io.IOUtil;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class TestHttpNotificationService extends TestHttpNotificationServiceCommon{
static final String CONFIGURATION_FILE_TEXT = "\n"+
"<services>\n"+
" <service>\n"+
" <id>http-notification</id>\n"+
" <class>org.apache.nifi.bootstrap.notification.http.HttpNotificationService</class>\n"+
" <property name=\"URL\">${test.server}</property>\n"+
" <property name=\"testProp\">${literal('testing')}</property>\n"+
" </service>\n"+
"</services>";
@BeforeClass
public static void startServer() throws IOException {
tempConfigFilePath = "./target/TestHttpNotificationService-config.xml";
Files.deleteIfExists(Paths.get(tempConfigFilePath));
mockWebServer = new MockWebServer();
String configFileOutput = CONFIGURATION_FILE_TEXT.replace("${test.server}", String.valueOf(mockWebServer.url("/")));
IOUtil.writeText(configFileOutput, new File(tempConfigFilePath));
}
@AfterClass
public static void shutdownServer() throws IOException {
Files.deleteIfExists(Paths.get(tempConfigFilePath));
mockWebServer.shutdown();
}
}

View File

@ -1,128 +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.bootstrap.http;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import okio.Buffer;
import org.apache.nifi.bootstrap.NotificationServiceManager;
import org.apache.nifi.bootstrap.notification.NotificationType;
import org.junit.Test;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.NOTIFICATION_SUBJECT_KEY;
import static org.apache.nifi.bootstrap.notification.http.HttpNotificationService.NOTIFICATION_TYPE_KEY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public abstract class TestHttpNotificationServiceCommon {
public static String tempConfigFilePath;
public static MockWebServer mockWebServer;
@Test
public void testStartNotification() throws ParserConfigurationException, SAXException, IOException, InterruptedException {
mockWebServer.enqueue(new MockResponse().setResponseCode(200));
NotificationServiceManager notificationServiceManager = new NotificationServiceManager();
notificationServiceManager.setMaxNotificationAttempts(1);
notificationServiceManager.loadNotificationServices(new File(tempConfigFilePath));
notificationServiceManager.registerNotificationService(NotificationType.NIFI_STARTED, "http-notification");
notificationServiceManager.notify(NotificationType.NIFI_STARTED, "Subject", "Message");
RecordedRequest recordedRequest = mockWebServer.takeRequest(2, TimeUnit.SECONDS);
assertNotNull(recordedRequest);
assertEquals(NotificationType.NIFI_STARTED.name(), recordedRequest.getHeader(NOTIFICATION_TYPE_KEY));
assertEquals("Subject", recordedRequest.getHeader(NOTIFICATION_SUBJECT_KEY));
assertEquals("testing", recordedRequest.getHeader("testProp"));
Buffer bodyBuffer = recordedRequest.getBody();
String bodyString =new String(bodyBuffer.readByteArray(), UTF_8);
assertEquals("Message", bodyString);
}
@Test
public void testStopNotification() throws ParserConfigurationException, SAXException, IOException, InterruptedException {
mockWebServer.enqueue(new MockResponse().setResponseCode(200));
NotificationServiceManager notificationServiceManager = new NotificationServiceManager();
notificationServiceManager.setMaxNotificationAttempts(1);
notificationServiceManager.loadNotificationServices(new File(tempConfigFilePath));
notificationServiceManager.registerNotificationService(NotificationType.NIFI_STOPPED, "http-notification");
notificationServiceManager.notify(NotificationType.NIFI_STOPPED, "Subject", "Message");
RecordedRequest recordedRequest = mockWebServer.takeRequest(2, TimeUnit.SECONDS);
assertNotNull(recordedRequest);
assertEquals(NotificationType.NIFI_STOPPED.name(), recordedRequest.getHeader(NOTIFICATION_TYPE_KEY));
assertEquals("Subject", recordedRequest.getHeader(NOTIFICATION_SUBJECT_KEY));
Buffer bodyBuffer = recordedRequest.getBody();
String bodyString =new String(bodyBuffer.readByteArray(), UTF_8);
assertEquals("Message", bodyString);
}
@Test
public void testDiedNotification() throws ParserConfigurationException, SAXException, IOException, InterruptedException {
mockWebServer.enqueue(new MockResponse().setResponseCode(200));
NotificationServiceManager notificationServiceManager = new NotificationServiceManager();
notificationServiceManager.setMaxNotificationAttempts(1);
notificationServiceManager.loadNotificationServices(new File(tempConfigFilePath));
notificationServiceManager.registerNotificationService(NotificationType.NIFI_DIED, "http-notification");
notificationServiceManager.notify(NotificationType.NIFI_DIED, "Subject", "Message");
RecordedRequest recordedRequest = mockWebServer.takeRequest(2, TimeUnit.SECONDS);
assertNotNull(recordedRequest);
assertEquals(NotificationType.NIFI_DIED.name(), recordedRequest.getHeader(NOTIFICATION_TYPE_KEY));
assertEquals("Subject", recordedRequest.getHeader(NOTIFICATION_SUBJECT_KEY));
Buffer bodyBuffer = recordedRequest.getBody();
String bodyString =new String(bodyBuffer.readByteArray(), UTF_8);
assertEquals("Message", bodyString);
}
@Test
public void testStartNotificationFailure() throws ParserConfigurationException, SAXException, IOException, InterruptedException {
// Web server will still get the request but will return an error. Observe that it is gracefully handled.
mockWebServer.enqueue(new MockResponse().setResponseCode(500));
NotificationServiceManager notificationServiceManager = new NotificationServiceManager();
notificationServiceManager.setMaxNotificationAttempts(1);
notificationServiceManager.loadNotificationServices(new File(tempConfigFilePath));
notificationServiceManager.registerNotificationService(NotificationType.NIFI_STARTED, "http-notification");
notificationServiceManager.notify(NotificationType.NIFI_STARTED, "Subject", "Message");
RecordedRequest recordedRequest = mockWebServer.takeRequest(2, TimeUnit.SECONDS);
assertNotNull(recordedRequest);
assertEquals(NotificationType.NIFI_STARTED.name(), recordedRequest.getHeader(NOTIFICATION_TYPE_KEY));
assertEquals("Subject", recordedRequest.getHeader(NOTIFICATION_SUBJECT_KEY));
Buffer bodyBuffer = recordedRequest.getBody();
String bodyString =new String(bodyBuffer.readByteArray(), UTF_8);
assertEquals("Message", bodyString);
}
}

View File

@ -1,252 +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.bootstrap.http;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.xml.parsers.ParserConfigurationException;
import okhttp3.mockwebserver.MockWebServer;
import org.apache.nifi.bootstrap.NotificationServiceManager;
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.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.internal.util.io.IOUtil;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
public class TestHttpNotificationServiceSSL extends TestHttpNotificationServiceCommon {
static final String CONFIGURATION_FILE_TEXT = "\n" +
"<services>\n" +
" <service>\n" +
" <id>http-notification</id>\n" +
" <class>org.apache.nifi.bootstrap.notification.http.HttpNotificationService</class>\n" +
" <property name=\"URL\">${test.server}</property>\n" +
" <property name=\"Truststore Filename\">./src/test/resources/truststore.jks</property>\n" +
" <property name=\"Truststore Type\">JKS</property>\n" +
" <property name=\"Truststore Password\">passwordpassword</property>\n" +
" <property name=\"Keystore Filename\">./src/test/resources/keystore.jks</property>\n" +
" <property name=\"Keystore Type\">JKS</property>\n" +
" <property name=\"Key Password\">passwordpassword</property>\n" +
" <property name=\"Keystore Password\">passwordpassword</property>\n" +
" <property name=\"testProp\">${literal('testing')}</property>\n" +
" </service>\n" +
"</services>";
static final String CONFIGURATION_FILE_TEXT_NO_KEYSTORE_PASSWORD = "\n" +
"<services>\n" +
" <service>\n" +
" <id>http-notification</id>\n" +
" <class>org.apache.nifi.bootstrap.notification.http.HttpNotificationService</class>\n" +
" <property name=\"URL\">${test.server}</property>\n" +
" <property name=\"Truststore Filename\">./src/test/resources/truststore.jks</property>\n" +
" <property name=\"Truststore Type\">JKS</property>\n" +
" <property name=\"Truststore Password\">passwordpassword</property>\n" +
" <property name=\"Keystore Filename\">./src/test/resources/keystore.jks</property>\n" +
" <property name=\"Keystore Type\">JKS</property>\n" +
" <property name=\"Key Password\">passwordpassword</property>\n" +
" <property name=\"testProp\">${literal('testing')}</property>\n" +
" </service>\n" +
"</services>";
static final String CONFIGURATION_FILE_TEXT_NO_KEY_PASSWORD = "\n" +
"<services>\n" +
" <service>\n" +
" <id>http-notification</id>\n" +
" <class>org.apache.nifi.bootstrap.notification.http.HttpNotificationService</class>\n" +
" <property name=\"URL\">${test.server}</property>\n" +
" <property name=\"Truststore Filename\">./src/test/resources/truststore.jks</property>\n" +
" <property name=\"Truststore Type\">JKS</property>\n" +
" <property name=\"Truststore Password\">passwordpassword</property>\n" +
" <property name=\"Keystore Filename\">./src/test/resources/keystore.jks</property>\n" +
" <property name=\"Keystore Type\">JKS</property>\n" +
" <property name=\"Keystore Password\">passwordpassword</property>\n" +
" <property name=\"testProp\">${literal('testing')}</property>\n" +
" </service>\n" +
"</services>";
static final String CONFIGURATION_FILE_TEXT_BLANK_KEY_PASSWORD = "\n" +
"<services>\n" +
" <service>\n" +
" <id>http-notification</id>\n" +
" <class>org.apache.nifi.bootstrap.notification.http.HttpNotificationService</class>\n" +
" <property name=\"URL\">${test.server}</property>\n" +
" <property name=\"Truststore Filename\">./src/test/resources/truststore.jks</property>\n" +
" <property name=\"Truststore Type\">JKS</property>\n" +
" <property name=\"Truststore Password\">passwordpassword</property>\n" +
" <property name=\"Keystore Filename\">./src/test/resources/keystore.jks</property>\n" +
" <property name=\"Keystore Type\">JKS</property>\n" +
" <property name=\"Keystore Password\">passwordpassword</property>\n" +
" <property name=\"Key Password\"></property>\n" +
" <property name=\"testProp\">${literal('testing')}</property>\n" +
" </service>\n" +
"</services>";
static final String CONFIGURATION_FILE_TEXT_BLANK_KEYSTORE_PASSWORD = "\n" +
"<services>\n" +
" <service>\n" +
" <id>http-notification</id>\n" +
" <class>org.apache.nifi.bootstrap.notification.http.HttpNotificationService</class>\n" +
" <property name=\"URL\">${test.server}</property>\n" +
" <property name=\"Truststore Filename\">./src/test/resources/truststore.jks</property>\n" +
" <property name=\"Truststore Type\">JKS</property>\n" +
" <property name=\"Truststore Password\">passwordpassword</property>\n" +
" <property name=\"Keystore Filename\">./src/test/resources/keystore.jks</property>\n" +
" <property name=\"Keystore Type\">JKS</property>\n" +
" <property name=\"Keystore Password\"></property>\n" +
" <property name=\"Key Password\">passwordpassword</property>\n" +
" <property name=\"testProp\">${literal('testing')}</property>\n" +
" </service>\n" +
"</services>";
@Before
public void startServer() throws IOException, TlsException {
tempConfigFilePath = "./target/TestHttpNotificationService-config.xml";
Files.deleteIfExists(Paths.get(tempConfigFilePath));
mockWebServer = new MockWebServer();
TlsConfiguration tlsConfiguration = new StandardTlsConfiguration("./src/test/resources/keystore.jks", "passwordpassword", null, "JKS",
"./src/test/resources/truststore.jks", "passwordpassword", "JKS", TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
final SSLContext sslContext = SslContextFactory.createSslContext(tlsConfiguration);
mockWebServer.useHttps(sslContext.getSocketFactory(), false);
String configFileOutput = CONFIGURATION_FILE_TEXT.replace("${test.server}", String.valueOf(mockWebServer.url("/")));
IOUtil.writeText(configFileOutput, new File(tempConfigFilePath));
}
@After
public void shutdownServer() throws IOException {
Files.deleteIfExists(Paths.get(tempConfigFilePath));
mockWebServer.shutdown();
}
@Test
public void testStartNotificationSucceedsNoKeystorePasswd() throws ParserConfigurationException, SAXException, IOException {
Logger notificationServiceLogger = (Logger) LoggerFactory.getLogger(NotificationServiceManager.class);
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
notificationServiceLogger.addAppender(listAppender);
String configFileOutput = CONFIGURATION_FILE_TEXT_NO_KEYSTORE_PASSWORD.replace("${test.server}", String.valueOf(mockWebServer.url("/")));
IOUtil.writeText(configFileOutput, new File(tempConfigFilePath));
NotificationServiceManager notificationServiceManager = new NotificationServiceManager();
notificationServiceManager.setMaxNotificationAttempts(1);
notificationServiceManager.loadNotificationServices(new File(tempConfigFilePath));
List<ILoggingEvent> logsList = listAppender.list;
boolean notificationServiceFailed = false;
for (ILoggingEvent logMessage : logsList) {
if (logMessage.getFormattedMessage().contains("is not valid for the following reasons")) {
notificationServiceFailed = true;
}
}
assertFalse(notificationServiceFailed);
}
@Test
public void testStartNotificationSucceedsNoKeyPasswd() throws ParserConfigurationException, SAXException, IOException {
Logger notificationServiceLogger = (Logger) LoggerFactory.getLogger(NotificationServiceManager.class);
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
notificationServiceLogger.addAppender(listAppender);
String configFileOutput = CONFIGURATION_FILE_TEXT_NO_KEY_PASSWORD.replace("${test.server}", String.valueOf(mockWebServer.url("/")));
IOUtil.writeText(configFileOutput, new File(tempConfigFilePath));
NotificationServiceManager notificationServiceManager = new NotificationServiceManager();
notificationServiceManager.setMaxNotificationAttempts(1);
notificationServiceManager.loadNotificationServices(new File(tempConfigFilePath));
List<ILoggingEvent> logsList = listAppender.list;
boolean notificationServiceFailed = false;
for (ILoggingEvent logMessage : logsList) {
if (logMessage.getFormattedMessage().contains("is not valid for the following reasons")) {
notificationServiceFailed = true;
}
}
assertFalse(notificationServiceFailed);
}
@Test
public void testStartNotificationFailsBlankKeystorePasswdCorrectKeypasswd() throws ParserConfigurationException, SAXException, IOException {
Logger notificationServiceLogger = (Logger) LoggerFactory.getLogger(NotificationServiceManager.class);
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
notificationServiceLogger.addAppender(listAppender);
String configFileOutput = CONFIGURATION_FILE_TEXT_BLANK_KEYSTORE_PASSWORD.replace("${test.server}", String.valueOf(mockWebServer.url("/")));
IOUtil.writeText(configFileOutput, new File(tempConfigFilePath));
NotificationServiceManager notificationServiceManager = new NotificationServiceManager();
notificationServiceManager.setMaxNotificationAttempts(1);
notificationServiceManager.loadNotificationServices(new File(tempConfigFilePath));
List<ILoggingEvent> logsList = listAppender.list;
boolean notificationServiceFailed = false;
for (ILoggingEvent logMessage : logsList) {
if (logMessage.getFormattedMessage().contains("'Keystore Password' validated against '' is invalid because Keystore Password cannot be empty")) {
notificationServiceFailed = true;
}
}
assertTrue(notificationServiceFailed);
}
@Test
public void testStartNotificationFailsCorrectKeystorePasswdBlankKeypasswd() throws ParserConfigurationException, SAXException, IOException {
Logger notificationServiceLogger = (Logger) LoggerFactory.getLogger(NotificationServiceManager.class);
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
notificationServiceLogger.addAppender(listAppender);
String configFileOutput = CONFIGURATION_FILE_TEXT_BLANK_KEY_PASSWORD.replace("${test.server}", String.valueOf(mockWebServer.url("/")));
IOUtil.writeText(configFileOutput, new File(tempConfigFilePath));
NotificationServiceManager notificationServiceManager = new NotificationServiceManager();
notificationServiceManager.setMaxNotificationAttempts(1);
notificationServiceManager.loadNotificationServices(new File(tempConfigFilePath));
List<ILoggingEvent> logsList = listAppender.list;
boolean notificationServiceFailed = false;
for (ILoggingEvent logMessage : logsList) {
if (logMessage.getFormattedMessage().contains("'Key Password' validated against '' is invalid because Key Password cannot be empty")) {
notificationServiceFailed = true;
}
}
assertTrue(notificationServiceFailed);
}
}

View File

@ -94,7 +94,7 @@
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.4</version>
<version>${okhttp.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -107,7 +107,7 @@ language governing permissions and limitations under the License. -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.4</version>
<version>4.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>

View File

@ -128,7 +128,7 @@
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
<version>${okhttp.version}</version>
</dependency>
<!-- spring dependencies -->

View File

@ -158,8 +158,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
// Assert
assert client.isTLSConfigured()
assert client.okHttpClient.sslSocketFactory
assert client.okHttpClient.sslSocketFactory.context.getX509KeyManager().credentialsMap["nifi-key"]
}
@Test
@ -183,8 +181,6 @@ class OkHttpReplicationClientTest extends GroovyTestCase {
// Assert
assert client.isTLSConfigured()
assert client.okHttpClient.sslSocketFactory
assert client.okHttpClient.sslSocketFactory.context.getX509KeyManager().credentialsMap["nifi-key"]
}
@Test

View File

@ -260,7 +260,7 @@
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.0</version>
<version>4.9.1</version>
</dependency>
<dependency>
<groupId>com.burgstaller</groupId>

View File

@ -79,7 +79,7 @@
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
<version>4.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>

View File

@ -74,7 +74,7 @@
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.4</version>
<version>4.9.1</version>
<scope>compile</scope>
</dependency>
<dependency>

View File

@ -21,7 +21,7 @@ language governing permissions and limitations under the License. -->
<artifactId>nifi-toolkit-api</artifactId>
<properties>
<okhttp-version>2.7.5</okhttp-version>
<okhttp.version>2.7.5</okhttp.version>
</properties>
<dependencies>
@ -44,12 +44,12 @@ language governing permissions and limitations under the License. -->
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp-version}</version>
<version>${okhttp.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>logging-interceptor</artifactId>
<version>${okhttp-version}</version>
<version>${okhttp.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>

View File

@ -88,6 +88,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<inceptionYear>2014</inceptionYear>
<okhttp.version>4.9.1</okhttp.version>
<org.bouncycastle.version>1.68</org.bouncycastle.version>
<org.slf4j.version>1.7.30</org.slf4j.version>
<ranger.version>2.1.0</ranger.version>