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=========================================================
20 package org.openecomp.sdc.fe.servlets;
22 import static org.apache.commons.lang3.StringUtils.isEmpty;
24 import com.google.common.annotations.VisibleForTesting;
25 import java.net.MalformedURLException;
27 import java.util.Base64;
28 import javax.servlet.http.HttpServletRequest;
29 import org.apache.commons.lang3.NotImplementedException;
30 import org.apache.commons.lang3.StringUtils;
31 import org.eclipse.jetty.client.api.Request;
32 import org.eclipse.jetty.client.api.Response;
33 import org.eclipse.jetty.http.HttpHeader;
34 import org.openecomp.sdc.common.api.Constants;
35 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
36 import org.openecomp.sdc.common.log.wrappers.Logger;
37 import org.openecomp.sdc.fe.config.Configuration;
38 import org.openecomp.sdc.fe.config.Configuration.BasicAuthConfig;
39 import org.openecomp.sdc.fe.config.Configuration.CatalogFacadeMsConfig;
40 import org.openecomp.sdc.fe.config.ConfigurationManager;
41 import org.openecomp.sdc.fe.config.FeEcompErrorManager;
42 import org.openecomp.sdc.fe.config.PluginsConfiguration;
43 import org.openecomp.sdc.fe.config.PluginsConfiguration.Plugin;
44 import org.openecomp.sdc.fe.impl.LogHandler;
45 import org.openecomp.sdc.fe.utils.BeProtocol;
47 public class FeProxyServlet extends SSLProxyServlet {
49 public static final String UUID = "uuid";
50 public static final String TRANSACTION_START_TIME = "transactionStartTime";
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 private static final String FACADE_PATH_IDENTIFIER = "uicache";
60 private static final String CATALOG_REQUEST_IDENTIFIER = "/v1/catalog";
61 private static final String ARCHIVE_PATH_IDENTIFIER = String.format("%s/archive/", CATALOG_REQUEST_IDENTIFIER);
62 private static final String HOME_REQUEST_IDENTIFIER = "/v1/followed";
63 private static Logger log = Logger.getLogger(FeProxyServlet.class.getName());
64 private static String msUrl;
67 protected String rewriteTarget(HttpServletRequest request) {
68 String originalUrl = "";
69 String redirectedUrl = "";
71 logFeRequest(request);
72 originalUrl = request.getRequestURL().toString();
73 Configuration config = getConfiguration(request);
75 log.error("failed to retrieve configuration.");
77 if (isMsRequest(request.getRequestURL().toString())) {
78 redirectedUrl = redirectMsRequestToMservice(request, config);
80 redirectedUrl = getModifiedUrl(config, getPluginConfiguration(request), request.getRequestURI(), getQueryString(request));
82 } catch (MalformedURLException mue) {
83 FeEcompErrorManager.getInstance().logFeHttpLoggingError("FE Request");
84 log.error(EcompLoggerErrorCode.DATA_ERROR, "FeProxyServlet rewriteTarget", "sdc-FE", "Malformed URL Exception: ", mue);
85 } catch (Exception e) {
86 log.error(EcompLoggerErrorCode.UNKNOWN_ERROR, "FeProxyServlet rewriteTarget", "sdc-FE", "Unexpected FE request processing error: ", e);
88 if (log.isDebugEnabled()) {
89 log.debug("FeProxyServlet Redirecting request from: {} , to: {}", originalUrl, redirectedUrl);
95 protected void addProxyHeaders(HttpServletRequest clientRequest, Request proxyRequest) {
96 Configuration config = getConfiguration(clientRequest);
98 log.error("Failed to retrieve configuration. Adding proxy header failed.");
101 BasicAuthConfig basicAuth = config.getBasicAuth();
102 if (basicAuth.isEnabled()) {
103 proxyRequest.header(HttpHeader.AUTHORIZATION,
104 "Basic " + Base64.getEncoder().encodeToString((basicAuth.getUserName() + ":" + basicAuth.getUserPass()).getBytes()));
106 super.addProxyHeaders(clientRequest, proxyRequest);
109 private void logFeRequest(HttpServletRequest httpRequest) {
110 LogHandler.logFeRequest(httpRequest);
111 inHttpRequest(httpRequest);
114 private void logFeResponse(HttpServletRequest request, Response proxyResponse) {
115 LogHandler.logFeResponse(request);
116 outHttpResponse(proxyResponse);
119 // Extracted for purpose of clear method name, for logback %M parameter
120 private void inHttpRequest(HttpServletRequest httpRequest) {
121 log.info("{} {} {}", httpRequest.getMethod(), httpRequest.getRequestURI(), httpRequest.getProtocol());
124 // Extracted for purpose of clear method name, for logback %M parameter
125 private void outHttpResponse(Response proxyResponse) {
126 log.info("SC=\"{}\"", proxyResponse.getStatus());
129 private String getModifiedUrl(Configuration config, PluginsConfiguration pluginConf, String uri, String queryString)
130 throws MalformedURLException {
131 if (config == null) {
132 log.error(EcompLoggerErrorCode.UNKNOWN_ERROR, "FeProxyServlet getModifiedUrl", "sdc-FE", "failed to retrieve configuration.");
133 throw new RuntimeException("failed to read FE configuration");
139 if (uri.contains(ONBOARDING_CONTEXT)) {
140 uri = uri.replace(SDC1_FE_PROXY + ONBOARDING_CONTEXT, ONBOARDING_CONTEXT);
141 protocol = config.getOnboarding().getProtocolBe();
142 host = config.getOnboarding().getHostBe();
143 port = config.getOnboarding().getPortBe().toString();
144 } else if (uri.contains(DCAED_CONTEXT)) {
145 uri = uri.replace(SDC1_FE_PROXY + DCAED_CONTEXT, DCAED_CONTEXT);
146 protocol = config.getBeProtocol();
147 host = config.getBeHost();
148 if (config.getBeProtocol().equals(BeProtocol.HTTP.getProtocolName())) {
149 port = config.getBeHttpPort().toString();
151 port = config.getBeSslPort().toString();
153 } else if (uri.contains(WORKFLOW_CONTEXT)) {
154 uri = uri.replace(SDC1_FE_PROXY + WORKFLOW_CONTEXT, WORKFLOW_CONTEXT);
155 String workflowPluginURL = pluginConf.getPluginsList().stream()
156 .filter(plugin -> plugin.getPluginId().equalsIgnoreCase(PLUGIN_ID_WORKFLOW)).map(Plugin::getPluginDiscoveryUrl).findFirst()
158 java.net.URL workflowURL = new URL(workflowPluginURL);
159 protocol = workflowURL.getProtocol();
160 host = workflowURL.getHost();
161 path = workflowURL.getPath();
162 port = String.valueOf(workflowURL.getPort());
164 uri = uri.replace(SDC1_FE_PROXY, "/sdc2");
165 protocol = config.getBeProtocol();
166 host = config.getBeHost();
167 if (config.getBeProtocol().equals(BeProtocol.HTTP.getProtocolName())) {
168 port = config.getBeHttpPort().toString();
170 port = config.getBeSslPort().toString();
173 final String authority = getAuthority(host, port);
174 String modifiedUrl = String.format(URL, protocol, authority, path, uri);
175 if (StringUtils.isNotEmpty(queryString)) {
176 modifiedUrl += "?" + queryString;
182 String redirectMsRequestToMservice(HttpServletRequest request, Configuration config) throws MalformedURLException {
183 boolean isMsToggledOn = isMsToggleOn(config);
184 String redirectValue;
186 redirectValue = handleMsToggleOnRedirect(request, config);
188 redirectValue = handleMsToggleOffRedirect(request, config);
190 return redirectValue;
193 private PluginsConfiguration getPluginConfiguration(HttpServletRequest request) {
194 return ((ConfigurationManager) request.getSession().getServletContext().getAttribute(Constants.CONFIGURATION_MANAGER_ATTR))
195 .getPluginsConfiguration();
198 private boolean isMsToggleOn(Configuration config) {
199 boolean toggleOn = true;
200 final CatalogFacadeMsConfig catalogFacadeMs = config.getCatalogFacadeMs();
201 if (catalogFacadeMs == null) {
204 } else if (isEmpty(catalogFacadeMs.getHealthCheckUri())) {
206 } else if (isEmpty(catalogFacadeMs.getHost())) {
208 } else if (isEmpty(catalogFacadeMs.getPath())) {
210 } else if (isEmpty(catalogFacadeMs.getProtocol())) {
212 } else if (catalogFacadeMs.getPort() == null) {
218 private String handleMsToggleOffRedirect(HttpServletRequest request, Configuration config) throws MalformedURLException {
219 String redirectValue;
220 String currentURI = request.getRequestURI();
221 if (isEmpty(request.getQueryString())) {
223 if (currentURI.endsWith(CATALOG_REQUEST_IDENTIFIER)) {
224 String facadeSuffix = String.format("%s%s", FACADE_PATH_IDENTIFIER, CATALOG_REQUEST_IDENTIFIER);
225 String nonFacadeUrl = currentURI.replace(facadeSuffix, "rest/v1/screen");
226 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), nonFacadeUrl,
227 "excludeTypes=VFCMT&excludeTypes=Configuration");
230 else if (currentURI.endsWith(HOME_REQUEST_IDENTIFIER)) {
231 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), currentURI, getQueryString(request));
234 else if (currentURI.endsWith(ARCHIVE_PATH_IDENTIFIER)) {
235 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), currentURI, getQueryString(request));
237 String message = String.format("facade is toggled off, Could not rediret url %s", currentURI);
239 throw new NotImplementedException(message);
243 if (currentURI.contains("/latestversion/notabstract/metadata")) {
244 String nonFacadeUrl = currentURI.replace(FACADE_PATH_IDENTIFIER, "rest");
245 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), nonFacadeUrl, getQueryString(request));
247 // Catalog with Query Params
248 else if (currentURI.endsWith(CATALOG_REQUEST_IDENTIFIER)) {
249 String facadeSuffix = String.format("%s%s", FACADE_PATH_IDENTIFIER, CATALOG_REQUEST_IDENTIFIER);
250 String nonFacadeUrl = currentURI.replace(facadeSuffix, "rest/v1/screen");
251 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), nonFacadeUrl,
252 "excludeTypes=VFCMT&excludeTypes=Configuration");
254 String message = String
255 .format("facade is toggled off, Could not rediret url %s with query params %s", currentURI, getQueryString(request));
257 throw new NotImplementedException(message);
260 return redirectValue;
263 private String handleMsToggleOnRedirect(HttpServletRequest request, Configuration config) {
264 String currentUrl = request.getRequestURL().toString();
265 if (StringUtils.isEmpty(msUrl)) {
267 msUrl = String.format(MS_URL, config.getCatalogFacadeMs().getProtocol(), config.getCatalogFacadeMs().getHost(),
268 config.getCatalogFacadeMs().getPort());
272 String msPath = config.getCatalogFacadeMs().getPath();
273 if (currentUrl.endsWith(ARCHIVE_PATH_IDENTIFIER)) {
274 url = new StringBuilder(msUrl + msPath + CATALOG_REQUEST_IDENTIFIER);
275 queryString = "arc=true";
277 url = new StringBuilder(msUrl + currentUrl.substring(currentUrl.indexOf(msPath)));
278 queryString = request.getQueryString();
280 if (queryString != null) {
281 url.append("?").append(queryString);
283 if (log.isDebugEnabled()) {
284 log.debug("Redirect catalog request to {}", url.toString());
286 return url.toString();
290 boolean isMsRequest(String currentUrl) {
291 return currentUrl.contains(FACADE_PATH_IDENTIFIER) || currentUrl.endsWith(ARCHIVE_PATH_IDENTIFIER);
294 private Configuration getConfiguration(HttpServletRequest request) {
295 return ((ConfigurationManager) request.getSession().getServletContext().getAttribute(Constants.CONFIGURATION_MANAGER_ATTR))
299 private String getAuthority(String host, String port) {
304 authority = host + ":" + port;
309 private String getQueryString(HttpServletRequest request) {
310 final String queryString = request.getQueryString();
311 return StringUtils.isEmpty(queryString) ? StringUtils.EMPTY : queryString;