Fix for Penetration test _ Session and cookie management
[vid.git] / vid-app-common / src / main / java / org / onap / vid / client / SyncRestClient.java
index b7f2264..24a78af 100644 (file)
@@ -2,14 +2,15 @@
  * ============LICENSE_START=======================================================
  * VID
  * ================================================================================
- * Copyright (C) 2018 Nokia. All rights reserved.
+ * Copyright (C) 2018 - 2019 Nokia. All rights reserved.
+ * Modifications Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- *
+ * 
  *      http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
 package org.onap.vid.client;
 
+import static org.onap.vid.client.UnirestPatchKt.patched;
+import static org.onap.vid.utils.KotlinUtilsKt.JOSHWORKS_JACKSON_OBJECT_MAPPER;
+
+import com.att.eelf.configuration.EELFLogger;
 import io.joshworks.restclient.http.HttpResponse;
 import io.joshworks.restclient.http.JsonNode;
 import io.joshworks.restclient.http.RestClient;
 import io.joshworks.restclient.http.exceptions.RestClientException;
 import io.joshworks.restclient.http.mapper.ObjectMapper;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
-import org.eclipse.jetty.util.security.Password;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.conn.ssl.SSLContexts;
-import io.vavr.CheckedFunction1;
-import lombok.SneakyThrows;
-import lombok.val;
-
-import java.security.UnrecoverableKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.KeyManagementException;
-import java.security.cert.CertificateException;
-import javax.net.ssl.SSLException;
-import java.security.KeyStoreException;
-import java.text.SimpleDateFormat;
-import javax.net.ssl.SSLContext;
+import io.joshworks.restclient.request.GetRequest;
+import java.io.File;
 import java.io.FileInputStream;
-import java.security.KeyStore;
-import java.text.DateFormat;
-import java.io.InputStream;
 import java.io.IOException;
-import java.util.Date;
+import java.io.InputStream;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
 import java.util.Map;
-import java.io.File;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLContexts;
+import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.eclipse.jetty.util.security.Password;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.onap.portalsdk.core.util.SystemProperties;
+import org.onap.vid.logging.ApacheClientMetricRequestInterceptor;
+import org.onap.vid.logging.ApacheClientMetricResponseInterceptor;
 import org.onap.vid.properties.VidProperties;
