2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018 - 2019 Nokia. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.vid.client;
23 import static org.apache.commons.lang3.StringUtils.isEmpty;
24 import static org.onap.vid.client.UnirestPatchKt.patched;
26 import com.att.eelf.configuration.EELFLogger;
27 import io.joshworks.restclient.http.HttpResponse;
28 import io.joshworks.restclient.http.JsonNode;
29 import io.joshworks.restclient.http.RestClient;
30 import io.joshworks.restclient.http.exceptions.RestClientException;
31 import io.joshworks.restclient.http.mapper.ObjectMapper;
32 import io.joshworks.restclient.request.GetRequest;
34 import java.io.FileInputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.security.KeyManagementException;
38 import java.security.KeyStore;
39 import java.security.KeyStoreException;
40 import java.security.NoSuchAlgorithmException;
41 import java.security.UnrecoverableKeyException;
42 import java.security.cert.CertificateException;
44 import javax.net.ssl.SSLContext;
45 import javax.net.ssl.SSLException;
46 import org.apache.commons.lang3.ObjectUtils;
47 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
48 import org.apache.http.conn.ssl.SSLContexts;
49 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
50 import org.apache.http.impl.client.CloseableHttpClient;
51 import org.apache.http.impl.client.HttpClients;
52 import org.eclipse.jetty.util.security.Password;
53 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
54 import org.onap.portalsdk.core.util.SystemProperties;
55 import org.onap.vid.properties.VidProperties;
56 import org.onap.vid.utils.Logging;
58 public class SyncRestClient implements SyncRestClientInterface {
59 private static final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(SyncRestClient.class);
60 private static final String[] SUPPORTED_SSL_VERSIONS = {"TLSv1", "TLSv1.2"};
61 private static final String HTTPS_SCHEMA = "https://";
62 private static final String HTTP_SCHEMA = "http://";
63 private final Logging loggingService;
64 private final EELFLogger outgoingRequestsLogger;
66 private RestClient restClient;
68 public SyncRestClient(Logging loggingService) {
69 this(null, null, loggingService);
72 public SyncRestClient(ObjectMapper objectMapper, Logging loggingService) {
73 this(null, objectMapper, loggingService);
76 public SyncRestClient(CloseableHttpClient httpClient, Logging loggingService) {
77 this(httpClient, null, loggingService);
80 public SyncRestClient(CloseableHttpClient httpClient, ObjectMapper objectMapper, Logging loggingService) {
81 restClient = RestClient
83 .objectMapper(ObjectUtils.defaultIfNull(objectMapper, defaultObjectMapper()))
84 .httpClient(ObjectUtils.defaultIfNull(httpClient , defaultHttpClient()))
86 this.loggingService = loggingService;
87 this.outgoingRequestsLogger = Logging.getRequestsLogger("syncRestClient");
91 public HttpResponse<JsonNode> post(String url, Map<String, String> headers, Object body) {
92 return callWithRetryOverHttp(url, url2 -> restClient.post(url2).headers(headers).body(body).asJson());
96 public <T> HttpResponse<T> post(String url, Map<String, String> headers, Object body, Class<T> responseClass) {
97 return callWithRetryOverHttp(url,
98 url2 -> restClient.post(url2).headers(headers).body(body).asObject(responseClass));
102 public HttpResponse<JsonNode> get(String url, Map<String, String> headers, Map<String, String> routeParams) {
103 return callWithRetryOverHttp(url, url2 -> {
104 GetRequest getRequest = restClient.get(url2).headers(headers);
105 routeParams.forEach(getRequest::routeParam);
106 return getRequest.asJson();
111 public <T> HttpResponse<T> get(String url, Map<String, String> headers, Map<String, String> routeParams,
112 Class<T> responseClass) {
113 return callWithRetryOverHttp(url, url2 -> {
114 GetRequest getRequest = restClient.get(url2).headers(headers);
115 routeParams.forEach(getRequest::routeParam);
116 return getRequest.asObject(responseClass);
121 public HttpResponse<InputStream> getStream(String url, Map<String, String> headers,
122 Map<String, String> routeParams) {
123 return callWithRetryOverHttp(url, url2 -> {
124 GetRequest getRequest = restClient.get(url2).headers(headers);
125 routeParams.forEach(getRequest::routeParam);
126 return getRequest.asBinary();
131 public HttpResponse<JsonNode> put(String url, Map<String, String> headers, Object body) {
132 return callWithRetryOverHttp(url, url2 -> restClient.put(url2).headers(headers).body(body).asJson());
136 public <T> HttpResponse<T> put(String url, Map<String, String> headers, Object body, Class<T> responseClass) {
137 return callWithRetryOverHttp(url,
138 url2 -> restClient.put(url2).headers(headers).body(body).asObject(responseClass));
142 public <T> HttpResponse<T> delete(String url, Map<String, String> headers, Object body, Class<T> responseClass) {
143 return callWithRetryOverHttp(url, url2 -> restClient.delete(url2).headers(headers).body(body).asObject(responseClass));
147 public <T> HttpResponse<T> delete(String url, Map<String, String> headers, Class<T> responseClass) {
148 return callWithRetryOverHttp(url, url2 -> restClient.delete(url2).headers(headers).asObject(responseClass));
152 public HttpResponse<JsonNode> delete(String url, Map<String, String> headers) {
153 return callWithRetryOverHttp(url, url2 -> restClient.delete(url2).headers(headers).asJson());
157 public void destroy() {
158 restClient.shutdown();
161 private <T> HttpResponse<T> callWithRetryOverHttp(String url, HttpRequest<T> httpRequest) {
163 return callWithRetryOverHttpThrows(url, httpRequest);
164 } catch (IOException e) {
165 throw new SyncRestClientException("IOException while calling rest service", e);
169 private <T> HttpResponse<T> callWithRetryOverHttpThrows(String url, HttpRequest<T> httpRequest) throws IOException {
171 return patched(httpRequest.apply(url));
172 } catch (RestClientException e) {
173 if (causedBySslHandshakeError(e)) {
174 logger.warn(EELFLoggerDelegate.debugLogger, "SSL Handshake problem occured. Will try to retry over Http.", e);
175 return patched(httpRequest.apply(url.replaceFirst(HTTPS_SCHEMA, HTTP_SCHEMA)));
181 private boolean causedBySslHandshakeError(RestClientException exception) {
182 return exception.getCause() instanceof SSLException;
185 private ObjectMapper defaultObjectMapper() {
186 com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
188 return new ObjectMapper() {
190 public <T> T readValue(String value, Class<T> aClass) {
192 return isEmpty(value) ? null : objectMapper.readValue(value, aClass);
193 } catch (IOException e) {
194 throw new SyncRestClientException("IOException while reading value", e);
199 public String writeValue(Object value) {
201 return objectMapper.writeValueAsString(value);
202 } catch (IOException e) {
203 throw new SyncRestClientException("IOException while writing value", e);
209 private CloseableHttpClient defaultHttpClient() {
211 String trustStorePath = SystemProperties.getProperty(VidProperties.VID_TRUSTSTORE_FILENAME);
212 String trustStorePass = SystemProperties.getProperty(VidProperties.VID_TRUSTSTORE_PASSWD_X);
213 String decryptedTrustStorePass = Password.deobfuscate(trustStorePass);
215 KeyStore trustStore = loadTruststore(trustStorePath, decryptedTrustStorePass);
216 SSLContext sslContext = trustOwnCACerts(decryptedTrustStorePass, trustStore);
217 SSLConnectionSocketFactory sslSf = allowTLSProtocols(sslContext);
219 return HttpClients.custom().setSSLSocketFactory(sslSf).build();
220 } catch (IOException | CertificateException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
221 logger.warn(EELFLoggerDelegate.debugLogger, "Cannot initialize custom http client from current configuration. Using default one.", e);
222 return HttpClients.createDefault();
226 private SSLConnectionSocketFactory allowTLSProtocols(SSLContext sslcontext) {
227 return new SSLConnectionSocketFactory(
229 SUPPORTED_SSL_VERSIONS,
231 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
234 private SSLContext trustOwnCACerts(String trustStorePass, KeyStore trustStore)
235 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
236 return SSLContexts.custom()
238 .loadKeyMaterial(trustStore, trustStorePass.toCharArray())
239 .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
243 private KeyStore loadTruststore(String trustStorePath, String trustStorePass)
244 throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
245 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
246 try (FileInputStream instream = new FileInputStream(new File(trustStorePath))) {
247 trustStore.load(instream, trustStorePass.toCharArray());
253 private interface HttpRequest<T> {
254 HttpResponse<T> apply(String url) throws IOException;