You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by am...@apache.org on 2021/09/22 22:17:58 UTC
[atlas] 01/02: ATLAS-4379 : Atlas Filter changes for user
inactivity on Atlas UI
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");