diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index c78bd83ec4b..3d45e134c12 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -408,6 +408,8 @@ Release 2.4.0 - UNRELEASED HADOOP-10047. Add a direct-buffer based apis for compression. (Gopal V via acmurthy) + HADOOP-10172. Cache SASL server factories (daryn) + BUG FIXES HADOOP-9964. Fix deadlocks in TestHttpServer by synchronize diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/SaslRpcServer.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/SaslRpcServer.java index 72b56c81749..bbabd887a2f 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/SaslRpcServer.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/SaslRpcServer.java @@ -25,6 +25,10 @@ import java.io.DataOutput; import java.io.IOException; import java.security.PrivilegedExceptionAction; import java.security.Security; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -38,6 +42,7 @@ import javax.security.sasl.RealmCallback; import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; @@ -63,6 +68,7 @@ public class SaslRpcServer { public static final String SASL_DEFAULT_REALM = "default"; public static final Map SASL_PROPS = new TreeMap(); + private static SaslServerFactory saslFactory; public static enum QualityOfProtection { AUTHENTICATION("auth"), @@ -151,7 +157,7 @@ public class SaslRpcServer { new PrivilegedExceptionAction() { @Override public SaslServer run() throws SaslException { - return Sasl.createSaslServer(mechanism, protocol, serverId, + return saslFactory.createSaslServer(mechanism, protocol, serverId, SaslRpcServer.SASL_PROPS, callback); } }); @@ -180,6 +186,7 @@ public class SaslRpcServer { SASL_PROPS.put(Sasl.QOP, saslQOP.getSaslQop()); SASL_PROPS.put(Sasl.SERVER_AUTH, "true"); Security.addProvider(new SaslPlainServer.SecurityProvider()); + saslFactory = new FastSaslServerFactory(SASL_PROPS); } static String encodeIdentifier(byte[] identifier) { @@ -363,4 +370,47 @@ public class SaslRpcServer { } } } + + // Sasl.createSaslServer is 100-200X slower than caching the factories! + private static class FastSaslServerFactory implements SaslServerFactory { + private final Map> factoryCache = + new HashMap>(); + + FastSaslServerFactory(Map props) { + final Enumeration factories = + Sasl.getSaslServerFactories(); + while (factories.hasMoreElements()) { + SaslServerFactory factory = factories.nextElement(); + for (String mech : factory.getMechanismNames(props)) { + if (!factoryCache.containsKey(mech)) { + factoryCache.put(mech, new ArrayList()); + } + factoryCache.get(mech).add(factory); + } + } + } + + @Override + public SaslServer createSaslServer(String mechanism, String protocol, + String serverName, Map props, CallbackHandler cbh) + throws SaslException { + SaslServer saslServer = null; + List factories = factoryCache.get(mechanism); + if (factories != null) { + for (SaslServerFactory factory : factories) { + saslServer = factory.createSaslServer( + mechanism, protocol, serverName, props, cbh); + if (saslServer != null) { + break; + } + } + } + return saslServer; + } + + @Override + public String[] getMechanismNames(Map props) { + return factoryCache.keySet().toArray(new String[0]); + } + } } diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestSaslRPC.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestSaslRPC.java index 1e96ed1ddbc..eecefc70c8d 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestSaslRPC.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestSaslRPC.java @@ -137,7 +137,9 @@ public class TestSaslRPC { LOG.info("Testing QOP:"+expectedQop); LOG.info("---------------------------------"); conf = new Configuration(); - conf.set(HADOOP_SECURITY_AUTHENTICATION, KERBEROS.toString()); + // the specific tests for kerberos will enable kerberos. forcing it + // for all tests will cause tests to fail if the user has a TGT + conf.set(HADOOP_SECURITY_AUTHENTICATION, SIMPLE.toString()); conf.set("hadoop.rpc.protection", expectedQop.name().toLowerCase()); UserGroupInformation.setConfiguration(conf); enableSecretManager = null;