TLS support in sdc-fe 83/136083/2
authorMichaelMorris <michael.morris@est.tech>
Tue, 3 Oct 2023 08:58:40 +0000 (09:58 +0100)
committerMichael Morris <michael.morris@est.tech>
Thu, 26 Oct 2023 15:43:18 +0000 (15:43 +0000)
Signed-off-by: MichaelMorris <michael.morris@est.tech>
Issue-ID: SDC-4642
Change-Id: I960c0a114889c7b5c1c7924cefff93168132e2b6

catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/files/default/org.onap.sdc.p12 [deleted file]
catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/files/default/org.onap.sdc.trust.jks [deleted file]
catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/recipes/FE_6_locate_keystore.rb [deleted file]
catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/recipes/FE_6_setup_key_and_trust_store.rb [new file with mode: 0644]
catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/recipes/FE_7_create_jetty_modules.rb
catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/templates/default/ssl-ini.erb
catalog-fe/sdc-frontend/chef-solo/roles/catalog-fe.json
catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/HealthCheckScheduledTask.java
catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/SSLProxyServlet.java
common-app-api/src/main/java/org/openecomp/sdc/common/http/client/api/HttpConnectionMngFactory.java
common-app-api/src/main/java/org/openecomp/sdc/common/http/config/ClientCertificate.java

diff --git a/catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/files/default/org.onap.sdc.p12 b/catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/files/default/org.onap.sdc.p12
deleted file mode 100644 (file)
index 4468560..0000000
Binary files a/catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/files/default/org.onap.sdc.p12 and /dev/null differ
diff --git a/catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/files/default/org.onap.sdc.trust.jks b/catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/files/default/org.onap.sdc.trust.jks
deleted file mode 100644 (file)
index e6686cc..0000000
Binary files a/catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/files/default/org.onap.sdc.trust.jks and /dev/null differ
diff --git a/catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/recipes/FE_6_locate_keystore.rb b/catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/recipes/FE_6_locate_keystore.rb
deleted file mode 100644 (file)
index 50cb263..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-directory "Jetty_etcdir_creation" do
-       path "#{ENV['JETTY_BASE']}/etc"
-       owner "#{ENV['JETTY_USER']}"
-       group "#{ENV['JETTY_GROUP']}"
-       mode '0755'
-       action :create
-end
-
-cookbook_file "#{ENV['JETTY_BASE']}/etc/org.onap.sdc.p12" do
-   source "org.onap.sdc.p12"
-   owner "#{ENV['JETTY_USER']}"
-   group "#{ENV['JETTY_GROUP']}"
-   mode 0755
-end
-
-cookbook_file "#{ENV['JETTY_BASE']}/etc/org.onap.sdc.trust.jks" do
-   source "org.onap.sdc.trust.jks"
-   owner "#{ENV['JETTY_USER']}"
-   group "#{ENV['JETTY_GROUP']}"
-   mode 0755
-end
diff --git a/catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/recipes/FE_6_setup_key_and_trust_store.rb b/catalog-fe/sdc-frontend/chef-repo/cookbooks/sdc-catalog-fe/recipes/FE_6_setup_key_and_trust_store.rb
new file mode 100644 (file)
index 0000000..2585d1b
--- /dev/null
@@ -0,0 +1,21 @@
+#Set the http module option
+if node['FE'][:tls_cert]
+  execute "generate-keystore" do
+    command "openssl pkcs12 -inkey #{node['FE'][:tls_key]} -in #{node['FE'][:tls_cert]} -export -out /tmp/keystore.pkcs12 -passin pass:#{node['FE'][:tls_password]} -passout pass:#{node['FE'][:tls_password]}"
+  end
+
+  execute "import-keystore" do
+    command "keytool -importkeystore -srcstoretype PKCS12 -srckeystore /tmp/keystore.pkcs12 -srcstorepass #{node['FE'][:tls_password]} -destkeystore #{ENV['JETTY_BASE']}/#{node['FE'][:keystore_path]} -deststorepass #{node['FE'][:keystore_password]} -noprompt"
+  end
+end
+
+if node['FE'][:ca_cert]
+  execute "delete-existing-ca-alias" do
+    command "keytool -delete -alias sdc-be -storepass #{node['FE'][:truststore_password]} -keystore #{ENV['JETTY_BASE']}/#{node['FE'][:truststore_path]}"
+    returns [0, 1]
+  end
+
+  execute "generate-truststore" do
+    command "keytool -import  -alias sdc-be -file #{node['FE'][:ca_cert]} -storetype JKS -keystore #{ENV['JETTY_BASE']}/#{node['FE'][:truststore_path]} -storepass #{node['FE'][:truststore_password]} -noprompt"
+  end
+end
index 734c05a..3a7433e 100644 (file)
@@ -49,8 +49,9 @@ template "ssl-ini" do
    mode "0755"
    variables({
      :https_port => "#{node['FE'][:https_port]}" ,
-     :jetty_keystore_pwd => "#{node['jetty'][:keystore_pwd]}" ,
-     :jetty_keymanager_pwd => "#{node['jetty'][:keymanager_pwd]}" ,
-     :jetty_truststore_pwd => "#{node['jetty'][:truststore_pwd]}"
+     :keystore_path => "#{node['FE'][:keystore_path]}" ,
+     :keystore_password => "#{node['FE'][:keystore_password]}" ,
+     :truststore_path => "#{node['FE'][:truststore_path]}" ,
+     :truststore_password => "#{node['FE'][:truststore_password]}"
    })
 end
