2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018 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 io.joshworks.restclient.http.HttpResponse;
24 import io.joshworks.restclient.http.JsonNode;
25 import io.joshworks.restclient.http.RestClient;
26 import io.joshworks.restclient.http.mapper.ObjectMapper;
27 import org.apache.http.impl.client.CloseableHttpClient;
28 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
29 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
30 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
31 import org.eclipse.jetty.util.security.Password;
32 import org.apache.http.impl.client.HttpClients;
33 import org.apache.http.conn.ssl.SSLContexts;
34 import io.vavr.CheckedFunction1;
35 import lombok.SneakyThrows;
38 import java.security.UnrecoverableKeyException;
39 import java.security.NoSuchAlgorithmException;
40 import java.security.KeyManagementException;
41 import java.security.cert.CertificateException;
42 import javax.net.ssl.SSLHandshakeException;
43 import java.security.KeyStoreException;
44 import java.text.SimpleDateFormat;
45 import javax.net.ssl.SSLContext;
46 import java.io.FileInputStream;
47 import java.security.KeyStore;
48 import java.text.DateFormat;
49 import java.io.InputStream;
50 import java.io.IOException;
51 import java.util.Date;
54 import org.onap.portalsdk.core.util.SystemProperties;
55 import org.onap.vid.properties.VidProperties;
57 public class SyncRestClient implements SyncRestClientInterface {
59 private static final String CANNOT_INITIALIZE_CUSTOM_HTTP_CLIENT = "Cannot initialize custom http client from current configuration. Using default one.";
60 private static final String TRY_TO_CALL_OVER_HTTP = "SSL Handshake problem occured. Will try to retry over Http.";
61 private static final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(SyncRestClient.class);
62 private static final DateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss:SSSS");
63 private static final String[] SUPPORTED_SSL_VERSIONS = {"TLSv1", "TLSv1.2"};
64 private static final String HTTPS_SCHEMA = "https://";
65 private static final String HTTP_SCHEMA = "http://";
67 private RestClient restClient;
69 public SyncRestClient() {
70 restClient = RestClient.newClient().objectMapper(defaultObjectMapper()).httpClient(defaultHttpClient()).build();
73 public SyncRestClient(ObjectMapper objectMapper) {
74 restClient = RestClient.newClient().objectMapper(objectMapper).httpClient(defaultHttpClient()).build();
77 public SyncRestClient(CloseableHttpClient httpClient) {
78 restClient = RestClient.newClient().objectMapper(defaultObjectMapper()).httpClient(httpClient).build();
81 public SyncRestClient(CloseableHttpClient httpClient, ObjectMapper objectMapper) {
82 restClient = RestClient.newClient().objectMapper(objectMapper).httpClient(httpClient).build();
86 public HttpResponse<JsonNode> post(String url, Map<String, String> headers, Object body) {
87 return callWithRetryOverHttp(url, url2 -> restClient.post(url2).headers(headers).body(body).asJson());
91 public <T> HttpResponse<T> post(String url, Map<String, String> headers, Object body, Class<T> responseClass) {
92 return callWithRetryOverHttp(url,
93 url2 -> restClient.post(url2).headers(headers).body(body).asObject(responseClass));
97 public HttpResponse<JsonNode> get(String url, Map<String, String> headers, Map<String, String> routeParams) {
98 return callWithRetryOverHttp(url, url2 -> {
99 val getRequest = restClient.get(url2).headers(headers);
100 routeParams.forEach(getRequest::routeParam);
101 return getRequest.asJson();
106 public <T> HttpResponse<T> get(String url, Map<String, String> headers, Map<String, String> routeParams,
107 Class<T> responseClass) {
108 return callWithRetryOverHttp(url, url2 -> {
109 val getRequest = restClient.get(url2).headers(headers);
110 routeParams.forEach(getRequest::routeParam);
111 return getRequest.asObject(responseClass);
116 public HttpResponse<InputStream> getStream(String url, Map<String, String> headers,
117 Map<String, String> routeParams) {
118 return callWithRetryOverHttp(url, url2 -> {
119 val getRequest = restClient.get(url2).headers(headers);
120 routeParams.forEach(getRequest::routeParam);
121 return getRequest.asBinary();
126 public HttpResponse<JsonNode> put(String url, Map<String, String> headers, Object body) {
127 return callWithRetryOverHttp(url, url2 -> restClient.put(url2).headers(headers).body(body).asJson());
131 public <T> HttpResponse<T> put(String url, Map<String, String> headers, Object body, Class<T> responseClass) {
132 return callWithRetryOverHttp(url,
133 url2 -> restClient.put(url2).headers(headers).body(body).asObject(responseClass));
137 public <T> HttpResponse<T> delete(String url, Map<String, String> headers, Class<T> responseClass) {
138 return callWithRetryOverHttp(url, url2 -> restClient.delete(url2).headers(headers).asObject(responseClass));
142 public HttpResponse<JsonNode> delete(String url, Map<String, String> headers) {
143 return callWithRetryOverHttp(url, url2 -> restClient.delete(url2).headers(headers).asJson());
147 public void destroy() {
148 restClient.shutdown();
152 private <T> HttpResponse<T> callWithRetryOverHttp(String url,
153 CheckedFunction1<String, HttpResponse<T>> httpRequest) {
155 return httpRequest.apply(url);
156 } catch (Exception e) {
157 if (e.getCause() instanceof SSLHandshakeException) {
158 logger.warn(EELFLoggerDelegate.debugLogger,
159 DATE_FORMAT.format(new Date()) + TRY_TO_CALL_OVER_HTTP, e);
160 return httpRequest.apply(url.replaceFirst(HTTPS_SCHEMA, HTTP_SCHEMA));
166 private ObjectMapper defaultObjectMapper() {
167 val objectMapper = new org.codehaus.jackson.map.ObjectMapper();
169 return new ObjectMapper() {
172 public <T> T readValue(String value, Class<T> aClass) {
173 return objectMapper.readValue(value, aClass);
178 public String writeValue(Object value) {
179 return objectMapper.writeValueAsString(value);
184 private CloseableHttpClient defaultHttpClient() {
186 val trustStorePath = SystemProperties.getProperty(VidProperties.VID_TRUSTSTORE_FILENAME);
187 val trustStorePass = SystemProperties.getProperty(VidProperties.VID_TRUSTSTORE_PASSWD_X);
188 val decryptedTrustStorePass = Password.deobfuscate(trustStorePass);
190 val trustStore = loadTruststore(trustStorePath, decryptedTrustStorePass);
191 val sslContext = trustOwnCACerts(decryptedTrustStorePass, trustStore);
192 val sslSf = allowTLSProtocols(sslContext);
194 return HttpClients.custom().setSSLSocketFactory(sslSf).build();
195 } catch (IOException | CertificateException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
196 logger.warn(EELFLoggerDelegate.debugLogger,
197 DATE_FORMAT.format(new Date()) + CANNOT_INITIALIZE_CUSTOM_HTTP_CLIENT, e);
198 return HttpClients.createDefault();
202 private SSLConnectionSocketFactory allowTLSProtocols(SSLContext sslcontext) {
203 return new SSLConnectionSocketFactory(
205 SUPPORTED_SSL_VERSIONS,
207 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
210 private SSLContext trustOwnCACerts(String trustStorePass, KeyStore trustStore)
211 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
212 return SSLContexts.custom()
214 .loadKeyMaterial(trustStore, trustStorePass.toCharArray())
215 .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
219 private KeyStore loadTruststore(String trustStorePath, String trustStorePass)
220 throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
221 val trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
222 try (FileInputStream instream = new FileInputStream(new File(trustStorePath))) {
223 trustStore.load(instream, trustStorePass.toCharArray());