SSL setup for dmaap publisher

Change-Id: I5dbfc551e515a5f3ce23ec9ffc766ae3012a057a
Issue-ID: DCAEGEN2-952
Signed-off-by: piotr.karas <piotr.karas@nokia.com>
diff --git a/prh-app-server/src/main/java/org/onap/dcaegen2/services/prh/tasks/DmaapPublisherTaskImpl.java b/prh-app-server/src/main/java/org/onap/dcaegen2/services/prh/tasks/DmaapPublisherTaskImpl.java
index 76c1bb5..d6ad540 100644
--- a/prh-app-server/src/main/java/org/onap/dcaegen2/services/prh/tasks/DmaapPublisherTaskImpl.java
+++ b/prh-app-server/src/main/java/org/onap/dcaegen2/services/prh/tasks/DmaapPublisherTaskImpl.java
@@ -24,6 +24,7 @@
 import org.onap.dcaegen2.services.prh.exceptions.DmaapNotFoundException;
 import org.onap.dcaegen2.services.prh.model.ConsumerDmaapModel;
 import org.onap.dcaegen2.services.prh.service.producer.DMaaPPublisherReactiveHttpClient;
+import org.onap.dcaegen2.services.prh.service.producer.DmaaPRestTemplateFactory;
 import org.onap.dcaegen2.services.prh.service.producer.PublisherReactiveHttpClientFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -44,7 +45,7 @@
 
     @Autowired
     public DmaapPublisherTaskImpl(Config config) {
-        this(config, new PublisherReactiveHttpClientFactory());
+        this(config, new PublisherReactiveHttpClientFactory(new DmaaPRestTemplateFactory()));
     }
 
     DmaapPublisherTaskImpl(Config config, PublisherReactiveHttpClientFactory httpClientFactory) {
diff --git a/prh-app-server/src/test/java/org/onap/dcaegen2/services/prh/tasks/DmaapPublisherTaskImplTest.java b/prh-app-server/src/test/java/org/onap/dcaegen2/services/prh/tasks/DmaapPublisherTaskImplTest.java
index 5bdcba5..538c197 100644
--- a/prh-app-server/src/test/java/org/onap/dcaegen2/services/prh/tasks/DmaapPublisherTaskImplTest.java
+++ b/prh-app-server/src/test/java/org/onap/dcaegen2/services/prh/tasks/DmaapPublisherTaskImplTest.java
@@ -24,7 +24,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
diff --git a/prh-dmaap-client/pom.xml b/prh-dmaap-client/pom.xml
index 751a4f0..ebc2b99 100644
--- a/prh-dmaap-client/pom.xml
+++ b/prh-dmaap-client/pom.xml
@@ -115,5 +115,13 @@
       <artifactId>reactor-test</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+    </dependency>
   </dependencies>
 </project>
diff --git a/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/consumer/ConsumerReactiveHttpClientFactory.java b/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/consumer/ConsumerReactiveHttpClientFactory.java
index a80f134..ece7c67 100644
--- a/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/consumer/ConsumerReactiveHttpClientFactory.java
+++ b/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/consumer/ConsumerReactiveHttpClientFactory.java
@@ -25,16 +25,16 @@
 
 public class ConsumerReactiveHttpClientFactory {
 
-    private final DMaaPReactiveWebClientFactory reactiveWebClient;
+    private final DMaaPReactiveWebClientFactory reactiveWebClientFactory;
 
-    public ConsumerReactiveHttpClientFactory(DMaaPReactiveWebClientFactory reactiveWebClient) {
-        this.reactiveWebClient = reactiveWebClient;
+    public ConsumerReactiveHttpClientFactory(DMaaPReactiveWebClientFactory reactiveWebClientFactory) {
+        this.reactiveWebClientFactory = reactiveWebClientFactory;
     }
 
     public DMaaPConsumerReactiveHttpClient create(DmaapConsumerConfiguration consumerConfiguration)
             throws SSLException {
         return new DMaaPConsumerReactiveHttpClient(consumerConfiguration,
-                reactiveWebClient.build(consumerConfiguration));
+                reactiveWebClientFactory.build(consumerConfiguration));
     }
 
 }
diff --git a/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/DMaaPPublisherReactiveHttpClient.java b/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/DMaaPPublisherReactiveHttpClient.java
index b262e6e..2b33977 100644
--- a/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/DMaaPPublisherReactiveHttpClient.java
+++ b/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/DMaaPPublisherReactiveHttpClient.java
@@ -41,7 +41,6 @@
 import reactor.core.publisher.Mono;
 
 
-
 /**
  * @author <a href="mailto:przemyslaw.wasala@nokia.com">Przemysław Wąsala</a> on 7/4/18
  */
@@ -53,7 +52,7 @@
     private final String dmaapProtocol;
     private final String dmaapTopicName;
     private final String dmaapContentType;
-    private final RestTemplate restTemplate;
+    private final Mono<RestTemplate> restTemplateMono;
 
     /**
      * Constructor DMaaPPublisherReactiveHttpClient.
@@ -61,13 +60,13 @@
      * @param dmaapPublisherConfiguration - DMaaP producer configuration object
      */
     DMaaPPublisherReactiveHttpClient(DmaapPublisherConfiguration dmaapPublisherConfiguration,
-                                     RestTemplate restTemplate) {
+                                     Mono<RestTemplate> restTemplateMono) {
         this.dmaapHostName = dmaapPublisherConfiguration.dmaapHostName();
         this.dmaapProtocol = dmaapPublisherConfiguration.dmaapProtocol();
         this.dmaapPortNumber = dmaapPublisherConfiguration.dmaapPortNumber();
         this.dmaapTopicName = dmaapPublisherConfiguration.dmaapTopicName();
         this.dmaapContentType = dmaapPublisherConfiguration.dmaapContentType();
-        this.restTemplate = restTemplate;
+        this.restTemplateMono = restTemplateMono;
     }
 
     /**
@@ -81,8 +80,8 @@
         return Mono.defer(() -> {
             HttpEntity<String> request = new HttpEntity<>(createJsonBody(consumerDmaapModelMono), getAllHeaders());
             logger.info("Request: {} {}", getUri(), request);
-            return Mono.just(restTemplate.exchange(getUri(), HttpMethod.POST, request, String.class));
-
+            return restTemplateMono.map(
+                restTemplate -> restTemplate.exchange(getUri(), HttpMethod.POST, request, String.class));
         });
     }
 
@@ -97,7 +96,7 @@
 
     URI getUri() {
         return new DefaultUriBuilderFactory().builder().scheme(dmaapProtocol).host(dmaapHostName).port(dmaapPortNumber)
-            .path(dmaapTopicName).build();
+                .path(dmaapTopicName).build();
     }
 
 }
diff --git a/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/DmaaPRestTemplateFactory.java b/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/DmaaPRestTemplateFactory.java
new file mode 100644
index 0000000..6c1005d
--- /dev/null
+++ b/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/DmaaPRestTemplateFactory.java
@@ -0,0 +1,115 @@
+/*
+ * ============LICENSE_START=======================================================
+ * PNF-REGISTRATION-HANDLER
+ * ================================================================================
+ * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.services.prh.service.producer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import javax.net.ssl.SSLContext;
+import org.apache.http.client.HttpClient;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.onap.dcaegen2.services.prh.config.DmaapPublisherConfiguration;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.web.client.RestTemplate;
+import reactor.core.publisher.Mono;
+
+public class DmaaPRestTemplateFactory {
+
+    /**
+     * Function for creating RestTemplate object.
+     *
+     * @param publisherConfiguration - DMaaP publisher configuration object
+     * @return RestTemplate with correct ssl configuration
+     */
+    public Mono<RestTemplate> build(DmaapPublisherConfiguration publisherConfiguration) {
+        if (publisherConfiguration.enableDmaapCertAuth()) {
+            return createRestTemplateWithSslSetup(publisherConfiguration);
+        }
+
+        return Mono.just(new RestTemplate());
+    }
+
+    private Mono<RestTemplate> createRestTemplateWithSslSetup(DmaapPublisherConfiguration publisherConfiguration) {
+        try {
+            RestTemplateBuilder builder = new RestTemplateBuilder();
+
+            SSLContext sslContext = createSslContext(publisherConfiguration,
+                    loadPasswordFromFile(publisherConfiguration.keyStorePasswordPath()),
+                    loadPasswordFromFile(publisherConfiguration.trustStorePasswordPath()));
+
+            return Mono.just(builder
+                    .requestFactory(() -> createRequestFactory(sslContext)).build());
+
+        } catch (GeneralSecurityException | IOException e) {
+            return Mono.error(e);
+        }
+    }
+
+    private SSLContext createSslContext(DmaapPublisherConfiguration publisherConfiguration,
+                                        String keyStorePassword, String trustStorePassword)
+            throws IOException, GeneralSecurityException {
+        return new SSLContextBuilder()
+                        .loadKeyMaterial(
+                                keyStore(publisherConfiguration.keyStorePath(), keyStorePassword),
+                                keyStorePassword.toCharArray())
+                        .loadTrustMaterial(
+                                getFile(publisherConfiguration.trustStorePath()), trustStorePassword.toCharArray())
+                        .build();
+    }
+
+    private HttpComponentsClientHttpRequestFactory createRequestFactory(SSLContext sslContext) {
+        SSLConnectionSocketFactory socketFactory =
+                new SSLConnectionSocketFactory(sslContext);
+        HttpClient httpClient = HttpClients.custom()
+                .setSSLSocketFactory(socketFactory).build();
+
+        return new HttpComponentsClientHttpRequestFactory(httpClient);
+    }
+
+    private KeyStore keyStore(String keyStoreFile, String keyStorePassword)
+            throws GeneralSecurityException, IOException {
+        KeyStore ks = KeyStore.getInstance("jks");
+        ks.load(getResource(keyStoreFile), keyStorePassword.toCharArray());
+        return ks;
+    }
+
+    private File getFile(String fileName) {
+        return new File(fileName);
+    }
+
+    private InputStream getResource(String fileName) throws FileNotFoundException {
+        return new FileInputStream(fileName);
+    }
+
+    private String loadPasswordFromFile(String path) throws IOException {
+        return new String(Files.readAllBytes(Paths.get(path)));
+    }
+
+}
diff --git a/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/PublisherReactiveHttpClientFactory.java b/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/PublisherReactiveHttpClientFactory.java
index 0fc8f16..7f97f90 100644
--- a/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/PublisherReactiveHttpClientFactory.java
+++ b/prh-dmaap-client/src/main/java/org/onap/dcaegen2/services/prh/service/producer/PublisherReactiveHttpClientFactory.java
@@ -21,12 +21,19 @@
 package org.onap.dcaegen2.services.prh.service.producer;
 
 import org.onap.dcaegen2.services.prh.config.DmaapPublisherConfiguration;
