From 451a3400b76511393c62a444f588a4ed15f4a549 Mon Sep 17 00:00:00 2001 From: Michael Lando Date: Sun, 19 Feb 2017 10:28:42 +0200 Subject: Initial OpenECOMP SDC commit Change-Id: I0924d5a6ae9cdc161ae17c68d3689a30d10f407b Signed-off-by: Michael Lando --- .../main/java/org/openecomp/sdc/fe/Constants.java | 15 ++ .../org/openecomp/sdc/fe/client/BackendClient.java | 179 +++++++++++++ .../main/java/org/openecomp/sdc/fe/impl/Audit.java | 73 ++++++ .../org/openecomp/sdc/fe/impl/CrudOperation.java | 26 ++ .../org/openecomp/sdc/fe/impl/HttpRequestInfo.java | 77 ++++++ .../org/openecomp/sdc/fe/impl/ImportMetadata.java | 80 ++++++ .../sdc/fe/listen/FEAppContextListener.java | 85 +++++++ .../sdc/fe/listen/MyObjectMapperProvider.java | 49 ++++ .../sdc/fe/servlets/ConfigMgrServlet.java | 88 +++++++ .../openecomp/sdc/fe/servlets/ConfigServlet.java | 114 +++++++++ .../sdc/fe/servlets/FeHealthCheckServlet.java | 49 ++++ .../openecomp/sdc/fe/servlets/FeProxyServlet.java | 214 ++++++++++++++++ .../sdc/fe/servlets/HealthCheckService.java | 219 ++++++++++++++++ .../openecomp/sdc/fe/servlets/KibanaServlet.java | 98 ++++++++ .../openecomp/sdc/fe/servlets/PortalServlet.java | 279 +++++++++++++++++++++ .../openecomp/sdc/fe/servlets/SSLProxyServlet.java | 108 ++++++++ 16 files changed, 1753 insertions(+) create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/Constants.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/client/BackendClient.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/Audit.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/CrudOperation.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/HttpRequestInfo.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/ImportMetadata.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/listen/FEAppContextListener.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/listen/MyObjectMapperProvider.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/ConfigMgrServlet.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/ConfigServlet.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeHealthCheckServlet.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeProxyServlet.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/HealthCheckService.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/KibanaServlet.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java create mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/SSLProxyServlet.java (limited to 'catalog-fe/src/main/java') diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/Constants.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/Constants.java new file mode 100644 index 0000000000..e157efcda9 --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/Constants.java @@ -0,0 +1,15 @@ +package org.openecomp.sdc.fe; + +public class Constants { + + public static String HTTP_IV_USER = "HTTP_IV_USER"; + public static String USER_ID = "USER_ID"; + public static String HTTP_CSP_FIRSTNAME = "HTTP_CSP_FIRSTNAME"; + public static String HTTP_CSP_LASTNAME = "HTTP_CSP_LASTNAME"; + public static String HTTP_IV_REMOTE_ADDRESS = "HTTP_IV_REMOTE_ADDRESS"; + public static String HTTP_CSP_WSTYPE = "HTTP_CSP_WSTYPE"; + public static String HTTP_CSP_EMAIL = "HTTP_CSP_EMAIL"; + + public static final String WEBSEAL_USER_ID_HEADER = "csp-attuid"; + +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/client/BackendClient.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/client/BackendClient.java new file mode 100644 index 0000000000..93e17144c0 --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/client/BackendClient.java @@ -0,0 +1,179 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.client; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.ws.rs.container.AsyncResponse; +import javax.ws.rs.core.Response; + +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.entity.InputStreamEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.api.ResponseInfo; +import org.openecomp.sdc.common.api.ResponseInfo.ResponseStatusEnum; +import org.openecomp.sdc.fe.impl.Audit; +import org.openecomp.sdc.fe.impl.HttpRequestInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BackendClient { + + private static Logger log = LoggerFactory.getLogger(BackendClient.class.getName()); + + private HostnameVerifier hostnameVerifier = null; + + private CloseableHttpClient backendHttpClient; + private String backendHost; + private String backendContext; + + public BackendClient(String protocol, String backendHost, String backendContext) { + + this.backendContext = backendContext; + hostnameVerifier = new HostnameVerifier() { + + public boolean verify(String hostname, SSLSession session) { + + return true; + } + }; + + if (protocol == null || protocol.isEmpty() || protocol.equals(Constants.HTTP)) { + backendHttpClient = HttpClients.createDefault(); + this.backendHost = Constants.HTTP + "://" + backendHost; + } else { + // NULL can be returned in case of error + backendHttpClient = getSslClient(); + this.backendHost = Constants.HTTPS + "://" + backendHost; + } + + } + + public HostnameVerifier getHostnameVerifier() { + return hostnameVerifier; + } + + private CloseableHttpClient getSslClient() { + + CloseableHttpClient httpClient = null; + try { + + // SSLContextBuilder is not thread safe + SSLContextBuilder builder = new SSLContextBuilder(); + builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); + SSLContext sslContext = builder.build(); + + httpClient = HttpClientBuilder.create().setSSLHostnameVerifier(hostnameVerifier).setSslcontext(sslContext) + .build(); + + } catch (Exception e) { + log.error("Failed to create https client", e); + return null; + } + + return httpClient; + + } + + public ResponseInfo forwardRequestToBackend(HttpRequestInfo requestInfo, List requiredHeaders, + AsyncResponse asyncResponse) { + + ResponseInfo responseInfo = null; + log.debug("forwardRequestToBackend"); + if (backendHttpClient == null) { + responseInfo = new ResponseInfo(ResponseStatusEnum.INTERNAL_ERROR, "Failed to create https client"); + Audit.error(log, requestInfo, HttpStatus.SC_INTERNAL_SERVER_ERROR); + asyncResponse.resume( + Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(responseInfo.toString()).build()); + return responseInfo; + } + + CloseableHttpResponse response = null; + int status = HttpStatus.SC_INTERNAL_SERVER_ERROR; + HttpPost httpPost = new HttpPost(backendHost + backendContext); + try { + + log.debug("Executing request {}", httpPost.getRequestLine()); + httpPost.setEntity(new InputStreamEntity(requestInfo.getRequestData())); + boolean allHeadersAreSet = copyHeadersToRequest(requiredHeaders, requestInfo, httpPost); + if (!allHeadersAreSet) { + responseInfo = new ResponseInfo(ResponseStatusEnum.MISSING_HEADERS, "Required headers are missing"); + asyncResponse + .resume(Response.status(HttpStatus.SC_BAD_REQUEST).entity(responseInfo.toString()).build()); + Audit.error(log, requestInfo, HttpStatus.SC_BAD_REQUEST); + } else { + response = backendHttpClient.execute(httpPost); + status = response.getStatusLine().getStatusCode(); + asyncResponse.resume(Response.status(status).entity(response.getEntity()).build()); + } + Audit.info(log, requestInfo, status); + + } catch (IOException e) { + log.error("connection with backend failed with exception", e); + responseInfo = new ResponseInfo(ResponseStatusEnum.INTERNAL_ERROR, e.getMessage()); + Audit.error(log, requestInfo, HttpStatus.SC_INTERNAL_SERVER_ERROR); + asyncResponse.resume( + Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(responseInfo.toString()).build()); + } finally { + try { + if (response != null) { + response.close(); + } + backendHttpClient.close(); + } catch (IOException e) { + log.error("failed to close httpClient: " + e.getMessage()); + } + + } + + return responseInfo; + + } + + private boolean copyHeadersToRequest(List requiredHeaders, HttpRequestInfo requestInfo, HttpPost httpPost) { + boolean allHeadersAreSet = false; + Map originalHeaders = requestInfo.getHeaders(); + for (String headerName : requiredHeaders) { + String headerValue = originalHeaders.get(headerName); + if (headerValue != null) { + httpPost.setHeader(headerName, headerValue); + } else { + log.error("missing required header " + headerName); + return allHeadersAreSet; + } + } + allHeadersAreSet = true; + return allHeadersAreSet; + } + +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/Audit.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/Audit.java new file mode 100644 index 0000000000..449d8a932d --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/Audit.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.impl; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.openecomp.sdc.common.api.Constants; +import org.slf4j.Logger; + +public class Audit { + + private Audit() { + } + + public static void error(Logger log, HttpRequestInfo requestInfo, int status) { + String errorMsg = "Internal Error"; + if (requestInfo != null && requestInfo.getHeaders() != null) { + Map requestHeaders = requestInfo.getHeaders(); + errorMsg = String.format(Constants.ERROR_LOG_FORMAT, requestHeaders.get(Constants.USER_ID_HEADER), + requestHeaders.get(Constants.FIRST_NAME_HEADER) + " " + + requestHeaders.get(Constants.LAST_NAME_HEADER), + requestHeaders.get(Constants.ORIGIN_HEADER), requestHeaders.get(Constants.ACCESS_HEADER), + requestInfo.getRequestURL(), status); + } + log.error(errorMsg); + } + + public static void error(Logger log, HttpServletRequest request, int status) { + String errorMsg = "Internal Error"; + if (request != null) { + + errorMsg = String.format(Constants.ERROR_LOG_FORMAT, request.getHeader(Constants.USER_ID_HEADER), + request.getHeader(Constants.FIRST_NAME_HEADER) + " " + + request.getHeader(Constants.LAST_NAME_HEADER), + request.getHeader(Constants.ORIGIN_HEADER), request.getHeader(Constants.ACCESS_HEADER), + request.getRequestURL(), status); + } + log.error(errorMsg); + } + + public static void info(Logger log, HttpRequestInfo requestInfo, int status) { + String errorMsg = "Internal Error"; + if (requestInfo != null && requestInfo.getHeaders() != null) { + Map requestHeaders = requestInfo.getHeaders(); + errorMsg = String.format(Constants.ERROR_LOG_FORMAT, requestHeaders.get(Constants.USER_ID_HEADER), + requestHeaders.get(Constants.FIRST_NAME_HEADER) + " " + + requestHeaders.get(Constants.LAST_NAME_HEADER), + requestHeaders.get(Constants.ORIGIN_HEADER), requestHeaders.get(Constants.ACCESS_HEADER), + requestInfo.getRequestURL(), status); + } + log.info(errorMsg); + } +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/CrudOperation.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/CrudOperation.java new file mode 100644 index 0000000000..27fc02c00a --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/CrudOperation.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.impl; + +public enum CrudOperation { + + CREATE, RETRIEVE, UPDATE, DELETE +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/HttpRequestInfo.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/HttpRequestInfo.java new file mode 100644 index 0000000000..6a2a41fe1d --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/HttpRequestInfo.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.impl; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +public class HttpRequestInfo { + + public HttpRequestInfo(HttpServletRequest request, Map headersMap, String data) { + headers = headersMap; + requestURL = request.getRequestURI(); + requestData = new ByteArrayInputStream(data.getBytes()); + originServletContext = request.getContextPath(); + } + + private Map headers; + private String requestURL; + private InputStream requestData; + private String originServletContext; + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public String getRequestURL() { + return requestURL; + } + + public void setRequestURL(String requestURL) { + this.requestURL = requestURL; + } + + public InputStream getRequestData() { + return requestData; + } + + public void setRequestData(InputStream requestData) { + this.requestData = requestData; + } + + public String getOriginServletContext() { + return originServletContext; + } + + public void setOriginServletContext(String originServletContext) { + this.originServletContext = originServletContext; + } +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/ImportMetadata.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/ImportMetadata.java new file mode 100644 index 0000000000..0d0aa7bd4c --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/impl/ImportMetadata.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.impl; + +public class ImportMetadata { + + private String name; + private long size; + private String mime; + private String creator; + private String md5Checksum; + + public ImportMetadata(String name, long size, String mime, String creator, String md5Checksum) { + super(); + this.name = name; + this.size = size; + this.mime = mime; + this.creator = creator; + this.md5Checksum = md5Checksum; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public String getMime() { + return mime; + } + + public void setMime(String mime) { + this.mime = mime; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public String getMd5Checksum() { + return md5Checksum; + } + + public void setMd5Checksum(String md5Checksum) { + this.md5Checksum = md5Checksum; + } + +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/listen/FEAppContextListener.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/listen/FEAppContextListener.java new file mode 100644 index 0000000000..b132c46866 --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/listen/FEAppContextListener.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.listen; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.impl.ExternalConfiguration; +import org.openecomp.sdc.common.listener.AppContextListener; +import org.openecomp.sdc.fe.config.ConfigurationManager; +import org.openecomp.sdc.fe.monitoring.FeMonitoringService; +import org.openecomp.sdc.fe.servlets.HealthCheckService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FEAppContextListener extends AppContextListener implements ServletContextListener { + + private static Logger log = LoggerFactory.getLogger(FEAppContextListener.class.getName()); + + public void contextInitialized(ServletContextEvent context) { + + super.contextInitialized(context); + + ConfigurationManager configurationManager = new ConfigurationManager( + ExternalConfiguration.getConfigurationSource()); + log.debug("loading configuration from configDir:{} appName:{}", ExternalConfiguration.getConfigDir(), + ExternalConfiguration.getAppName()); + context.getServletContext().setAttribute(Constants.CONFIGURATION_MANAGER_ATTR, configurationManager); + + // Health Check service + HealthCheckService hcs = new HealthCheckService(context.getServletContext()); + hcs.start(configurationManager.getConfiguration().getHealthCheckIntervalInSeconds(5)); + context.getServletContext().setAttribute(Constants.HEALTH_CHECK_SERVICE_ATTR, hcs); + + // Monitoring service + FeMonitoringService fms = new FeMonitoringService(context.getServletContext()); + fms.start(configurationManager.getConfiguration().getSystemMonitoring().getProbeIntervalInSeconds(15)); + + if (configurationManager.getConfiguration() == null) { + log.debug("ERROR: configuration was not properly loaded"); + return; + } + + ExecutorService executorPool = Executors + .newFixedThreadPool(configurationManager.getConfiguration().getThreadpoolSize()); + context.getServletContext().setAttribute(Constants.THREAD_EXECUTOR_ATTR, executorPool); + + log.debug("After executing {}", this.getClass()); + } + + public void contextDestroyed(ServletContextEvent context) { + + ExecutorService executorPool = (ExecutorService) context.getServletContext() + .getAttribute(Constants.THREAD_EXECUTOR_ATTR); + if (executorPool != null) { + executorPool.shutdown(); + } + + super.contextDestroyed(context); + + } + +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/listen/MyObjectMapperProvider.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/listen/MyObjectMapperProvider.java new file mode 100644 index 0000000000..f891ba4e3f --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/listen/MyObjectMapperProvider.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.listen; + +import javax.ws.rs.ext.ContextResolver; +import javax.ws.rs.ext.Provider; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +@Provider +public class MyObjectMapperProvider implements ContextResolver { + final ObjectMapper defaultObjectMapper; + + public MyObjectMapperProvider() { + defaultObjectMapper = createDefaultMapper(); + } + + @Override + public ObjectMapper getContext(Class type) { + return defaultObjectMapper; + } + + private static ObjectMapper createDefaultMapper() { + final ObjectMapper result = new ObjectMapper(); + result.configure(SerializationFeature.INDENT_OUTPUT, true); + + return result; + } + +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/ConfigMgrServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/ConfigMgrServlet.java new file mode 100644 index 0000000000..7792225742 --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/ConfigMgrServlet.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.servlets; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; + +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.rest.api.RestConfigurationInfo; +import org.openecomp.sdc.common.servlets.BasicServlet; +import org.openecomp.sdc.fe.config.Configuration; +import org.openecomp.sdc.fe.config.ConfigurationManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Root resource (exposed at "/" path) + */ +@Path("/configmgr") +public class ConfigMgrServlet extends BasicServlet { + + private static Logger log = LoggerFactory.getLogger(ConfigMgrServlet.class.getName()); + + @GET + @Path("/get") + @Produces(MediaType.APPLICATION_JSON) + public String getConfig(@Context final HttpServletRequest request, @QueryParam("type") String type) { + + String result = null; + + ServletContext context = request.getSession().getServletContext(); + + ConfigurationManager configurationManager = (ConfigurationManager) context + .getAttribute(Constants.CONFIGURATION_MANAGER_ATTR); + + if (type == null || type.equals("configuration")) { + + Configuration configuration = configurationManager.getConfiguration(); + if (configuration == null) { + log.warn("Configuration of type " + Configuration.class + " was not found"); + } else { + log.info("The value returned from getConfig is " + configuration); + + result = gson.toJson(configuration); + + } + } else if (type.equals("rest")) { + + RestConfigurationInfo configuration = configurationManager.getRestClientConfiguration(); + if (configuration == null) { + log.warn("Configuration of type " + RestConfigurationInfo.class + " was not found"); + } else { + log.info("The value returned from getConfig is " + configuration); + + result = gson.toJson(configuration); + + } + + } + return result; + + } + +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/ConfigServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/ConfigServlet.java new file mode 100644 index 0000000000..92bb9e8743 --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/ConfigServlet.java @@ -0,0 +1,114 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.servlets; + +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.container.AsyncResponse; +import javax.ws.rs.container.Suspended; +import javax.ws.rs.container.TimeoutHandler; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.common.api.ConfigurationSource; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.servlets.BasicServlet; +import org.openecomp.sdc.fe.config.Configuration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Root resource (exposed at "/" path) + */ +@Path("/config") +public class ConfigServlet extends BasicServlet { + + private static Logger log = LoggerFactory.getLogger(ConfigServlet.class.getName()); + + @GET + @Path("/get") + @Produces(MediaType.APPLICATION_JSON) + public String getConfig(@Context final HttpServletRequest request) { + + String result = null; + + ServletContext context = request.getSession().getServletContext(); + + ConfigurationSource configurationSource = (ConfigurationSource) context + .getAttribute(Constants.CONFIGURATION_SOURCE_ATTR); + if (configurationSource != null) { + Configuration configuration = configurationSource.getAndWatchConfiguration(Configuration.class, null); + + if (configuration == null) { + log.warn("Configuration of type " + Configuration.class + " was not found"); + } + log.debug("{}", configuration); + if (log.isInfoEnabled()) { + log.info("Info level ENABLED..."); + } + log.info("The value returned from getConfig is " + configuration); + + result = gson.toJson(configuration); + + } else { + log.warn("Source Configuration object was not initialized in the context."); + } + + return result; + + } + + @GET + @Path("/asyncget") + public void asyncGet(@Suspended final AsyncResponse asyncResponse) { + + asyncResponse.setTimeoutHandler(new TimeoutHandler() { + + @Override + public void handleTimeout(AsyncResponse asyncResponse) { + asyncResponse.resume( + Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("Operation time out.").build()); + } + }); + asyncResponse.setTimeout(3, TimeUnit.SECONDS); + + new Thread(new Runnable() { + @Override + public void run() { + String result = veryExpensiveOperation(); + asyncResponse.resume(result); + } + + private String veryExpensiveOperation() { + + return "veryExpensiveOperation SUCCESS"; + + } + }).start(); + } + +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeHealthCheckServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeHealthCheckServlet.java new file mode 100644 index 0000000000..da5b321339 --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeHealthCheckServlet.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.servlets; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.servlets.BasicServlet; + +import com.jcabi.aspects.Loggable; + +@Loggable(prepend = true, value = Loggable.TRACE, trim = false) +@Path("/healthCheck") +public class FeHealthCheckServlet extends BasicServlet { + + // private static Logger log = + // LoggerFactory.getLogger(FeHealthCheckServlet.class.getName()); + + @GET + public Response getFEandBeHealthCheck(@Context final HttpServletRequest request) { + ServletContext context = request.getSession().getServletContext(); + HealthCheckService hcs = ((HealthCheckService) context.getAttribute(Constants.HEALTH_CHECK_SERVICE_ATTR)); + return hcs.getFeHealth(); + } + +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeProxyServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeProxyServlet.java new file mode 100644 index 0000000000..1cd28deb7a --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeProxyServlet.java @@ -0,0 +1,214 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.servlets; + +import java.net.URI; +import java.util.concurrent.TimeUnit; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.api.Response; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.fe.config.Configuration; +import org.openecomp.sdc.fe.config.ConfigurationManager; +import org.openecomp.sdc.fe.config.FeEcompErrorManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +public class FeProxyServlet extends SSLProxyServlet { + private static final long serialVersionUID = 1L; + private static final String URL = "%s://%s:%s%s"; + private static Logger log = LoggerFactory.getLogger(FeProxyServlet.class.getName()); + private static Cache mdcDataCache = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build(); + + @Override + public URI rewriteURI(HttpServletRequest request) { + try { + logFeRequest(request); + } catch (Exception e) { + FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHttpLoggingError, "FE Request"); + FeEcompErrorManager.getInstance().logFeHttpLoggingError("FE Request"); + log.error("Unexpected FE request logging error :", e); + } + String originalUrl = request.getRequestURL().toString(); + String redirectedUrl = getModifiedUrl(request); + + log.debug("FeProxyServlet Redirecting request from: {} , to: {}", originalUrl, redirectedUrl); + + return URI.create(redirectedUrl); + } + + @Override + protected void onResponseSuccess(HttpServletRequest request, HttpServletResponse response, Response proxyResponse) { + try { + logFeResponse(request, proxyResponse); + } catch (Exception e) { + FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHttpLoggingError, "FE Response"); + FeEcompErrorManager.getInstance().logFeHttpLoggingError("FE Response"); + log.error("Unexpected FE response logging error :", e); + } + super.onResponseSuccess(request, response, proxyResponse); + } + + private void logFeRequest(HttpServletRequest httpRequest) { + + MDC.clear(); + + Long transactionStartTime = System.currentTimeMillis(); + // UUID - In FE, we are supposed to get the below header from UI. + // We do not generate it if it's missing - BE does. + String uuid = httpRequest.getHeader(Constants.X_ECOMP_REQUEST_ID_HEADER); + String serviceInstanceID = httpRequest.getHeader(Constants.X_ECOMP_SERVICE_ID_HEADER); + + if (uuid != null && uuid.length() > 0) { + // User Id for logging + String userId = httpRequest.getHeader(Constants.USER_ID_HEADER); + + String remoteAddr = httpRequest.getRemoteAddr(); + String localAddr = httpRequest.getLocalAddr(); + + mdcDataCache.put(uuid, new MdcData(serviceInstanceID, userId, remoteAddr, localAddr, transactionStartTime)); + + updateMdc(uuid, serviceInstanceID, userId, remoteAddr, localAddr, null); + } + inHttpRequest(httpRequest); + } + + private void logFeResponse(HttpServletRequest request, Response proxyResponse) { + String uuid = request.getHeader(Constants.X_ECOMP_REQUEST_ID_HEADER); + String transactionRoundTime = null; + + if (uuid != null) { + MdcData mdcData = mdcDataCache.getIfPresent(uuid); + if (mdcData != null) { + Long transactionStartTime = mdcData.getTransactionStartTime(); + if (transactionStartTime != null) {// should'n ever be null, but + // just to be defensive + transactionRoundTime = Long.toString(System.currentTimeMillis() - transactionStartTime); + } + updateMdc(uuid, mdcData.getServiceInstanceID(), mdcData.getUserId(), mdcData.getRemoteAddr(), mdcData.getLocalAddr(), transactionRoundTime); + } + } + outHttpResponse(proxyResponse); + + MDC.clear(); + } + + // Extracted for purpose of clear method name, for logback %M parameter + private void inHttpRequest(HttpServletRequest httpRequest) { + log.info("{} {} {}", httpRequest.getMethod(), httpRequest.getRequestURI(), httpRequest.getProtocol()); + } + + // Extracted for purpose of clear method name, for logback %M parameter + private void outHttpResponse(Response proxyResponse) { + log.info("SC=\"{}\"", proxyResponse.getStatus()); + } + + private void updateMdc(String uuid, String serviceInstanceID, String userId, String remoteAddr, String localAddr, String transactionStartTime) { + MDC.put("uuid", uuid); + MDC.put("serviceInstanceID", serviceInstanceID); + MDC.put("userId", userId); + MDC.put("remoteAddr", remoteAddr); + MDC.put("localAddr", localAddr); + MDC.put("timer", transactionStartTime); + } + + private class MdcData { + private String serviceInstanceID; + private String userId; + private String remoteAddr; + private String localAddr; + private Long transactionStartTime; + + public MdcData(String serviceInstanceID, String userId, String remoteAddr, String localAddr, Long transactionStartTime) { + super(); + this.serviceInstanceID = serviceInstanceID; + this.userId = userId; + this.remoteAddr = remoteAddr; + this.localAddr = localAddr; + this.transactionStartTime = transactionStartTime; + } + + public Long getTransactionStartTime() { + return transactionStartTime; + } + + public String getUserId() { + return userId; + } + + public String getRemoteAddr() { + return remoteAddr; + } + + public String getLocalAddr() { + return localAddr; + } + + public String getServiceInstanceID() { + return serviceInstanceID; + } + } + + public String getModifiedUrl(HttpServletRequest request) { + + Configuration config = getConfiguration(request); + if (config == null) { + log.error("failed to retrive configuration."); + } + String scheme = config.getBeProtocol(); + String uri = request.getRequestURI().toString(); + StringBuilder url = new StringBuilder(); + url.append(scheme).append("://").append(config.getBeHost()); + url.append(":"); + if (config.getBeProtocol().equals(BE_PROTOCOL.HTTP.getProtocolName())) { + url.append(config.getBeHttpPort()); + } else { + url.append(config.getBeSslPort()); + } + url.append(uri); + String queryString = request.getQueryString(); // d=789 + if (queryString != null) { + url.append("?").append(queryString); + } + + String redirectedUrl = url.toString(); + String onboardingForwardContext = config.getOnboardingForwardContext(); + if (onboardingForwardContext == null || onboardingForwardContext.isEmpty()) { + onboardingForwardContext = "/onboarding-api"; + } + redirectedUrl = redirectedUrl.replace("/sdc1/feProxy/onboarding-api", onboardingForwardContext); + redirectedUrl = redirectedUrl.replace("/sdc1/feProxy", "/sdc2"); + return redirectedUrl; + + } + + private Configuration getConfiguration(HttpServletRequest request) { + Configuration config = ((ConfigurationManager) request.getSession().getServletContext().getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)).getConfiguration(); + return config; + } +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/HealthCheckService.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/HealthCheckService.java new file mode 100644 index 0000000000..338e8d4c01 --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/HealthCheckService.java @@ -0,0 +1,219 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.servlets; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletContext; +import javax.ws.rs.core.Response; + +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.api.HealthCheckInfo; +import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckComponent; +import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckStatus; +import org.openecomp.sdc.common.api.HealthCheckWrapper; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.impl.ExternalConfiguration; +import org.openecomp.sdc.fe.config.Configuration; +import org.openecomp.sdc.fe.config.ConfigurationManager; +import org.openecomp.sdc.fe.config.FeEcompErrorManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +public class HealthCheckService { + + private class HealthStatus { + public String body; + public int statusCode; + + public HealthStatus(int code, String body) { + this.body = body; + this.statusCode = code; + } + } + + private static final String URL = "%s://%s:%s/sdc2/rest/healthCheck"; + private static Logger healthLogger = LoggerFactory.getLogger("asdc.fe.healthcheck"); + private static Logger log = LoggerFactory.getLogger(HealthCheckService.class.getName()); + + private HealthStatus lastHealthStatus = new HealthStatus(500, "{}"); + + private class HealthCheckScheduledTask implements Runnable { + @Override + public void run() { + healthLogger.trace("Executing FE Health Check Task - Start"); + HealthStatus currentHealth = checkHealth(); + int currentHealthStatus = currentHealth.statusCode; + healthLogger.trace("Executing FE Health Check Task - Status = {}", currentHealthStatus); + + // In case health status was changed, issue alarm/recovery + if (currentHealthStatus != lastHealthStatus.statusCode) { + log.trace("FE Health State Changed to {}. Issuing alarm / recovery alarm...", currentHealthStatus); + logFeAlarm(currentHealthStatus); + } + + // Anyway, update latest response + lastHealthStatus = currentHealth; + } + } + + /** + * This executor will execute the health check task. + */ + ScheduledExecutorService healthCheckExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "FE-Health-Check-Thread"); + } + }); + private ServletContext context; + + public HealthCheckService(ServletContext context) { + this.context = context; + } + + public void start(int interval) { + this.healthCheckExecutor.scheduleAtFixedRate(new HealthCheckScheduledTask(), 0, interval, TimeUnit.SECONDS); + } + + /** + * To be used by the HealthCheckServlet + * + * @return + */ + public Response getFeHealth() { + return this.buildResponse(lastHealthStatus.statusCode, lastHealthStatus.body); + } + + private HealthStatus checkHealth() { + CloseableHttpClient httpClient = null; + try { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + Configuration config = ((ConfigurationManager) context.getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)) + .getConfiguration(); + String redirectedUrl = String.format(URL, config.getBeProtocol(), config.getBeHost(), + config.getBeHttpPort()); + httpClient = getHttpClient(config); + HttpGet httpGet = new HttpGet(redirectedUrl); + CloseableHttpResponse beResponse; + int beStatus; + String feAggHealthCheck; + try { + beResponse = httpClient.execute(httpGet); + beStatus = beResponse.getStatusLine().getStatusCode(); + String beJsonResponse = EntityUtils.toString(beResponse.getEntity()); + feAggHealthCheck = getFeHealthCheckInfos(gson, beJsonResponse); + } catch (Exception e) { + log.error("Health Check error when trying to connect to BE", e); + String beDowneResponse = gson.toJson(getBeDownCheckInfos()); + return new HealthStatus(500, beDowneResponse); + } + return new HealthStatus(beStatus, feAggHealthCheck); + } catch (Exception e) { + FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHealthCheckGeneralError, "Unexpected FE Health check error"); + FeEcompErrorManager.getInstance().logFeHealthCheckGeneralError("Unexpected FE Health check error"); + log.error("Unexpected FE health check error {}", e.getMessage()); + return new HealthStatus(500, e.getMessage()); + } finally { + if (httpClient != null) { + try { + httpClient.close(); + } catch (IOException e) { + } + } + } + } + + private Response buildResponse(int status, String jsonResponse) { + healthLogger.trace("FE and BE health check status: {}", jsonResponse); + return Response.status(status).entity(jsonResponse).build(); + } + + private void logFeAlarm(int lastFeStatus) { + + switch (lastFeStatus) { + case 200: + FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHealthCheckRecovery, + "FE Health Recovered"); + FeEcompErrorManager.getInstance().logFeHealthCheckRecovery("FE Health Recovered"); + break; + case 500: + FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHealthCheckConnectionError, + "Connection with ASDC-BE is probably down"); + FeEcompErrorManager.getInstance().logFeHealthCheckError("Connection with ASDC-BE is probably down"); + break; + default: + break; + } + + } + + private String getFeHealthCheckInfos(Gson gson, String responseString) { + Type wrapperType = new TypeToken() { + }.getType(); + HealthCheckWrapper healthCheckWrapper = gson.fromJson(responseString, wrapperType); + String appVersion = ExternalConfiguration.getAppVersion(); + String description = "OK"; + healthCheckWrapper.getComponentsInfo() + .add(new HealthCheckInfo(HealthCheckComponent.FE, HealthCheckStatus.UP, appVersion, description)); + return gson.toJson(healthCheckWrapper); + } + + private HealthCheckWrapper getBeDownCheckInfos() { + List healthCheckInfos = new ArrayList(); + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.FE, HealthCheckStatus.UP, + ExternalConfiguration.getAppVersion(), "OK")); + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.BE, HealthCheckStatus.DOWN, null, null)); + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.ES, HealthCheckStatus.UNKNOWN, null, null)); + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.UNKNOWN, null, null)); + healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.DE, HealthCheckStatus.UNKNOWN, null, null)); + HealthCheckWrapper hcWrapper = new HealthCheckWrapper(healthCheckInfos, "UNKNOWN", "UNKNOWN"); + return hcWrapper; + } + + private CloseableHttpClient getHttpClient(Configuration config) { + int timeout = 3000; + int socketTimeout = config.getHealthCheckSocketTimeoutInMs(5000); + RequestConfig.Builder requestBuilder = RequestConfig.custom(); + requestBuilder.setConnectTimeout(timeout).setConnectionRequestTimeout(timeout).setSocketTimeout(socketTimeout); + + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setDefaultRequestConfig(requestBuilder.build()); + return builder.build(); + } +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/KibanaServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/KibanaServlet.java new file mode 100644 index 0000000000..64784b3265 --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/KibanaServlet.java @@ -0,0 +1,98 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.servlets; + +import java.net.URI; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.proxy.ProxyServlet; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.fe.config.Configuration; +import org.openecomp.sdc.fe.config.ConfigurationManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class KibanaServlet extends ProxyServlet { + private static final long serialVersionUID = 1L; + private static Logger log = LoggerFactory.getLogger(KibanaServlet.class.getName()); + + @Override + public URI rewriteURI(HttpServletRequest request) { + + String originalUrl = request.getRequestURI(); + + String redirectedUrl = getModifiedUrl(request); + + log.debug("KibanaServlet Redirecting request from: {} , to: {}", originalUrl, redirectedUrl); + + return URI.create(redirectedUrl); + } + + @Override + public void customizeProxyRequest(Request proxyRequest, HttpServletRequest request) { + super.customizeProxyRequest(proxyRequest, request); + + } + + @Override + protected void onResponseSuccess(HttpServletRequest request, HttpServletResponse response, Response proxyResponse) { + + super.onResponseSuccess(request, response, proxyResponse); + } + + public String getModifiedUrl(HttpServletRequest request) { + Configuration config = getConfiguration(request); + if (config == null) { + log.error("failed to retrive configuration."); + } + // String scheme = request.getScheme(); + String contextPath = request.getContextPath(); // /mywebapp + String servletPath = request.getServletPath(); // /servlet/MyServlet + String pathInfo = request.getPathInfo(); // /a/b;c=123 + String queryString = request.getQueryString(); // d=789 + + StringBuilder url = new StringBuilder(); + url.append(config.getKibanaProtocol()).append("://").append(config.getKibanaHost()); + url.append(":").append(config.getKibanaPort()); + url.append(contextPath).append(servletPath); + + if (pathInfo != null) { + url.append(pathInfo); + } + if (queryString != null) { + url.append("?").append(queryString); + } + + String redirectedUrl = url.toString().replace("/sdc1/kibanaProxy/", "/"); + return redirectedUrl; + + } + + private Configuration getConfiguration(HttpServletRequest request) { + Configuration config = ((ConfigurationManager) request.getSession().getServletContext() + .getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)).getConfiguration(); + return config; + } +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java new file mode 100644 index 0000000000..4eba2e5eb5 --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java @@ -0,0 +1,279 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.servlets; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.List; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; + +import org.openecomp.portalsdk.core.onboarding.crossapi.ECOMPSSO; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.impl.MutableHttpServletRequest; +import org.openecomp.sdc.fe.Constants; +import org.openecomp.sdc.fe.config.Configuration; +import org.openecomp.sdc.fe.config.ConfigurationManager; +import org.openecomp.sdc.fe.config.FeEcompErrorManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Root resource (exposed at "/" path) + */ +@Path("/") +public class PortalServlet extends HttpServlet { + + private static Logger log = LoggerFactory.getLogger(PortalServlet.class.getName()); + private static final long serialVersionUID = 1L; + public static final String MISSING_HEADERS_MSG = "Missing Headers In Request"; + public static final String AUTHORIZATION_ERROR_MSG = "Autherization error"; + public static final String NEW_LINE = System.getProperty("line.separator"); + + /** + * Entry point from ECOMP portal + */ + @GET + @Path("/portal") + public void doGet(@Context final HttpServletRequest request, @Context final HttpServletResponse response) { + try { + addRequestHeadersUsingWebseal(request, response); + } catch (Exception e) { + FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FePortalServletError, "Portal Servlet"); + FeEcompErrorManager.getInstance().logFePortalServletError("Portal Servlet"); + log.error("Error during getting portal page", e); + } + } + + /** + * Building new HTTP request and setting headers for the request The request + * will dispatch to index.html + * + * @param request + * @param response + * @throws ServletException + * @throws IOException + */ + private void addRequestHeadersUsingWebseal(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { + + response.setContentType("text/html"); + + // Create new request object to dispatch + MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(request); + + // Get configuration object (reads data from configuration.yaml) + Configuration configuration = getConfiguration(request); + + // Check if we got header from webseal + String userId = request.getHeader(Constants.WEBSEAL_USER_ID_HEADER); + if (null == userId) { + // Authentication via ecomp portal + try { + String valdiateECOMPSSO = ECOMPSSO.valdiateECOMPSSO(request); + String userIdFromCookie = ECOMPSSO.getUserIdFromCookie(request); + if (valdiateECOMPSSO == null || ("").equals(userIdFromCookie)) { + // This is probably a webseal request, so missing header in request should be printed. + response.sendError(HttpServletResponse.SC_USE_PROXY, MISSING_HEADERS_MSG); + } + userId = userIdFromCookie; + } catch (Exception e) { + response.sendError(HttpServletResponse.SC_USE_PROXY, AUTHORIZATION_ERROR_MSG); + } + } + + // Replace webseal header with open source header + mutableRequest.putHeader(Constants.USER_ID, userId); + + // Getting identification headers from configuration.yaml + // (identificationHeaderFields) and setting them to new request + // mutableRequest + List> identificationHeaderFields = configuration.getIdentificationHeaderFields(); + for (List possibleHeadersToRecieve : identificationHeaderFields) { + String allowedHeaderToPass = possibleHeadersToRecieve.get(0); + setNewHeader(possibleHeadersToRecieve, allowedHeaderToPass, request, mutableRequest); + } + + // Getting optional headers from configuration.yaml + // (optionalHeaderFields) and setting them to new request mutableRequest + List> optionalHeaderFields = configuration.getOptionalHeaderFields(); + for (List possibleHeadersToRecieve : optionalHeaderFields) { + String allowedHeaderToPass = possibleHeadersToRecieve.get(0); + setNewHeader(possibleHeadersToRecieve, allowedHeaderToPass, request, mutableRequest); + } + + // Print headers from original request for debug purposes + printHeaders(request); + + // In case using webseal, validate all mandatory headers (identificationHeaderFields) are included in the new request (mutableRequest). + // Via ecomp portal do not need to check the headers. + boolean allHeadersExist = true; + if (null != request.getHeader(Constants.WEBSEAL_USER_ID_HEADER)) { + allHeadersExist = checkHeaders(mutableRequest); + } + + if (allHeadersExist) { + addCookies(response, mutableRequest, getMandatoryHeaders(request)); + addCookies(response, mutableRequest, getOptionalHeaders(request)); + RequestDispatcher rd = request.getRequestDispatcher("index.html"); + rd.forward(mutableRequest, response); + } else { + response.sendError(HttpServletResponse.SC_USE_PROXY, MISSING_HEADERS_MSG); + } + } + + /** + * Print all request headers to the log + * + * @param request + */ + private void printHeaders(HttpServletRequest request) { + + if (log.isDebugEnabled()) { + StringBuilder builder = new StringBuilder(); + String sessionId = ""; + if (request.getSession() != null) { + String id = request.getSession().getId(); + if (id != null) { + sessionId = id; + } + } + + builder.append("Receiving request with headers:" + NEW_LINE); + log.debug("{}", request.getHeaderNames()); + @SuppressWarnings("unchecked") + Enumeration headerNames = request.getHeaderNames(); + if (headerNames != null) { + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + String headerValue = request.getHeader(headerName); + builder.append("session " + sessionId + " header: name = " + headerName + ", value = " + headerValue + NEW_LINE); + } + } + + log.debug(builder.toString()); + } + + } + + /** + * Add cookies (that where set in the new request headers) in the response + * + * @param response + * @param request + * @param headers + */ + private void addCookies(HttpServletResponse response, HttpServletRequest request, String[] headers) { + for (int i = 0; i < headers.length; i++) { + String currHeader = headers[i]; + String headerValue = request.getHeader(currHeader); + if (headerValue != null) { + response.addCookie(new Cookie(currHeader, headerValue)); + } + } + } + + /** + * Get mandatory headers (identificationHeaderFields) String array, and + * checks that each header exists in the new request + * + * @param request + * @return boolean + */ + private boolean checkHeaders(HttpServletRequest request) { + String[] mandatoryHeaders = getMandatoryHeaders(request); + + boolean allHeadersExist = true; + for (int i = 0; i < mandatoryHeaders.length; i++) { + String headerValue = request.getHeader(mandatoryHeaders[i]); + if (headerValue == null) { + allHeadersExist = false; + break; + } + } + return allHeadersExist; + } + + /** + * Get mandatory headers (identificationHeaderFields) from + * configuration.yaml file and return String[] + * + * @param request + * @return String[] + */ + private String[] getMandatoryHeaders(HttpServletRequest request) { + Configuration configuration = getConfiguration(request); + List> identificationHeaderFields = configuration.getIdentificationHeaderFields(); + String[] mandatoryHeaders = new String[identificationHeaderFields.size()]; + for (int i = 0; i < identificationHeaderFields.size(); i++) { + mandatoryHeaders[i] = identificationHeaderFields.get(i).get(0); + } + return mandatoryHeaders; + } + + /** + * Get optional headers (optionalHeaderFields) from configuration.yaml file + * and return String[] + * + * @param request + * @return String[] + */ + private String[] getOptionalHeaders(HttpServletRequest request) { + Configuration configuration = getConfiguration(request); + List> optionalHeaderFields = configuration.getOptionalHeaderFields(); + String[] optionalHeaders = new String[optionalHeaderFields.size()]; + for (int i = 0; i < optionalHeaderFields.size(); i++) { + optionalHeaders[i] = optionalHeaderFields.get(i).get(0); + } + return optionalHeaders; + } + + /** + * Return Configuration object to read from configuration.yaml + * + * @param request + * @return Configuration + */ + private Configuration getConfiguration(HttpServletRequest request) { + ConfigurationManager configManager = (ConfigurationManager) request.getSession().getServletContext().getAttribute(org.openecomp.sdc.common.api.Constants.CONFIGURATION_MANAGER_ATTR); + return configManager.getConfiguration(); + } + + private boolean setNewHeader(List possibleOldHeaders, String newHeaderToSet, HttpServletRequest oldRequest, MutableHttpServletRequest newRequest) { + boolean newHeaderIsSet = false; + for (int i = 0; i < possibleOldHeaders.size() && !newHeaderIsSet; i++) { + String headerValue = oldRequest.getHeader(possibleOldHeaders.get(i)); + if (headerValue != null) { + newRequest.putHeader(newHeaderToSet, headerValue); + newHeaderIsSet = true; + } + } + return newHeaderIsSet; + } + +} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/SSLProxyServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/SSLProxyServlet.java new file mode 100644 index 0000000000..c3ba279c8c --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/SSLProxyServlet.java @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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.openecomp.sdc.fe.servlets; + +import java.util.Enumeration; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.proxy.ProxyServlet; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.fe.config.Configuration; +import org.openecomp.sdc.fe.config.ConfigurationManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class SSLProxyServlet extends ProxyServlet { + + private static final long serialVersionUID = 1L; + private static Logger log = LoggerFactory.getLogger(SSLProxyServlet.class.getName()); + + public enum BE_PROTOCOL { + HTTP("http"), SSL("ssl"); + private String protocolName; + + public String getProtocolName() { + return protocolName; + } + + BE_PROTOCOL(String protocolName) { + this.protocolName = protocolName; + } + }; + + @Override + public void customizeProxyRequest(Request proxyRequest, HttpServletRequest request) { + super.customizeProxyRequest(proxyRequest, request); + // Add Missing Headers to proxy request + @SuppressWarnings("unchecked") + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + if (!proxyRequest.getHeaders().containsKey(headerName)) { + String headerVal = request.getHeader(headerName); + log.debug("Adding missing header to request, header name: {} , header value: {}", headerName, + headerVal); + proxyRequest.header(headerName, headerVal); + } + } + proxyRequest.getHeaders().remove(HttpHeader.HOST); + + } + + @Override + protected HttpClient createHttpClient() throws ServletException { + Configuration config = ((ConfigurationManager) getServletConfig().getServletContext() + .getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)).getConfiguration(); + boolean isSecureClient = !config.getBeProtocol().equals(BE_PROTOCOL.HTTP.getProtocolName()); + HttpClient client = (isSecureClient) ? getSecureHttpClient() : super.createHttpClient(); + setTimeout(600000); + client.setIdleTimeout(600000); + client.setStopTimeout(600000); + + return client; + } + + private HttpClient getSecureHttpClient() throws ServletException { + // Instantiate and configure the SslContextFactory + SslContextFactory sslContextFactory = new SslContextFactory(true); + + // Instantiate HttpClient with the SslContextFactory + HttpClient httpClient = new HttpClient(sslContextFactory); + + // Configure HttpClient, for example: + httpClient.setFollowRedirects(false); + + // Start HttpClient + try { + httpClient.start(); + + return httpClient; + } catch (Exception x) { + throw new ServletException(x); + } + } +} -- cgit 1.2.3-korg