This is an automated email from the ASF dual-hosted git repository.

amestry pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git

commit be5d557a0038536733730ca47ff473d876415c3f
Author: nixonrodrigues <ni...@apache.org>
AuthorDate: Mon Aug 23 17:27:18 2021 +0530

    ATLAS-4379 : Atlas Filter changes for user inactivity on Atlas UI
---
 .../java/org/apache/atlas/AtlasConfiguration.java  |   4 +-
 .../web/filters/AtlasAuthenticationFilter.java     |  48 ++++++++-
 .../org/apache/atlas/web/filters/RestUtil.java     | 108 +++++++++++++++++++++
 .../apache/atlas/web/resources/AdminResource.java  |   1 +
 .../AtlasAuthenticationSuccessHandler.java         |  16 ++-
 5 files changed, 170 insertions(+), 7 deletions(-)

diff --git a/intg/src/main/java/org/apache/atlas/AtlasConfiguration.java 
b/intg/src/main/java/org/apache/atlas/AtlasConfiguration.java
index 2f2c8a5..fa519ef 100644
--- a/intg/src/main/java/org/apache/atlas/AtlasConfiguration.java
+++ b/intg/src/main/java/org/apache/atlas/AtlasConfiguration.java
@@ -80,7 +80,9 @@ public enum AtlasConfiguration {
     DSL_EXECUTOR_TRAVERSAL("atlas.dsl.executor.traversal", true),
     DSL_CACHED_TRANSLATOR("atlas.dsl.cached.translator", true),
     DEBUG_METRICS_ENABLED("atlas.debug.metrics.enabled", false),
-    TASKS_USE_ENABLED("atlas.tasks.enabled", true);
+    TASKS_USE_ENABLED("atlas.tasks.enabled", true),
+    SESSION_TIMEOUT_SECS("atlas.session.timeout.secs", 3600);
+
 
     private static final Configuration APPLICATION_PROPERTIES;
 
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
 
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
index d9b1c82..b8d21b9 100644
--- 
a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
+++ 
b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
@@ -19,6 +19,7 @@
 package org.apache.atlas.web.filters;
 
 import org.apache.atlas.ApplicationProperties;
+import org.apache.atlas.AtlasConfiguration;
 import org.apache.atlas.security.SecurityProperties;
 import org.apache.atlas.utils.AuthenticationUtil;
 import org.apache.atlas.web.security.AtlasAuthenticationProvider;
@@ -73,6 +74,9 @@ import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.apache.hadoop.security.authorize.AuthorizationException;
+import 
org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
+
+import static org.apache.atlas.web.filters.RestUtil.constructForwardableURL;
 
 
 /**
@@ -90,6 +94,7 @@ public class AtlasAuthenticationFilter extends 
AuthenticationFilter {
     private   static final String[]       DEFAULT_PROXY_USERS   = new String[] 
{ "knox" };
     private   static final String         CONF_PROXYUSER_PREFIX = 
"atlas.proxyuser";
     protected static final ServletContext nullContext           = new 
NullServletContext();
+    private   static final String         ORIGINAL_URL_QUERY_PARAM = 
"originalUrl";
 
     private Signer               signer;
     private SignerSecretProvider secretProvider;
@@ -102,8 +107,9 @@ public class AtlasAuthenticationFilter extends 
AuthenticationFilter {
     private Set<String>          atlasProxyUsers = new HashSet<>();
     private HttpServlet          optionsServlet;
     private boolean              supportTrustedProxy = false;
+    private int                  sessionTimeout;
 
-
+    private SecurityContextLogoutHandler logoutHandler;
 
     public AtlasAuthenticationFilter() {
         LOG.info("==> AtlasAuthenticationFilter()");
@@ -193,7 +199,7 @@ public class AtlasAuthenticationFilter extends 
AuthenticationFilter {
         optionsServlet = new HttpServlet() {
         };
         optionsServlet.init();
-
+        logoutHandler = new SecurityContextLogoutHandler();
         LOG.info("<== AtlasAuthenticationFilter.init(filterConfig={})", 
filterConfig);
 
     }
@@ -301,6 +307,10 @@ public class AtlasAuthenticationFilter extends 
AuthenticationFilter {
 
         LOG.debug(" AuthenticationFilterConfig: {}", ret);
 
+        sessionTimeout = AtlasConfiguration.SESSION_TIMEOUT_SECS.getInt();
+        if(sessionTimeout < 30){
+            LOG.warn("AtlasAuthenticationFilter:: sessionTimeout is set low");
+        }
         supportKeyTabBrowserLogin = 
configuration.getBoolean("atlas.authentication.method.kerberos.support.keytab.browser.login",
 false);
         supportTrustedProxy = 
configuration.getBoolean("atlas.authentication.method.trustedproxy", true);
         String agents = 
configuration.getString(AtlasCSRFPreventionFilter.BROWSER_USER_AGENT_PARAM, 
AtlasCSRFPreventionFilter.BROWSER_USER_AGENTS_DEFAULT);
@@ -332,6 +342,8 @@ public class AtlasAuthenticationFilter extends 
AuthenticationFilter {
             Authentication              existingAuth    = 
SecurityContextHolder.getContext().getAuthentication();
             HttpServletResponse         httpResponse    = 
(HttpServletResponse) response;
             AtlasResponseRequestWrapper responseWrapper = new 
AtlasResponseRequestWrapper(httpResponse);
+            String action = httpRequest.getParameter("action");
+            String doAsUser = request.getParameter("doAs");
 
             HeadersUtil.setHeaderMapAttributes(responseWrapper, 
HeadersUtil.X_FRAME_OPTIONS_KEY);
             HeadersUtil.setHeaderMapAttributes(responseWrapper, 
HeadersUtil.X_CONTENT_TYPE_OPTIONS_KEY);
@@ -344,6 +356,14 @@ public class AtlasAuthenticationFilter extends 
AuthenticationFilter {
                 }
             }
 
+            if (supportTrustedProxy && StringUtils.isNotEmpty(doAsUser) && 
StringUtils.equals(action, RestUtil.TIMEOUT_ACTION)) {
+                if (existingAuth != null) {
+                    logoutHandler.logout(httpRequest, httpResponse, 
existingAuth);
+                }
+                redirectTimeoutReqeust(httpRequest, httpResponse);
+                return;
+            }
+
             if (existingAuth == null) {
                 String authHeader = httpRequest.getHeader("Authorization");
 
@@ -365,6 +385,28 @@ public class AtlasAuthenticationFilter extends 
AuthenticationFilter {
         }
     }
 
+    private void redirectTimeoutReqeust(HttpServletRequest httpRequest, 
HttpServletResponse httpResponse) throws IOException{
+        String logoutUrl = httpRequest.getRequestURL().toString();
+
+        logoutUrl =  StringUtils.replace(logoutUrl, 
httpRequest.getRequestURI(), RestUtil.LOGOUT_URL);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("logoutUrl value is " + logoutUrl);
+        }
+        String xForwardedURL = constructForwardableURL(httpRequest);
+
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("xForwardedURL = " + xForwardedURL);
+        }
+        String redirectUrl = RestUtil.constructRedirectURL(httpRequest, 
logoutUrl, xForwardedURL, ORIGINAL_URL_QUERY_PARAM);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Redirect URL = " + redirectUrl);
+            LOG.debug("session id = " + httpRequest.getRequestedSessionId());
+        }
+
+        httpResponse.sendRedirect(redirectUrl);
+    }
 
 
     /**
@@ -717,7 +759,7 @@ public class AtlasAuthenticationFilter extends 
AuthenticationFilter {
                 ((AbstractAuthenticationToken) 
finalAuthentication).setDetails(webDetails);
 
                 
SecurityContextHolder.getContext().setAuthentication(finalAuthentication);
-
+                
httpRequest.getSession().setMaxInactiveInterval(sessionTimeout);
                 request.setAttribute("atlas.http.authentication.type", true);
 
                 if (!StringUtils.equals(loggedInUser, userName)) {
diff --git a/webapp/src/main/java/org/apache/atlas/web/filters/RestUtil.java 
b/webapp/src/main/java/org/apache/atlas/web/filters/RestUtil.java
new file mode 100644
index 0000000..01b64d7
--- /dev/null
+++ b/webapp/src/main/java/org/apache/atlas/web/filters/RestUtil.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.atlas.web.filters;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Enumeration;
+
+public class RestUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RestUtil.class);
+    public static final String TIMEOUT_ACTION = "timeout";
+    public static final String LOGOUT_URL = "/logout.html";
+    private static final String PROXY_ATLAS_URL_PATH = "/atlas";
+    private static final String X_FORWARDED_PROTO = "x-forwarded-proto";
+    private static final String X_FORWARDED_HOST = "x-forwarded-host";
+    private static final String X_FORWARDED_CONTEXT = "x-forwarded-context";
+    public static final String DELIMITTER = "://";
+
+    public static String constructForwardableURL(HttpServletRequest 
httpRequest) {
+        String xForwardedProto = "";
+        String xForwardedHost = "";
+        String xForwardedContext = "";
+        Enumeration<?> headerNames = httpRequest.getHeaderNames();
+        while (headerNames.hasMoreElements()) {
+            String name = (String) headerNames.nextElement();
+            Enumeration<?> values = httpRequest.getHeaders(name);
+            String value = "";
+            if (values != null) {
+                while (values.hasMoreElements()) {
+                    value = (String) values.nextElement();
+                }
+            }
+            if (StringUtils.trimToNull(name) != null && 
StringUtils.trimToNull(value) != null) {
+                if (name.equalsIgnoreCase(X_FORWARDED_PROTO)) {
+                    xForwardedProto = value;
+                } else if (name.equalsIgnoreCase(X_FORWARDED_HOST)) {
+                    xForwardedHost = value;
+                } else if (name.equalsIgnoreCase(X_FORWARDED_CONTEXT)) {
+                    xForwardedContext = value;
+                }
+            }
+        }
+        if (xForwardedHost.contains(",")) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("xForwardedHost value is " + xForwardedHost + " it 
contains multiple hosts, selecting the first host.");
+            }
+            xForwardedHost = xForwardedHost.split(",")[0].trim();
+        }
+        String xForwardedURL = "";
+        if (StringUtils.trimToNull(xForwardedProto) != null) {
+            //if header contains x-forwarded-host and x-forwarded-context
+            if (StringUtils.trimToNull(xForwardedHost) != null && 
StringUtils.trimToNull(xForwardedContext) != null) {
+                xForwardedURL = xForwardedProto + DELIMITTER + xForwardedHost 
+ xForwardedContext + PROXY_ATLAS_URL_PATH + httpRequest.getRequestURI();
+            } else if (StringUtils.trimToNull(xForwardedHost) != null) {
+                //if header contains x-forwarded-host and does not contains 
x-forwarded-context
+                xForwardedURL = xForwardedProto + DELIMITTER + xForwardedHost 
+ httpRequest.getRequestURI();
+            } else {
+                //if header does not contains x-forwarded-host and 
x-forwarded-context
+                //preserve the x-forwarded-proto value coming from the request.
+                String requestURL = httpRequest.getRequestURL().toString();
+                if (StringUtils.trimToNull(requestURL) != null && 
requestURL.startsWith("http:")) {
+                    requestURL = requestURL.replaceFirst("http", 
xForwardedProto);
+                }
+                xForwardedURL = requestURL;
+            }
+        }
+        return xForwardedURL;
+    }
+
+    public static String constructRedirectURL(HttpServletRequest request, 
String redirectUrl, String xForwardedURL, String originalUrlQueryParam) {
+        String delimiter = "?";
+        if (redirectUrl.contains("?")) {
+            delimiter = "&";
+        }
+        String loginURL = redirectUrl + delimiter + originalUrlQueryParam + 
"=";
+        if (StringUtils.trimToNull(xForwardedURL) != null) {
+            loginURL += xForwardedURL;
+        } else {
+            loginURL += 
request.getRequestURL().append(getOriginalQueryString(request));
+        }
+        return loginURL;
+    }
+
+    private static String getOriginalQueryString(HttpServletRequest request) {
+        String originalQueryString = request.getQueryString();
+        return (originalQueryString == null) ? "" : "?" + originalQueryString;
+    }
+}
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java 
b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
index 01fb8ec..baa040f 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
@@ -370,6 +370,7 @@ public class AdminResource {
         responseData.put(UI_DATE_FORMAT, uiDateFormat);
         
responseData.put(AtlasConfiguration.DEBUG_METRICS_ENABLED.getPropertyName(), 
isDebugMetricsEnabled);
         
responseData.put(AtlasConfiguration.TASKS_USE_ENABLED.getPropertyName(), 
isTasksEnabled);
+        
responseData.put(AtlasConfiguration.SESSION_TIMEOUT_SECS.getPropertyName(), 
AtlasConfiguration.SESSION_TIMEOUT_SECS.getInt());
 
         String salt = (String) request.getSession().getAttribute(CSRF_TOKEN);
         if (StringUtils.isEmpty(salt)) {
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
 
b/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
index e7a5d66..1b1a808 100644
--- 
a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
+++ 
b/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
@@ -18,6 +18,7 @@
 
 package org.apache.atlas.web.security;
 
+import org.apache.atlas.AtlasConfiguration;
 import org.json.simple.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -25,6 +26,7 @@ import org.springframework.security.core.Authentication;
 import 
org.springframework.security.web.authentication.AuthenticationSuccessHandler;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.PostConstruct;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -35,6 +37,14 @@ import java.io.IOException;
 public class AtlasAuthenticationSuccessHandler implements 
AuthenticationSuccessHandler {
 
     private static Logger LOG = 
LoggerFactory.getLogger(AuthenticationSuccessHandler.class);
+    private int sessionTimeout = 3600;
+    public static final String LOCALLOGIN = "locallogin";
+
+    @PostConstruct
+    public void setup() {
+        sessionTimeout = AtlasConfiguration.SESSION_TIMEOUT_SECS.getInt();
+    }
+
     @Override
     public void onAuthenticationSuccess(HttpServletRequest request, 
HttpServletResponse response,
                                         Authentication authentication) throws 
IOException, ServletException {
@@ -45,10 +55,10 @@ public class AtlasAuthenticationSuccessHandler implements 
AuthenticationSuccessH
         json.put("msgDesc", "Success");
 
         if (request.getSession() != null) { // incase of form based login mark 
it as local login in session
-            request.getSession().setAttribute("locallogin","true");
-            
request.getServletContext().setAttribute(request.getSession().getId(), 
"locallogin");
+            request.getSession().setAttribute(LOCALLOGIN,"true");
+            
request.getServletContext().setAttribute(request.getSession().getId(), 
LOCALLOGIN);
+            request.getSession().setMaxInactiveInterval(sessionTimeout);
         }
-
         response.setContentType("application/json");
         response.setStatus(HttpServletResponse.SC_OK);
         response.setCharacterEncoding("UTF-8");

Reply via email to