-import org.springframework.web.client.RestTemplate;
+
 
 public class PublisherReactiveHttpClientFactory {
 
+    private final DmaaPRestTemplateFactory restTemplateFactory;
+
+    public PublisherReactiveHttpClientFactory(DmaaPRestTemplateFactory restTemplateFactory) {
+        this.restTemplateFactory = restTemplateFactory;
+    }
+
     public DMaaPPublisherReactiveHttpClient create(DmaapPublisherConfiguration publisherConfiguration) {
-        return new DMaaPPublisherReactiveHttpClient(publisherConfiguration, new RestTemplate());
+        return new DMaaPPublisherReactiveHttpClient(publisherConfiguration,
+                restTemplateFactory.build(publisherConfiguration));
     }
 
 }
diff --git a/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/DMaaPPublisherReactiveHttpClientTest.java b/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/DMaaPPublisherReactiveHttpClientTest.java
index ce2f7f3..a163fb7 100644
--- a/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/DMaaPPublisherReactiveHttpClientTest.java
+++ b/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/DMaaPPublisherReactiveHttpClientTest.java
@@ -37,6 +37,7 @@
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.client.RestTemplate;
+import reactor.core.publisher.Mono;
 import reactor.test.StepVerifier;
 
 /**
@@ -62,7 +63,7 @@
         when(dmaapPublisherConfigurationMock.dmaapContentType()).thenReturn("application/json");
         when(dmaapPublisherConfigurationMock.dmaapTopicName()).thenReturn("unauthenticated.PNF_READY");
         dmaapPublisherReactiveHttpClient =
-                new DMaaPPublisherReactiveHttpClient(dmaapPublisherConfigurationMock, restTemplate);
+                new DMaaPPublisherReactiveHttpClient(dmaapPublisherConfigurationMock, Mono.just(restTemplate));
 
     }
 
diff --git a/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/DmaaPRestTemplateFactoryTest.java b/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/DmaaPRestTemplateFactoryTest.java
new file mode 100644
index 0000000..97303b3
--- /dev/null
+++ b/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/DmaaPRestTemplateFactoryTest.java
@@ -0,0 +1,62 @@
+/*
+ * ============LICENSE_START=======================================================
+ * PNF-REGISTRATION-HANDLER
+ * ================================================================================
+ * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.services.prh.service.producer;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import javax.net.ssl.SSLException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.onap.dcaegen2.services.prh.config.DmaapPublisherConfiguration;
+
+
+class DmaaPRestTemplateFactoryTest {
+
+    private static final String KEY_STORE = "org.onap.dcae.jks";
+    private static final String KEYSTORE_PASSWORD = "keystore.password";
+    private static final String TRUSTSTORE_PASSWORD = "truststore.password";
+    private static final String TRUST_STORE = "org.onap.dcae.trust.jks";
+    private DmaapPublisherConfiguration publisherConfiguration = mock(DmaapPublisherConfiguration.class);
+    private DmaaPRestTemplateFactory factory = new DmaaPRestTemplateFactory();
+
+    @Test
+    void build_shouldCreateRestTemplateWithoutSslConfiguration() {
+        when(publisherConfiguration.enableDmaapCertAuth()).thenReturn(false);
+
+        Assertions.assertNotNull(factory.build(publisherConfiguration).block());
+    }
+
+    @Test
+    void build_shouldCreateRestTemplateWithSslConfiguration() {
+        when(publisherConfiguration.enableDmaapCertAuth()).thenReturn(true);
+        when(publisherConfiguration.keyStorePath()).thenReturn(getPath(KEY_STORE));
+        when(publisherConfiguration.keyStorePasswordPath()).thenReturn(getPath(KEYSTORE_PASSWORD));
+        when(publisherConfiguration.trustStorePath()).thenReturn(getPath(TRUST_STORE));
+        when(publisherConfiguration.trustStorePasswordPath()).thenReturn(getPath(TRUSTSTORE_PASSWORD));
+
+        Assertions.assertNotNull(factory.build(publisherConfiguration).block());
+    }
+
+    private String getPath(String fileName) {
+        return this.getClass().getClassLoader().getResource(fileName).getPath();
+    }
+}
\ No newline at end of file
diff --git a/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/PublisherReactiveHttpClientFactoryTest.java b/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/PublisherReactiveHttpClientFactoryTest.java
index 3acfde9..764d578 100644
--- a/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/PublisherReactiveHttpClientFactoryTest.java
+++ b/prh-dmaap-client/src/test/java/org/onap/dcaegen2/services/prh/service/producer/PublisherReactiveHttpClientFactoryTest.java
@@ -29,8 +29,10 @@
 
 class PublisherReactiveHttpClientFactoryTest {
 
+    private DmaaPRestTemplateFactory restTemplateFactory = mock(DmaaPRestTemplateFactory.class);
     private DmaapPublisherConfiguration dmaapPublisherConfiguration = mock(DmaapPublisherConfiguration.class);
-    private PublisherReactiveHttpClientFactory httpClientFactory = new PublisherReactiveHttpClientFactory();
+    private PublisherReactiveHttpClientFactory httpClientFactory =
+            new PublisherReactiveHttpClientFactory(restTemplateFactory);
 
     @Test
     void create_shouldReturnNotNullFactoryInstance() {
diff --git a/prh-dmaap-client/src/test/resources/keystore.password b/prh-dmaap-client/src/test/resources/keystore.password
new file mode 100644
index 0000000..3982387
--- /dev/null
+++ b/prh-dmaap-client/src/test/resources/keystore.password
@@ -0,0 +1 @@
+mYHC98!qX}7h?W}jRv}MIXTJ
\ No newline at end of file
diff --git a/prh-dmaap-client/src/test/resources/org.onap.dcae.jks b/prh-dmaap-client/src/test/resources/org.onap.dcae.jks
new file mode 100644
index 0000000..e74ce64
--- /dev/null
+++ b/prh-dmaap-client/src/test/resources/org.onap.dcae.jks
Binary files differ
diff --git a/prh-dmaap-client/src/test/resources/org.onap.dcae.trust.jks b/prh-dmaap-client/src/test/resources/org.onap.dcae.trust.jks
new file mode 100644
index 0000000..10103cf
--- /dev/null
+++ b/prh-dmaap-client/src/test/resources/org.onap.dcae.trust.jks
Binary files differ
diff --git a/prh-dmaap-client/src/test/resources/truststore.password b/prh-dmaap-client/src/test/resources/truststore.password
new file mode 100644
index 0000000..168e64b
--- /dev/null
+++ b/prh-dmaap-client/src/test/resources/truststore.password
@@ -0,0 +1 @@
+*TQH?Lnszprs4LmlAj38yds(
\ No newline at end of file