Commit 395296ce by Hemanth Yamijala

ATLAS-820 Kerberized env: Authentication failing (nixonrodrigues via yhemanth)

parent b66f0572
...@@ -562,7 +562,7 @@ public class HiveMetaStoreBridge { ...@@ -562,7 +562,7 @@ public class HiveMetaStoreBridge {
String atlasEndpoint = atlasConf.getString(ATLAS_ENDPOINT, DEFAULT_DGI_URL); String atlasEndpoint = atlasConf.getString(ATLAS_ENDPOINT, DEFAULT_DGI_URL);
AtlasClient atlasClient; AtlasClient atlasClient;
if (!AuthenticationUtil.isKerberosAuthicationEnabled()) { if (!AuthenticationUtil.isKerberosAuthenticationEnabled()) {
String[] basicAuthUsernamePassword = AuthenticationUtil.getBasicAuthenticationInput(); String[] basicAuthUsernamePassword = AuthenticationUtil.getBasicAuthenticationInput();
atlasClient = new AtlasClient(new String[]{atlasEndpoint}, basicAuthUsernamePassword); atlasClient = new AtlasClient(new String[]{atlasEndpoint}, basicAuthUsernamePassword);
} else { } else {
......
...@@ -64,7 +64,7 @@ public class AtlasAdminClient { ...@@ -64,7 +64,7 @@ public class AtlasAdminClient {
AtlasConstants.ATLAS_REST_ADDRESS_KEY, AtlasConstants.DEFAULT_ATLAS_REST_ADDRESS); AtlasConstants.ATLAS_REST_ADDRESS_KEY, AtlasConstants.DEFAULT_ATLAS_REST_ADDRESS);
AtlasClient atlasClient = null; AtlasClient atlasClient = null;
if (!AuthenticationUtil.isKerberosAuthicationEnabled()) { if (!AuthenticationUtil.isKerberosAuthenticationEnabled()) {
String[] basicAuthUsernamePassword = AuthenticationUtil.getBasicAuthenticationInput(); String[] basicAuthUsernamePassword = AuthenticationUtil.getBasicAuthenticationInput();
atlasClient = new AtlasClient(new String[]{atlasServerUri}, basicAuthUsernamePassword); atlasClient = new AtlasClient(new String[]{atlasServerUri}, basicAuthUsernamePassword);
} else { } else {
......
...@@ -189,7 +189,7 @@ public class AtlasClient { ...@@ -189,7 +189,7 @@ public class AtlasClient {
configuration = getClientProperties(); configuration = getClientProperties();
Client client = getClient(configuration, ugi, doAsUser); Client client = getClient(configuration, ugi, doAsUser);
if ((!AuthenticationUtil.isKerberosAuthicationEnabled()) && basicAuthUser!=null && basicAuthPassword!=null) { if ((!AuthenticationUtil.isKerberosAuthenticationEnabled()) && basicAuthUser!=null && basicAuthPassword!=null) {
final HTTPBasicAuthFilter authFilter = new HTTPBasicAuthFilter(basicAuthUser, basicAuthPassword); final HTTPBasicAuthFilter authFilter = new HTTPBasicAuthFilter(basicAuthUser, basicAuthPassword);
client.addFilter(authFilter); client.addFilter(authFilter);
} }
...@@ -221,7 +221,7 @@ public class AtlasClient { ...@@ -221,7 +221,7 @@ public class AtlasClient {
URLConnectionClientHandler handler = null; URLConnectionClientHandler handler = null;
if ((!AuthenticationUtil.isKerberosAuthicationEnabled()) && basicAuthUser!=null && basicAuthPassword!=null) { if ((!AuthenticationUtil.isKerberosAuthenticationEnabled()) && basicAuthUser!=null && basicAuthPassword!=null) {
handler = new URLConnectionClientHandler(); handler = new URLConnectionClientHandler();
} else { } else {
handler = handler =
......
...@@ -35,22 +35,21 @@ public final class AuthenticationUtil { ...@@ -35,22 +35,21 @@ public final class AuthenticationUtil {
private AuthenticationUtil() { private AuthenticationUtil() {
} }
public static boolean isKerberosAuthicationEnabled() { public static boolean isKerberosAuthenticationEnabled() {
boolean isKerberosAuthicationEnabled = false; boolean isKerberosAuthenticationEnabled = false;
try { try {
Configuration atlasConf = ApplicationProperties.get(); Configuration atlasConf = ApplicationProperties.get();
if ("true".equalsIgnoreCase(atlasConf.getString("atlas.http.authentication.enabled")) if ("true".equalsIgnoreCase(atlasConf.getString("atlas.authentication.method.kerberos"))) {
&& "kerberos".equalsIgnoreCase(atlasConf.getString("atlas.http.authentication.type"))) { isKerberosAuthenticationEnabled = true;
isKerberosAuthicationEnabled = true;
} else { } else {
isKerberosAuthicationEnabled = false; isKerberosAuthenticationEnabled = false;
} }
} catch (AtlasException e) { } catch (AtlasException e) {
LOG.error("Error while isKerberosAuthicationEnabled ", e); LOG.error("Error while isKerberosAuthenticationEnabled ", e);
} }
return isKerberosAuthicationEnabled; return isKerberosAuthenticationEnabled;
} }
public static String[] getBasicAuthenticationInput() { public static String[] getBasicAuthenticationInput() {
......
...@@ -63,10 +63,13 @@ atlas.enableTLS=false ...@@ -63,10 +63,13 @@ atlas.enableTLS=false
# Authentication config # Authentication config
# enabled: true or false atlas.authentication.method.kerberos=false
atlas.http.authentication.enabled=false atlas.authentication.method.ldap=false
# type: simple or kerberos atlas.authentication.method.file=true
atlas.http.authentication.type=simple
atlas.authentication.method.ldap.type=LDAP
atlas.authentication.method.ldap.url=
atlas.authentication.method.file.filename=${sys:atlas.home}/conf/users-credentials.properties
######### JAAS Configuration ######## ######### JAAS Configuration ########
...@@ -102,11 +105,6 @@ atlas.server.ha.enabled=false ...@@ -102,11 +105,6 @@ atlas.server.ha.enabled=false
#atlas.server.ha.zookeeper.auth=<scheme>:<authinfo> #atlas.server.ha.zookeeper.auth=<scheme>:<authinfo>
#### atlas.login.method {FILE,LDAP,AD} ####
atlas.login.method=FILE
### File path of users-credentials
atlas.login.credentials.file=${sys:atlas.home}/conf/users-credentials.properties
#########POLICY FILE PATH ######### #########POLICY FILE PATH #########
atlas.auth.policy.file=${sys:atlas.home}/conf/policy-store.txt atlas.auth.policy.file=${sys:atlas.home}/conf/policy-store.txt
......
...@@ -5,3 +5,4 @@ ...@@ -5,3 +5,4 @@
adminPolicy;;admin:rwud;;ROLE_ADMIN:rwud;;type:*,entity:*,operation:*,taxonomy:*,term:* adminPolicy;;admin:rwud;;ROLE_ADMIN:rwud;;type:*,entity:*,operation:*,taxonomy:*,term:*
dataScientistPolicy;;;;DATA_SCIENTIST:r;;type:*,entity:*,taxonomy:*,term:* dataScientistPolicy;;;;DATA_SCIENTIST:r;;type:*,entity:*,taxonomy:*,term:*
dataStewardPolicy;;;;DATA_STEWARD:rwu;;type:*,entity:*,taxonomy:*,term:* dataStewardPolicy;;;;DATA_STEWARD:rwu;;type:*,entity:*,taxonomy:*,term:*
hadoopPolicy;;;;hadoop:rwud;;type:*,entity:*,operation:*,taxonomy:*,term:*
...@@ -22,6 +22,7 @@ ATLAS-409 Atlas will not import avro tables with schema read from a file (dosset ...@@ -22,6 +22,7 @@ ATLAS-409 Atlas will not import avro tables with schema read from a file (dosset
ATLAS-379 Create sqoop and falcon metadata addons (venkatnrangan,bvellanki,sowmyaramesh via shwethags) ATLAS-379 Create sqoop and falcon metadata addons (venkatnrangan,bvellanki,sowmyaramesh via shwethags)
ALL CHANGES: ALL CHANGES:
ATLAS-820 Kerberized env: Authentication failing (nixonrodrigues via yhemanth)
ATLAS-852 Change Default landing page to taxonomy (kevalbhatt18 via yhemanth) ATLAS-852 Change Default landing page to taxonomy (kevalbhatt18 via yhemanth)
ATLAS-858 Unable to delete terms via API which are 3 or more levels deep (jspeidel via sumasai) ATLAS-858 Unable to delete terms via API which are 3 or more levels deep (jspeidel via sumasai)
ATLAS-848 Atlas UI: Search term box in left navigation is not auto refresh.(Kalyanikashikar via sumasai) ATLAS-848 Atlas UI: Search term box in left navigation is not auto refresh.(Kalyanikashikar via sumasai)
......
...@@ -72,7 +72,7 @@ public class QuickStart { ...@@ -72,7 +72,7 @@ public class QuickStart {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
String[] basicAuthUsernamePassword = null; String[] basicAuthUsernamePassword = null;
if (!AuthenticationUtil.isKerberosAuthicationEnabled()) { if (!AuthenticationUtil.isKerberosAuthenticationEnabled()) {
basicAuthUsernamePassword = AuthenticationUtil.getBasicAuthenticationInput(); basicAuthUsernamePassword = AuthenticationUtil.getBasicAuthenticationInput();
} }
...@@ -84,7 +84,7 @@ public class QuickStart { ...@@ -84,7 +84,7 @@ public class QuickStart {
String baseUrl = getServerUrl(args); String baseUrl = getServerUrl(args);
QuickStart quickStart; QuickStart quickStart;
if (!AuthenticationUtil.isKerberosAuthicationEnabled()) { if (!AuthenticationUtil.isKerberosAuthenticationEnabled()) {
quickStart = new QuickStart(baseUrl, basicAuthUsernamePassword); quickStart = new QuickStart(baseUrl, basicAuthUsernamePassword);
} else { } else {
quickStart = new QuickStart(baseUrl); quickStart = new QuickStart(baseUrl);
......
...@@ -58,7 +58,7 @@ public class UserDao { ...@@ -58,7 +58,7 @@ public class UserDao {
Configuration configuration = ApplicationProperties.get(); Configuration configuration = ApplicationProperties.get();
PROPERTY_FILE_PATH = configuration PROPERTY_FILE_PATH = configuration
.getString("atlas.login.credentials.file"); .getString("atlas.authentication.method.file.filename");
if (PROPERTY_FILE_PATH != null && !"".equals(PROPERTY_FILE_PATH)) { if (PROPERTY_FILE_PATH != null && !"".equals(PROPERTY_FILE_PATH)) {
userLogins = new Properties(); userLogins = new Properties();
userLogins.load(new FileInputStream(PROPERTY_FILE_PATH)); userLogins.load(new FileInputStream(PROPERTY_FILE_PATH));
......
...@@ -18,20 +18,38 @@ ...@@ -18,20 +18,38 @@
package org.apache.atlas.web.filters; package org.apache.atlas.web.filters;
import com.google.inject.Singleton;
import org.apache.atlas.ApplicationProperties; import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.RequestContext; import org.apache.atlas.RequestContext;
import org.apache.atlas.security.SecurityProperties; import org.apache.atlas.security.SecurityProperties;
import org.apache.atlas.utils.AuthenticationUtil;
import org.apache.atlas.web.listeners.LoginProcessor;
import org.apache.atlas.web.util.Servlets; import org.apache.atlas.web.util.Servlets;
import org.apache.commons.collections.iterators.IteratorEnumeration;
import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationConverter; import org.apache.commons.configuration.ConfigurationConverter;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.security.SecurityUtil; import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
import org.apache.hadoop.security.authentication.server.AuthenticationFilter; import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
import org.apache.hadoop.security.authentication.server.AuthenticationToken;
import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler; import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler;
import org.apache.hadoop.security.authentication.server.AuthenticationHandler;
import org.apache.hadoop.security.authentication.util.Signer;
import org.apache.hadoop.security.authentication.util.SignerSecretProvider;
import org.apache.log4j.NDC; import org.apache.log4j.NDC;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.FilterConfig; import javax.servlet.FilterConfig;
import javax.servlet.ServletException; import javax.servlet.ServletException;
...@@ -39,22 +57,39 @@ import javax.servlet.ServletRequest; ...@@ -39,22 +57,39 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletContext;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Enumeration; import java.security.Principal;
import java.util.Properties; import java.text.SimpleDateFormat;
import java.util.*;
/** /**
* This enforces authentication as part of the filter before processing the request. * This enforces authentication as part of the filter before processing the request.
* todo: Subclass of {@link org.apache.hadoop.security.authentication.server.AuthenticationFilter}. * todo: Subclass of {@link org.apache.hadoop.security.authentication.server.AuthenticationFilter}.
*/ */
@Singleton
public class AtlasAuthenticationFilter extends AuthenticationFilter { public class AtlasAuthenticationFilter extends AuthenticationFilter {
private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthenticationFilter.class); private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthenticationFilter.class);
static final String PREFIX = "atlas.http.authentication"; static final String PREFIX = "atlas.authentication.method";
protected static ServletContext nullContext = new NullServletContext();
private Signer signer;
private SignerSecretProvider secretProvider;
public final boolean isKerberos = AuthenticationUtil.isKerberosAuthenticationEnabled();
public AtlasAuthenticationFilter() {
try {
LOG.info("AtlasAuthenticationFilter initialization started");
init(null);
} catch (ServletException e) {
LOG.error("Error while initializing AtlasAuthenticationFilter : " + e.getMessage());
}
}
private HttpServlet optionsServlet; private HttpServlet optionsServlet;
...@@ -67,10 +102,66 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { ...@@ -67,10 +102,66 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
@Override @Override
public void init(FilterConfig filterConfig) throws ServletException { public void init(FilterConfig filterConfig) throws ServletException {
LOG.info("AtlasAuthenticationFilter initialization started"); LOG.info("AtlasAuthenticationFilter initialization started");
super.init(filterConfig); final FilterConfig globalConf = filterConfig;
final Map<String, String> params = new HashMap<String, String>();
FilterConfig filterConfig1 = new FilterConfig() {
@Override
public ServletContext getServletContext() {
if (globalConf != null) {
return globalConf.getServletContext();
} else {
return nullContext;
}
}
optionsServlet = new HttpServlet() {}; @SuppressWarnings("unchecked")
@Override
public Enumeration<String> getInitParameterNames() {
return new IteratorEnumeration(params.keySet().iterator());
}
@Override
public String getInitParameter(String param) {
return params.get(param);
}
@Override
public String getFilterName() {
return "AtlasAuthenticationFilter";
}
};
super.init(filterConfig1);
optionsServlet = new HttpServlet() {
};
optionsServlet.init(); optionsServlet.init();
}
@Override
public void initializeSecretProvider(FilterConfig filterConfig)
throws ServletException {
LOG.debug("AtlasAuthenticationFilter :: initializeSecretProvider "+filterConfig);
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);
} catch (Exception ex) {
throw new ServletException(ex);
}
}
signer = new Signer(secretProvider);
} }
@Override @Override
...@@ -82,10 +173,28 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { ...@@ -82,10 +173,28 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
throw new ServletException(e); throw new ServletException(e);
} }
// transfer atlas-application.properties config items starting with defined prefix Properties config = new Properties();
Configuration subConfiguration = ApplicationProperties.getSubsetConfiguration(configuration, PREFIX);
Properties config = ConfigurationConverter.getProperties(subConfiguration);
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 = "";
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"));
}
config.put(AuthenticationFilter.AUTH_TYPE, authMethod );
config.put(AuthenticationFilter.COOKIE_PATH, "/"); config.put(AuthenticationFilter.COOKIE_PATH, "/");
// add any config passed in as init parameters // add any config passed in as init parameters
...@@ -115,7 +224,7 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { ...@@ -115,7 +224,7 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
config.put(KerberosAuthenticationHandler.PRINCIPAL, principal); config.put(KerberosAuthenticationHandler.PRINCIPAL, principal);
} }
LOG.info("AuthenticationFilterConfig: {}", config); LOG.debug(" AuthenticationFilterConfig: {}", config);
return config; return config;
} }
...@@ -123,21 +232,53 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { ...@@ -123,21 +232,53 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
@Override @Override
public void doFilter(final ServletRequest request, final ServletResponse response, public void doFilter(final ServletRequest request, final ServletResponse response,
final FilterChain filterChain) throws IOException, ServletException { final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) request;
FilterChain filterChainWrapper = new FilterChain() { FilterChain filterChainWrapper = new FilterChain() {
@Override @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse)
throws IOException, ServletException { throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; 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))) {
UserGroupInformation ugi = UserGroupInformation.getLoginUser();
String[] groupsName = ugi.getGroupNames();
final List<GrantedAuthority> grantedAuths = new ArrayList<>();
for (String group : groupsName) {
grantedAuths.add(new SimpleGrantedAuthority(group));
}
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")) { if (httpRequest.getMethod().equals("OPTIONS")) {
optionsServlet.service(request, response); optionsServlet.service(request, response);
} else { } else {
try { try {
String requestUser = httpRequest.getRemoteUser(); String requestUser = httpRequest.getRemoteUser();
NDC.push(requestUser + ":" + httpRequest.getMethod() + httpRequest.getRequestURI()); NDC.push(requestUser + ":" + httpRequest.getMethod() + httpRequest.getRequestURI());
RequestContext requestContext = RequestContext.get(); RequestContext requestContext = RequestContext.get();
requestContext.setUser(requestUser); if(requestContext!=null) {
requestContext.setUser(requestUser);
}
LOG.info("Request from authenticated user: {}, URL={}", requestUser, LOG.info("Request from authenticated user: {}, URL={}", requestUser,
Servlets.getRequestURI(httpRequest)); Servlets.getRequestURI(httpRequest));
...@@ -149,9 +290,18 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { ...@@ -149,9 +290,18 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
} }
}; };
try { try {
super.doFilter(request, response, filterChainWrapper); String authHeader = httpRequest.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Basic")) {
filterChain.doFilter(request, response);
} else if (isKerberos) {
doKerberosAuth(request, response, filterChainWrapper);
} else {
filterChain.doFilter(request, response);
}
} catch (NullPointerException e) { } catch (NullPointerException e) {
LOG.error("Exception in AtlasAuthenticationFilter ", e);
//PseudoAuthenticationHandler.getUserName() from hadoop-auth throws NPE if user name is not specified //PseudoAuthenticationHandler.getUserName() from hadoop-auth throws NPE if user name is not specified
((HttpServletResponse) response).sendError(Response.Status.BAD_REQUEST.getStatusCode(), ((HttpServletResponse) response).sendError(Response.Status.BAD_REQUEST.getStatusCode(),
"Authentication is enabled and user is not specified. Specify user.name parameter"); "Authentication is enabled and user is not specified. Specify user.name parameter");
...@@ -159,9 +309,202 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter { ...@@ -159,9 +309,202 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
} }
/**
* This method is copied from hadoop auth lib, code added for error handling and fallback to other auth methods
*
* If the request has a valid authentication token it allows the request to continue to the target resource,
* otherwise it triggers an authentication sequence using the configured {@link org.apache.hadoop.security.authentication.server.AuthenticationHandler}.
*
* @param request the request object.
* @param response the response object.
* @param filterChain the filter chain object.
*
* @throws IOException thrown if an IO error occurred.
* @throws ServletException thrown if a processing error occurred.
*/
public void doKerberosAuth(ServletRequest request, ServletResponse response, 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();
try {
boolean newToken = false;
AuthenticationToken token;
try {
token = getToken(httpRequest);
}
catch (AuthenticationException ex) {
LOG.warn("AuthenticationToken ignored: " + ex.getMessage());
// will be sent back in a 401 unless filter authenticates
authenticationEx = ex;
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) {
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());
}
final AuthenticationToken authToken = token;
httpRequest = new HttpServletRequestWrapper(httpRequest) {
@Override
public String getAuthType() {
return authToken.getType();
}
@Override
public String getRemoteUser() {
return authToken.getUserName();
}
@Override
public Principal getUserPrincipal() {
return (authToken != AuthenticationToken.ANONYMOUS) ? authToken : null;
}
};
if (newToken && !token.isExpired() && token != AuthenticationToken.ANONYMOUS) {
String signedToken = signer.sign(token.toString());
createAuthCookie(httpResponse, signedToken, getCookieDomain(),
getCookiePath(), token.getExpires(), isHttps);
}
filterChain.doFilter(httpRequest, httpResponse);
}
} else {
unauthorizedResponse = false;
}
} catch (AuthenticationException ex) {
// exception from the filter itself is fatal
errCode = HttpServletResponse.SC_FORBIDDEN;
authenticationEx = ex;
LOG.warn("Authentication exception: " + ex.getMessage(), ex);
}
if (unauthorizedResponse) {
if (!httpResponse.isCommitted()) {
createAuthCookie(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))) {
errCode = HttpServletResponse.SC_FORBIDDEN;
}
if (authenticationEx == null) { // added this code for atlas error handling and fallback
boolean chk = true;
Collection<String> headerNames = httpResponse.getHeaderNames();
for (String headerName : headerNames) {
String value = httpResponse.getHeader(headerName);
if (headerName.equalsIgnoreCase("Set-Cookie") && value.startsWith("JSESSIONID")) {
chk = false;
break;
}
}
String authHeader = httpRequest.getHeader("Authorization");
if (authHeader == null && chk) {
filterChain.doFilter(request, response);
} else if (authHeader != null && authHeader.startsWith("Basic")) {
filterChain.doFilter(request, response);
}
} else {
httpResponse.sendError(errCode, authenticationEx.getMessage());
}
}
}
}
@Override @Override
public void destroy() { public void destroy() {
optionsServlet.destroy(); optionsServlet.destroy();
super.destroy(); super.destroy();
} }
private static String readUserFromCookie(HttpServletResponse response1) {
String userName = null;
boolean isCookieSet = response1.containsHeader("Set-Cookie");
if (isCookieSet) {
Collection<String> authUserName = response1.getHeaders("Set-Cookie");
if (authUserName != null) {
Iterator<String> i = authUserName.iterator();
while (i.hasNext()) {
String cookie = i.next();
if (!StringUtils.isEmpty(cookie)) {
if (cookie.toLowerCase().startsWith("hadoop.auth".toLowerCase()) && cookie.contains("u=")) {
String[] split = cookie.split(";");
if (split != null) {
for (String s : split) {
if (!StringUtils.isEmpty(s) && s.toLowerCase().startsWith("hadoop.auth".toLowerCase())) {
int ustr = s.indexOf("u=");
if (ustr != -1) {
int andStr = s.indexOf("&", ustr);
if (andStr != -1) {
try {
userName = s.substring(ustr + 2, andStr);
break;
} catch (Exception e) {
userName = null;
}
}
}
}
}
}
}
}
}
}
}
return userName;
}
public static void createAuthCookie(HttpServletResponse resp, String token, String domain, String path, long expires, boolean isSecure) {
StringBuilder sb = (new StringBuilder("hadoop.auth")).append("=");
if(token != null && token.length() > 0) {
sb.append("\"").append(token).append("\"");
}
sb.append("; Version=1");
if(path != null) {
sb.append("; Path=").append(path);
}
if(domain != null) {
sb.append("; Domain=").append(domain);
}
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));
}
if(isSecure) {
sb.append("; Secure");
}
sb.append("; HttpOnly");
resp.addHeader("Set-Cookie", sb.toString());
}
} }
/**
* 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. See accompanying LICENSE file.
*/
package org.apache.atlas.web.filters;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletRegistration;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import javax.servlet.FilterRegistration.Dynamic;
import javax.servlet.descriptor.JspConfigDescriptor;
import java.util.EventListener;
import java.util.Map;
/**
*/
public class NullServletContext implements ServletContext {
public void setSessionTrackingModes(
Set<SessionTrackingMode> sessionTrackingModes) {
}
public boolean setInitParameter(String name, String value) {
return false;
}
public void setAttribute(String name, Object object) {
}
public void removeAttribute(String name) {
}
public void log(String message, Throwable throwable) {
}
public void log(Exception exception, String msg) {
}
public void log(String msg) {
}
public String getVirtualServerName() {
return null;
}
public SessionCookieConfig getSessionCookieConfig() {
return null;
}
public Enumeration<Servlet> getServlets() {
return null;
}
public Map<String, ? extends ServletRegistration> getServletRegistrations() {
return null;
}
public ServletRegistration getServletRegistration(String servletName) {
return null;
}
public Enumeration<String> getServletNames() {
return null;
}
public String getServletContextName() {
return null;
}
public Servlet getServlet(String name) throws ServletException {
return null;
}
public String getServerInfo() {
return null;
}
public Set<String> getResourcePaths(String path) {
return null;
}
public InputStream getResourceAsStream(String path) {
return null;
}
public URL getResource(String path) throws MalformedURLException {
return null;
}
public RequestDispatcher getRequestDispatcher(String path) {
return null;
}
public String getRealPath(String path) {
return null;
}
public RequestDispatcher getNamedDispatcher(String name) {
return null;
}
public int getMinorVersion() {
return 0;
}
public String getMimeType(String file) {
return null;
}
public int getMajorVersion() {
return 0;
}
public JspConfigDescriptor getJspConfigDescriptor() {
return null;
}
public Enumeration<String> getInitParameterNames() {
return null;
}
public String getInitParameter(String name) {
return null;
}
public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
return null;
}
public FilterRegistration getFilterRegistration(String filterName) {
return null;
}
public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
return null;
}
public int getEffectiveMinorVersion() {
return 0;
}
public int getEffectiveMajorVersion() {
return 0;
}
public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
return null;
}
public String getContextPath() {
return null;
}
public ServletContext getContext(String uripath) {
return null;
}
public ClassLoader getClassLoader() {
return null;
}
public Enumeration<String> getAttributeNames() {
return null;
}
public Object getAttribute(String name) {
return null;
}
public void declareRoles(String... roleNames) {
}
public <T extends Servlet> T createServlet(Class<T> clazz)
throws ServletException {
return null;
}
public <T extends EventListener> T createListener(Class<T> clazz)
throws ServletException {
return null;
}
public <T extends Filter> T createFilter(Class<T> clazz)
throws ServletException {
return null;
}
public javax.servlet.ServletRegistration.Dynamic addServlet(
String servletName, Class<? extends Servlet> servletClass) {
return null;
}
public javax.servlet.ServletRegistration.Dynamic addServlet(
String servletName, Servlet servlet) {
return null;
}
public javax.servlet.ServletRegistration.Dynamic addServlet(
String servletName, String className) {
return null;
}
public void addListener(Class<? extends EventListener> listenerClass) {
}
public <T extends EventListener> void addListener(T t) {
}
public void addListener(String className) {
}
public Dynamic addFilter(String filterName,
Class<? extends Filter> filterClass) {
return null;
}
public Dynamic addFilter(String filterName, Filter filter) {
return null;
}
public Dynamic addFilter(String filterName, String className) {
return null;
}
}
...@@ -95,11 +95,6 @@ public class GuiceServletConfig extends GuiceServletContextListener { ...@@ -95,11 +95,6 @@ public class GuiceServletConfig extends GuiceServletContextListener {
protected void configureServlets() { protected void configureServlets() {
filter("/*").through(AuditFilter.class); filter("/*").through(AuditFilter.class);
configureActiveServerFilterIfNecessary(); configureActiveServerFilterIfNecessary();
try {
configureAuthenticationFilter();
} catch (ConfigurationException e) {
LOG.warn("Unable to add and configure authentication filter", e);
}
String packages = getServletContext().getInitParameter(GUICE_CTX_PARAM); String packages = getServletContext().getInitParameter(GUICE_CTX_PARAM);
...@@ -120,16 +115,6 @@ public class GuiceServletConfig extends GuiceServletContextListener { ...@@ -120,16 +115,6 @@ public class GuiceServletConfig extends GuiceServletContextListener {
} }
} }
private void configureAuthenticationFilter() throws ConfigurationException {
Configuration configuration = getConfiguration();
if (configuration == null) {
throw new ConfigurationException("Could not load application configuration");
}
if (Boolean.valueOf(configuration.getString(AtlasClient.HTTP_AUTHENTICATION_ENABLED))) {
LOG.info("Enabling AuthenticationFilter");
filter("/*").through(AtlasAuthenticationFilter.class);
}
}
}); });
LOG.info("Guice modules loaded"); LOG.info("Guice modules loaded");
......
...@@ -38,7 +38,7 @@ public class LoginProcessor { ...@@ -38,7 +38,7 @@ public class LoginProcessor {
private static final Logger LOG = LoggerFactory.getLogger(LoginProcessor.class); private static final Logger LOG = LoggerFactory.getLogger(LoginProcessor.class);
public static final String ATLAS_AUTHENTICATION_PREFIX = "atlas.authentication."; public static final String ATLAS_AUTHENTICATION_PREFIX = "atlas.authentication.";
public static final String AUTHENTICATION_METHOD = ATLAS_AUTHENTICATION_PREFIX + "method"; public static final String AUTHENTICATION_KERBEROS_METHOD = ATLAS_AUTHENTICATION_PREFIX + "method.kerberos";
public static final String AUTHENTICATION_PRINCIPAL = ATLAS_AUTHENTICATION_PREFIX + "principal"; public static final String AUTHENTICATION_PRINCIPAL = ATLAS_AUTHENTICATION_PREFIX + "principal";
public static final String AUTHENTICATION_KEYTAB = ATLAS_AUTHENTICATION_PREFIX + "keytab"; public static final String AUTHENTICATION_KEYTAB = ATLAS_AUTHENTICATION_PREFIX + "keytab";
...@@ -95,12 +95,14 @@ public class LoginProcessor { ...@@ -95,12 +95,14 @@ public class LoginProcessor {
protected void setupHadoopConfiguration(Configuration hadoopConfig, org.apache.commons.configuration.Configuration protected void setupHadoopConfiguration(Configuration hadoopConfig, org.apache.commons.configuration.Configuration
configuration) { configuration) {
String authMethod; String authMethod = "";
authMethod = configuration != null ? configuration.getString(AUTHENTICATION_METHOD) : null; String kerberosAuthNEnabled = configuration != null ? configuration.getString(AUTHENTICATION_KERBEROS_METHOD) : null;
// getString may return null, and would like to log the nature of the default setting // getString may return null, and would like to log the nature of the default setting
if (authMethod == null) { if (kerberosAuthNEnabled == null || kerberosAuthNEnabled.equalsIgnoreCase("false")) {
LOG.info("No authentication method configured. Defaulting to simple authentication"); LOG.info("No authentication method configured. Defaulting to simple authentication");
authMethod = "simple"; authMethod = "simple";
} else if (kerberosAuthNEnabled.equalsIgnoreCase("true")) {
authMethod = "kerberos";
} }
SecurityUtil SecurityUtil
.setAuthenticationMethod(UserGroupInformation.AuthenticationMethod.valueOf(authMethod.toUpperCase()), .setAuthenticationMethod(UserGroupInformation.AuthenticationMethod.valueOf(authMethod.toUpperCase()),
......
...@@ -34,11 +34,12 @@ public class AtlasAuthenticationProvider extends ...@@ -34,11 +34,12 @@ public class AtlasAuthenticationProvider extends
private static final Logger LOG = LoggerFactory private static final Logger LOG = LoggerFactory
.getLogger(AtlasAuthenticationProvider.class); .getLogger(AtlasAuthenticationProvider.class);
private String atlasAuthenticationMethod = "UNKNOWN"; private boolean fileAuthenticationMethodEnabled = true;
private boolean ldapAuthenticationMethodEnabled = false;
enum AUTH_METHOD { private String ldapType = "UNKNOWN";
FILE, LDAP, AD public static final String FILE_AUTH_METHOD = "atlas.authentication.method.file";
}; public static final String LDAP_AUTH_METHOD = "atlas.authentication.method.ldap";
public static final String LDAP_TYPE = "atlas.authentication.method.ldap.type";
@Autowired @Autowired
AtlasLdapAuthenticationProvider ldapAuthenticationProvider; AtlasLdapAuthenticationProvider ldapAuthenticationProvider;
...@@ -53,8 +54,12 @@ public class AtlasAuthenticationProvider extends ...@@ -53,8 +54,12 @@ public class AtlasAuthenticationProvider extends
void setAuthenticationMethod() { void setAuthenticationMethod() {
try { try {
Configuration configuration = ApplicationProperties.get(); Configuration configuration = ApplicationProperties.get();
this.atlasAuthenticationMethod = configuration.getString(
"atlas.login.method", "UNKNOWN"); this.fileAuthenticationMethodEnabled = configuration.getBoolean(
FILE_AUTH_METHOD, true);
this.ldapAuthenticationMethodEnabled = configuration.getBoolean(
LDAP_AUTH_METHOD, false);
this.ldapType = configuration.getString(LDAP_TYPE, "UNKNOWN");
} catch (Exception e) { } catch (Exception e) {
LOG.error( LOG.error(
"Error while getting atlas.login.method application properties", "Error while getting atlas.login.method application properties",
...@@ -66,37 +71,30 @@ public class AtlasAuthenticationProvider extends ...@@ -66,37 +71,30 @@ public class AtlasAuthenticationProvider extends
public Authentication authenticate(Authentication authentication) public Authentication authenticate(Authentication authentication)
throws AuthenticationException { throws AuthenticationException {
if (atlasAuthenticationMethod.equalsIgnoreCase(AUTH_METHOD.FILE.name())) { if (ldapAuthenticationMethodEnabled) {
authentication = fileAuthenticationProvider
.authenticate(authentication); if (ldapType.equalsIgnoreCase("LDAP")) {
} else if (atlasAuthenticationMethod.equalsIgnoreCase(AUTH_METHOD.LDAP try {
.name())) { authentication = ldapAuthenticationProvider
try { .authenticate(authentication);
authentication = ldapAuthenticationProvider } catch (Exception ex) {
.authenticate(authentication); LOG.error("Error while LDAP authentication", ex);
} catch (Exception ex) { }
LOG.error("Error while LDAP authentication", ex); } else if (ldapType.equalsIgnoreCase("AD")) {
} try {
} else if (atlasAuthenticationMethod.equalsIgnoreCase(AUTH_METHOD.AD authentication = adAuthenticationProvider
.name())) { .authenticate(authentication);
try { } catch (Exception ex) {
authentication = adAuthenticationProvider LOG.error("Error while AD authentication", ex);
.authenticate(authentication); }
} catch (Exception ex) {
LOG.error("Error while AD authentication", ex);
} }
} else {
LOG.error("Invalid authentication method :"
+ atlasAuthenticationMethod);
} }
if (authentication != null && authentication.isAuthenticated()) { if (authentication != null && authentication.isAuthenticated()) {
return authentication; return authentication;
} else { } else {
// If the LDAP/AD authentication fails try the local file login method // If the LDAP/AD authentication fails try the local filebased login method
if (atlasAuthenticationMethod.equalsIgnoreCase(AUTH_METHOD.AD if (fileAuthenticationMethodEnabled) {
.name()) || atlasAuthenticationMethod.equalsIgnoreCase(AUTH_METHOD.LDAP
.name())) {
authentication = fileAuthenticationProvider authentication = fileAuthenticationProvider
.authenticate(authentication); .authenticate(authentication);
} }
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
<security:http pattern="/login.jsp" security="none" /> <security:http pattern="/login.jsp" security="none" />
<security:http pattern="/css/**" security="none" /> <security:http pattern="/css/**" security="none" />
<security:http pattern="/img/**" security="none" />
<security:http pattern="/libs/**" security="none" /> <security:http pattern="/libs/**" security="none" />
<security:http pattern="/js/**" security="none" /> <security:http pattern="/js/**" security="none" />
<security:http pattern="/api/atlas/admin/status" security="none" /> <security:http pattern="/api/atlas/admin/status" security="none" />
...@@ -41,6 +42,8 @@ ...@@ -41,6 +42,8 @@
session-fixation-protection="newSession" /> session-fixation-protection="newSession" />
<intercept-url pattern="/**" access="isAuthenticated()" /> <intercept-url pattern="/**" access="isAuthenticated()" />
<security:custom-filter ref="krbAuthenticationFilter" after="SERVLET_API_SUPPORT_FILTER" />
<form-login <form-login
login-page="/login.jsp" login-page="/login.jsp"
authentication-success-handler-ref="atlasAuthenticationSuccessHandler" authentication-success-handler-ref="atlasAuthenticationSuccessHandler"
...@@ -51,9 +54,12 @@ ...@@ -51,9 +54,12 @@
<security:logout logout-success-url="/login.jsp" delete-cookies="JSESSIONID" <security:logout logout-success-url="/login.jsp" delete-cookies="JSESSIONID"
logout-url="/logout.html" /> logout-url="/logout.html" />
<http-basic /> <http-basic />
<security:custom-filter position="LAST" ref="atlasAuthorizationFilter"/> <security:custom-filter position="LAST" ref="atlasAuthorizationFilter"/>
</security:http> </security:http>
<beans:bean id="krbAuthenticationFilter" class="org.apache.atlas.web.filters.AtlasAuthenticationFilter">
</beans:bean>
<beans:bean id="atlasAuthenticationSuccessHandler" <beans:bean id="atlasAuthenticationSuccessHandler"
class="org.apache.atlas.web.security.AtlasAuthenticationSuccessHandler" /> class="org.apache.atlas.web.security.AtlasAuthenticationSuccessHandler" />
......
...@@ -89,7 +89,7 @@ public abstract class BaseResourceIT { ...@@ -89,7 +89,7 @@ public abstract class BaseResourceIT {
service = client.resource(UriBuilder.fromUri(baseUrl).build()); service = client.resource(UriBuilder.fromUri(baseUrl).build());
if (!AuthenticationUtil.isKerberosAuthicationEnabled()) { if (!AuthenticationUtil.isKerberosAuthenticationEnabled()) {
serviceClient = new AtlasClient(new String[]{baseUrl}, new String[]{"admin", "admin"}); serviceClient = new AtlasClient(new String[]{baseUrl}, new String[]{"admin", "admin"});
} else { } else {
serviceClient = new AtlasClient(baseUrl); serviceClient = new AtlasClient(baseUrl);
......
...@@ -77,8 +77,8 @@ public class FileAuthenticationTest { ...@@ -77,8 +77,8 @@ public class FileAuthenticationTest {
private void setUpAltasApplicationProperties(String persistDir) throws Exception { private void setUpAltasApplicationProperties(String persistDir) throws Exception {
final PropertiesConfiguration configuration = new PropertiesConfiguration(); final PropertiesConfiguration configuration = new PropertiesConfiguration();
configuration.setProperty("atlas.login.method", "FILE"); configuration.setProperty("atlas.authentication.method.file", "true");
configuration.setProperty("atlas.login.credentials.file", persistDir configuration.setProperty("atlas.authentication.method.file.filename", persistDir
+ "/users-credentials"); + "/users-credentials");
configuration.setProperty("atlas.auth.policy.file",persistDir configuration.setProperty("atlas.auth.policy.file",persistDir
+ "/policy-store.txt" ); + "/policy-store.txt" );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment