summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openecomp/sparky/security/filter
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/openecomp/sparky/security/filter')
-rw-r--r--src/main/java/org/openecomp/sparky/security/filter/CspCookieFilter.java271
-rw-r--r--src/main/java/org/openecomp/sparky/security/filter/LoginFilter.java230
2 files changed, 501 insertions, 0 deletions
diff --git a/src/main/java/org/openecomp/sparky/security/filter/CspCookieFilter.java b/src/main/java/org/openecomp/sparky/security/filter/CspCookieFilter.java
new file mode 100644
index 0000000..7140e96
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/filter/CspCookieFilter.java
@@ -0,0 +1,271 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.security.filter;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.openecomp.cl.api.Logger;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.sparky.logging.AaiUiMsgs;
+import org.openecomp.sparky.util.NodeUtils;
+import org.openecomp.sparky.viewandinspect.config.TierSupportUiConstants;
+
+import org.openecomp.cl.mdc.MdcContext;
+
+// import esGateKeeper.esGateKeeper;
+
+/**
+ * Redirects to the AT&T global login page if the user is not authenticated.<br>
+ * Filter properties need to be configured in: csp-cookie-filter.properties
+ */
+public class CspCookieFilter implements Filter {
+
+ /** Redirect URL for the login page. */
+ private String globalLoginUrl;
+
+ /** Application identifier. */
+ private String applicationId;
+
+ /** Gatekeeper environment setting (development or production). */
+ private String gateKeeperEnvironment;
+
+ private static final String FILTER_PARAMETER_CONFIG = "config";
+ private static final String PROPERTY_GLOBAL_LOGIN_URL = "global.login.url";
+ private static final String PROPERTY_APPLICATION_ID = "application.id";
+ private static final String PROPERTY_GATEKEEPER_ENVIRONMENT = "gatekeeper.environment";
+ // valid open redirect domains
+ private List<String> redirectDomains = new ArrayList<>();
+ private static final String PROPERTY_REDIRECT_DOMAINS = "redirect-domain";
+
+ /** Needed by esGateKeeper, does not accept any other value. */
+ private static final String GATEKEEPER_ACCOUNT_NAME = "CSP";
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(CspCookieFilter.class);
+
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
+ */
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "CspCookieFilter", "", "Init", "");
+
+ try {
+ setConfigurationProperties(filterConfig);
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ERROR_CSP_CONFIG_FILE);
+ throw new ServletException(exc);
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
+ */
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ Cookie[] cookies = request.getCookies();
+ if ((cookies == null) || (cookies.length == 0)) {
+ doLogin(request, response);
+ return;
+ }
+
+ /*
+ * String attEsSec = getSecurityCookie(cookies);
+ *
+ * if (attESSec == null || attESSec.length() == 0) { doLogin(request, response); return; }
+ *
+ * String attESSecUnEncrypted = esGateKeeper.esGateKeeper(attESSec, GATEKEEPER_ACCOUNT_NAME,
+ * gateKeeperEnvironment); if (attESSecUnEncrypted == null) { doLogin(request, response); } else
+ * {
+ */
+ // LOG.info("User has valid cookie");
+ chain.doFilter(request, response);
+ // }
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#destroy()
+ */
+ @Override
+ public void destroy() {}
+
+ /**
+ * Sets all required properties needed by this filter.
+ *
+ * @param filterConfig the filter configuration defined in the application web.xml
+ * @throws IOException if the properties failed to load.
+ */
+ private void setConfigurationProperties(FilterConfig filterConfig) throws IOException {
+ InputStream inputStream = new FileInputStream(TierSupportUiConstants.STATIC_CONFIG_APP_LOCATION
+ + filterConfig.getInitParameter(FILTER_PARAMETER_CONFIG));
+ Properties cspProperties = new Properties();
+ cspProperties.load(inputStream);
+ globalLoginUrl = cspProperties.getProperty(PROPERTY_GLOBAL_LOGIN_URL);
+ applicationId = cspProperties.getProperty(PROPERTY_APPLICATION_ID);
+ gateKeeperEnvironment = cspProperties.getProperty(PROPERTY_GATEKEEPER_ENVIRONMENT);
+ redirectDomains = Arrays.asList(cspProperties.getProperty(PROPERTY_REDIRECT_DOMAINS).split(","));
+ }
+
+ /**
+ * Returns the attESSec cookie if found in the client.
+ *
+ * @param cookies the cookies available in the client
+ * @return the attESSec authentication cookie generated by the login page.
+ */
+ private String getSecurityCookie(Cookie[] cookies) {
+ String attEsSec = null;
+ for (int i = 0; i < cookies.length; i++) {
+ Cookie thisCookie = cookies[i];
+ String cookieName = thisCookie.getName();
+
+ if ("attESSec".equals(cookieName)) {
+ attEsSec = thisCookie.getValue();
+ break;
+ }
+ }
+ return attEsSec;
+ }
+
+ /**
+ * Redirects to the AT&T global login page. If this is an AJAX request it returns an unauthorized
+ * HTTP error in the response.
+ *
+ * @param request the filter request object
+ * @param response the filter response object
+ * @throws IOException if there is an error setting the error response
+ */
+ private void doLogin(HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+ if (isAjaxRequest(request)) {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
+ "User is not authorized. Please login to application");
+ } else {
+ // Fix for Safari 7.0.2 onwards to avoid login page cache
+ response.addHeader("Cache-Control", "no-cache, no-store");
+ String redirectURL = createRedirectUrl(request);
+ if (this.isValidRedirectURL(redirectURL)){
+ response.sendRedirect(redirectURL);
+ LOG.debug(AaiUiMsgs.VALID_REDIRECT_URL, redirectURL);
+ } else{
+ response.sendError(400, "Bad redirect URL: " + redirectURL);
+ LOG.error(AaiUiMsgs.INVALID_REDIRECT_URL, redirectURL);
+ }
+ }
+ }
+
+ /**
+ * Checks if a redirect url is valid
+ * @param url URL to validate
+ * @return true if URL is a valid redirect URL, false otherwise
+ */
+ private boolean isValidRedirectURL (String url){
+ String redirectTo = url.substring(url.indexOf("?retURL=")+ "?retURL=".length());
+ try {
+ redirectTo = URLDecoder.decode(redirectTo, StandardCharsets.UTF_8.toString());
+ } catch (UnsupportedEncodingException e) {
+ LOG.error(AaiUiMsgs.UNSUPPORTED_URL_ENCODING, e.getLocalizedMessage());
+ return false;
+ }
+ for (String domain: this.redirectDomains){
+ if (redirectTo.endsWith(domain))
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Returns <code>true</code> if the request is an AJAX request.
+ *
+ * @param request the filter request object
+ * @return <code>true</code> if the request is an AJAX request.
+ */
+ private boolean isAjaxRequest(HttpServletRequest request) {
+ String headerValue = request.getHeader("X-Requested-With");
+ if ("XMLHttpRequest".equals(headerValue)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the redirection URL to the AT&T Global login page.
+ *
+ * @param request the request
+ * @return the string
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private String createRedirectUrl(HttpServletRequest request) throws UnsupportedEncodingException {
+ String returnUrl = getReturnUrl(request);
+
+ return globalLoginUrl + "?retURL=" + returnUrl + "&sysName=" + applicationId;
+ }
+
+ /**
+ * Gets the URL encoded return URL.
+ *
+ * @param request the HTTP request
+ * @return an encoded URL to return to following login
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private String getReturnUrl(HttpServletRequest request) throws UnsupportedEncodingException {
+ StringBuffer retUrl = request.getRequestURL();
+ String urlParams = request.getQueryString();
+ if (urlParams != null) {
+ retUrl.append("?" + urlParams);
+ }
+ return URLEncoder.encode(retUrl.toString(), StandardCharsets.UTF_8.toString());
+ }
+}
diff --git a/src/main/java/org/openecomp/sparky/security/filter/LoginFilter.java b/src/main/java/org/openecomp/sparky/security/filter/LoginFilter.java
new file mode 100644
index 0000000..3ab8990
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/filter/LoginFilter.java
@@ -0,0 +1,230 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.security.filter;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.ws.rs.core.HttpHeaders;
+
+import org.openecomp.cl.api.Logger;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.portalsdk.core.onboarding.listener.PortalTimeoutHandler;
+import org.openecomp.portalsdk.core.onboarding.util.PortalApiConstants;
+import org.openecomp.portalsdk.core.onboarding.util.PortalApiProperties;
+import org.openecomp.portalsdk.core.onboarding.util.SSOUtil;
+import org.openecomp.sparky.logging.AaiUiMsgs;
+import org.openecomp.sparky.security.EcompSso;
+import org.openecomp.sparky.security.portal.config.PortalAuthenticationConfig;
+
+/**
+ * This filter checks every request for proper ECOMP Portal single sign on initialization. The
+ * possible paths and actions:
+ * <OL>
+ * <LI>User starts at an app page via a bookmark. No ECOMP portal cookie is set. Redirect there to
+ * get one; then continue as below.
+ * <LI>User starts at ECOMP Portal and goes to app. Alternately, the user's session times out and
+ * the user hits refresh. The ECOMP Portal cookie is set, but there is no valid session. Create one
+ * and publish info.
+ * <LI>User has valid ECOMP Portal cookie and session. Reset the max idle in that session.
+ * </OL>
+ * <P>
+ * Notes:
+ * <UL>
+ * <LI>Portal Session should be up prior to App Session</LI>
+ * <LI>If App Session Expires or if EPService cookie is unavailable, we need to redirect to Portal.
+ * <LI>Method {@link #initiateSessionMgtHandler(HttpServletRequest)} should be called for Session
+ * management when the initial session is created
+ * <LI>While redirecting, the cookie "redirectUrl" should also be set so that Portal knows where to
+ * forward the request to once the Portal Session is created and EPService cookie is set.
+ * <LI>Method {@link #resetSessionMaxIdleTimeOut(HttpServletRequest)} should be called for every
+ * request to reset the MaxInactiveInterval to the right value.
+ * </UL>
+ * <P>
+ * This filter incorporates most features of the SDK application's SessionTimeoutInterceptor and
+ * SingleSignOnController classes
+ */
+public class LoginFilter implements Filter {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(LoginFilter.class);
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // Validate that app has provided useful portal properties
+ if (PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL) == null) {
+ throw new ServletException("Failed to find URL in portal.properties");
+ }
+
+ PortalAuthenticationConfig appProperties;
+ try {
+ appProperties = PortalAuthenticationConfig.getInstance();
+ } catch (Exception ex) {
+ throw new ServletException("Failed to get properties", ex);
+ }
+
+ String restUser = appProperties.getUsername();
+ String restPassword = appProperties.getPassword();
+ if (restUser == null || restPassword == null) {
+ throw new ServletException("Failed to find user and/or password from properties");
+ }
+ }
+
+ @Override
+ public void destroy() {
+ // No resources to release
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse,
+ * javax.servlet.FilterChain)
+ */
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws ServletException, IOException {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ // Choose authentication appropriate for the request.
+ final String restApiURI = request.getContextPath() + PortalApiConstants.API_PREFIX;
+ if (request.getRequestURI().startsWith(restApiURI)) {
+ // REST servlet checks credentials
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "doFilter: delegating auth to REST servlet for request " + request.getRequestURI());
+ chain.doFilter(request, response);
+ } else {
+ // All other requests require ECOMP Portal authentication
+ if (EcompSso.validateEcompSso(request) == null) {
+ String redirectURL, logMessage;
+
+ // Redirect to Portal UI
+ redirectURL = PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL);
+ logMessage = "Unauthorized login attempt.";
+
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG,
+ logMessage +
+ " | Remote IP: " + request.getRemoteAddr() +
+ " | User agent: " + request.getHeader(HttpHeaders.USER_AGENT) +
+ " | Request URL: " + request.getRequestURL() +
+ " | Redirecting to: " + redirectURL);
+
+ response.sendRedirect(redirectURL);
+ } else {
+ HttpSession session = request.getSession(false);
+ if (session == null) {
+ // New session
+ session = request.getSession(true);
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "doFilter: created new session " + session.getId());
+ initiateSessionMgtHandler(request);
+ } else {
+ // Existing session
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "doFilter: resetting idle in existing session " + session.getId());
+ resetSessionMaxIdleTimeOut(request);
+ }
+ // Pass request back down the filter chain
+ chain.doFilter(request, response);
+ }
+ }
+ }
+
+ /**
+ * Publishes information about the session.
+ *
+ * @param request
+ */
+ private void initiateSessionMgtHandler(HttpServletRequest request) {
+ String portalJSessionId = getPortalJSessionId(request);
+ String jSessionId = getJessionId(request);
+ storeMaxInactiveTime(request);
+ PortalTimeoutHandler.sessionCreated(portalJSessionId, jSessionId, request.getSession(false));
+ }
+
+ /**
+ * Gets the ECOMP Portal service cookie value.
+ *
+ * @param request
+ * @return Cookie value, or null if not found.
+ */
+ private String getPortalJSessionId(HttpServletRequest request) {
+ Cookie ep = EcompSso.getCookie(request, EcompSso.EP_SERVICE);
+ return ep == null ? null : ep.getValue();
+ }
+
+ /**
+ * Gets the container session ID.
+ *
+ * @param request
+ * @return Session ID, or null if no session.
+ */
+ private String getJessionId(HttpServletRequest request) {
+ HttpSession session = request.getSession();
+ return session == null ? null : session.getId();
+ }
+
+ /**
+ * Sets the global session's max idle time to the session's max inactive interval.
+ *
+ * @param request
+ */
+ private void storeMaxInactiveTime(HttpServletRequest request) {
+ HttpSession session = request.getSession(false);
+ if (session != null
+ && session.getAttribute(PortalApiConstants.GLOBAL_SESSION_MAX_IDLE_TIME) == null) {
+ session.setAttribute(PortalApiConstants.GLOBAL_SESSION_MAX_IDLE_TIME,
+ session.getMaxInactiveInterval());
+ }
+ }
+
+ /**
+ * Sets the session's max inactive interval.
+ *
+ * @param request
+ */
+ private void resetSessionMaxIdleTimeOut(HttpServletRequest request) {
+ try {
+ HttpSession session = request.getSession(false);
+ if (session != null) {
+ final Object maxIdleAttribute = session
+ .getAttribute(PortalApiConstants.GLOBAL_SESSION_MAX_IDLE_TIME);
+ if (maxIdleAttribute != null) {
+ session.setMaxInactiveInterval(Integer.parseInt(maxIdleAttribute.toString()));
+ }
+ }
+ } catch (Exception e) {
+ LOG.info(AaiUiMsgs.LOGIN_FILTER_INFO, "resetSessionMaxIdleTimeOut: failed to set session max inactive interval - " + e.getLocalizedMessage());
+ }
+ }
+
+}