index 278fdea..d3c8bc1 100644 (file)
@@ -42,33 +42,42 @@ jetty.ssl.port=<%= @https_port %>
 ## See http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
 
 ## Keystore file path (relative to $jetty.base)
-jetty.sslContext.keyStorePath=etc/org.onap.sdc.p12
+<% unless @keystore_path.nil? || @keystore_path.strip.empty?  -%>
+jetty.sslContext.keyStorePath=<%= @keystore_path %>
+<% end -%>
 
 ## Truststore file path (relative to $jetty.base)
-jetty.sslContext.trustStorePath=etc/org.onap.sdc.trust.jks
+<% unless @truststore_path.nil? || @truststore_path.strip.empty? -%>
+jetty.sslContext.trustStorePath=<%= @truststore_path %>
+<% end -%>
 
 ## Keystore password
-# jetty.sslContext.keyStorePassword=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
-jetty.sslContext.keyStorePassword=<%= @jetty_keystore_pwd %>
+<% unless @keystore_password.nil? || @keystore_password.strip.empty? -%>
+jetty.sslContext.keyStorePassword=<%= @keystore_password %>
+<% end -%>
 
 ## Keystore type and provider
 # jetty.sslContext.keyStoreType=JKS
 # jetty.sslContext.keyStoreProvider=
 
 ## KeyManager password
-# jetty.sslContext.keyManagerPassword=OBF:1u2u1wml1z7s1z7a1wnl1u2g
-jetty.sslContext.keyManagerPassword=<%= @jetty_keymanager_pwd %>
+<% unless @keystore_password.nil? || @keystore_password.strip.empty? -%>
+jetty.sslContext.keyManagerPassword=<%= @keystore_password %>
+<% end -%>
 
 ## Truststore password
-# jetty.sslContext.trustStorePassword=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
-jetty.sslContext.trustStorePassword=<%= @jetty_truststore_pwd %>
+# tp<%= @truststore_password %>end
+# kp<%= @keystore_password %>end
+<% unless @truststore_password.nil? || @truststore_password.strip.empty? -%>
+jetty.sslContext.trustStorePassword=<%= @truststore_password %>
+<% end -%>
 
 ## Truststore type and provider
 # jetty.sslContext.trustStoreType=JKS
 # jetty.sslContext.trustStoreProvider=
 
 ## whether client certificate authentication is required
-# jetty.sslContext.needClientAuth=false
+jetty.sslContext.needClientAuth=<%= !@truststore_password.nil? && !@truststore_password.strip.empty? %>
 
 ## Whether client certificate authentication is desired
 # jetty.sslContext.wantClientAuth=false
index 44bb56b..815a38c 100644 (file)
@@ -15,7 +15,7 @@
     "recipe[sdc-catalog-fe::FE_3_errors_config]",
     "recipe[sdc-catalog-fe::FE_4_logback]",
     "recipe[sdc-catalog-fe::FE_5_rest_configuration]",
-    "recipe[sdc-catalog-fe::FE_6_locate_keystore]",
+    "recipe[sdc-catalog-fe::FE_6_setup_key_and_trust_store]",
     "recipe[sdc-catalog-fe::FE_7_create_jetty_modules]",
     "recipe[sdc-catalog-fe::FE_8_prepareProbeFile]"
   ],
