2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
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=========================================================
21 package org.openecomp.sdc.fe.servlets;
23 import com.google.common.annotations.VisibleForTesting;
24 import java.util.Base64;
25 import org.apache.commons.lang3.NotImplementedException;
26 import org.apache.commons.lang3.StringUtils;
27 import org.eclipse.jetty.client.api.Request;
28 import org.eclipse.jetty.client.api.Response;
29 import org.eclipse.jetty.http.HttpHeader;
30 import org.openecomp.sdc.common.api.Constants;
31 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
32 import org.openecomp.sdc.common.log.wrappers.Logger;
33 import org.openecomp.sdc.fe.config.Configuration;
34 import org.openecomp.sdc.fe.config.Configuration.BasicAuthConfig;
35 import org.openecomp.sdc.fe.config.Configuration.CatalogFacadeMsConfig;
36 import org.openecomp.sdc.fe.config.ConfigurationManager;
37 import org.openecomp.sdc.fe.config.FeEcompErrorManager;
38 import org.openecomp.sdc.fe.config.PluginsConfiguration;
39 import org.openecomp.sdc.fe.config.PluginsConfiguration.Plugin;
40 import org.openecomp.sdc.fe.impl.LogHandler;
41 import org.openecomp.sdc.fe.utils.BeProtocol;
43 import javax.servlet.http.HttpServletRequest;
44 import java.net.MalformedURLException;
47 import static org.apache.commons.lang3.StringUtils.isEmpty;
50 public class FeProxyServlet extends SSLProxyServlet {
51 private static final long serialVersionUID = 1L;
52 private static final String URL = "%s://%s%s%s";
53 private static final String MS_URL = "%s://%s:%s";
54 private static final String ONBOARDING_CONTEXT = "/onboarding-api";
55 private static final String DCAED_CONTEXT = "/dcae-api";
56 private static final String WORKFLOW_CONTEXT = "/wf";
57 private static final String SDC1_FE_PROXY = "/sdc1/feProxy";
58 private static final String PLUGIN_ID_WORKFLOW = "WORKFLOW";
59 public static final String UUID = "uuid";
60 public static final String TRANSACTION_START_TIME = "transactionStartTime";
61 private static Logger log = Logger.getLogger(FeProxyServlet.class.getName());
63 private static String msUrl;
64 private static final String FACADE_PATH_IDENTIFIER = "uicache";
65 private static final String CATALOG_REQUEST_IDENTIFIER = "/v1/catalog";
66 private static final String ARCHIVE_PATH_IDENTIFIER = String.format("%s/archive/", CATALOG_REQUEST_IDENTIFIER);
67 private static final String HOME_REQUEST_IDENTIFIER = "/v1/followed";
69 protected String rewriteTarget(HttpServletRequest request) {
70 String originalUrl="";
71 String redirectedUrl = "";
74 logFeRequest(request);
75 originalUrl = request.getRequestURL().toString();
77 Configuration config = getConfiguration(request);
79 log.error("failed to retrieve configuration.");
81 if (isMsRequest(request.getRequestURL().toString())) {
82 redirectedUrl = redirectMsRequestToMservice(request, config);
84 redirectedUrl = getModifiedUrl(config, getPluginConfiguration(request), request.getRequestURI(), getQueryString(request));
87 catch (MalformedURLException mue) {
88 FeEcompErrorManager.getInstance().logFeHttpLoggingError("FE Request");
89 log.error(EcompLoggerErrorCode.DATA_ERROR, "FeProxyServlet rewriteTarget", "sdc-FE", "Malformed URL Exception: ", mue);
92 log.error(EcompLoggerErrorCode.UNKNOWN_ERROR,"FeProxyServlet rewriteTarget", "sdc-FE", "Unexpected FE request processing error: ", e);
94 if (log.isDebugEnabled()) {
95 log.debug("FeProxyServlet Redirecting request from: {} , to: {}", originalUrl, redirectedUrl);
102 protected void addProxyHeaders(HttpServletRequest clientRequest, Request proxyRequest)
104 Configuration config = getConfiguration(clientRequest);
105 if (config == null) {
106 log.error("Failed to retrieve configuration. Adding proxy header failed.");
109 BasicAuthConfig basicAuth = config.getBasicAuth();
110 if (basicAuth.getEnabled()) {
111 proxyRequest.header(HttpHeader.AUTHORIZATION,
112 "Basic " + Base64.getEncoder().encodeToString((basicAuth.getUserName() + ":" + basicAuth.getUserPass()).getBytes()));
114 super.addProxyHeaders(clientRequest, proxyRequest);
117 private void logFeRequest(HttpServletRequest httpRequest){
118 LogHandler.logFeRequest(httpRequest);
119 inHttpRequest(httpRequest);
122 private void logFeResponse(HttpServletRequest request, Response proxyResponse){
123 LogHandler.logFeResponse(request);
124 outHttpResponse(proxyResponse);
127 // Extracted for purpose of clear method name, for logback %M parameter
128 private void inHttpRequest(HttpServletRequest httpRequest) {
129 log.info("{} {} {}", httpRequest.getMethod(), httpRequest.getRequestURI(), httpRequest.getProtocol());
132 // Extracted for purpose of clear method name, for logback %M parameter
133 private void outHttpResponse(Response proxyResponse) {
134 log.info("SC=\"{}\"", proxyResponse.getStatus());
137 private String getModifiedUrl(Configuration config, PluginsConfiguration pluginConf, String uri, String queryString) throws MalformedURLException{
138 if (config == null) {
139 log.error(EcompLoggerErrorCode.UNKNOWN_ERROR,"FeProxyServlet getModifiedUrl", "sdc-FE", "failed to retrieve configuration.");
140 throw new RuntimeException("failed to read FE configuration");
146 if (uri.contains(ONBOARDING_CONTEXT)){
147 uri = uri.replace(SDC1_FE_PROXY+ONBOARDING_CONTEXT,ONBOARDING_CONTEXT);
148 protocol = config.getOnboarding().getProtocolBe();
149 host = config.getOnboarding().getHostBe();
150 port = config.getOnboarding().getPortBe().toString();
151 }else if(uri.contains(DCAED_CONTEXT)){
152 uri = uri.replace(SDC1_FE_PROXY+DCAED_CONTEXT,DCAED_CONTEXT);
153 protocol = config.getBeProtocol();
154 host = config.getBeHost();
155 if (config.getBeProtocol().equals(BeProtocol.HTTP.getProtocolName())) {
156 port = config.getBeHttpPort().toString();
158 port = config.getBeSslPort().toString();
161 else if (uri.contains(WORKFLOW_CONTEXT)){
162 uri = uri.replace(SDC1_FE_PROXY +WORKFLOW_CONTEXT,WORKFLOW_CONTEXT);
163 String workflowPluginURL = pluginConf.getPluginsList()
165 .filter(plugin -> plugin.getPluginId().equalsIgnoreCase(PLUGIN_ID_WORKFLOW))
166 .map(Plugin::getPluginDiscoveryUrl)
167 .findFirst().orElse(null);
169 java.net.URL workflowURL = new URL(workflowPluginURL);
170 protocol = workflowURL.getProtocol();
171 host = workflowURL.getHost();
172 path = workflowURL.getPath();
173 port = String.valueOf(workflowURL.getPort());
176 uri = uri.replace(SDC1_FE_PROXY,"/sdc2");
177 protocol = config.getBeProtocol();
178 host = config.getBeHost();
179 if (config.getBeProtocol().equals(BeProtocol.HTTP.getProtocolName())) {
180 port = config.getBeHttpPort().toString();
182 port = config.getBeSslPort().toString();
186 final String authority = getAuthority(host, port);
187 String modifiedUrl = String.format(URL, protocol, authority, path, uri);
188 if (StringUtils.isNotEmpty(queryString)) {
189 modifiedUrl += "?" + queryString;
196 String redirectMsRequestToMservice(HttpServletRequest request, Configuration config) throws MalformedURLException {
198 boolean isMsToggledOn = isMsToggleOn(config);
199 String redirectValue;
201 redirectValue = handleMsToggleOnRedirect(request, config);
203 redirectValue = handleMsToggleOffRedirect(request, config);
205 return redirectValue;
207 private PluginsConfiguration getPluginConfiguration(HttpServletRequest request) {
208 return ((ConfigurationManager) request.getSession().getServletContext().getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)).getPluginsConfiguration();
210 private boolean isMsToggleOn(Configuration config) {
211 boolean toggleOn = true;
212 final CatalogFacadeMsConfig catalogFacadeMs = config.getCatalogFacadeMs();
213 if (catalogFacadeMs == null) {
216 } else if (isEmpty(catalogFacadeMs.getHealthCheckUri())) {
218 } else if (isEmpty(catalogFacadeMs.getHost())) {
220 } else if (isEmpty(catalogFacadeMs.getPath())) {
222 } else if (isEmpty(catalogFacadeMs.getProtocol())) {
224 } else if (catalogFacadeMs.getPort() == null) {
229 private String handleMsToggleOffRedirect(HttpServletRequest request, Configuration config) throws MalformedURLException {
230 String redirectValue;
231 String currentURI = request.getRequestURI();
232 if (isEmpty(request.getQueryString())) {
234 if (currentURI.endsWith(CATALOG_REQUEST_IDENTIFIER)) {
235 String facadeSuffix = String.format("%s%s", FACADE_PATH_IDENTIFIER, CATALOG_REQUEST_IDENTIFIER);
236 String nonFacadeUrl = currentURI.replace(facadeSuffix, "rest/v1/screen");
237 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), nonFacadeUrl, "excludeTypes=VFCMT&excludeTypes=Configuration");
240 else if (currentURI.endsWith(HOME_REQUEST_IDENTIFIER)){
241 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), currentURI, getQueryString(request));
244 else if (currentURI.endsWith(ARCHIVE_PATH_IDENTIFIER)) {
245 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), currentURI, getQueryString(request));
247 String message = String.format("facade is toggled off, Could not rediret url %s", currentURI);
249 throw new NotImplementedException(message);
253 if (currentURI.contains("/latestversion/notabstract/metadata")) {
254 String nonFacadeUrl = currentURI.replace(FACADE_PATH_IDENTIFIER, "rest");
255 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), nonFacadeUrl, getQueryString(request));
257 // Catalog with Query Params
258 else if (currentURI.endsWith(CATALOG_REQUEST_IDENTIFIER)) {
259 String facadeSuffix = String.format("%s%s", FACADE_PATH_IDENTIFIER, CATALOG_REQUEST_IDENTIFIER);
260 String nonFacadeUrl = currentURI.replace(facadeSuffix, "rest/v1/screen");
261 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), nonFacadeUrl, "excludeTypes=VFCMT&excludeTypes=Configuration");
263 String message = String.format("facade is toggled off, Could not rediret url %s with query params %s",
264 currentURI, getQueryString(request));
266 throw new NotImplementedException(message);
270 return redirectValue;
273 private String handleMsToggleOnRedirect(HttpServletRequest request, Configuration config) {
274 String currentUrl = request.getRequestURL()
276 if (StringUtils.isEmpty(msUrl)) {
278 msUrl = String.format(MS_URL, config.getCatalogFacadeMs()
280 config.getCatalogFacadeMs().getHost(),
281 config.getCatalogFacadeMs().getPort());
285 String msPath = config.getCatalogFacadeMs().getPath();
286 if (currentUrl.endsWith(ARCHIVE_PATH_IDENTIFIER)) {
287 url = new StringBuilder(msUrl + msPath + CATALOG_REQUEST_IDENTIFIER);
288 queryString = "arc=true";
290 url = new StringBuilder(msUrl + currentUrl.substring(currentUrl.indexOf(msPath)));
291 queryString = request.getQueryString();
293 if (queryString != null) {
294 url.append("?").append(queryString);
296 if (log.isDebugEnabled()) {
297 log.debug("Redirect catalog request to {}", url.toString());
299 return url.toString();
303 boolean isMsRequest(String currentUrl) {
304 return currentUrl.contains(FACADE_PATH_IDENTIFIER) || currentUrl.endsWith(ARCHIVE_PATH_IDENTIFIER);
306 private Configuration getConfiguration(HttpServletRequest request) {
307 return ((ConfigurationManager) request.getSession().getServletContext().getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)).getConfiguration();
310 private String getAuthority(String host, String port) {
315 authority = host + ":" + port;
320 private String getQueryString(HttpServletRequest request){
321 final String queryString = request.getQueryString();
322 return StringUtils.isEmpty(queryString) ? StringUtils.EMPTY : queryString;