You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by wh...@apache.org on 2015/03/30 20:44:30 UTC
hadoop git commit: HADOOP-11754. RM fails to start in non-secure mode
due to authentication filter failure. Contributed by Haohui Mai.
Repository: hadoop
Updated Branches:
refs/heads/branch-2 a84fdd565 -> 24d879026
HADOOP-11754. RM fails to start in non-secure mode due to authentication filter failure. Contributed by Haohui Mai.
Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/24d87902
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/24d87902
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/24d87902
Branch: refs/heads/branch-2
Commit: 24d879026d3316fe4015aab627bc13ca7dc08fa5
Parents: a84fdd5
Author: Haohui Mai <wh...@apache.org>
Authored: Mon Mar 30 11:44:22 2015 -0700
Committer: Haohui Mai <wh...@apache.org>
Committed: Mon Mar 30 11:44:30 2015 -0700
----------------------------------------------------------------------
.../server/AuthenticationFilter.java | 108 +++++++++----------
.../server/TestAuthenticationFilter.java | 20 ++--
hadoop-common-project/hadoop-common/CHANGES.txt | 3 +
.../org/apache/hadoop/http/HttpServer2.java | 53 ++++++++-
.../AuthenticationFilterInitializer.java | 18 ++--
5 files changed, 128 insertions(+), 74 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hadoop/blob/24d87902/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
index 5c22fce..684e91c 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
@@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -183,8 +184,6 @@ public class AuthenticationFilter implements Filter {
private Signer signer;
private SignerSecretProvider secretProvider;
private AuthenticationHandler authHandler;
- private boolean randomSecret;
- private boolean customSecretProvider;
private long validity;
private String cookieDomain;
private String cookiePath;
@@ -226,7 +225,6 @@ public class AuthenticationFilter implements Filter {
initializeAuthHandler(authHandlerClassName, filterConfig);
-
cookieDomain = config.getProperty(COOKIE_DOMAIN, null);
cookiePath = config.getProperty(COOKIE_PATH, null);
}
@@ -237,11 +235,8 @@ public class AuthenticationFilter implements Filter {
Class<?> klass = Thread.currentThread().getContextClassLoader().loadClass(authHandlerClassName);
authHandler = (AuthenticationHandler) klass.newInstance();
authHandler.init(config);
- } catch (ClassNotFoundException ex) {
- throw new ServletException(ex);
- } catch (InstantiationException ex) {
- throw new ServletException(ex);
- } catch (IllegalAccessException ex) {
+ } catch (ClassNotFoundException | InstantiationException |
+ IllegalAccessException ex) {
throw new ServletException(ex);
}
}
@@ -251,62 +246,59 @@ public class AuthenticationFilter implements Filter {
secretProvider = (SignerSecretProvider) filterConfig.getServletContext().
getAttribute(SIGNER_SECRET_PROVIDER_ATTRIBUTE);
if (secretProvider == null) {
- Class<? extends SignerSecretProvider> providerClass
- = getProviderClass(config);
- try {
- secretProvider = providerClass.newInstance();
- } catch (InstantiationException ex) {
- throw new ServletException(ex);
- } catch (IllegalAccessException ex) {
- throw new ServletException(ex);
- }
+ // As tomcat cannot specify the provider object in the configuration.
+ // It'll go into this path
try {
- secretProvider.init(config, filterConfig.getServletContext(), validity);
+ secretProvider = constructSecretProvider(
+ filterConfig.getServletContext(),
+ config, false);
} catch (Exception ex) {
throw new ServletException(ex);
}
- } else {
- customSecretProvider = true;
}
signer = new Signer(secretProvider);
}
- @SuppressWarnings("unchecked")
- private Class<? extends SignerSecretProvider> getProviderClass(Properties config)
- throws ServletException {
- String providerClassName;
- String signerSecretProviderName
- = config.getProperty(SIGNER_SECRET_PROVIDER, null);
- // fallback to old behavior
- if (signerSecretProviderName == null) {
- String signatureSecretFile = config.getProperty(
- SIGNATURE_SECRET_FILE, null);
- // The precedence from high to low : file, random
- if (signatureSecretFile != null) {
- providerClassName = FileSignerSecretProvider.class.getName();
- } else {
- providerClassName = RandomSignerSecretProvider.class.getName();
- randomSecret = true;
+ public static SignerSecretProvider constructSecretProvider(
+ ServletContext ctx, Properties config,
+ boolean disallowFallbackToRandomSecretProvider) throws Exception {
+ String name = config.getProperty(SIGNER_SECRET_PROVIDER, "file");
+ long validity = Long.parseLong(config.getProperty(AUTH_TOKEN_VALIDITY,
+ "36000")) * 1000;
+
+ if (!disallowFallbackToRandomSecretProvider
+ && "file".equals(name)
+ && config.getProperty(SIGNATURE_SECRET_FILE) == null) {
+ name = "random";
+ }
+
+ SignerSecretProvider provider;
+ if ("file".equals(name)) {
+ provider = new FileSignerSecretProvider();
+ try {
+ provider.init(config, ctx, validity);
+ } catch (Exception e) {
+ if (!disallowFallbackToRandomSecretProvider) {
+ LOG.info("Unable to initialize FileSignerSecretProvider, " +
+ "falling back to use random secrets.");
+ provider = new RandomSignerSecretProvider();
+ provider.init(config, ctx, validity);
+ } else {
+ throw e;
+ }
}
+ } else if ("random".equals(name)) {
+ provider = new RandomSignerSecretProvider();
+ provider.init(config, ctx, validity);
+ } else if ("zookeeper".equals(name)) {
+ provider = new ZKSignerSecretProvider();
+ provider.init(config, ctx, validity);
} else {
- if ("random".equals(signerSecretProviderName)) {
- providerClassName = RandomSignerSecretProvider.class.getName();
- randomSecret = true;
- } else if ("file".equals(signerSecretProviderName)) {
- providerClassName = FileSignerSecretProvider.class.getName();
- } else if ("zookeeper".equals(signerSecretProviderName)) {
- providerClassName = ZKSignerSecretProvider.class.getName();
- } else {
- providerClassName = signerSecretProviderName;
- customSecretProvider = true;
- }
- }
- try {
- return (Class<? extends SignerSecretProvider>) Thread.currentThread().
- getContextClassLoader().loadClass(providerClassName);
- } catch (ClassNotFoundException ex) {
- throw new ServletException(ex);
+ provider = (SignerSecretProvider) Thread.currentThread().
+ getContextClassLoader().loadClass(name).newInstance();
+ provider.init(config, ctx, validity);
}
+ return provider;
}
/**
@@ -335,7 +327,7 @@ public class AuthenticationFilter implements Filter {
* @return if a random secret is being used.
*/
protected boolean isRandomSecret() {
- return randomSecret;
+ return secretProvider.getClass() == RandomSignerSecretProvider.class;
}
/**
@@ -344,7 +336,10 @@ public class AuthenticationFilter implements Filter {
* @return if a custom implementation of a SignerSecretProvider is being used.
*/
protected boolean isCustomSignerSecretProvider() {
- return customSecretProvider;
+ Class<?> clazz = secretProvider.getClass();
+ return clazz != FileSignerSecretProvider.class && clazz !=
+ RandomSignerSecretProvider.class && clazz != ZKSignerSecretProvider
+ .class;
}
/**
@@ -385,9 +380,6 @@ public class AuthenticationFilter implements Filter {
authHandler.destroy();
authHandler = null;
}
- if (secretProvider != null) {
- secretProvider.destroy();
- }
}
/**
http://git-wip-us.apache.org/repos/asf/hadoop/blob/24d87902/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
index 26c10a9..63b812d 100644
--- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
+++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
@@ -18,7 +18,9 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.HttpCookie;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
@@ -151,8 +153,7 @@ public class TestAuthenticationFilter {
}
@Test
- public void testInit() throws Exception {
-
+ public void testFallbackToRandomSecretProvider() throws Exception {
// minimal configuration & simple auth handler (Pseudo)
AuthenticationFilter filter = new AuthenticationFilter();
try {
@@ -162,8 +163,8 @@ public class TestAuthenticationFilter {
AuthenticationFilter.AUTH_TOKEN_VALIDITY)).thenReturn(
(new Long(TOKEN_VALIDITY_SEC)).toString());
Mockito.when(config.getInitParameterNames()).thenReturn(
- new Vector<String>(Arrays.asList(AuthenticationFilter.AUTH_TYPE,
- AuthenticationFilter.AUTH_TOKEN_VALIDITY)).elements());
+ new Vector<>(Arrays.asList(AuthenticationFilter.AUTH_TYPE,
+ AuthenticationFilter.AUTH_TOKEN_VALIDITY)).elements());
ServletContext context = Mockito.mock(ServletContext.class);
Mockito.when(context.getAttribute(AuthenticationFilter.SIGNER_SECRET_PROVIDER_ATTRIBUTE))
.thenReturn(null);
@@ -178,16 +179,17 @@ public class TestAuthenticationFilter {
} finally {
filter.destroy();
}
-
+ }
+ @Test
+ public void testInit() throws Exception {
// custom secret as inline
- filter = new AuthenticationFilter();
+ AuthenticationFilter filter = new AuthenticationFilter();
try {
FilterConfig config = Mockito.mock(FilterConfig.class);
Mockito.when(config.getInitParameter(AuthenticationFilter.AUTH_TYPE)).thenReturn("simple");
- Mockito.when(config.getInitParameter(AuthenticationFilter.SIGNATURE_SECRET)).thenReturn("secret");
Mockito.when(config.getInitParameterNames()).thenReturn(
- new Vector<String>(Arrays.asList(AuthenticationFilter.AUTH_TYPE,
- AuthenticationFilter.SIGNATURE_SECRET)).elements());
+ new Vector<>(Arrays.asList(AuthenticationFilter.AUTH_TYPE))
+ .elements());
ServletContext context = Mockito.mock(ServletContext.class);
Mockito.when(context.getAttribute(
AuthenticationFilter.SIGNER_SECRET_PROVIDER_ATTRIBUTE)).thenReturn(
http://git-wip-us.apache.org/repos/asf/hadoop/blob/24d87902/hadoop-common-project/hadoop-common/CHANGES.txt
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt
index 80b8459..95ff032 100644
--- a/hadoop-common-project/hadoop-common/CHANGES.txt
+++ b/hadoop-common-project/hadoop-common/CHANGES.txt
@@ -762,6 +762,9 @@ Release 2.7.0 - UNRELEASED
HADOOP-11761. Fix findbugs warnings in org.apache.hadoop.security
.authentication. (Li Lu via wheat9)
+ HADOOP-11754. RM fails to start in non-secure mode due to authentication
+ filter failure. (wheat9)
+
Release 2.6.1 - UNRELEASED
INCOMPATIBLE CHANGES
http://git-wip-us.apache.org/repos/asf/hadoop/blob/24d87902/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
index 945aba8..39d14d8 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
@@ -31,6 +31,7 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Properties;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@@ -53,6 +54,11 @@ import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.ConfServlet;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
+import org.apache.hadoop.security.AuthenticationFilterInitializer;
+import org.apache.hadoop.security.authentication.util.FileSignerSecretProvider;
+import org.apache.hadoop.security.authentication.util.RandomSignerSecretProvider;
+import org.apache.hadoop.security.authentication.util.SignerSecretProvider;
+import org.apache.hadoop.security.authentication.util.ZKSignerSecretProvider;
import org.apache.hadoop.security.ssl.SslSocketConnectorSecure;
import org.apache.hadoop.jmx.JMXJsonServlet;
import org.apache.hadoop.log.LogLevel;
@@ -91,6 +97,8 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.sun.jersey.spi.container.servlet.ServletContainer;
+import static org.apache.hadoop.security.authentication.server
+ .AuthenticationFilter.*;
/**
* Create a Jetty embedded server to answer http requests. The primary goal is
* to serve up status information for the server. There are three contexts:
@@ -160,6 +168,8 @@ public final class HttpServer2 implements FilterContainer {
private boolean findPort;
private String hostName;
+ private boolean disallowFallbackToRandomSignerSecretProvider;
+ private String authFilterConfigurationPrefix = "hadoop.http.authentication.";
public Builder setName(String name){
this.name = name;
@@ -254,6 +264,16 @@ public final class HttpServer2 implements FilterContainer {
return this;
}
+ public Builder disallowFallbackToRandomSingerSecretProvider(boolean value) {
+ this.disallowFallbackToRandomSignerSecretProvider = value;
+ return this;
+ }
+
+ public Builder authFilterConfigurationPrefix(String value) {
+ this.authFilterConfigurationPrefix = value;
+ return this;
+ }
+
public HttpServer2 build() throws IOException {
Preconditions.checkNotNull(name, "name is not set");
Preconditions.checkState(!endpoints.isEmpty(), "No endpoints specified");
@@ -314,6 +334,18 @@ public final class HttpServer2 implements FilterContainer {
this.webServer = new Server();
this.adminsAcl = b.adminsAcl;
this.webAppContext = createWebAppContext(b.name, b.conf, adminsAcl, appDir);
+ try {
+ SignerSecretProvider secretProvider =
+ constructSecretProvider(b, webAppContext.getServletContext());
+ this.webAppContext.getServletContext().setAttribute
+ (AuthenticationFilter.SIGNER_SECRET_PROVIDER_ATTRIBUTE,
+ secretProvider);
+ } catch(IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+
this.findPort = b.findPort;
initializeWebServer(b.name, b.hostName, b.conf, b.pathSpecs);
}
@@ -405,9 +437,28 @@ public final class HttpServer2 implements FilterContainer {
return ctx;
}
+ private static SignerSecretProvider constructSecretProvider(final Builder b,
+ ServletContext ctx)
+ throws Exception {
+ final Configuration conf = b.conf;
+ Properties config = getFilterProperties(conf,
+ b.authFilterConfigurationPrefix);
+ return AuthenticationFilter.constructSecretProvider(
+ ctx, config, b.disallowFallbackToRandomSignerSecretProvider);
+ }
+
+ private static Properties getFilterProperties(Configuration conf, String
+ prefix) {
+ Properties prop = new Properties();
+ Map<String, String> filterConfig = AuthenticationFilterInitializer
+ .getFilterConfigMap(conf, prefix);
+ prop.putAll(filterConfig);
+ return prop;
+ }
+
private static void addNoCacheFilter(WebAppContext ctxt) {
defineFilter(ctxt, NO_CACHE_FILTER, NoCacheFilter.class.getName(),
- Collections.<String, String> emptyMap(), new String[] { "/*" });
+ Collections.<String, String> emptyMap(), new String[] { "/*" });
}
private static class SelectChannelConnectorWithSafeStartup
http://git-wip-us.apache.org/repos/asf/hadoop/blob/24d87902/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/AuthenticationFilterInitializer.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/AuthenticationFilterInitializer.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/AuthenticationFilterInitializer.java
index cb3830d..ca221f5 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/AuthenticationFilterInitializer.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/AuthenticationFilterInitializer.java
@@ -56,6 +56,15 @@ public class AuthenticationFilterInitializer extends FilterInitializer {
*/
@Override
public void initFilter(FilterContainer container, Configuration conf) {
+ Map<String, String> filterConfig = getFilterConfigMap(conf, PREFIX);
+
+ container.addFilter("authentication",
+ AuthenticationFilter.class.getName(),
+ filterConfig);
+ }
+
+ public static Map<String, String> getFilterConfigMap(Configuration conf,
+ String prefix) {
Map<String, String> filterConfig = new HashMap<String, String>();
//setting the cookie path to root '/' so it is used for all resources.
@@ -63,9 +72,9 @@ public class AuthenticationFilterInitializer extends FilterInitializer {
for (Map.Entry<String, String> entry : conf) {
String name = entry.getKey();
- if (name.startsWith(PREFIX)) {
+ if (name.startsWith(prefix)) {
String value = conf.get(name);
- name = name.substring(PREFIX.length());
+ name = name.substring(prefix.length());
filterConfig.put(name, value);
}
}
@@ -82,10 +91,7 @@ public class AuthenticationFilterInitializer extends FilterInitializer {
}
filterConfig.put(KerberosAuthenticationHandler.PRINCIPAL, principal);
}
-
- container.addFilter("authentication",
- AuthenticationFilter.class.getName(),
- filterConfig);
+ return filterConfig;
}
}