From 8ac3e42050884ef8d5e9bcf8a7083b01350a134a Mon Sep 17 00:00:00 2001 From: Michal Jagiello Date: Thu, 28 May 2020 10:49:20 +0000 Subject: CDS client gRPC SSL/TLS support Issue-ID: SO-3003 Change-Id: Id9150c7da5c29fc0854ebaf13d845adf89fc60ff Signed-off-by: Michal Jagiello --- .../java/org/onap/so/client/KeyStoreLoader.java | 48 ++++++++++++++++++++++ .../java/org/onap/so/client/RestClientSSL.java | 27 +----------- .../onap/so/client/cds/CDSProcessingClient.java | 41 ++++++++++++++++-- .../java/org/onap/so/client/cds/CDSProperties.java | 5 ++- 4 files changed, 91 insertions(+), 30 deletions(-) create mode 100644 common/src/main/java/org/onap/so/client/KeyStoreLoader.java (limited to 'common/src/main') 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 index 0000000000..8279be8635 --- /dev/null +++ b/common/src/main/java/org/onap/so/client/KeyStoreLoader.java @@ -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"); + } +} diff --git a/common/src/main/java/org/onap/so/client/RestClientSSL.java b/common/src/main/java/org/onap/so/client/RestClientSSL.java index f5737b862c..1e8953892e 100644 --- a/common/src/main/java/org/onap/so/client/RestClientSSL.java +++ b/common/src/main/java/org/onap/so/client/RestClientSSL.java @@ -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 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"); - } } diff --git a/common/src/main/java/org/onap/so/client/cds/CDSProcessingClient.java b/common/src/main/java/org/onap/so/client/cds/CDSProcessingClient.java index 7ef158996d..fa309b54fe 100644 --- a/common/src/main/java/org/onap/so/client/cds/CDSProcessingClient.java +++ b/common/src/main/java/org/onap/so/client/cds/CDSProcessingClient.java @@ -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"); } diff --git a/common/src/main/java/org/onap/so/client/cds/CDSProperties.java b/common/src/main/java/org/onap/so/client/cds/CDSProperties.java index 37a5c0bc18..db566fa3de 100644 --- a/common/src/main/java/org/onap/so/client/cds/CDSProperties.java +++ b/common/src/main/java/org/onap/so/client/cds/CDSProperties.java @@ -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(); } -- cgit 1.2.3-korg