From 820f4ec65a28ed822d4205b05ac6fbbd910a46cc Mon Sep 17 00:00:00 2001 From: ilanap Date: Mon, 18 Nov 2019 13:38:23 +0200 Subject: Changes for backend to support SSL Changes to support starting in https mode and changes to support making a secured call to the SDC backend Issue-ID: SDC-2405 Signed-off-by: ilanap Change-Id: I0588484fdcb0903934814906672f4fc9a76eca2c Signed-off-by: ilanap --- workflow-designer-be/docker/Dockerfile | 17 ++++ workflow-designer-be/docker/org.onap.sdc.p12 | Bin 0 -> 4459 bytes workflow-designer-be/docker/org.onap.sdc.trust.jks | Bin 0 -> 1413 bytes workflow-designer-be/docker/startup.sh | 28 ++++++ workflow-designer-be/pom.xml | 50 ++++++++-- .../workflow/api/ArtifactAssociationService.java | 108 +++++++++++++++++---- .../src/main/resources/application.properties | 7 ++ 7 files changed, 182 insertions(+), 28 deletions(-) create mode 100644 workflow-designer-be/docker/Dockerfile create mode 100644 workflow-designer-be/docker/org.onap.sdc.p12 create mode 100644 workflow-designer-be/docker/org.onap.sdc.trust.jks create mode 100644 workflow-designer-be/docker/startup.sh diff --git a/workflow-designer-be/docker/Dockerfile b/workflow-designer-be/docker/Dockerfile new file mode 100644 index 00000000..ea20fa5c --- /dev/null +++ b/workflow-designer-be/docker/Dockerfile @@ -0,0 +1,17 @@ +FROM openjdk:8-jdk-alpine + +EXPOSE 8080 + +USER root + +ARG ARTIFACT + +ADD ${ARTIFACT} /app.jar + +COPY org.onap.sdc.p12 /keystore +COPY org.onap.sdc.trust.jks /truststore + +COPY startup.sh . +RUN chmod 744 startup.sh + +ENTRYPOINT [ "./startup.sh" ] \ No newline at end of file diff --git a/workflow-designer-be/docker/org.onap.sdc.p12 b/workflow-designer-be/docker/org.onap.sdc.p12 new file mode 100644 index 00000000..d03ca1c9 Binary files /dev/null and b/workflow-designer-be/docker/org.onap.sdc.p12 differ diff --git a/workflow-designer-be/docker/org.onap.sdc.trust.jks b/workflow-designer-be/docker/org.onap.sdc.trust.jks new file mode 100644 index 00000000..d07ce1a6 Binary files /dev/null and b/workflow-designer-be/docker/org.onap.sdc.trust.jks differ diff --git a/workflow-designer-be/docker/startup.sh b/workflow-designer-be/docker/startup.sh new file mode 100644 index 00000000..bc1d6463 --- /dev/null +++ b/workflow-designer-be/docker/startup.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +HTTPS_ENABLED=${SERVER_SSL_ENABLED:-"false"} +if [ "$HTTPS_ENABLED" = "true" ] +then + KEYSTORE=${SERVER_SSL_KEYSTORE_PATH} + if [ -f "$KEYSTORE" ]; then + echo "$KEYSTORE exist" + else + echo "Copying default keystore" + KEYSTORE_DIR=${KEYSTORE%/*} + mkdir -p $KEYSTORE_DIR + cp /keystore $KEYSTORE_DIR + chmod 755 $KEYSTORE + fi + + TRUSTSTORE=${SERVER_SSL_TRUSTSTORE_PATH} + if [ -f "$TRUSTSTORE" ]; then + echo "$TRUSTSTORE exist" + else + echo "Copying default truststore" + TRUSTSTORE_DIR=${TRUSTSTORE%/*} + mkdir -p $TRUSTSTORE_DIR + cp /truststore $TRUSTSTORE_DIR + chmod 755 $TRUSTSTORE + fi +fi +java ${JAVA_OPTIONS} -jar /app.jar ${SPRING_BOOT_OPTIONS} \ No newline at end of file diff --git a/workflow-designer-be/pom.xml b/workflow-designer-be/pom.xml index 9bf4e75d..601f10ee 100644 --- a/workflow-designer-be/pom.xml +++ b/workflow-designer-be/pom.xml @@ -120,6 +120,10 @@ + + org.apache.httpcomponents + httpclient + org.mapstruct mapstruct-jdk8 @@ -174,6 +178,28 @@ + + maven-resources-plugin + 2.6 + + + copy-resources-docker + install + + copy-resources + + + ${basedir}/docker + + + ${project.build.directory} + ${project.build.finalName}.jar + + + + + + io.fabric8 docker-maven-plugin @@ -185,20 +211,26 @@ ${project.version} - openjdk:8-jdk-alpine - root - - / - ${project.basedir}/src/main/resources/assembly.xml - - - java ${JAVA_OPTIONS} -jar /${project.build.finalName}.jar - + ${project.basedir}/docker + + ${project.build.finalName}.jar + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + onap-staging + ${nexus.proxy} + ${staging.profile.id} + + diff --git a/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/ArtifactAssociationService.java b/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/ArtifactAssociationService.java index 621d1803..2b24577a 100644 --- a/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/ArtifactAssociationService.java +++ b/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/ArtifactAssociationService.java @@ -19,30 +19,47 @@ package org.onap.sdc.workflow.api; import static org.apache.commons.codec.digest.DigestUtils.md5Hex; import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.nio.charset.Charset; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.Optional; + +import org.apache.http.conn.ssl.TrustStrategy; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; + +import java.util.Base64; + import org.apache.commons.io.IOUtils; +import org.apache.http.HttpHost; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContexts; import org.onap.sdc.workflow.api.types.dto.ArtifactDeliveriesRequestDto; import org.onap.sdc.workflow.persistence.types.ArtifactEntity; -import org.openecomp.sdc.logging.api.Logger; -import org.openecomp.sdc.logging.api.LoggerFactory; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; +import javax.net.ssl.SSLContext; + @Component("ArtifactAssociationHandler") public class ArtifactAssociationService { @@ -54,6 +71,8 @@ public class ArtifactAssociationService { private static final String X_ECOMP_INSTANCE_ID_HEADER = "X-ECOMP-InstanceID"; private static final String INIT_ERROR_MSG = "Failed while attaching workflow artifact to Operation in SDC. Parameters were not initialized: %s"; + private static final String INIT_CLIENT_MSG = + "Failed while creating the HTTP client to SDC. Following exception: %s"; private static final Logger LOGGER = LoggerFactory.getLogger(ArtifactAssociationService.class); @Value("${sdc.be.endpoint}") private String sdcBeEndpoint; @@ -66,12 +85,63 @@ public class ArtifactAssociationService { private RestTemplate restClient; + private KeyStore getKeyStore(String file, String password, String keyStoreType) throws IOException, GeneralSecurityException { + KeyStore keyStore = KeyStore.getInstance(keyStoreType); + File keyFile = new File(file); + try (FileInputStream inStr = new FileInputStream(keyFile)) { + keyStore.load(inStr, password.toCharArray()); + } + return keyStore; + + } + + @Autowired - public ArtifactAssociationService(RestTemplateBuilder builder) { - this.restClient = builder.build(); + public ArtifactAssociationService(RestTemplateBuilder builder, + @Value("${server.ssl.trust-store}") + String truststorePath, + @Value("${server.ssl.trust-store-password}") + String truststorePassword, + @Value("${server.ssl.trust-store-type}") + String truststoreType, + @Value("${server.ssl.key-store}") + String keystorePath, + @Value("${server.ssl.key-password}") + String keystorePassword, + @Value("${server.ssl.key-store-type}") + String keystoreType, + @Value("${sdc.be.protocol}") + String protocol) { + if (protocol != null && + !protocol.equalsIgnoreCase(HttpHost.DEFAULT_SCHEME_NAME)) { + try { + KeyStore trustStore = getKeyStore(truststorePath, truststorePassword, truststoreType); + KeyStore keyStore = getKeyStore(keystorePath, keystorePassword, keystoreType); + + SSLContext sslcontext = SSLContexts.custom() + .loadKeyMaterial(keyStore, keystorePassword.toCharArray()) + .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) + .build(); + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + sslcontext, + new NoopHostnameVerifier() + ); + CloseableHttpClient httpClient = + HttpClients.custom() + .setSSLSocketFactory(sslsf) + .setSSLHostnameVerifier(new NoopHostnameVerifier()) + .build(); + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); + this.restClient = new RestTemplate(factory); + } catch (Exception e) { + LOGGER.error(String.format(INIT_CLIENT_MSG, e.getMessage()), e); + } + } else { + this.restClient = builder.build(); + } } - void setRestClient(RestTemplate restClient) { + void setRestClient(RestTemplate restClient) { this.restClient = restClient; } @@ -80,12 +150,12 @@ public class ArtifactAssociationService { } ResponseEntity execute(String userId, ArtifactDeliveriesRequestDto deliveriesRequestDto, - ArtifactEntity artifactEntity) { + ArtifactEntity artifactEntity) { Optional initializationState = parametersInitializationState(); - if(initializationState.isPresent()) { - LOGGER.error(String.format(INIT_ERROR_MSG,initializationState.get())); - return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(String.format(INIT_ERROR_MSG,initializationState.get())); + if (initializationState.isPresent()) { + LOGGER.error(String.format(INIT_ERROR_MSG, initializationState.get())); + return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(String.format(INIT_ERROR_MSG, initializationState.get())); } String formattedArtifact; @@ -96,7 +166,7 @@ public class ArtifactAssociationService { return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(e.getMessage()); } - HttpEntity request = new HttpEntity<>(formattedArtifact, createHeaders(userId,formattedArtifact)); + HttpEntity request = new HttpEntity<>(formattedArtifact, createHeaders(userId, formattedArtifact)); return restClient.exchange(sdcBeProtocol + "://" + sdcBeEndpoint + "/" + deliveriesRequestDto.getEndpoint(), HttpMethod.valueOf(deliveriesRequestDto.getMethod()), request, String.class); @@ -117,7 +187,7 @@ public class ArtifactAssociationService { result.add("SDC_PASSWORD"); } - if (result.isEmpty()) { + if (result.isEmpty() || this.restClient == null) { return Optional.empty(); } else { return Optional.of(result.toString()); @@ -143,7 +213,7 @@ public class ArtifactAssociationService { private HttpHeaders createHeaders(String userId, String formattedArtifact) { HttpHeaders headers = new HttpHeaders(); headers.add(USER_ID_HEADER, userId); - headers.add(HttpHeaders.AUTHORIZATION, createAuthorizationsHeaderValue(sdcUser,sdcPassword)); + headers.add(HttpHeaders.AUTHORIZATION, createAuthorizationsHeaderValue(sdcUser, sdcPassword)); headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); headers.add(MD5_HEADER, calculateMD5Base64EncodedByString(formattedArtifact)); headers.add(X_ECOMP_INSTANCE_ID_HEADER, "InstanceId"); diff --git a/workflow-designer-be/src/main/resources/application.properties b/workflow-designer-be/src/main/resources/application.properties index 44b048ac..5a4b7af7 100644 --- a/workflow-designer-be/src/main/resources/application.properties +++ b/workflow-designer-be/src/main/resources/application.properties @@ -19,8 +19,15 @@ http.port=${HTTP_PORT:8080} server.port=${SERVER_PORT:8443} server.ssl.enabled=${SERVER_SSL_ENABLED:true} server.ssl.key-password=${SERVER_SSL_KEY_PASSWORD:} +server.ssl.key-store-password=${SERVER_SSL_KEY_PASSWORD:} server.ssl.key-store=${SERVER_SSL_KEYSTORE_PATH:} server.ssl.key-store-type=${SERVER_SSL_KEYSTORE_TYPE:} +server.ssl.trust-store-password=${SERVER_SSL_TRUST_PASSWORD:} +server.ssl.trust-store=${SERVER_SSL_TRUSTSTORE_PATH:} +server.ssl.trust-store-type=${SERVER_SSL_TRUSTSTORE_TYPE:} +#server.ssl.protocol=${SERVER_SSL_PROTOCOL:TLS} +#server.ssl.enabled-protocols=${SERVER_SSL_ENABLED_PROTOCOL:TLSv1.2} + sdc.be.protocol=${SDC_PROTOCOL:} sdc.be.endpoint=${SDC_ENDPOINT:} -- cgit 1.2.3-korg