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