+import org.onap.vid.utils.Logging;
+import org.springframework.http.HttpMethod;
 
 public class SyncRestClient implements SyncRestClientInterface {
-
-    private static final String CANNOT_INITIALIZE_CUSTOM_HTTP_CLIENT = "Cannot initialize custom http client from current configuration. Using default one.";
-    private static final String TRY_TO_CALL_OVER_HTTP = "SSL Handshake problem occured. Will try to retry over Http.";
     private static final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(SyncRestClient.class);
-    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss:SSSS");
     private static final String[] SUPPORTED_SSL_VERSIONS = {"TLSv1", "TLSv1.2"};
     private static final String HTTPS_SCHEMA = "https://";
     private static final String HTTP_SCHEMA = "http://";
+    private final Logging loggingService;
+    private final EELFLogger outgoingRequestsLogger;
 
     private RestClient restClient;
 
-    public SyncRestClient() {
-        restClient = RestClient.newClient().objectMapper(defaultObjectMapper()).httpClient(defaultHttpClient()).build();
+    public SyncRestClient(Logging loggingService) {
+        this(null, null, loggingService, false);
     }
 
-    public SyncRestClient(ObjectMapper objectMapper) {
-        restClient = RestClient.newClient().objectMapper(objectMapper).httpClient(defaultHttpClient()).build();
+    public SyncRestClient(Logging loggingService, boolean useLoggingInterceptor) {
+        this(null, null, loggingService, useLoggingInterceptor);
     }
 
-    public SyncRestClient(CloseableHttpClient httpClient) {
-        restClient = RestClient.newClient().objectMapper(defaultObjectMapper()).httpClient(httpClient).build();
+    public SyncRestClient(ObjectMapper objectMapper, Logging loggingService) {
+        this(null, objectMapper,  loggingService, true);
     }
 
-    public SyncRestClient(CloseableHttpClient httpClient, ObjectMapper objectMapper) {
-        restClient = RestClient.newClient().objectMapper(objectMapper).httpClient(httpClient).build();
+    public SyncRestClient(CloseableHttpClient httpClient, Logging loggingService) {
+        this(httpClient, null,  loggingService, false);
+    }
+
+    public SyncRestClient(CloseableHttpClient httpClient,
+        ObjectMapper objectMapper,
+        Logging loggingService,
+        boolean useLoggingInterceptor) {
+        restClient = RestClient
+            .newClient()
+            .objectMapper(ObjectUtils.defaultIfNull(objectMapper, defaultObjectMapper()))
+            .httpClient(ObjectUtils.defaultIfNull(httpClient , defaultHttpClient(useLoggingInterceptor)))
+            .build();
+        this.loggingService = loggingService;
+        this.outgoingRequestsLogger = Logging.getRequestsLogger("syncRestClient");
     }
 
     @Override
     public HttpResponse<JsonNode> post(String url, Map<String, String> headers, Object body) {
-        return callWithRetryOverHttp(url, url2 -> restClient.post(url2).headers(headers).body(body).asJson());
+        loggingService.logRequest(outgoingRequestsLogger, HttpMethod.POST, url, body);
+
+        HttpResponse<JsonNode> response = callWithRetryOverHttp(url,
+            url2 -> restClient.post(url2).headers(headers).body(body).asJson());
+
+        loggingService.logResponse(outgoingRequestsLogger, HttpMethod.POST, url, response);
+
+        return response;
     }
 
     @Override
     public <T> HttpResponse<T> post(String url, Map<String, String> headers, Object body, Class<T> responseClass) {
-        return callWithRetryOverHttp(url,
+        loggingService.logRequest(outgoingRequestsLogger, HttpMethod.POST, url, body);
+
+        HttpResponse<T> response = callWithRetryOverHttp(url,
             url2 -> restClient.post(url2).headers(headers).body(body).asObject(responseClass));
+
+        loggingService.logResponse(outgoingRequestsLogger, HttpMethod.POST, url, response);
+
+        return response;
     }
 
     @Override
     public HttpResponse<JsonNode> get(String url, Map<String, String> headers, Map<String, String> routeParams) {
-        return callWithRetryOverHttp(url, url2 -> {
-            val getRequest = restClient.get(url2).headers(headers);
+        loggingService.logRequest(outgoingRequestsLogger, HttpMethod.GET, url, routeParams);
+
+        HttpResponse<JsonNode> response = callWithRetryOverHttp(url, url2 -> {
+            GetRequest getRequest = restClient.get(url2).headers(headers);
             routeParams.forEach(getRequest::routeParam);
             return getRequest.asJson();
         });
+
+        loggingService.logResponse(outgoingRequestsLogger, HttpMethod.GET, url, response);
+
+        return response;
     }
 
     @Override
     public <T> HttpResponse<T> get(String url, Map<String, String> headers, Map<String, String> routeParams,
-        Class<T> responseClass) {
-        return callWithRetryOverHttp(url, url2 -> {
-            val getRequest = restClient.get(url2).headers(headers);
+                                   Class<T> responseClass) {
+        loggingService.logRequest(outgoingRequestsLogger, HttpMethod.GET, url, routeParams);
+
+        HttpResponse<T> response = callWithRetryOverHttp(url, url2 -> {
+            GetRequest getRequest = restClient.get(url2).headers(headers);
             routeParams.forEach(getRequest::routeParam);
             return getRequest.asObject(responseClass);
         });
+
+        loggingService.logResponse(outgoingRequestsLogger, HttpMethod.GET, url, response);
+
+        return response;
     }
 
     @Override
     public HttpResponse<InputStream> getStream(String url, Map<String, String> headers,
-        Map<String, String> routeParams) {
-        return callWithRetryOverHttp(url, url2 -> {
-            val getRequest = restClient.get(url2).headers(headers);
+                                               Map<String, String> routeParams) {
+        loggingService.logRequest(outgoingRequestsLogger, HttpMethod.GET, url, routeParams);
+
+        HttpResponse<InputStream> response = callWithRetryOverHttp(url, url2 -> {
+            GetRequest getRequest = restClient.get(url2).headers(headers);
             routeParams.forEach(getRequest::routeParam);
             return getRequest.asBinary();
         });
+
+        //no logging of the response since the response is too long
+        return response;
+
     }
 
     @Override
     public HttpResponse<JsonNode> put(String url, Map<String, String> headers, Object body) {
-        return callWithRetryOverHttp(url, url2 -> restClient.put(url2).headers(headers).body(body).asJson());
+        loggingService.logRequest(outgoingRequestsLogger, HttpMethod.PUT, url, body);
+
+        HttpResponse<JsonNode> response = callWithRetryOverHttp(url,
+            url2 -> restClient.put(url2).headers(headers).body(body).asJson());
+
+        loggingService.logResponse(outgoingRequestsLogger, HttpMethod.PUT, url, response);
+
+        return response;
     }
 
     @Override
     public <T> HttpResponse<T> put(String url, Map<String, String> headers, Object body, Class<T> responseClass) {
-        return callWithRetryOverHttp(url,
+        loggingService.logRequest(outgoingRequestsLogger, HttpMethod.PUT, url, body);
+
+        HttpResponse<T> response = callWithRetryOverHttp(url,
             url2 -> restClient.put(url2).headers(headers).body(body).asObject(responseClass));
+
+        loggingService.logResponse(outgoingRequestsLogger, HttpMethod.PUT, url, response);
+
+        return response;
+    }
+
+    @Override
+    public <T> HttpResponse<T> delete(String url, Map<String, String> headers, Object body, Class<T> responseClass) {
+        loggingService.logRequest(outgoingRequestsLogger, HttpMethod.DELETE, url, body);
+
+        HttpResponse<T> response = callWithRetryOverHttp(url,
+            url2 -> restClient.delete(url2).headers(headers).body(body).asObject(responseClass));
+
+        loggingService.logResponse(outgoingRequestsLogger, HttpMethod.DELETE, url, response);
+
+        return response;
     }
 
     @Override
     public <T> HttpResponse<T> delete(String url, Map<String, String> headers, Class<T> responseClass) {
-        return callWithRetryOverHttp(url, url2 -> restClient.delete(url2).headers(headers).asObject(responseClass));
+        loggingService.logRequest(outgoingRequestsLogger, HttpMethod.DELETE, url);
+
+        HttpResponse<T> response = callWithRetryOverHttp(url,
+            url2 -> restClient.delete(url2).headers(headers).asObject(responseClass));
+
+        loggingService.logResponse(outgoingRequestsLogger, HttpMethod.DELETE, url, response);
+
+        return response;
     }
 
     @Override
     public HttpResponse<JsonNode> delete(String url, Map<String, String> headers) {
-        return callWithRetryOverHttp(url, url2 -> restClient.delete(url2).headers(headers).asJson());
+        loggingService.logRequest(outgoingRequestsLogger, HttpMethod.DELETE, url);
+
+        HttpResponse<JsonNode> response = callWithRetryOverHttp(url,
+            url2 -> restClient.delete(url2).headers(headers).asJson());
+
+        loggingService.logResponse(outgoingRequestsLogger, HttpMethod.DELETE, url, response);
+
+        return response;
     }
 
     @Override
@@ -149,81 +235,86 @@ public class SyncRestClient implements SyncRestClientInterface {
         restClient.shutdown();
     }
 
-    @SneakyThrows
-    private <T> HttpResponse<T> callWithRetryOverHttp(String url,
-                                                      CheckedFunction1<String, HttpResponse<T>> httpRequest) {
+    private <T> HttpResponse<T> callWithRetryOverHttp(String url, HttpRequest<T> httpRequest) {
+        try {
+            return callWithRetryOverHttpThrows(url, httpRequest);
+        } catch (IOException e) {
+            throw new SyncRestClientException("IOException while calling rest service", e);
+        }
+    }
+
+    private <T> HttpResponse<T> callWithRetryOverHttpThrows(String url, HttpRequest<T> httpRequest) throws IOException {
         try {
-            return httpRequest.apply(url);
+            return patched(httpRequest.apply(url));
         } catch (RestClientException e) {
-            if (e.getCause() instanceof SSLException) {
-                logger.warn(EELFLoggerDelegate.debugLogger,
-                        DATE_FORMAT.format(new Date()) + TRY_TO_CALL_OVER_HTTP, e);
-                return httpRequest.apply(url.replaceFirst(HTTPS_SCHEMA, HTTP_SCHEMA));
+            if (causedBySslHandshakeError(e)) {
+                logger.warn("SSL Handshake problem occured. Will try to retry over Http.", e);
+                return patched(httpRequest.apply(url.replaceFirst(HTTPS_SCHEMA, HTTP_SCHEMA)));
             }
             throw e;
         }
     }
 
-    private ObjectMapper defaultObjectMapper() {
-        val objectMapper = new org.codehaus.jackson.map.ObjectMapper();
-
-        return new ObjectMapper() {
-            @Override
-            @SneakyThrows
-            public <T> T readValue(String value, Class<T> aClass) {
-                return objectMapper.readValue(value, aClass);
-            }
+    private boolean causedBySslHandshakeError(RestClientException exception) {
+        return exception.getCause() instanceof SSLException;
+    }
 
-            @Override
-            @SneakyThrows
-            public String writeValue(Object value) {
-                return objectMapper.writeValueAsString(value);
-            }
-        };
+    private ObjectMapper defaultObjectMapper() {
+        return JOSHWORKS_JACKSON_OBJECT_MAPPER;
     }
 
-    private CloseableHttpClient defaultHttpClient() {
+    private CloseableHttpClient defaultHttpClient(boolean useLoggingInterceptor) {
         try {
-            val trustStorePath = SystemProperties.getProperty(VidProperties.VID_TRUSTSTORE_FILENAME);
-            val trustStorePass = SystemProperties.getProperty(VidProperties.VID_TRUSTSTORE_PASSWD_X);
-            val decryptedTrustStorePass = Password.deobfuscate(trustStorePass);
+            String trustStorePath = SystemProperties.getProperty(VidProperties.VID_TRUSTSTORE_FILENAME);
+            String trustStorePass = SystemProperties.getProperty(VidProperties.VID_TRUSTSTORE_PASSWD_X);
+            String decryptedTrustStorePass = Password.deobfuscate(trustStorePass);
 
-            val trustStore = loadTruststore(trustStorePath, decryptedTrustStorePass);
-            val sslContext = trustOwnCACerts(decryptedTrustStorePass, trustStore);
-            val sslSf = allowTLSProtocols(sslContext);
+            KeyStore trustStore = loadTruststore(trustStorePath, decryptedTrustStorePass);
+            SSLContext sslContext = trustOwnCACerts(decryptedTrustStorePass, trustStore);
+            SSLConnectionSocketFactory sslSf = allowTLSProtocols(sslContext);
 
-            return HttpClients.custom().setSSLSocketFactory(sslSf).build();
+            HttpClientBuilder httpClientBuilder = HttpClients.custom().setSSLSocketFactory(sslSf);
+            if (useLoggingInterceptor) {
+                httpClientBuilder
+                    .addInterceptorFirst(new ApacheClientMetricRequestInterceptor())
+                    .addInterceptorLast(new ApacheClientMetricResponseInterceptor());
+            }
+            return httpClientBuilder.build();
         } catch (IOException | CertificateException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
-            logger.warn(EELFLoggerDelegate.debugLogger,
-                DATE_FORMAT.format(new Date()) + CANNOT_INITIALIZE_CUSTOM_HTTP_CLIENT, e);
+            logger.warn("Cannot initialize custom http client from current configuration. Using default one.", e);
             return HttpClients.createDefault();
         }
     }
 
     private SSLConnectionSocketFactory allowTLSProtocols(SSLContext sslcontext) {
         return new SSLConnectionSocketFactory(
-            sslcontext,
-            SUPPORTED_SSL_VERSIONS,
-            null,
-            SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+                sslcontext,
+                SUPPORTED_SSL_VERSIONS,
+                null,
+                SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
     }
 
     private SSLContext trustOwnCACerts(String trustStorePass, KeyStore trustStore)
-        throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+            throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
         return SSLContexts.custom()
-            .useTLS()
-            .loadKeyMaterial(trustStore, trustStorePass.toCharArray())
-            .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
-            .build();
+                .useTLS()
+                .loadKeyMaterial(trustStore, trustStorePass.toCharArray())
+                .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
+                .build();
     }
 
     private KeyStore loadTruststore(String trustStorePath, String trustStorePass)
-        throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
-        val trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
+        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
         try (FileInputStream instream = new FileInputStream(new File(trustStorePath))) {
             trustStore.load(instream, trustStorePass.toCharArray());
         }
         return trustStore;
     }
 
+    @FunctionalInterface
+    private interface HttpRequest<T> {
+        HttpResponse<T> apply(String url) throws IOException;
+    }
+
 }