2 * Copyright © 2018 European Support Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.onap.sdc.workflow.api;
19 import static org.apache.commons.codec.digest.DigestUtils.md5Hex;
21 import com.fasterxml.jackson.databind.ObjectMapper;
24 import java.io.FileInputStream;
25 import java.io.IOException;
26 import java.nio.charset.Charset;
27 import java.security.GeneralSecurityException;
28 import java.security.KeyStore;
29 import java.security.cert.CertificateException;
30 import java.security.cert.X509Certificate;
31 import java.util.ArrayList;
32 import java.util.HashMap;
34 import java.util.Optional;
36 import org.apache.http.conn.ssl.TrustStrategy;
37 import org.openecomp.sdc.logging.api.Logger;
38 import org.openecomp.sdc.logging.api.LoggerFactory;
40 import java.util.Base64;
42 import org.apache.commons.io.IOUtils;
43 import org.apache.http.HttpHost;
44 import org.apache.http.conn.ssl.NoopHostnameVerifier;
45 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
46 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
47 import org.apache.http.impl.client.CloseableHttpClient;
48 import org.apache.http.impl.client.HttpClients;
49 import org.apache.http.ssl.SSLContexts;
50 import org.onap.sdc.workflow.api.types.dto.ArtifactDeliveriesRequestDto;
51 import org.onap.sdc.workflow.persistence.types.ArtifactEntity;
53 import org.springframework.beans.factory.annotation.Autowired;
54 import org.springframework.beans.factory.annotation.Value;
55 import org.springframework.boot.web.client.RestTemplateBuilder;
56 import org.springframework.http.*;
57 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
58 import org.springframework.stereotype.Component;
59 import org.springframework.web.client.RestTemplate;
61 import javax.net.ssl.SSLContext;
64 @Component("ArtifactAssociationHandler")
65 public class ArtifactAssociationService {
67 private static final String WORKFLOW_ARTIFACT_TYPE = "WORKFLOW";
68 private static final String WORKFLOW_ARTIFACT_DESCRIPTION = "Workflow Artifact Description";
69 private static final String USER_ID_HEADER = "USER_ID";
70 private static final String MD5_HEADER = "Content-MD5";
71 private static final String X_ECOMP_INSTANCE_ID_HEADER = "X-ECOMP-InstanceID";
72 private static final String INIT_ERROR_MSG =
73 "Failed while attaching workflow artifact to Operation in SDC. Parameters were not initialized: %s";
74 private static final String INIT_CLIENT_MSG =
75 "Failed while creating the HTTP client to SDC. Following exception: %s";
76 private static final Logger LOGGER = LoggerFactory.getLogger(ArtifactAssociationService.class);
77 @Value("${sdc.be.endpoint}")
78 private String sdcBeEndpoint;
79 @Value("${sdc.be.protocol}")
80 private String sdcBeProtocol;
81 @Value("${sdc.be.external.user}")
82 private String sdcUser;
83 @Value("${sdc.be.external.password}")
84 private String sdcPassword;
86 private RestTemplate restClient;
88 private KeyStore getKeyStore(String file, String password, String keyStoreType) throws IOException, GeneralSecurityException {
89 KeyStore keyStore = KeyStore.getInstance(keyStoreType);
90 File keyFile = new File(file);
91 try (FileInputStream inStr = new FileInputStream(keyFile)) {
92 keyStore.load(inStr, password.toCharArray());
100 public ArtifactAssociationService(RestTemplateBuilder builder,
101 @Value("${server.ssl.trust-store}")
102 String truststorePath,
103 @Value("${server.ssl.trust-store-password}")
104 String truststorePassword,
105 @Value("${server.ssl.trust-store-type}")
106 String truststoreType,
107 @Value("${server.ssl.key-store}")
109 @Value("${server.ssl.key-password}")
110 String keystorePassword,
111 @Value("${server.ssl.key-store-type}")
113 @Value("${sdc.be.protocol}")
115 if (protocol != null &&
116 !protocol.equalsIgnoreCase(HttpHost.DEFAULT_SCHEME_NAME)) {
118 KeyStore trustStore = getKeyStore(truststorePath, truststorePassword, truststoreType);
119 KeyStore keyStore = getKeyStore(keystorePath, keystorePassword, keystoreType);
121 SSLContext sslcontext = SSLContexts.custom()
122 .loadKeyMaterial(keyStore, keystorePassword.toCharArray())
123 .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
125 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
127 new NoopHostnameVerifier()
129 CloseableHttpClient httpClient =
131 .setSSLSocketFactory(sslsf)
132 .setSSLHostnameVerifier(new NoopHostnameVerifier())
134 HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
135 this.restClient = new RestTemplate(factory);
136 } catch (Exception e) {
137 LOGGER.error(String.format(INIT_CLIENT_MSG, e.getMessage()), e);
140 this.restClient = builder.build();
144 void setRestClient(RestTemplate restClient) {
145 this.restClient = restClient;
148 void setSdcBeEndpoint(String value) {
149 this.sdcBeEndpoint = value;
152 ResponseEntity<String> execute(String userId, ArtifactDeliveriesRequestDto deliveriesRequestDto,
153 ArtifactEntity artifactEntity) {
155 Optional<String> initializationState = parametersInitializationState();
156 if (initializationState.isPresent()) {
157 LOGGER.error(String.format(INIT_ERROR_MSG, initializationState.get()));
158 return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(String.format(INIT_ERROR_MSG, initializationState.get()));
161 String formattedArtifact;
163 formattedArtifact = getFormattedWorkflowArtifact(artifactEntity);
164 } catch (IOException e) {
165 LOGGER.error("Failed while attaching workflow artifact to Operation in SDC", e);
166 return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(e.getMessage());
169 HttpEntity<String> request = new HttpEntity<>(formattedArtifact, createHeaders(userId, formattedArtifact));
171 return restClient.exchange(sdcBeProtocol + "://" + sdcBeEndpoint + "/" + deliveriesRequestDto.getEndpoint(),
172 HttpMethod.valueOf(deliveriesRequestDto.getMethod()), request, String.class);
175 Optional<String> parametersInitializationState() {
176 ArrayList<String> result = new ArrayList<>();
177 if (sdcBeEndpoint == null || sdcBeEndpoint.equals("")) {
178 result.add("SDC_ENDPOINT");
180 if (sdcBeProtocol == null || sdcBeProtocol.equals("")) {
181 result.add("SDC_PROTOCOL");
183 if (sdcUser == null || sdcUser.equals("")) {
184 result.add("SDC_USER");
186 if (sdcPassword == null || sdcPassword.equals("")) {
187 result.add("SDC_PASSWORD");
190 if (result.isEmpty() || this.restClient == null) {
191 return Optional.empty();
193 return Optional.of(result.toString());
198 private String getFormattedWorkflowArtifact(ArtifactEntity artifactEntity) throws IOException {
200 byte[] encodeBase64 = Base64.getEncoder().encode(IOUtils.toByteArray(artifactEntity.getArtifactData()));
201 String encodedPayloadData = new String(encodeBase64);
203 Map<String, String> artifactInfo = new HashMap<>();
204 artifactInfo.put("artifactName", artifactEntity.getFileName());
205 artifactInfo.put("payloadData", encodedPayloadData);
206 artifactInfo.put("artifactType", WORKFLOW_ARTIFACT_TYPE);
207 artifactInfo.put("description", WORKFLOW_ARTIFACT_DESCRIPTION);
209 ObjectMapper mapper = new ObjectMapper();
210 return mapper.writeValueAsString(artifactInfo);
213 private HttpHeaders createHeaders(String userId, String formattedArtifact) {
214 HttpHeaders headers = new HttpHeaders();
215 headers.add(USER_ID_HEADER, userId);
216 headers.add(HttpHeaders.AUTHORIZATION, createAuthorizationsHeaderValue(sdcUser, sdcPassword));
217 headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
218 headers.add(MD5_HEADER, calculateMD5Base64EncodedByString(formattedArtifact));
219 headers.add(X_ECOMP_INSTANCE_ID_HEADER, "InstanceId");
223 private String calculateMD5Base64EncodedByString(String data) {
224 String calculatedMd5 = md5Hex(data);
225 // encode base-64 result
226 byte[] encodeBase64 = Base64.getEncoder().encode(calculatedMd5.getBytes());
227 return new String(encodeBase64);
230 private String createAuthorizationsHeaderValue(String username, String password) {
231 String auth = username + ":" + password;
232 byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(Charset.forName("US-ASCII")));
233 return "Basic " + new String(encodedAuth);