2 * ============LICENSE_START=======================================================
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
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=========================================================
20 package org.onap.aaf.cadi.sidecar.rproxy;
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;
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;
52 @EnableConfigurationProperties({ForwardProxyProperties.class, PrimaryServiceProperties.class})
53 public class ReverseProxyService {
55 private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyService.class);
57 private String validatedTransactionId;
59 @Resource(name = "ForwardProxyProperties")
60 private ForwardProxyProperties forwardProxyProperties;
62 @Resource(name = "PrimaryServiceProperties")
63 private PrimaryServiceProperties primaryServiceProperties;
66 private RestTemplate restTemplate;
68 @Value("${transactionid.header.name}")
69 private String transactionIdHeader;
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);
78 // Extract Request Permissions and store in Forward Proxy cache
79 CredentialCacheData credentialCacheData = getCredentialDataFromRequest(request);
80 if (credentialCacheData != null) {
81 postCredentialsToCache(credentialCacheData);
84 // Call out to Primary Service & Return Response
85 URI requestURI = new URI(request.getRequestURI());
87 LOGGER.debug("Request URI: {}", request.getRequestURI());
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());
94 LOGGER.debug("Primary Service URI:{}, HTTP Method: {}", primaryServiceURI, requestMethod);
96 HttpHeaders requestHeaders = setForwardedRequestHeaders(request);
97 HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, requestHeaders);
99 return restTemplate.exchange(primaryServiceURI, requestMethod, httpEntity, String.class);
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();
107 LOGGER.debug("Validated transaction ID: {}", transactionId);
108 return transactionId;
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));
120 // Always set transaction ID
121 httpHeaders.set(transactionIdHeader, validatedTransactionId);
127 * Retrieves credential data from request.
129 * @param request The request to retrieve credentials from
130 * @return The retrieved credential data, or null if no credentials are found in request
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);
138 return credentialCacheData;
142 * Posts credential data to credential cache endpoint
144 * @param credentialCacheData The credential data to post
145 * @throws URISyntaxException
147 private void postCredentialsToCache(CredentialCacheData credentialCacheData) throws URISyntaxException {
148 URI forwardProxyURI = new URI(forwardProxyProperties.getProtocol(), null, forwardProxyProperties.getHost(),
149 forwardProxyProperties.getPort(), forwardProxyProperties.getCacheurl() + "/" + validatedTransactionId,
152 ResponseEntity<String> response =
153 restTemplate.postForEntity(forwardProxyURI, credentialCacheData, String.class);
155 if (!response.getStatusCode().is2xxSuccessful()) {
156 throw new HttpClientErrorException(response.getStatusCode(),
157 "Error posting to credential cache. Message: " + response.getBody());
162 public String toString() {
163 return this.getClass().getName() + ": Forward proxy host:" + forwardProxyProperties.getHost()
164 + ": Primary service host:" + primaryServiceProperties.getHost();