index 2d99f84..0db9fe9 100644 (file)
@@ -37,15 +37,22 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+
+import javax.servlet.ServletException;
+
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpStatus;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.onap.config.api.JettySSLUtils;
 import org.openecomp.sdc.common.api.Constants;
 import org.openecomp.sdc.common.api.HealthCheckInfo;
 import org.openecomp.sdc.common.api.HealthCheckWrapper;
 import org.openecomp.sdc.common.config.EcompErrorEnum;
 import org.openecomp.sdc.common.http.client.api.HttpRequest;
 import org.openecomp.sdc.common.http.client.api.HttpResponse;
+import org.openecomp.sdc.common.http.config.ClientCertificate;
 import org.openecomp.sdc.common.http.config.HttpClientConfig;
 import org.openecomp.sdc.common.http.config.Timeouts;
 import org.openecomp.sdc.common.impl.ExternalConfiguration;
@@ -116,7 +123,9 @@ public class HealthCheckScheduledTask implements Runnable {
         if (healthCheckUrl != null) {
             ObjectMapper mapper = new ObjectMapper();
             try {
-                HttpResponse<String> response = HttpRequest.get(healthCheckUrl, new HttpClientConfig(new Timeouts(connectTimeoutMs, readTimeoutMs)));
+                HttpClientConfig clientConfig = new HttpClientConfig(new Timeouts(connectTimeoutMs, readTimeoutMs), getHttpClientCertificate());
+                
+                HttpResponse<String> response = HttpRequest.get(healthCheckUrl, clientConfig);
                 int beStatus = response.getStatusCode();
                 if (beStatus == HttpStatus.SC_OK || beStatus == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
                     String beJsonResponse = response.getResponse();
@@ -135,6 +144,15 @@ public class HealthCheckScheduledTask implements Runnable {
         String compName = requestedByBE ? Constants.HC_COMPONENT_FE : baseComponent;
         return Collections.singletonList(new HealthCheckInfo(compName, HealthCheckInfo.HealthCheckStatus.DOWN, null, description.toString()));
     }
+    
+    private ClientCertificate getHttpClientCertificate() {
+        ClientCertificate clientCertificate = new ClientCertificate();
+        clientCertificate.setKeyStore(JettySSLUtils.getSSLConfig().getKeystorePath());
+        clientCertificate.setKeyStorePassword(JettySSLUtils.getSSLConfig().getKeystorePass(), false);
+        clientCertificate.setTrustStore(JettySSLUtils.getSSLConfig().getTruststorePath());
+        clientCertificate.setTrustStorePassword(JettySSLUtils.getSSLConfig().getTruststorePass());
+        return clientCertificate;
+    }
 
     private String getExternalComponentHcUri(String baseComponent) {
         String healthCheckUri = null;
@@ -197,7 +215,8 @@ public class HealthCheckScheduledTask implements Runnable {
         ErrorLogOptionalData errorLogOptionalData = ErrorLogOptionalData.newBuilder().targetEntity(LOG_TARGET_ENTITY_BE)
             .targetServiceName(LOG_SERVICE_NAME).build();
         try {
-            HttpResponse<String> response = HttpRequest.get(redirectedUrl, new HttpClientConfig(new Timeouts(connectTimeoutMs, readTimeoutMs)));
+            HttpClientConfig clientConfig = new HttpClientConfig(new Timeouts(connectTimeoutMs, readTimeoutMs), getHttpClientCertificate());
+            HttpResponse<String> response = HttpRequest.get(redirectedUrl, clientConfig);
             log.debug("HC call to BE - status code is {}", response.getStatusCode());
             String beJsonResponse = response.getResponse();
             feAggHealthCheck = getFeHealthCheckInfos(gson, beJsonResponse);
index 891bc4a..0923716 100644 (file)
 package org.openecomp.sdc.fe.servlets;
 
 import javax.servlet.ServletException;
+
 import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.proxy.ProxyServlet;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.onap.config.api.JettySSLUtils;
 import org.openecomp.sdc.common.api.Constants;
 import org.openecomp.sdc.fe.config.Configuration;
 import org.openecomp.sdc.fe.config.ConfigurationManager;
@@ -52,8 +54,17 @@ public abstract class SSLProxyServlet extends ProxyServlet {
     }
 
     private HttpClient getSecureHttpClient() throws ServletException {
+        final JettySSLUtils.JettySslConfig sslConfig = JettySSLUtils.getSSLConfig();
+        SslContextFactory sslContextFactory = new SslContextFactory.Client();
+        sslContextFactory.setKeyStorePath(sslConfig.getKeystorePath());
+        sslContextFactory.setKeyStorePassword(sslConfig.getKeystorePass());
+        sslContextFactory.setKeyManagerPassword(sslConfig.getKeystorePass());
+        sslContextFactory.setTrustStorePath(sslConfig.getTruststorePath());
+        sslContextFactory.setTrustStorePassword(sslConfig.getTruststorePass());
+        sslContextFactory.setKeyStorePath(sslConfig.getKeystorePath());
+        
         // Instantiate HttpClient with the SslContextFactory
-        final var httpClient = new HttpClient(new SslContextFactory.Client(true));
+        final var httpClient = new HttpClient(sslContextFactory);
         // Configure HttpClient, for example:
         httpClient.setFollowRedirects(false);
         // Start HttpClient
index 966bf85..8f3e460 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.openecomp.sdc.common.http.client.api;
 
+import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -70,9 +71,10 @@ public class HttpConnectionMngFactory {
         SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
         SSLConnectionSocketFactory sslsf = null;
         try {
-            sslContextBuilder.loadTrustMaterial(new TrustSelfSignedStrategy());
             if (clientCertificate != null) {
                 setClientSsl(clientCertificate, sslContextBuilder);
+            } else {
+                sslContextBuilder.loadTrustMaterial(new TrustSelfSignedStrategy());
             }
             sslsf = new SSLConnectionSocketFactory(sslContextBuilder.build(), NoopHostnameVerifier.INSTANCE);
         } catch (GeneralSecurityException e) {
@@ -93,6 +95,11 @@ public class HttpConnectionMngFactory {
             char[] keyStorePassword = clientCertificate.getKeyStorePassword().toCharArray();
             KeyStore clientKeyStore = createClientKeyStore(clientCertificate.getKeyStore(), keyStorePassword);
             sslContextBuilder.loadKeyMaterial(clientKeyStore, keyStorePassword);
+            if (StringUtils.isEmpty(clientCertificate.getTrustStore())) {
+                sslContextBuilder.loadTrustMaterial(new TrustSelfSignedStrategy());
+            } else {
+                sslContextBuilder.loadTrustMaterial(new File(clientCertificate.getTrustStore()), clientCertificate.getTrustStorePassword().toCharArray());
+            }
             logger.debug("#setClientSsl - Set Client Certificate authentication");
         } catch (IOException | GeneralSecurityException e) {
             logger.debug("#setClientSsl - Set Client Certificate authentication failed with exception, diasable client SSL authentication ", e);
@@ -107,6 +114,7 @@ public class HttpConnectionMngFactory {
         }
         return keyStore;
     }
+    
 
     private String getKeyStoreType(String keyStore) {
         if (!StringUtils.isEmpty(keyStore)) {
index 93fc3b9..2946217 100644 (file)
@@ -21,24 +21,33 @@ package org.openecomp.sdc.common.http.config;
 
 import fj.data.Either;
 import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
 import org.apache.commons.lang3.StringUtils;
 import org.onap.sdc.security.SecurityUtil;
 
 @EqualsAndHashCode
+@Getter
+@Setter
 public class ClientCertificate {
 
     private String keyStore;
     private String keyStorePassword;
-
+    private String trustStore;
+    private String trustStorePassword;
+    
     public ClientCertificate() {
     }
 
     public ClientCertificate(ClientCertificate clientCertificate) {
         setKeyStore(clientCertificate.getKeyStore());
         setKeyStorePassword(clientCertificate.getKeyStorePassword(), false);
+        setTrustStore(clientCertificate.getTrustStore());
+        setTrustStorePassword(clientCertificate.getTrustStorePassword());
     }
 
-    private void setKeyStorePassword(String keyStorePassword, boolean isEncoded) {
+    public void setKeyStorePassword(String keyStorePassword, boolean isEncoded) {
         validate(keyStorePassword);
         if (isEncoded) {
             Either<String, String> passkey = SecurityUtil.decrypt(keyStorePassword);
@@ -52,32 +61,15 @@ public class ClientCertificate {
         }
     }
 
-    public String getKeyStore() {
-        return keyStore;
-    }
-
     public void setKeyStore(String keyStore) {
         validate(keyStore);
         this.keyStore = keyStore;
     }
 
-    public String getKeyStorePassword() {
-        return keyStorePassword;
-    }
-
     public void setKeyStorePassword(String keyStorePassword) {
         setKeyStorePassword(keyStorePassword, true);
     }
 
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("ClientCertificate [keyStore=");
-        builder.append(keyStore);
-        builder.append("]");
-        return builder.toString();
-    }
-
     private void validate(String str) {
         if (StringUtils.isEmpty(str)) {
             throw new IllegalArgumentException("ClientCertificate keystore and/or kestorePassword cannot be empty");