SSL implementation for PRH to AAI calls 34/71934/1
authorMaciej Wejs <maciej.wejs@nokia.com>
Tue, 6 Nov 2018 11:07:12 +0000 (12:07 +0100)
committerMaciej Wejs <maciej.wejs@nokia.com>
Tue, 6 Nov 2018 11:07:12 +0000 (12:07 +0100)
Change-Id: Ic9777760346258afb40610fa9c9bc261964752cf
Issue-ID: DCAEGEN2-950
Signed-off-by: Maciej Wejs <maciej.wejs@nokia.com>
prh-aai-client/src/main/java/org/onap/dcaegen2/services/prh/service/AaiReactiveWebClient.java
prh-app-server/src/main/java/org/onap/dcaegen2/services/prh/configuration/AppConfig.java
prh-app-server/src/main/java/org/onap/dcaegen2/services/prh/configuration/PrhAppConfig.java
prh-app-server/src/main/java/org/onap/dcaegen2/services/prh/tasks/AaiProducerTask.java
prh-commons/pom.xml
prh-commons/src/main/java/org/onap/dcaegen2/services/prh/ssl/SslFactory.java [new file with mode: 0644]

index 5963d9c..ad57ba4 100644 (file)
@@ -25,11 +25,10 @@ import static org.onap.dcaegen2.services.prh.model.logging.MdcVariables.SERVICE_
 import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;
 
 import io.netty.handler.ssl.SslContext;
-import io.netty.handler.ssl.SslContextBuilder;
-import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
 import java.util.Map;
 import javax.net.ssl.SSLException;
 import org.onap.dcaegen2.services.prh.config.AaiClientConfiguration;
