Fix NexusIQ security vulnerabilities
[aaf/cadi.git] / sidecar / rproxy / src / main / java / org / onap / aaf / rproxy / ReverseProxyService.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aaf
4  * ================================================================================
5  * Copyright © 2018 European Software Marketing Ltd.
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
10  *
11  *       http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20 package org.onap.aaf.rproxy;
21
22 import java.net.URI;
23 import java.net.URISyntaxException;
24 import java.util.Enumeration;
25 import java.util.UUID;
26 import javax.annotation.Resource;
27 import javax.servlet.http.HttpServletRequest;
28 import org.onap.aaf.fproxy.data.CredentialCacheData;
29 import org.onap.aaf.fproxy.data.CredentialCacheData.CredentialType;
30 import org.onap.aaf.rproxy.config.ForwardProxyProperties;
31 import org.onap.aaf.rproxy.config.PrimaryServiceProperties;
32 import org.onap.aaf.rproxy.logging.ReverseProxyMethodLogTimeAnnotation;
33 import org.onap.aaf.rproxy.utils.ReverseProxyUtils;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.springframework.beans.factory.annotation.Autowired;
37 import org.springframework.beans.factory.annotation.Value;
38 import org.springframework.boot.context.properties.EnableConfigurationProperties;
39 import org.springframework.http.HttpEntity;
40 import org.springframework.http.HttpHeaders;
41 import org.springframework.http.HttpMethod;
42 import org.springframework.http.ResponseEntity;
43 import org.springframework.web.bind.annotation.RequestBody;
44 import org.springframework.web.bind.annotation.RequestHeader;
45 import org.springframework.web.bind.annotation.RequestMapping;
46 import org.springframework.web.bind.annotation.RestController;
47 import org.springframework.web.client.HttpClientErrorException;
48 import org.springframework.web.client.RestTemplate;
49
50 @RestController
51 @EnableConfigurationProperties({ForwardProxyProperties.class, PrimaryServiceProperties.class})
52 public class ReverseProxyService {
53
54     private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyService.class);
55
56     private String validatedTransactionId;
57
58     @Resource(name = "ForwardProxyProperties")
59     private ForwardProxyProperties forwardProxyProperties;
60
61     @Resource(name = "PrimaryServiceProperties")
62     private PrimaryServiceProperties primaryServiceProperties;
63
64     @Autowired
65     private RestTemplate restTemplate;
66
67     @Value("${transactionid.header.name}")
68     private String transactionIdHeader;
69
70     @RequestMapping("/**")
71     @ReverseProxyMethodLogTimeAnnotation
72     public ResponseEntity<String> handleRequest(HttpServletRequest request,
73             @RequestHeader(value = "${transactionid.header.name}", defaultValue = "") String transactionId,
74             @RequestBody(required = false) String requestBody, HttpMethod requestMethod) throws URISyntaxException {
75         validatedTransactionId = getValidTransactionId(transactionId);
76
77         // Extract Request Permissions and store in Forward Proxy cache
78         CredentialCacheData credentialCacheData = getCredentialDataFromRequest(request);
79         if (credentialCacheData != null) {
80             postCredentialsToCache(credentialCacheData);
81         }
82
83         // Call out to Primary Service & Return Response
84         URI requestURI = new URI(request.getRequestURI());
85
86         LOGGER.debug("Request URI: {}", request.getRequestURI());
87
88         // Get Request Endpoint & substitute in local values
89         URI primaryServiceURI = new URI(primaryServiceProperties.getProtocol(), requestURI.getUserInfo(),
90                 primaryServiceProperties.getHost(), Integer.parseInt(primaryServiceProperties.getPort()),
91                 requestURI.getPath(), requestURI.getQuery(), requestURI.getFragment());
92
93         LOGGER.debug("Primary Service URI:{}, HTTP Method: {}", primaryServiceURI, requestMethod);
94
95         HttpHeaders requestHeaders = setForwardedRequestHeaders(request);
96         HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, requestHeaders);
97
98         return restTemplate.exchange(primaryServiceURI, requestMethod, httpEntity, String.class);
99     }
100
101     private String getValidTransactionId(String transactionId) {
102         LOGGER.debug("Request transaction ID: {}", transactionId);
103         if (transactionId == null || !ReverseProxyUtils.validTransactionId(transactionId)) {
104             transactionId = UUID.randomUUID().toString();
105         }
106         LOGGER.debug("Validated transaction ID: {}", transactionId);
107         return transactionId;
108     }
109
110     private HttpHeaders setForwardedRequestHeaders(HttpServletRequest httpServletRequest) {
111         HttpHeaders httpHeaders = new HttpHeaders();
112         Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
113         while (headerNames.hasMoreElements()) {
114             String headerName = headerNames.nextElement();
115             if (!headerName.equals(transactionIdHeader)) {
116                 httpHeaders.set(headerName, httpServletRequest.getHeader(headerName));
117             }
118         }
119         // Always set transaction ID
120         httpHeaders.set(transactionIdHeader, validatedTransactionId);
121
122         return httpHeaders;
123     }
124
125     /**
126      * Retrieves credential data from request.
127      * 
128      * @param request The request to retrieve credentials from
129      * @return The retrieved credential data, or null if no credentials are found in request
130      */
131     private CredentialCacheData getCredentialDataFromRequest(HttpServletRequest request) {
132         CredentialCacheData credentialCacheData = null;
133         String authValue = request.getHeader(HttpHeaders.AUTHORIZATION);
134         if (authValue != null) {
135             credentialCacheData = new CredentialCacheData(HttpHeaders.AUTHORIZATION, authValue, CredentialType.HEADER);
136         }
137         return credentialCacheData;
138     }
139
140     /**
141      * Posts credential data to credential cache endpoint
142      * 
143      * @param credentialCacheData The credential data to post
144      * @throws URISyntaxException
145      */
146     private void postCredentialsToCache(CredentialCacheData credentialCacheData) throws URISyntaxException {
147         URI forwardProxyURI = new URI(forwardProxyProperties.getProtocol(), null, forwardProxyProperties.getHost(),
148                 forwardProxyProperties.getPort(), forwardProxyProperties.getCacheurl() + "/" + validatedTransactionId,
149                 null, null);
150
151         ResponseEntity<String> response =
152                 restTemplate.postForEntity(forwardProxyURI, credentialCacheData, String.class);
153
154         if (!response.getStatusCode().is2xxSuccessful()) {
155             throw new HttpClientErrorException(response.getStatusCode(),
156                     "Error posting to credential cache. Message: " + response.getBody());
157         }
158     }
159
160     @Override
161     public String toString() {
162         return this.getClass().getName() + ": Forward proxy host:" + forwardProxyProperties.getHost()
163                 + ": Primary service host:" + primaryServiceProperties.getHost();
164
165     }
166 }