CDS client gRPC SSL/TLS support 79/109479/3
authorMichal Jagiello <michal.jagiello@t-mobile.pl>
Thu, 28 May 2020 10:49:20 +0000 (10:49 +0000)
committerMichal Jagiello <michal.jagiello@t-mobile.pl>
Mon, 13 Jul 2020 10:06:02 +0000 (10:06 +0000)
Issue-ID: SO-3003

Change-Id: Id9150c7da5c29fc0854ebaf13d845adf89fc60ff
Signed-off-by: Michal Jagiello <michal.jagiello@t-mobile.pl>
bpmn/MSOCommonBPMN/src/main/java/org/onap/so/client/restproperties/CDSPropertiesImpl.java
common/pom.xml
common/src/main/java/org/onap/so/client/KeyStoreLoader.java [new file with mode: 0644]
common/src/main/java/org/onap/so/client/RestClientSSL.java
common/src/main/java/org/onap/so/client/cds/CDSProcessingClient.java
common/src/main/java/org/onap/so/client/cds/CDSProperties.java
common/src/test/java/org/onap/so/client/cds/CDSProcessingClientTest.java
common/src/test/java/org/onap/so/client/cds/TestCDSPropertiesImpl.java
pom.xml

index 64c4565..2efd74d 100644 (file)
@@ -80,4 +80,14 @@ public class CDSPropertiesImpl implements CDSProperties {
     public int getTimeout() {
         return Integer.parseInt(Objects.requireNonNull(UrnPropertiesReader.getVariable(TIMEOUT)));
     }
+
+    @Override
+    public boolean getUseSSL() {
+        return false;
+    }
+
+    @Override
+    public boolean getUseBasicAuth() {
+        return true;
+    }
 }
index 08dfc4d..6b54ad0 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0"?>
+<?xml version="1.0" ?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
       </plugin>
     </plugins>
   </build>
-</project>
+</project>
\ No newline at end of file
diff --git a/common/src/main/java/org/onap/so/client/KeyStoreLoader.java b/common/src/main/java/org/onap/so/client/KeyStoreLoader.java
new file mode 100644 (file)
index 0000000..8279be8
--- /dev/null
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2020 Deutsche Telekom.
+ * ================================================================================
+ * 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.so.client;
+
+import java.io.FileInputStream;
+import java.nio.file.Paths;
+import java.security.KeyStore;
+
+public abstract class KeyStoreLoader {
+
+    static final String SSL_KEY_STORE_KEY = "javax.net.ssl.keyStore";
+
+    static public KeyStore getKeyStore() {
+        KeyStore ks = null;
+        final char[] password = getSSlKeyStorePassword().toCharArray();
+        try (FileInputStream fis =
+                new FileInputStream(Paths.get(System.getProperty(SSL_KEY_STORE_KEY)).normalize().toString())) {
+            ks = KeyStore.getInstance(KeyStore.getDefaultType());
+            ks.load(fis, password);
+        } catch (final Exception e) {
+            return null;
+        }
+
+        return ks;
+    }
+
+    static public String getSSlKeyStorePassword() {
+        return System.getProperty("javax.net.ssl.keyStorePassword");
+    }
+}
index f5737b8..1e89538 100644 (file)
@@ -20,9 +20,7 @@
 
 package org.onap.so.client;
 
-import java.io.FileInputStream;
 import java.net.URI;
-import java.nio.file.Paths;
 import java.security.KeyStore;
 import java.security.NoSuchAlgorithmException;
 import java.util.Optional;
