From 5aa8aec689a399e7803e84e531532d0c61631ec1 Mon Sep 17 00:00:00 2001 From: Instrumental Date: Wed, 7 Nov 2018 20:52:15 -0600 Subject: Fix/Renable sidecar builds Issue-ID: AAF-613 Change-Id: Ic13411eebbf3c1c9b6d8492aff1b37db37a965e4 Signed-off-by: Instrumental --- .../cadi/sidecar/rproxy/ReverseProxyService.java | 167 +++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyService.java (limited to 'sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyService.java') diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyService.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyService.java new file mode 100644 index 0000000..e15fb2a --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyService.java @@ -0,0 +1,167 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.UUID; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.cadi.sidecar.fproxy.data.CredentialCacheData; +import org.onap.aaf.cadi.sidecar.fproxy.data.CredentialCacheData.CredentialType; +import org.onap.aaf.cadi.sidecar.rpoxy.logging.ReverseProxyMethodLogTimeAnnotation; +import org.onap.aaf.cadi.sidecar.rproxy.config.ForwardProxyProperties; +import org.onap.aaf.cadi.sidecar.rproxy.config.PrimaryServiceProperties; +import org.onap.aaf.cadi.sidecar.rproxy.utils.ReverseProxyUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +@RestController +@EnableConfigurationProperties({ForwardProxyProperties.class, PrimaryServiceProperties.class}) +public class ReverseProxyService { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyService.class); + + private String validatedTransactionId; + + @Resource(name = "ForwardProxyProperties") + private ForwardProxyProperties forwardProxyProperties; + + @Resource(name = "PrimaryServiceProperties") + private PrimaryServiceProperties primaryServiceProperties; + + @Autowired + private RestTemplate restTemplate; + + @Value("${transactionid.header.name}") + private String transactionIdHeader; + + @RequestMapping("/**") + @ReverseProxyMethodLogTimeAnnotation + public ResponseEntity handleRequest(HttpServletRequest request, + @RequestHeader(value = "${transactionid.header.name}", defaultValue = "") String transactionId, + @RequestBody(required = false) String requestBody, HttpMethod requestMethod) throws URISyntaxException { + validatedTransactionId = getValidTransactionId(transactionId); + + // Extract Request Permissions and store in Forward Proxy cache + CredentialCacheData credentialCacheData = getCredentialDataFromRequest(request); + if (credentialCacheData != null) { + postCredentialsToCache(credentialCacheData); + } + + // Call out to Primary Service & Return Response + URI requestURI = new URI(request.getRequestURI()); + + LOGGER.debug("Request URI: {}", request.getRequestURI()); + + // Get Request Endpoint & substitute in local values + URI primaryServiceURI = new URI(primaryServiceProperties.getProtocol(), requestURI.getUserInfo(), + primaryServiceProperties.getHost(), Integer.parseInt(primaryServiceProperties.getPort()), + requestURI.getPath(), requestURI.getQuery(), requestURI.getFragment()); + + LOGGER.debug("Primary Service URI:{}, HTTP Method: {}", primaryServiceURI, requestMethod); + + HttpHeaders requestHeaders = setForwardedRequestHeaders(request); + HttpEntity httpEntity = new HttpEntity<>(requestBody, requestHeaders); + + return restTemplate.exchange(primaryServiceURI, requestMethod, httpEntity, String.class); + } + + private String getValidTransactionId(String transactionId) { + LOGGER.debug("Request transaction ID: {}", transactionId); + if (transactionId == null || !ReverseProxyUtils.validTransactionId(transactionId)) { + transactionId = UUID.randomUUID().toString(); + } + LOGGER.debug("Validated transaction ID: {}", transactionId); + return transactionId; + } + + private HttpHeaders setForwardedRequestHeaders(HttpServletRequest httpServletRequest) { + HttpHeaders httpHeaders = new HttpHeaders(); + Enumeration headerNames = httpServletRequest.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + if (!headerName.equals(transactionIdHeader)) { + httpHeaders.set(headerName, httpServletRequest.getHeader(headerName)); + } + } + // Always set transaction ID + httpHeaders.set(transactionIdHeader, validatedTransactionId); + + return httpHeaders; + } + + /** + * Retrieves credential data from request. + * + * @param request The request to retrieve credentials from + * @return The retrieved credential data, or null if no credentials are found in request + */ + private CredentialCacheData getCredentialDataFromRequest(HttpServletRequest request) { + CredentialCacheData credentialCacheData = null; + String authValue = request.getHeader(HttpHeaders.AUTHORIZATION); + if (authValue != null) { + credentialCacheData = new CredentialCacheData(HttpHeaders.AUTHORIZATION, authValue, CredentialType.HEADER); + } + return credentialCacheData; + } + + /** + * Posts credential data to credential cache endpoint + * + * @param credentialCacheData The credential data to post + * @throws URISyntaxException + */ + private void postCredentialsToCache(CredentialCacheData credentialCacheData) throws URISyntaxException { + URI forwardProxyURI = new URI(forwardProxyProperties.getProtocol(), null, forwardProxyProperties.getHost(), + forwardProxyProperties.getPort(), forwardProxyProperties.getCacheurl() + "/" + validatedTransactionId, + null, null); + + ResponseEntity response = + restTemplate.postForEntity(forwardProxyURI, credentialCacheData, String.class); + + if (!response.getStatusCode().is2xxSuccessful()) { + throw new HttpClientErrorException(response.getStatusCode(), + "Error posting to credential cache. Message: " + response.getBody()); + } + } + + @Override + public String toString() { + return this.getClass().getName() + ": Forward proxy host:" + forwardProxyProperties.getHost() + + ": Primary service host:" + primaryServiceProperties.getHost(); + + } +} -- cgit 1.2.3-korg