Fix potential NPE
[sdc.git] / catalog-fe / src / main / java / org / openecomp / sdc / fe / servlets / FeProxyServlet.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
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
21 package org.openecomp.sdc.fe.servlets;
22
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;
42
43 import javax.servlet.http.HttpServletRequest;
44 import java.net.MalformedURLException;
45 import java.net.URL;
46
47 import static org.apache.commons.lang3.StringUtils.isEmpty;
48
49
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());
62
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";
68         @Override
69         protected String rewriteTarget(HttpServletRequest request) {
70                 String originalUrl="";
71                 String redirectedUrl = "";
72
73                 try {
74                         logFeRequest(request);
75                         originalUrl = request.getRequestURL().toString();
76
77                         Configuration config = getConfiguration(request);
78                         if (config == null) {
79                                 log.error("failed to retrieve configuration.");
80                         }
81                         if (isMsRequest(request.getRequestURL().toString())) {
82                                 redirectedUrl = redirectMsRequestToMservice(request, config);
83                         } else {
84                                 redirectedUrl = getModifiedUrl(config, getPluginConfiguration(request), request.getRequestURI(), getQueryString(request));
85                         }
86                 }
87                 catch (MalformedURLException mue) {
88                         FeEcompErrorManager.getInstance().logFeHttpLoggingError("FE Request");
89                         log.error(EcompLoggerErrorCode.DATA_ERROR, "FeProxyServlet rewriteTarget", "sdc-FE", "Malformed URL Exception: ", mue);
90                 }
91                 catch (Exception e) {
92             log.error(EcompLoggerErrorCode.UNKNOWN_ERROR,"FeProxyServlet rewriteTarget", "sdc-FE", "Unexpected FE request processing error: ", e);
93                 }
94                 if (log.isDebugEnabled()) {
95                         log.debug("FeProxyServlet Redirecting request from: {} , to: {}", originalUrl, redirectedUrl);
96                 }
97
98                 return redirectedUrl;
99         }
100
101         @Override
102         protected void addProxyHeaders(HttpServletRequest clientRequest, Request proxyRequest)
103         {
104                 Configuration config = getConfiguration(clientRequest);
105                 if (config == null) {
106                         log.error("Failed to retrieve configuration. Adding proxy header failed.");
107                         return;
108                 }
109                 BasicAuthConfig basicAuth = config.getBasicAuth();
110                 if (basicAuth.getEnabled()) {
111                         proxyRequest.header(HttpHeader.AUTHORIZATION,
112                                 "Basic " + Base64.getEncoder().encodeToString((basicAuth.getUserName() + ":" + basicAuth.getUserPass()).getBytes()));
113                 }
114                 super.addProxyHeaders(clientRequest, proxyRequest);
115         }
116
117         private void logFeRequest(HttpServletRequest httpRequest){
118                 LogHandler.logFeRequest(httpRequest);
119                 inHttpRequest(httpRequest);
120         }
121
122         private void logFeResponse(HttpServletRequest request, Response proxyResponse){
123                 LogHandler.logFeResponse(request);
124                 outHttpResponse(proxyResponse);
125         }
126
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());
130         }
131
132         // Extracted for purpose of clear method name, for logback %M parameter
133         private void outHttpResponse(Response proxyResponse) {
134                 log.info("SC=\"{}\"", proxyResponse.getStatus());
135         }
136
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");
141                 }
142                 String protocol;
143                 String host;
144                 String port;
145                 String path = "";
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();
157                         } else {
158                                 port = config.getBeSslPort().toString();
159                         }
160                 }
161                 else if (uri.contains(WORKFLOW_CONTEXT)){
162                         uri = uri.replace(SDC1_FE_PROXY +WORKFLOW_CONTEXT,WORKFLOW_CONTEXT);
163                         String workflowPluginURL = pluginConf.getPluginsList()
164                                         .stream()
165                                         .filter(plugin -> plugin.getPluginId().equalsIgnoreCase(PLUGIN_ID_WORKFLOW))
166                                         .map(Plugin::getPluginDiscoveryUrl)
167                                         .findFirst().orElse(null);
168
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());
174                 }
175                 else{
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();
181                         } else {
182                                 port = config.getBeSslPort().toString();
183                         }
184                 }       
185
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;
190                 }
191                  
192                 return modifiedUrl;
193         }
194
195         @VisibleForTesting
196         String redirectMsRequestToMservice(HttpServletRequest request, Configuration config) throws MalformedURLException {
197
198                 boolean isMsToggledOn = isMsToggleOn(config);
199                 String redirectValue;
200                 if (isMsToggledOn) {
201                         redirectValue = handleMsToggleOnRedirect(request, config);
202                 } else {
203                         redirectValue = handleMsToggleOffRedirect(request, config);
204                 }
205                 return redirectValue;
206         }
207 private PluginsConfiguration getPluginConfiguration(HttpServletRequest request) {
208                 return ((ConfigurationManager) request.getSession().getServletContext().getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)).getPluginsConfiguration();
209   }
210         private boolean isMsToggleOn(Configuration config) {
211                 boolean toggleOn = true;
212                 final CatalogFacadeMsConfig catalogFacadeMs = config.getCatalogFacadeMs();
213                 if (catalogFacadeMs == null) {
214                         toggleOn = false;
215                         ;
216                 } else if (isEmpty(catalogFacadeMs.getHealthCheckUri())) {
217                         toggleOn = false;
218                 } else if (isEmpty(catalogFacadeMs.getHost())) {
219                         toggleOn = false;
220                 } else if (isEmpty(catalogFacadeMs.getPath())) {
221                         toggleOn = false;
222                 } else if (isEmpty(catalogFacadeMs.getProtocol())) {
223                         toggleOn = false;
224                 } else if (catalogFacadeMs.getPort() == null) {
225                         toggleOn = false;
226                 }
227                 return toggleOn;
228         }
229         private String handleMsToggleOffRedirect(HttpServletRequest request, Configuration config) throws MalformedURLException {
230                 String redirectValue;
231                 String currentURI = request.getRequestURI();
232                 if (isEmpty(request.getQueryString())) {
233                         // Catalog
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");
238                         }
239                         // Home
240                         else if (currentURI.endsWith(HOME_REQUEST_IDENTIFIER)){
241                                 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), currentURI, getQueryString(request));
242                         }
243                         // Archive
244                         else if (currentURI.endsWith(ARCHIVE_PATH_IDENTIFIER)) {
245                                 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), currentURI, getQueryString(request));
246                         } else {
247                                 String message = String.format("facade is toggled off, Could not rediret url %s", currentURI);
248                                 log.error(message);
249                                 throw new NotImplementedException(message);
250                         }
251                 } else {
252                         // Left Pallet
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));
256                         }
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");
262                         } else {
263                                 String message = String.format("facade is toggled off, Could not rediret url %s with query params %s",
264                                                 currentURI, getQueryString(request));
265                                 log.error(message);
266                                 throw new NotImplementedException(message);
267                         }
268                 }
269
270                 return redirectValue;
271         }
272
273   private String handleMsToggleOnRedirect(HttpServletRequest request, Configuration config) {
274                 String currentUrl = request.getRequestURL()
275                                 .toString();
276                 if (StringUtils.isEmpty(msUrl)) {
277                         // do that only once
278                         msUrl = String.format(MS_URL, config.getCatalogFacadeMs()
279                                         .getProtocol(),
280                                         config.getCatalogFacadeMs().getHost(),
281                                         config.getCatalogFacadeMs().getPort());
282                 }
283                 StringBuilder url;
284                 String queryString;
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";
289                 } else {
290                         url = new StringBuilder(msUrl + currentUrl.substring(currentUrl.indexOf(msPath)));
291                         queryString = request.getQueryString();
292                 }
293                 if (queryString != null) {
294                         url.append("?").append(queryString);
295                 }
296                 if (log.isDebugEnabled()) {
297                         log.debug("Redirect catalog request to {}", url.toString());
298                 }
299                 return url.toString();
300         }
301
302         @VisibleForTesting
303         boolean isMsRequest(String currentUrl) {
304                 return currentUrl.contains(FACADE_PATH_IDENTIFIER) || currentUrl.endsWith(ARCHIVE_PATH_IDENTIFIER);
305         }
306         private Configuration getConfiguration(HttpServletRequest request) {
307                 return ((ConfigurationManager) request.getSession().getServletContext().getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)).getConfiguration();
308         }
309
310         private String getAuthority(String host, String port) {
311                 String authority;
312                 if (port == null) {
313                         authority = host;
314                 } else {
315                         authority = host + ":" + port;
316                 }
317                 return authority;
318         }
319         
320         private String getQueryString(HttpServletRequest request){
321                 final String queryString = request.getQueryString();
322                 return StringUtils.isEmpty(queryString) ? StringUtils.EMPTY : queryString;
323         }
324
325 }