@@ -33,10 +31,8 @@ import javax.ws.rs.client.ClientBuilder;
 public abstract class RestClientSSL extends RestClient {
 
     private static final String TRUE = "true";
-    private static final String SSL_KEY_STORE_KEY = "javax.net.ssl.keyStore";
     private static final String MSO_LOAD_SSL_CLIENT_KEYSTORE_KEY = "mso.load.ssl.client.keystore";
 
-
     protected RestClientSSL(RestProperties props, Optional<URI> path) {
         super(props, path);
     }
@@ -52,9 +48,9 @@ public abstract class RestClientSSL extends RestClient {
         try {
             String loadSSLKeyStore = System.getProperty(RestClientSSL.MSO_LOAD_SSL_CLIENT_KEYSTORE_KEY);
             if (loadSSLKeyStore != null && loadSSLKeyStore.equalsIgnoreCase(TRUE)) {
-                KeyStore ks = getKeyStore();
+                KeyStore ks = KeyStoreLoader.getKeyStore();
                 if (ks != null) {
-                    client = ClientBuilder.newBuilder().keyStore(ks, getSSlKeyStorePassword()).build();
+                    client = ClientBuilder.newBuilder().keyStore(ks, KeyStoreLoader.getSSlKeyStorePassword()).build();
                     logger.info("RestClientSSL not using default SSL context - setting keystore here.");
                     return client;
                 }
@@ -67,23 +63,4 @@ public abstract class RestClientSSL extends RestClient {
         }
         return client;
     }
-
-    private KeyStore getKeyStore() {
-        KeyStore ks = null;
-        char[] password = getSSlKeyStorePassword().toCharArray();
-        try (FileInputStream fis = new FileInputStream(
-                Paths.get(System.getProperty(RestClientSSL.SSL_KEY_STORE_KEY)).normalize().toString())) {
-            ks = KeyStore.getInstance(KeyStore.getDefaultType());
-
-            ks.load(fis, password);
-        } catch (Exception e) {
-            return null;
-        }
-
-        return ks;
-    }
-
-    private String getSSlKeyStorePassword() {
-        return System.getProperty("javax.net.ssl.keyStorePassword");
-    }
 }
index 7ef1589..fa309b5 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP - SO
  * ================================================================================
- * Copyright (C) 2017 - 2019 Bell Canada.
+ * Copyright (C) 2017 - 2019 Bell Canada, Deutsche Telekom.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,9 +23,16 @@ package org.onap.so.client.cds;
 import io.grpc.ManagedChannel;
 import io.grpc.internal.DnsNameResolverProvider;
 import io.grpc.internal.PickFirstLoadBalancerProvider;
+import io.grpc.netty.GrpcSslContexts;
 import io.grpc.netty.NettyChannelBuilder;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
 import java.util.concurrent.CountDownLatch;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.TrustManagerFactory;
 import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput;
+import org.onap.so.client.KeyStoreLoader;
 import org.onap.so.client.PreconditionFailedException;
 import org.onap.so.client.RestPropertiesLoader;
 import org.slf4j.Logger;
@@ -73,10 +80,36 @@ public class CDSProcessingClient implements AutoCloseable {
             throw new PreconditionFailedException(
                     "No RestProperty.CDSProperties implementation found on classpath, can't create client.");
         }
-        this.channel = NettyChannelBuilder.forAddress(props.getHost(), props.getPort())
+        NettyChannelBuilder builder = NettyChannelBuilder.forAddress(props.getHost(), props.getPort())
                 .nameResolverFactory(new DnsNameResolverProvider())
-                .loadBalancerFactory(new PickFirstLoadBalancerProvider())
-                .intercept(new BasicAuthClientInterceptor(props)).usePlaintext().build();
+                .loadBalancerFactory(new PickFirstLoadBalancerProvider());
+        if (props.getUseSSL()) {
+            log.info("Configure SSL connection");
+            KeyStore ks = KeyStoreLoader.getKeyStore();
+            if (ks == null) {
+                log.error("Can't load KeyStore");
+                throw new RuntimeException("Can't load KeyStore to create secure channel");
+            }
+            try {
+                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+                tmf.init(ks);
+                builder.sslContext(GrpcSslContexts.forClient().trustManager(tmf).build());
+            } catch (NoSuchAlgorithmException e) {
+                log.error("Can't get default TrustManager algorithm");
+                throw new RuntimeException(e);
+            } catch (KeyStoreException e) {
+                log.error("TrustManagerFactory initialization failed");
+                throw new RuntimeException(e);
+            } catch (SSLException e) {
+                log.error("SslContext build error");
+                throw new RuntimeException(e);
+            }
+        }
+        if (props.getUseBasicAuth()) {
+            log.info("Configure Basic authentication");
+            builder.intercept(new BasicAuthClientInterceptor(props)).usePlaintext();
+        }
+        this.channel = builder.build();
         this.handler = new CDSProcessingHandler(listener);
         log.info("CDSProcessingClient started");
     }
index 37a5c0b..db566fa 100644 (file)
@@ -22,7 +22,6 @@ package org.onap.so.client.cds;
 
 import org.onap.so.client.RestProperties;
 
-
 public interface CDSProperties extends RestProperties {
 
     String getHost();
@@ -32,4 +31,8 @@ public interface CDSProperties extends RestProperties {
     String getBasicAuth();
 
     int getTimeout();
+
+    boolean getUseSSL();
+
+    boolean getUseBasicAuth();
 }
index 18ec9ef..5792c28 100644 (file)
@@ -20,7 +20,6 @@
 
 package org.onap.so.client.cds;
 
-
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 import io.grpc.inprocess.InProcessChannelBuilder;
@@ -58,7 +57,6 @@ public class CDSProcessingClientTest {
     private CDSProcessingHandler handler;
     private CDSProcessingClient client;
 
-
     private final MutableHandlerRegistry serviceRegistry = new MutableHandlerRegistry();
     private final List<String> messagesDelivered = new ArrayList<>();
     private final CountDownLatch allRequestsDelivered = new CountDownLatch(1);
@@ -115,7 +113,6 @@ public class CDSProcessingClientTest {
         new CDSProcessingClient(listener);
     }
 
-
     @Test
     public void testSendMessageFail() throws Exception {
 
index 2834d37..41238e5 100644 (file)
@@ -72,4 +72,14 @@ public class TestCDSPropertiesImpl implements CDSProperties {
     public int getTimeout() {
         return 60;
     }
+
+    @Override
+    public boolean getUseSSL() {
+        return false;
+    }
+
+    @Override
+    public boolean getUseBasicAuth() {
+        return true;
+    }
 }
diff --git a/pom.xml b/pom.xml
index b2fd0d5..264b3d9 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<?xml version="1.0" ?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.onap.oparent</groupId>
     </plugins>
     <pluginManagement>
       <plugins>
-           <plugin>
+        <plugin>
           <groupId>org.eclipse.m2e</groupId>
           <artifactId>lifecycle-mapping</artifactId>
           <version>1.0.0</version>
                     <execute />
                   </action>
                 </pluginExecution>
-                 <pluginExecution>
+                <pluginExecution>
                   <pluginExecutionFilter>
                     <groupId>org.codehaus.gmaven</groupId>
                     <artifactId>groovy-maven-plugin</artifactId>
       </build>
     </profile>
   </profiles>
-</project>
+</project>
\ No newline at end of file