+import org.onap.dcaegen2.services.prh.ssl.SslFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
@@ -45,21 +44,32 @@ public class AaiReactiveWebClient {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(AaiReactiveWebClient.class);
 
-    private String aaiUserName;
-    private String aaiUserPassword;
-    private Map<String, String> aaiHeaders;
+    private final String aaiUserName;
+    private final String aaiUserPassword;
+    private final Map<String, String> aaiHeaders;
+    private final Boolean enableAaiCertAuth;
+    private final String trustStore;
+    private final String trustStorePassword;
+    private final String keyStore;
+    private final String keyStorePassword;
+    private final SslFactory sslFactory;
 
     /**
      * Creating AaiReactiveWebClient.
      *
      * @param configuration - configuration object
-     * @return AaiReactiveWebClient
+     * @param sslFactory - factory for ssl setup
      */
-    public AaiReactiveWebClient fromConfiguration(AaiClientConfiguration configuration) {
+    public AaiReactiveWebClient(SslFactory sslFactory, AaiClientConfiguration configuration) {
         this.aaiUserName = configuration.aaiUserName();
         this.aaiUserPassword = configuration.aaiUserPassword();
         this.aaiHeaders = configuration.aaiHeaders();
-        return this;
+        this.trustStore = configuration.trustStore();
+        this.trustStorePassword = configuration.trustStorePassword();
+        this.keyStore = configuration.keyStore();
+        this.keyStorePassword = configuration.keyStorePassword();
+        this.enableAaiCertAuth = configuration.enableAaiCertAuth();
+        this.sslFactory = sslFactory;
     }
 
     /**
@@ -69,12 +79,12 @@ public class AaiReactiveWebClient {
      */
     public WebClient build() throws SSLException {
         LOGGER.debug("Setting ssl context");
-        SslContext sslContext = SslContextBuilder
-            .forClient()
-            .trustManager(InsecureTrustManagerFactory.INSTANCE)
-            .build();
+        
+        SslContext sslContext = createSslContext();
+        
         ClientHttpConnector reactorClientHttpConnector = new ReactorClientHttpConnector(
             HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext)));
+
         return WebClient.builder()
             .clientConnector(reactorClientHttpConnector)
             .defaultHeaders(httpHeaders -> httpHeaders.setAll(aaiHeaders))
@@ -84,6 +94,18 @@ public class AaiReactiveWebClient {
             .build();
     }
 
+    private SslContext createSslContext() throws SSLException {
+        if (enableAaiCertAuth) {
+            return sslFactory.createSecureContext(
+                keyStore,
+                keyStorePassword,
+                trustStore,
+                trustStorePassword
+            );
+        }
+        return sslFactory.createInsecureContext();
+    }
+    
     private ExchangeFilterFunction logRequest() {
         return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
             MDC.put(SERVICE_NAME, String.valueOf(clientRequest.url()));
index 643462f..191294f 100644 (file)
@@ -174,16 +174,16 @@ public class AppConfig extends PrhAppConfig {
             .consumerId(Optional.ofNullable(consumerId).filter(isEmpty.negate())
                 .orElse(dmaapConsumerConfiguration.consumerId()))
             .keyFile(
-                Optional.ofNullable(keyFile).filter(p -> !p.isEmpty())
+                Optional.ofNullable(keyFile).filter(isEmpty.negate())
                     .orElse(dmaapConsumerConfiguration.keyFile()))
             .trustStore(
-                Optional.ofNullable(trustStore).filter(p -> !p.isEmpty())
+                Optional.ofNullable(trustStore).filter(isEmpty.negate())
                     .orElse(dmaapConsumerConfiguration.trustStore()))
             .trustStorePassword(
                 Optional.ofNullable(trustStorePassword).filter(isEmpty.negate())
                     .orElse(dmaapConsumerConfiguration.trustStorePassword()))
             .keyStore(
-                Optional.ofNullable(keyStore).filter(p -> !p.isEmpty())
+                Optional.ofNullable(keyStore).filter(isEmpty.negate())
                     .orElse(dmaapConsumerConfiguration.keyStore()))
             .keyStorePassword(
                 Optional.ofNullable(keyStorePassword).filter(isEmpty.negate())
@@ -216,16 +216,16 @@ public class AppConfig extends PrhAppConfig {
                 Optional.ofNullable(aaiPnfPath).filter(isEmpty.negate()).orElse(aaiClientConfiguration.aaiPnfPath()))
             .aaiHeaders(aaiClientConfiguration.aaiHeaders())
             .keyFile(
-                Optional.ofNullable(keyFile).filter(p -> !p.isEmpty())
+                Optional.ofNullable(keyFile).filter(isEmpty.negate())
                     .orElse(aaiClientConfiguration.keyFile()))
             .trustStore(
-                Optional.ofNullable(trustStore).filter(p -> !p.isEmpty())
+                Optional.ofNullable(trustStore).filter(isEmpty.negate())
                     .orElse(aaiClientConfiguration.trustStore()))
             .trustStorePassword(
                 Optional.ofNullable(trustStorePassword).filter(isEmpty.negate())
                     .orElse(aaiClientConfiguration.trustStorePassword()))
             .keyStore(
-                Optional.ofNullable(keyStore).filter(p -> !p.isEmpty())
+                Optional.ofNullable(keyStore).filter(isEmpty.negate())
                     .orElse(aaiClientConfiguration.keyStore()))
             .keyStorePassword(
                 Optional.ofNullable(keyStorePassword).filter(isEmpty.negate())
@@ -261,16 +261,16 @@ public class AppConfig extends PrhAppConfig {
                 Optional.ofNullable(producerDmaapUserPassword).filter(isEmpty.negate())
                     .orElse(dmaapPublisherConfiguration.dmaapUserPassword()))
             .keyFile(
-                Optional.ofNullable(keyFile).filter(p -> !p.isEmpty())
+                Optional.ofNullable(keyFile).filter(isEmpty.negate())
                     .orElse(dmaapPublisherConfiguration.keyFile()))
             .trustStore(
-                Optional.ofNullable(trustStore).filter(p -> !p.isEmpty())
+                Optional.ofNullable(trustStore).filter(isEmpty.negate())
                     .orElse(dmaapPublisherConfiguration.trustStore()))
             .trustStorePassword(
                 Optional.ofNullable(trustStorePassword).filter(isEmpty.negate())
                     .orElse(dmaapPublisherConfiguration.trustStorePassword()))
             .keyStore(
-                Optional.ofNullable(keyStore).filter(p -> !p.isEmpty())
+                Optional.ofNullable(keyStore).filter(isEmpty.negate())
                     .orElse(dmaapPublisherConfiguration.keyStore()))
             .keyStorePassword(
                 Optional.ofNullable(keyStorePassword).filter(isEmpty.negate())
index 54c6353..2b4b201 100644 (file)
@@ -95,11 +95,10 @@ public abstract class PrhAppConfig implements Config {
         try (InputStream inputStream = resourceFile.getInputStream()) {
             JsonElement rootElement = getJsonElement(parser, inputStream);
             if (rootElement.isJsonObject()) {
-                JsonObject jsonObject = concatenateJsonObjects(
-                        rootElement.getAsJsonObject().getAsJsonObject(CONFIG).getAsJsonObject(AAI).getAsJsonObject(AAI_CONFIG),
-                        rootElement.getAsJsonObject().getAsJsonObject(CONFIG).getAsJsonObject(SECURITY));
                 aaiClientConfiguration = deserializeType(gsonBuilder,
-                        jsonObject,
+                    concatenateJsonObjects(
+                        rootElement.getAsJsonObject().getAsJsonObject(CONFIG).getAsJsonObject(AAI).getAsJsonObject(AAI_CONFIG),
+                        rootElement.getAsJsonObject().getAsJsonObject(CONFIG).getAsJsonObject(SECURITY)),
                     AaiClientConfiguration.class);
                 dmaapConsumerConfiguration = deserializeType(gsonBuilder,
                     concatenateJsonObjects(
index efa4f66..54a8ad8 100644 (file)
@@ -27,6 +27,7 @@ import org.onap.dcaegen2.services.prh.exceptions.PrhTaskException;
 import org.onap.dcaegen2.services.prh.model.ConsumerDmaapModel;
 import org.onap.dcaegen2.services.prh.service.AaiReactiveWebClient;
 import org.onap.dcaegen2.services.prh.service.producer.AaiProducerReactiveHttpClient;
+import org.onap.dcaegen2.services.prh.ssl.SslFactory;
 import org.springframework.web.reactive.function.client.WebClient;
 import reactor.core.publisher.Mono;
 
@@ -46,6 +47,6 @@ public abstract class AaiProducerTask {
         throws PrhTaskException, SSLException;
 
     WebClient buildWebClient() throws SSLException {
-        return new AaiReactiveWebClient().fromConfiguration(resolveConfiguration()).build();
+        return new AaiReactiveWebClient(new SslFactory(), resolveConfiguration()).build();
     }
 }
index 91fd908..11a0bab 100644 (file)
@@ -74,5 +74,9 @@
       <groupId>org.springframework</groupId>
       <artifactId>spring-web</artifactId>
     </dependency>
+    <dependency>
+      <groupId>io.projectreactor.netty</groupId>
+      <artifactId>reactor-netty</artifactId>
+    </dependency>
   </dependencies>
 </project>
diff --git a/prh-commons/src/main/java/org/onap/dcaegen2/services/prh/ssl/SslFactory.java b/prh-commons/src/main/java/org/onap/dcaegen2/services/prh/ssl/SslFactory.java
new file mode 100644 (file)
index 0000000..6ffff1b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * ============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.ssl;
+
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.KeyStore;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.TrustManagerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SslFactory {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(SslFactory.class);
+
+    public SslContext createSecureContext(String keyStoreFilename,
+        String keyStorePassword,
+        String trustStoreFilename,
+        String trustStorePassword) throws SSLException {
+        LOGGER.info("Creating secure ssl context for: {} {}", keyStoreFilename, trustStoreFilename);
+        try {
+            return SslContextBuilder
+                .forClient()
+                .keyManager(keyManagerFactory(keyStoreFilename, loadPasswordFromFile(keyStorePassword)))
+                .trustManager(trustManagerFactory(trustStoreFilename, loadPasswordFromFile(trustStorePassword)))
+                .build();
+        } catch (Exception ex) {
+            throw new SSLException(ex);
+        }
+    }
+
+    public SslContext createInsecureContext() throws SSLException {
+        LOGGER.info("Creating insecure ssl context");
+        return SslContextBuilder
+            .forClient()
+            .trustManager(InsecureTrustManagerFactory.INSTANCE)
+            .build();
+    }
+
+    private KeyManagerFactory keyManagerFactory(String fileName, String password) throws Exception {
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(loadKeyStoreFromFile(fileName, password),
+            password.toCharArray());
+        return kmf;
+    }
+
+    private TrustManagerFactory trustManagerFactory(String fileName, String password) throws Exception {
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+        tmf.init(loadKeyStoreFromFile(fileName, password));
+        return tmf;
+    }
+
+    private KeyStore loadKeyStoreFromFile(String fileName, String keyStorePassword) throws Exception {
+        KeyStore ks = KeyStore.getInstance("jks");
+        ks.load(getResource(fileName), keyStorePassword.toCharArray());
+        return ks;
+    }
+
+    private InputStream getResource(String fileName) throws Exception {
+        return new FileInputStream(fileName);
+    }
+
+    private String loadPasswordFromFile(String path) throws Exception {
+        return new String(Files.readAllBytes(Paths.get(path)));
+    }
+}