Repository: atlas Updated Branches: refs/heads/master 854208c1e -> 62cdbdc6d
ATLAS-2824 updated authentication to support trusted proxy. Project: http://git-wip-us.apache.org/repos/asf/atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/62cdbdc6 Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/62cdbdc6 Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/62cdbdc6 Branch: refs/heads/master Commit: 62cdbdc6d45c32fc3b135b4c6100f1ed02c6390a Parents: 854208c Author: nixonrodrigues <[email protected]> Authored: Wed Nov 14 00:24:31 2018 +0530 Committer: nixonrodrigues <[email protected]> Committed: Wed Nov 14 16:51:42 2018 +0530 ---------------------------------------------------------------------- .../web/filters/AtlasAuthenticationFilter.java | 374 ++++++++++++------- .../security/NegativeSSLAndKerberosTest.java | 1 + .../atlas/web/security/SSLAndKerberosTest.java | 1 + 3 files changed, 243 insertions(+), 133 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/atlas/blob/62cdbdc6/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java ---------------------------------------------------------------------- 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 e5c40d0..3a2b9d4 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 @@ -38,6 +38,7 @@ import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHa import org.apache.hadoop.security.authentication.util.Signer; import org.apache.hadoop.security.authentication.util.SignerException; import org.apache.hadoop.security.authentication.util.SignerSecretProvider; +import org.apache.hadoop.security.authorize.ProxyUsers; import org.apache.log4j.NDC; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +51,7 @@ import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.stereotype.Component; - +import org.apache.hadoop.security.UserGroupInformation; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; @@ -71,6 +72,7 @@ import java.text.SimpleDateFormat; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.hadoop.security.authorize.AuthorizationException; /** @@ -83,10 +85,11 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthenticationFilter.class); private static final String CONFIG_KERBEROS_TOKEN_VALIDITY = "atlas.authentication.method.kerberos.token.validity"; - private static final String CONFIG_PROXY_USERS = "atlas.proxyusers"; - private static final String PREFIX = "atlas.authentication.method"; - private static final String[] DEFAULT_PROXY_USERS = new String[] { "knox" }; - protected static final ServletContext nullContext = new NullServletContext(); + private static final String CONFIG_PROXY_USERS = "atlas.proxyusers"; + private static final String PREFIX = "atlas.authentication.method"; + 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 Signer signer; private SignerSecretProvider secretProvider; @@ -97,18 +100,22 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { private Configuration configuration; private Properties headerProperties; private Set<String> atlasProxyUsers = new HashSet<>(); + private HttpServlet optionsServlet; + private boolean supportTrustedProxy = false; + public AtlasAuthenticationFilter() { + LOG.info("==> AtlasAuthenticationFilter()"); + try { - LOG.info("AtlasAuthenticationFilter initialization started"); init(null); } catch (ServletException e) { - LOG.error("Error while initializing AtlasAuthenticationFilter : {}", e.getMessage()); + LOG.error("Error while initializing AtlasAuthenticationFilter", e); } - } - private HttpServlet optionsServlet; + LOG.info("<== AtlasAuthenticationFilter()"); + } /** * Initialize the filter. @@ -118,9 +125,10 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { */ @Override public void init(FilterConfig filterConfig) throws ServletException { - LOG.info("AtlasAuthenticationFilter initialization started"); - final FilterConfig globalConf = filterConfig; - final Map<String, String> params = new HashMap<>(); + LOG.info("==> AtlasAuthenticationFilter.init"); + + final FilterConfig globalConf = filterConfig; + final Map<String, String> params = new HashMap<>(); try { configuration = ApplicationProperties.get(); } catch (Exception e) { @@ -131,7 +139,11 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { headerProperties = ConfigurationConverter.getProperties(configuration.subset("atlas.headers")); } - String tokenValidityStr = configuration.getString(CONFIG_KERBEROS_TOKEN_VALIDITY); + String tokenValidityStr = null; + + if(configuration != null) { + tokenValidityStr = configuration.getString(CONFIG_KERBEROS_TOKEN_VALIDITY); + } if (StringUtils.isNotBlank(tokenValidityStr)) { try { @@ -176,97 +188,121 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { super.init(filterConfig1); + ProxyUsers.refreshSuperUserGroupsConfiguration(getProxyuserConfiguration(), CONF_PROXYUSER_PREFIX); + optionsServlet = new HttpServlet() { }; optionsServlet.init(); + + LOG.info("<== AtlasAuthenticationFilter.init(filterConfig={})", filterConfig); + } @Override - public void initializeSecretProvider(FilterConfig filterConfig) - throws ServletException { - LOG.debug("AtlasAuthenticationFilter :: initializeSecretProvider {}", filterConfig); - secretProvider = (SignerSecretProvider) filterConfig.getServletContext(). - getAttribute(AuthenticationFilter.SIGNER_SECRET_PROVIDER_ATTRIBUTE); + public void initializeSecretProvider(FilterConfig filterConfig) throws ServletException { + LOG.info("==> AtlasAuthenticationFilter.initializeSecretProvider"); + + secretProvider = (SignerSecretProvider) filterConfig.getServletContext().getAttribute(AuthenticationFilter.SIGNER_SECRET_PROVIDER_ATTRIBUTE); + if (secretProvider == null) { // As tomcat cannot specify the provider object in the configuration. // It'll go into this path String configPrefix = filterConfig.getInitParameter(CONFIG_PREFIX); + configPrefix = (configPrefix != null) ? configPrefix + "." : ""; + try { - secretProvider = AuthenticationFilter.constructSecretProvider( - filterConfig.getServletContext(), - super.getConfiguration(configPrefix, filterConfig), false); + secretProvider = AuthenticationFilter.constructSecretProvider(filterConfig.getServletContext(), super.getConfiguration(configPrefix, filterConfig), false); + this.isInitializedByTomcat = true; } catch (Exception ex) { throw new ServletException(ex); } } + signer = new Signer(secretProvider); + + LOG.info("<== AtlasAuthenticationFilter.initializeSecretProvider(filterConfig={})", filterConfig); } @Override protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) throws ServletException { + LOG.info("==> AtlasAuthenticationFilter.getConfiguration()"); + try { configuration = ApplicationProperties.get(); } catch (Exception e) { throw new ServletException(e); } - Properties config = new Properties(); + Properties ret = new Properties(); String kerberosAuthEnabled = configuration != null ? configuration.getString("atlas.authentication.method.kerberos") : null; - // getString may return null, and would like to log the nature of the default setting - String authMethod = ""; + + final String authMethod; + if (kerberosAuthEnabled == null || kerberosAuthEnabled.equalsIgnoreCase("false")) { LOG.info("No authentication method configured. Defaulting to simple authentication"); + authMethod = "simple"; } else if (kerberosAuthEnabled.equalsIgnoreCase("true")) { authMethod = "kerberos"; - } - if (configuration.getString("atlas.authentication.method.kerberos.name.rules") != null) { - config.put("kerberos.name.rules", configuration.getString("atlas.authentication.method.kerberos.name.rules")); - } - if (configuration.getString("atlas.authentication.method.kerberos.keytab") != null) { - config.put("kerberos.keytab", configuration.getString("atlas.authentication.method.kerberos.keytab")); - } - if (configuration.getString("atlas.authentication.method.kerberos.principal") != null) { - config.put("kerberos.principal", configuration.getString("atlas.authentication.method.kerberos.principal")); + if (configuration.getString("atlas.authentication.method.kerberos.name.rules") != null) { + ret.put("kerberos.name.rules", configuration.getString("atlas.authentication.method.kerberos.name.rules")); + } + + if (configuration.getString("atlas.authentication.method.kerberos.keytab") != null) { + ret.put("kerberos.keytab", configuration.getString("atlas.authentication.method.kerberos.keytab")); + } + + if (configuration.getString("atlas.authentication.method.kerberos.principal") != null) { + ret.put("kerberos.principal", configuration.getString("atlas.authentication.method.kerberos.principal")); + } + } else { + authMethod = ""; } - config.put(AuthenticationFilter.AUTH_TYPE, authMethod); - config.put(AuthenticationFilter.COOKIE_PATH, "/"); + + ret.put(AuthenticationFilter.AUTH_TYPE, authMethod); + ret.put(AuthenticationFilter.COOKIE_PATH, "/"); // add any config passed in as init parameters Enumeration<String> enumeration = filterConfig.getInitParameterNames(); while (enumeration.hasMoreElements()) { String name = enumeration.nextElement(); - config.put(name, filterConfig.getInitParameter(name)); + + ret.put(name, filterConfig.getInitParameter(name)); } //Resolve _HOST into bind address String bindAddress = configuration.getString(SecurityProperties.BIND_ADDRESS); if (bindAddress == null) { - LOG.info("No host name configured. Defaulting to local host name."); + LOG.info("No host name configured. Defaulting to local host name."); + try { bindAddress = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { throw new ServletException("Unable to obtain host name", e); } } - String principal = config.getProperty(KerberosAuthenticationHandler.PRINCIPAL); + + String principal = ret.getProperty(KerberosAuthenticationHandler.PRINCIPAL); if (principal != null) { try { principal = SecurityUtil.getServerPrincipal(principal, bindAddress); } catch (IOException ex) { throw new RuntimeException("Could not resolve Kerberos principal name: " + ex.toString(), ex); } - config.put(KerberosAuthenticationHandler.PRINCIPAL, principal); + + ret.put(KerberosAuthenticationHandler.PRINCIPAL, principal); } - LOG.debug(" AuthenticationFilterConfig: {}", config); + + LOG.debug(" AuthenticationFilterConfig: {}", ret); 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); if (agents == null) { @@ -283,67 +319,20 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { parseBrowserUserAgents(agents); - return config; + LOG.info("<== AtlasAuthenticationFilter.getConfiguration(configPrefix={}, filterConfig={}): {}", configPrefix, filterConfig, ret); + + return ret; } @Override - public void doFilter(final ServletRequest request, final ServletResponse response, - final FilterChain filterChain) throws IOException, ServletException { - + public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest httpRequest = (HttpServletRequest) request; - FilterChain filterChainWrapper = new FilterChain() { - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) - throws IOException, ServletException { - final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; - final HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; - - if (isKerberos) { - Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); - String userName = readUserFromCookie(httpResponse); - - if (StringUtils.isEmpty(userName) && !StringUtils.isEmpty(httpRequest.getRemoteUser())) { - userName = httpRequest.getRemoteUser(); - } - - if ((existingAuth == null || !existingAuth.isAuthenticated()) && (!StringUtils.isEmpty(userName))) { - - List<GrantedAuthority> grantedAuths = AtlasAuthenticationProvider.getAuthoritiesFromUGI(userName); - - final UserDetails principal = new User(userName, "", grantedAuths); - final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken(principal, "", grantedAuths); - WebAuthenticationDetails webDetails = new WebAuthenticationDetails(httpRequest); - ((AbstractAuthenticationToken) finalAuthentication).setDetails(webDetails); - SecurityContextHolder.getContext().setAuthentication(finalAuthentication); - - request.setAttribute("atlas.http.authentication.type", true); - LOG.info("Logged into Atlas as = {}", userName); - } - } - // OPTIONS method is sent from quick start jersey atlas client - if (httpRequest.getMethod().equals("OPTIONS")) { - optionsServlet.service(request, response); - } else { - try { - String requestUser = httpRequest.getRemoteUser(); - NDC.push(requestUser + ":" + httpRequest.getMethod() + httpRequest.getRequestURI()); - - LOG.info("Request from authenticated user: {}, URL={}", requestUser, - Servlets.getRequestURI(httpRequest)); - - filterChain.doFilter(servletRequest, servletResponse); - } finally { - NDC.pop(); - } - } - } - }; - try { - Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); - HttpServletResponse httpResponse = (HttpServletResponse) response; + Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); + HttpServletResponse httpResponse = (HttpServletResponse) response; AtlasResponseRequestWrapper responseWrapper = new AtlasResponseRequestWrapper(httpResponse); + responseWrapper.setHeader("X-Frame-Options", "DENY"); responseWrapper.setHeader("X-Content-Type-Options", "nosniff"); responseWrapper.setHeader("X-XSS-Protection", "1; mode=block"); @@ -351,17 +340,17 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { if (headerProperties != null) { for (String headerKey : headerProperties.stringPropertyNames()) { - String headerValue = headerProperties.getProperty(headerKey); - responseWrapper.setHeader(headerKey, headerValue); + responseWrapper.setHeader(headerKey, headerProperties.getProperty(headerKey)); } } if (existingAuth == null) { String authHeader = httpRequest.getHeader("Authorization"); + if (authHeader != null && authHeader.startsWith("Basic")) { filterChain.doFilter(request, response); } else if (isKerberos) { - doKerberosAuth(request, response, filterChainWrapper, filterChain); + doKerberosAuth(request, response, filterChain); } else { filterChain.doFilter(request, response); } @@ -391,46 +380,54 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { * @throws IOException thrown if an IO error occurred. * @throws ServletException thrown if a processing error occurred. */ - public void doKerberosAuth(ServletRequest request, ServletResponse response, FilterChain filterChainWrapper, FilterChain filterChain) - throws IOException, ServletException { - boolean unauthorizedResponse = true; - int errCode = HttpServletResponse.SC_UNAUTHORIZED; - AuthenticationException authenticationEx = null; - HttpServletRequest httpRequest = (HttpServletRequest) request; - HttpServletResponse httpResponse = (HttpServletResponse) response; - boolean isHttps = "https".equals(httpRequest.getScheme()); - AuthenticationHandler authHandler = getAuthenticationHandler(); + private void doKerberosAuth(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { + KerberosFilterChainWrapper filterChainWrapper = new KerberosFilterChainWrapper(request, response, filterChain); + boolean unauthorizedResponse = true; + int errCode = HttpServletResponse.SC_UNAUTHORIZED; + AuthenticationException authenticationEx = null; + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + boolean isHttps = "https".equals(httpRequest.getScheme()); + AuthenticationHandler authHandler = getAuthenticationHandler(); + try { - boolean newToken = false; + boolean newToken = false; AuthenticationToken token; + try { token = getToken(httpRequest); } catch (AuthenticationException ex) { - LOG.warn("AuthenticationToken ignored: {}", ex.getMessage()); + LOG.warn("AuthenticationToken ignored: {}", ex); // will be sent back in a 401 unless filter authenticates authenticationEx = ex; - token = null; + token = null; } + if (authHandler.managementOperation(token, httpRequest, httpResponse)) { if (token == null) { if (LOG.isDebugEnabled()) { LOG.debug("Request [{}] triggering authentication", getRequestURL(httpRequest)); } + token = authHandler.authenticate(httpRequest, httpResponse); - if (token != null && token.getExpires() != 0 && - token != AuthenticationToken.ANONYMOUS) { + + if (token != null && token.getExpires() != 0 && token != AuthenticationToken.ANONYMOUS) { token.setExpires(System.currentTimeMillis() + getValidity() * 1000); } + newToken = true; } + if (token != null) { - unauthorizedResponse = false; if (LOG.isDebugEnabled()) { LOG.debug("Request [{}] user [{}] authenticated", getRequestURL(httpRequest), token.getUserName()); } + + unauthorizedResponse = false; + final AuthenticationToken authToken = token; - httpRequest = new HttpServletRequestWrapper(httpRequest) { + httpRequest = new HttpServletRequestWrapper(httpRequest) { @Override public String getAuthType() { return authToken.getType(); @@ -447,7 +444,31 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { } }; - if(StringUtils.isNotBlank(httpRequest.getRemoteUser()) && atlasProxyUsers.contains(httpRequest.getRemoteUser())){ + // Create the proxy user if doAsUser exists + String doAsUser = supportTrustedProxy ? Servlets.getDoAsUser(httpRequest) : null; + + if (supportTrustedProxy && doAsUser != null) { + LOG.debug("doAsUser is {}", doAsUser); + + UserGroupInformation requestUgi = (token != null) ? UserGroupInformation.createRemoteUser(token.getUserName()) : null; + + if (requestUgi != null) { + requestUgi = UserGroupInformation.createProxyUser(doAsUser, requestUgi); + + try { + ProxyUsers.authorize(requestUgi, request.getRemoteAddr()); + request.setAttribute("proxyUser", doAsUser); + } catch (AuthorizationException ex) { + LOG.warn("Proxy user AuthorizationException", ex); + + httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); + filterChain.doFilter(request, response); + + return; + + } + } + } else if(StringUtils.isNotBlank(httpRequest.getRemoteUser()) && atlasProxyUsers.contains(httpRequest.getRemoteUser())){ LOG.info("Ignoring kerberos login from proxy user "+ httpRequest.getRemoteUser()); httpResponse.setHeader(KerberosAuthenticator.WWW_AUTHENTICATE, ""); @@ -457,11 +478,10 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { return; } - if (newToken && !token.isExpired() && token != AuthenticationToken.ANONYMOUS) { String signedToken = signer.sign(token.toString()); - createAuthCookie(httpResponse, signedToken, getCookieDomain(), - getCookiePath(), token.getExpires(), isHttps); + + createAtlasAuthCookie(httpResponse, signedToken, getCookieDomain(), getCookiePath(), token.getExpires(), isHttps); } filterChainWrapper.doFilter(httpRequest, httpResponse); @@ -470,36 +490,41 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { unauthorizedResponse = false; } } catch (AuthenticationException ex) { + LOG.warn("Authentication exception: {}", ex.getMessage(), ex); + // exception from the filter itself is fatal - errCode = HttpServletResponse.SC_FORBIDDEN; + errCode = HttpServletResponse.SC_FORBIDDEN; authenticationEx = ex; - LOG.warn("Authentication exception: {}", ex.getMessage(), ex); } + if (unauthorizedResponse) { if (!httpResponse.isCommitted()) { - createAuthCookie(httpResponse, "", getCookieDomain(), - getCookiePath(), 0, isHttps); + createAtlasAuthCookie(httpResponse, "", getCookieDomain(), getCookiePath(), 0, isHttps); + // If response code is 401. Then WWW-Authenticate Header should be // present.. reset to 403 if not found.. - if ((errCode == HttpServletResponse.SC_UNAUTHORIZED) - && (!httpResponse.containsHeader( - KerberosAuthenticator.WWW_AUTHENTICATE))) { + if (errCode == HttpServletResponse.SC_UNAUTHORIZED && !httpResponse.containsHeader(KerberosAuthenticator.WWW_AUTHENTICATE)) { errCode = HttpServletResponse.SC_FORBIDDEN; } + if (authenticationEx == null) { // added this code for atlas error handling and fallback if (!supportKeyTabBrowserLogin && isBrowser(httpRequest.getHeader("User-Agent"))) { filterChain.doFilter(request, response); } else { - boolean chk = true; + boolean chk = true; Collection<String> headerNames = httpResponse.getHeaderNames(); + for (String headerName : headerNames) { String value = httpResponse.getHeader(headerName); + if (headerName.equalsIgnoreCase("Set-Cookie") && value.startsWith("ATLASSESSIONID")) { chk = false; break; } } + String authHeader = httpRequest.getHeader("Authorization"); + if (authHeader == null && chk) { filterChain.doFilter(request, response); } else if (authHeader != null && authHeader.startsWith("Basic")) { @@ -527,21 +552,26 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { private static String readUserFromCookie(HttpServletResponse response1) { - String userName = null; + String userName = null; boolean isCookieSet = response1.containsHeader("Set-Cookie"); + if (isCookieSet) { Collection<String> authUserName = response1.getHeaders("Set-Cookie"); + if (authUserName != null) { for (String cookie : authUserName) { if (!StringUtils.isEmpty(cookie)) { if (cookie.toLowerCase().startsWith(AuthenticatedURL.AUTH_COOKIE.toLowerCase()) && cookie.contains("u=")) { String[] split = cookie.split(";"); + if (split != null) { for (String s : split) { if (!StringUtils.isEmpty(s) && s.toLowerCase().startsWith(AuthenticatedURL.AUTH_COOKIE.toLowerCase())) { int ustr = s.indexOf("u="); + if (ustr != -1) { int andStr = s.indexOf("&", ustr); + if (andStr != -1) { try { userName = s.substring(ustr + 2, andStr); @@ -559,16 +589,19 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { } } } + return userName; } - public static void createAuthCookie(HttpServletResponse resp, String token, String domain, String path, long expires, boolean isSecure) { + private void createAtlasAuthCookie(HttpServletResponse resp, String token, String domain, String path, long expires, boolean isSecure) { StringBuilder sb = (new StringBuilder(AuthenticatedURL.AUTH_COOKIE)).append("="); + if (token != null && token.length() > 0) { sb.append("\"").append(token).append("\""); } sb.append("; Version=1"); + if (path != null) { sb.append("; Path=").append(path); } @@ -578,10 +611,9 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { } if (expires >= 0L) { - Date date = new Date(expires); SimpleDateFormat df = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss zzz"); df.setTimeZone(TimeZone.getTimeZone("GMT")); - sb.append("; Expires=").append(df.format(date)); + sb.append("; Expires=").append(df.format(new Date(expires))); } if (isSecure) { @@ -635,18 +667,94 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { } boolean isBrowser(String userAgent) { - if (userAgent == null) { - return false; - } - if (browserUserAgents != null) { + if (userAgent != null) { for (Pattern pattern : browserUserAgents) { Matcher matcher = pattern.matcher(userAgent); + if (matcher.matches()) { return true; } } } + return false; } + + private class KerberosFilterChainWrapper implements FilterChain { + private final ServletRequest request; + private final ServletResponse response; + private final FilterChain filterChain; + + KerberosFilterChainWrapper(ServletRequest request, ServletResponse response, FilterChain filterChain) { + this.request = request; + this.response = response; + this.filterChain = filterChain; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException { + final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; + final HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; + final Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); + String loggedInUser = readUserFromCookie(httpResponse); + String userName = loggedInUser; + + if (!StringUtils.isEmpty((String) httpRequest.getAttribute("proxyUser"))) { + userName = (String) httpRequest.getAttribute("proxyUser"); + } else if (StringUtils.isEmpty(userName) && !StringUtils.isEmpty(httpRequest.getRemoteUser())) { + userName = httpRequest.getRemoteUser(); + } + + if ((existingAuth == null || !existingAuth.isAuthenticated()) && !StringUtils.isEmpty(userName)) { + final List<GrantedAuthority> grantedAuths = AtlasAuthenticationProvider.getAuthoritiesFromUGI(userName); + final UserDetails principal = new User(userName, "", grantedAuths); + final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken(principal, "", grantedAuths); + final WebAuthenticationDetails webDetails = new WebAuthenticationDetails(httpRequest); + + ((AbstractAuthenticationToken) finalAuthentication).setDetails(webDetails); + + SecurityContextHolder.getContext().setAuthentication(finalAuthentication); + + request.setAttribute("atlas.http.authentication.type", true); + + if (!StringUtils.equals(loggedInUser, userName)) { + LOG.info("Logged into Atlas as = {}, by proxyUser = {}", userName, loggedInUser); + } else { + LOG.info("Logged into Atlas as = {}", userName); + } + } + + // OPTIONS method is sent from quick start jersey atlas client + if (httpRequest.getMethod().equals("OPTIONS")) { + optionsServlet.service(request, response); + } else { + try { + String requestUser = httpRequest.getRemoteUser(); + + NDC.push(requestUser + ":" + httpRequest.getMethod() + httpRequest.getRequestURI()); + + LOG.info("Request from authenticated user: {}, URL={}", requestUser, Servlets.getRequestURI(httpRequest)); + + filterChain.doFilter(servletRequest, servletResponse); + } finally { + NDC.pop(); + } + } + } + } + + private org.apache.hadoop.conf.Configuration getProxyuserConfiguration() { + org.apache.hadoop.conf.Configuration ret = new org.apache.hadoop.conf.Configuration(false); + + if(configuration!=null) { + Properties props = ConfigurationConverter.getProperties(configuration.subset(CONF_PROXYUSER_PREFIX)); + + for (String key : props.stringPropertyNames()) { + ret.set(CONF_PROXYUSER_PREFIX + "." + key, props.getProperty(key)); + } + } + + return ret; + } } http://git-wip-us.apache.org/repos/asf/atlas/blob/62cdbdc6/webapp/src/test/java/org/apache/atlas/web/security/NegativeSSLAndKerberosTest.java ---------------------------------------------------------------------- diff --git a/webapp/src/test/java/org/apache/atlas/web/security/NegativeSSLAndKerberosTest.java b/webapp/src/test/java/org/apache/atlas/web/security/NegativeSSLAndKerberosTest.java index 21d4f85..ae07ca4 100755 --- a/webapp/src/test/java/org/apache/atlas/web/security/NegativeSSLAndKerberosTest.java +++ b/webapp/src/test/java/org/apache/atlas/web/security/NegativeSSLAndKerberosTest.java @@ -91,6 +91,7 @@ public class NegativeSSLAndKerberosTest extends BaseSSLAndKerberosTest { + "/users-credentials"); configuration.setProperty("atlas.auth.policy.file",persistDir + "/policy-store.txt" ); + configuration.setProperty("atlas.authentication.method.trustedproxy", "false"); TestUtils.writeConfiguration(configuration, persistDir + File.separator + ApplicationProperties.APPLICATION_PROPERTIES); http://git-wip-us.apache.org/repos/asf/atlas/blob/62cdbdc6/webapp/src/test/java/org/apache/atlas/web/security/SSLAndKerberosTest.java ---------------------------------------------------------------------- diff --git a/webapp/src/test/java/org/apache/atlas/web/security/SSLAndKerberosTest.java b/webapp/src/test/java/org/apache/atlas/web/security/SSLAndKerberosTest.java index 49d56b2..e039d6c 100755 --- a/webapp/src/test/java/org/apache/atlas/web/security/SSLAndKerberosTest.java +++ b/webapp/src/test/java/org/apache/atlas/web/security/SSLAndKerberosTest.java @@ -91,6 +91,7 @@ public class SSLAndKerberosTest extends BaseSSLAndKerberosTest { configuration.setProperty("atlas.authentication.principal","dgi/localhost@"+kdc.getRealm()); configuration.setProperty("atlas.authentication.method.file", "false"); + configuration.setProperty("atlas.authentication.method.trustedproxy", "false"); configuration.setProperty("atlas.authentication.method.kerberos", "true"); configuration.setProperty("atlas.authentication.method.kerberos.principal", "HTTP/localhost@" + kdc.getRealm()); configuration.setProperty("atlas.authentication.method.kerberos.keytab", httpKeytabFile.getAbsolutePath());
