From 49d2deae8aa7b57ecf6fb692803594c1bae8e8bf Mon Sep 17 00:00:00 2001 From: dfarrelly Date: Wed, 3 Apr 2019 14:40:31 +0000 Subject: Add support for HTTPS *Add AAF certificates *Switch PM Mapper endpoints to HTTPS *Make external API calls secure if applicable Issue-ID: DCAEGEN2-1296 Change-Id: I63aef8a93cfe6d6a37dcd32496b35ed0841cec4b Signed-off-by: dfarrelly --- .../pmmapper/config/util/RequestSenderTests.java | 1 - .../pmmapper/ssl/SSLContextFactoryTest.java | 84 ++++++++++++++++++++++ .../pmmapper/utils/DataRouterUtilsTest.java | 68 ++++++++++++++++-- src/test/resources/password | 1 + src/test/resources/testkeystore.jks.b64 | 35 +++++++++ src/test/resources/valid_mapper_config.json | 7 +- 6 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactoryTest.java create mode 100644 src/test/resources/password create mode 100644 src/test/resources/testkeystore.jks.b64 (limited to 'src/test') diff --git a/src/test/java/org/onap/dcaegen2/pmmapper/config/util/RequestSenderTests.java b/src/test/java/org/onap/dcaegen2/pmmapper/config/util/RequestSenderTests.java index 770ae43..b349b80 100644 --- a/src/test/java/org/onap/dcaegen2/pmmapper/config/util/RequestSenderTests.java +++ b/src/test/java/org/onap/dcaegen2/pmmapper/config/util/RequestSenderTests.java @@ -26,7 +26,6 @@ import static org.mockserver.integration.ClientAndServer.startClientAndServer; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; -import java.io.IOException; import java.net.URL; import java.net.UnknownHostException; diff --git a/src/test/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactoryTest.java b/src/test/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactoryTest.java new file mode 100644 index 0000000..6f5cee9 --- /dev/null +++ b/src/test/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactoryTest.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.dcaegen2.services.pmmapper.ssl; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.Rule; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.rules.ExpectedException; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.dcaegen2.services.pmmapper.model.MapperConfig; + +import javax.net.ssl.*; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.junit.Assert.assertNotNull; + +@ExtendWith(MockitoExtension.class) + +public class SSLContextFactoryTest { + + @Rule + public ExpectedException exception = ExpectedException.none(); + + private static String validConfigFileContents; + private static MapperConfig validConfig; + private static MapperConfig inValidConfig; + + + private static final Path validConfigPath = Paths.get("src/test/resources/valid_mapper_config.json"); + + private SSLContextFactory objUnderTest; + + @BeforeEach + void setUp() throws Exception { + validConfigFileContents = new String(Files.readAllBytes(validConfigPath)); + JsonObject configObject = new JsonParser().parse(validConfigFileContents).getAsJsonObject(); + validConfig = new Gson().fromJson(configObject, MapperConfig.class); + + objUnderTest = new SSLContextFactory(validConfig); + } + + @Test + void testCreateSSLContext() throws IOException { + SSLContext sslContext = objUnderTest.createSSLContext(validConfig); + + assertNotNull(sslContext); + } + + @Test + void testCreateSSLContextInvalidPassword() { + JsonObject configObject = new JsonParser().parse(validConfigFileContents).getAsJsonObject(); + configObject.addProperty("key_store_pass_path", "src/test/resources/nopassword"); + inValidConfig = new Gson().fromJson(configObject, MapperConfig.class); + + assertThrows(IOException.class, () -> objUnderTest.createSSLContext(inValidConfig)); + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtilsTest.java b/src/test/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtilsTest.java index 73967c2..9975849 100644 --- a/src/test/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtilsTest.java +++ b/src/test/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtilsTest.java @@ -31,25 +31,74 @@ import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import org.junit.Test; import org.junit.runner.RunWith; +import org.onap.dcaegen2.services.pmmapper.datarouter.DataRouterSubscriber; import org.onap.dcaegen2.services.pmmapper.exceptions.ProcessEventException; import org.onap.dcaegen2.services.pmmapper.model.Event; import org.onap.dcaegen2.services.pmmapper.model.EventMetadata; import org.onap.dcaegen2.services.pmmapper.model.MapperConfig; +import org.onap.dcaegen2.services.pmmapper.ssl.SSLContextFactory; import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.reflect.Whitebox; import utils.EventUtils; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +@PowerMockIgnore({"org.apache.http.conn.ssl.*", "javax.net.ssl.*" , "javax.crypto.*"}) +@PrepareForTest({RequestSender.class,DataRouterSubscriber.class}) @RunWith(PowerMockRunner.class) -@PrepareForTest(RequestSender.class) public class DataRouterUtilsTest { + private static String validConfigFileContents; + private static MapperConfig validConfig; + private SSLContextFactory sslContextFactory; + private static final Path validConfigPath = Paths.get("src/test/resources/valid_mapper_config.json"); + @Test public void processEventSuccessful() throws Exception { + validConfigFileContents = new String(Files.readAllBytes(validConfigPath)); + JsonObject configObject = new JsonParser().parse(validConfigFileContents).getAsJsonObject(); + validConfig = new Gson().fromJson(configObject, MapperConfig.class); + sslContextFactory = new SSLContextFactory(validConfig); + + SSLContext sslContext = sslContextFactory.createSSLContext(validConfig); + SSLContext.setDefault(sslContext); + + String serviceResponse = "I'm a service response ;)"; + String publishIdentity = "12"; + PowerMockito.mockStatic(Thread.class); + MapperConfig mockMapperConfig = mock(MapperConfig.class); + URL mockURL = mock(URL.class); + HttpsURLConnection mockConnection = mock(HttpsURLConnection.class, RETURNS_DEEP_STUBS); + when(mockConnection.getResponseCode()).thenReturn(200); + when(mockConnection.getInputStream()).thenReturn(new ByteArrayInputStream(serviceResponse.getBytes())); + + when(mockURL.openConnection()).thenReturn(mockConnection); + when(mockURL.getProtocol()).thenReturn("https"); + when(mockMapperConfig.getDmaapDRDeleteEndpoint()).thenReturn("https://dmaap-dr-node/delete/"); + when(mockMapperConfig.getSubscriberIdentity()).thenReturn("12"); + + PowerMockito.whenNew(URL.class).withAnyArguments().thenReturn(mockURL); + + Event testEvent = EventUtils.makeMockEvent("", mock(EventMetadata.class), publishIdentity); + assertEquals(serviceResponse, DataRouterUtils.processEvent(mockMapperConfig, testEvent)); + verify(mockConnection, times(1)).setRequestMethod(RequestSender.DELETE); + } + + @Test + public void processEventSuccessfulHttp() throws Exception { String serviceResponse = "I'm a service response ;)"; String publishIdentity = "12"; PowerMockito.mockStatic(Thread.class); @@ -60,7 +109,8 @@ public class DataRouterUtilsTest { when(mockConnection.getInputStream()).thenReturn(new ByteArrayInputStream(serviceResponse.getBytes())); when(mockURL.openConnection()).thenReturn(mockConnection); - when(mockMapperConfig.getDmaapDRDeleteEndpoint()).thenReturn("dmaap-dr-node/delete/"); + when(mockURL.getProtocol()).thenReturn("http"); + when(mockMapperConfig.getDmaapDRDeleteEndpoint()).thenReturn("http://dmaap-dr-node/delete/"); when(mockMapperConfig.getSubscriberIdentity()).thenReturn("12"); PowerMockito.whenNew(URL.class).withAnyArguments().thenReturn(mockURL); @@ -72,17 +122,26 @@ public class DataRouterUtilsTest { @Test public void testNegativeResponse() throws Exception { + validConfigFileContents = new String(Files.readAllBytes(validConfigPath)); + JsonObject configObject = new JsonParser().parse(validConfigFileContents).getAsJsonObject(); + validConfig = new Gson().fromJson(configObject, MapperConfig.class); + sslContextFactory = new SSLContextFactory(validConfig); + + SSLContext sslContext = sslContextFactory.createSSLContext(validConfig); + SSLContext.setDefault(sslContext); + String serviceResponse = "I'm a negative service response ;)"; String publishIdentity = "12"; PowerMockito.mockStatic(Thread.class); MapperConfig mockMapperConfig = mock(MapperConfig.class); URL mockURL = mock(URL.class); - HttpURLConnection mockConnection = mock(HttpURLConnection.class, RETURNS_DEEP_STUBS); + HttpsURLConnection mockConnection = mock(HttpsURLConnection.class, RETURNS_DEEP_STUBS); when(mockConnection.getResponseCode()).thenReturn(503); when(mockConnection.getInputStream()) .thenAnswer(invocationOnMock -> new ByteArrayInputStream(serviceResponse.getBytes())); when(mockURL.openConnection()).thenReturn(mockConnection); + when(mockURL.getProtocol()).thenReturn("https"); when(mockMapperConfig.getDmaapDRDeleteEndpoint()).thenReturn("dmaap-dr-node/delete/"); when(mockMapperConfig.getSubscriberIdentity()).thenReturn("12"); @@ -102,10 +161,11 @@ public class DataRouterUtilsTest { PowerMockito.mockStatic(Thread.class); MapperConfig mockMapperConfig = mock(MapperConfig.class); URL mockURL = mock(URL.class); - HttpURLConnection mockConnection = mock(HttpURLConnection.class, RETURNS_DEEP_STUBS); + HttpsURLConnection mockConnection = mock(HttpsURLConnection.class, RETURNS_DEEP_STUBS); when(mockConnection.getResponseCode()).thenReturn(503); when(mockURL.openConnection()).thenReturn(mockConnection); + when(mockURL.getProtocol()).thenReturn("https"); when(mockMapperConfig.getDmaapDRDeleteEndpoint()).thenReturn("dmaap-dr-node/delete/"); when(mockMapperConfig.getSubscriberIdentity()).thenReturn("12"); diff --git a/src/test/resources/password b/src/test/resources/password new file mode 100644 index 0000000..547d6c7 --- /dev/null +++ b/src/test/resources/password @@ -0,0 +1 @@ +pmmapper \ No newline at end of file diff --git a/src/test/resources/testkeystore.jks.b64 b/src/test/resources/testkeystore.jks.b64 new file mode 100644 index 0000000..f466fce --- /dev/null +++ b/src/test/resources/testkeystore.jks.b64 @@ -0,0 +1,35 @@ +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 diff --git a/src/test/resources/valid_mapper_config.json b/src/test/resources/valid_mapper_config.json index 040406f..e37b77e 100644 --- a/src/test/resources/valid_mapper_config.json +++ b/src/test/resources/valid_mapper_config.json @@ -30,5 +30,10 @@ "dmaap_dr_feed_id": "2", "buscontroller_feed_subscription_endpoint": "http://dmaap-bc.onap.svc.cluster.local:8080/webapi/dr_subs", "dmaap_dr_delete_endpoint": "http://dmaap-dr-node.onap.svc.cluster.local:8443/delete", - "services_calls": {} + "services_calls": {}, + "key_store_path": "src/test/resources/testkeystore.jks.b64", + "key_store_pass_path": "src/test/resources/password", + "trust_store_path": "src/test/resources/testkeystore.jks.b64", + "trust_store_pass_path": "src/test/resources/password", + "enable_http": false } \ No newline at end of file -- cgit 1.2.3-korg