HBASE-11149 Wire encryption is broken (Devaraj Das)

This commit is contained in:
Andrew Purtell 2014-05-22 18:46:29 -07:00
parent 9dcebc396b
commit b168b8b2d5
5 changed files with 83 additions and 32 deletions

View File

@ -50,6 +50,7 @@ import org.apache.hadoop.hbase.protobuf.generated.RPCProtos.UserInformation;
import org.apache.hadoop.hbase.protobuf.generated.TracingProtos.RPCTInfo; import org.apache.hadoop.hbase.protobuf.generated.TracingProtos.RPCTInfo;
import org.apache.hadoop.hbase.security.AuthMethod; import org.apache.hadoop.hbase.security.AuthMethod;
import org.apache.hadoop.hbase.security.HBaseSaslRpcClient; import org.apache.hadoop.hbase.security.HBaseSaslRpcClient;
import org.apache.hadoop.hbase.security.SaslUtil.QualityOfProtection;
import org.apache.hadoop.hbase.security.SecurityInfo; import org.apache.hadoop.hbase.security.SecurityInfo;
import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.UserProvider; import org.apache.hadoop.hbase.security.UserProvider;
@ -804,7 +805,9 @@ public class RpcClient {
private synchronized boolean setupSaslConnection(final InputStream in2, private synchronized boolean setupSaslConnection(final InputStream in2,
final OutputStream out2) throws IOException { final OutputStream out2) throws IOException {
saslRpcClient = new HBaseSaslRpcClient(authMethod, token, serverPrincipal, fallbackAllowed); saslRpcClient = new HBaseSaslRpcClient(authMethod, token, serverPrincipal, fallbackAllowed,
conf.get("hbase.rpc.protection",
QualityOfProtection.AUTHENTICATION.name().toLowerCase()));
return saslRpcClient.saslConnect(in2, out2); return saslRpcClient.saslConnect(in2, out2);
} }

View File

@ -57,7 +57,6 @@ public class HBaseSaslRpcClient {
private final SaslClient saslClient; private final SaslClient saslClient;
private final boolean fallbackAllowed; private final boolean fallbackAllowed;
/** /**
* Create a HBaseSaslRpcClient for an authentication method * Create a HBaseSaslRpcClient for an authentication method
* *
@ -65,11 +64,37 @@ public class HBaseSaslRpcClient {
* the requested authentication method * the requested authentication method
* @param token * @param token
* token to use if needed by the authentication method * token to use if needed by the authentication method
* @param serverPrincipal
* the server principal that we are trying to set the connection up to
* @param fallbackAllowed
* does the client allow fallback to simple authentication
* @throws IOException
*/ */
public HBaseSaslRpcClient(AuthMethod method, public HBaseSaslRpcClient(AuthMethod method,
Token<? extends TokenIdentifier> token, String serverPrincipal, boolean fallbackAllowed) Token<? extends TokenIdentifier> token, String serverPrincipal, boolean fallbackAllowed)
throws IOException { throws IOException {
this(method, token, serverPrincipal, fallbackAllowed, "authentication");
}
/**
* Create a HBaseSaslRpcClient for an authentication method
*
* @param method
* the requested authentication method
* @param token
* token to use if needed by the authentication method
* @param serverPrincipal
* the server principal that we are trying to set the connection up to
* @param fallbackAllowed
* does the client allow fallback to simple authentication
* @param rpcProtection
* the protection level ("authentication", "integrity" or "privacy")
* @throws IOException
*/
public HBaseSaslRpcClient(AuthMethod method,
Token<? extends TokenIdentifier> token, String serverPrincipal, boolean fallbackAllowed,
String rpcProtection) throws IOException {
this.fallbackAllowed = fallbackAllowed; this.fallbackAllowed = fallbackAllowed;
SaslUtil.initSaslProperties(rpcProtection);
switch (method) { switch (method) {
case DIGEST: case DIGEST:
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())

View File

@ -23,12 +23,30 @@ import org.apache.commons.codec.binary.Base64;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import javax.security.sasl.Sasl;
public class SaslUtil { public class SaslUtil {
public static final String SASL_DEFAULT_REALM = "default"; public static final String SASL_DEFAULT_REALM = "default";
public static final Map<String, String> SASL_PROPS = public static final Map<String, String> SASL_PROPS =
new TreeMap<String, String>(); new TreeMap<String, String>();
public static final int SWITCH_TO_SIMPLE_AUTH = -88; public static final int SWITCH_TO_SIMPLE_AUTH = -88;
public static enum QualityOfProtection {
AUTHENTICATION("auth"),
INTEGRITY("auth-int"),
PRIVACY("auth-conf");
public final String saslQop;
private QualityOfProtection(String saslQop) {
this.saslQop = saslQop;
}
public String getSaslQop() {
return saslQop;
}
}
/** Splitting fully qualified Kerberos name into parts */ /** Splitting fully qualified Kerberos name into parts */
public static String[] splitKerberosName(String fullName) { public static String[] splitKerberosName(String fullName) {
return fullName.split("[/@]"); return fullName.split("[/@]");
@ -45,4 +63,18 @@ public class SaslUtil {
static char[] encodePassword(byte[] password) { static char[] encodePassword(byte[] password) {
return new String(Base64.encodeBase64(password)).toCharArray(); return new String(Base64.encodeBase64(password)).toCharArray();
} }
static void initSaslProperties(String rpcProtection) {
QualityOfProtection saslQOP = QualityOfProtection.AUTHENTICATION;
if (QualityOfProtection.INTEGRITY.name().toLowerCase()
.equals(rpcProtection)) {
saslQOP = QualityOfProtection.INTEGRITY;
} else if (QualityOfProtection.PRIVACY.name().toLowerCase().equals(
rpcProtection)) {
saslQOP = QualityOfProtection.PRIVACY;
}
SaslUtil.SASL_PROPS.put(Sasl.QOP, saslQOP.getSaslQop());
SaslUtil.SASL_PROPS.put(Sasl.SERVER_AUTH, "true");
}
} }

View File

@ -29,12 +29,12 @@ import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.AuthorizeCallback; import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.RealmCallback; import javax.security.sasl.RealmCallback;
import javax.security.sasl.Sasl;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ipc.RpcServer; import org.apache.hadoop.hbase.ipc.RpcServer;
import org.apache.hadoop.hbase.security.SaslUtil.QualityOfProtection;
import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.token.SecretManager; import org.apache.hadoop.security.token.SecretManager;
import org.apache.hadoop.security.token.TokenIdentifier; import org.apache.hadoop.security.token.TokenIdentifier;
@ -46,36 +46,9 @@ import org.apache.hadoop.security.token.SecretManager.InvalidToken;
public class HBaseSaslRpcServer { public class HBaseSaslRpcServer {
public static final Log LOG = LogFactory.getLog(HBaseSaslRpcServer.class); public static final Log LOG = LogFactory.getLog(HBaseSaslRpcServer.class);
public static enum QualityOfProtection {
AUTHENTICATION("auth"),
INTEGRITY("auth-int"),
PRIVACY("auth-conf");
public final String saslQop;
private QualityOfProtection(String saslQop) {
this.saslQop = saslQop;
}
public String getSaslQop() {
return saslQop;
}
}
public static void init(Configuration conf) { public static void init(Configuration conf) {
QualityOfProtection saslQOP = QualityOfProtection.AUTHENTICATION; SaslUtil.initSaslProperties(conf.get("hbase.rpc.protection",
String rpcProtection = conf.get("hbase.rpc.protection", QualityOfProtection.AUTHENTICATION.name().toLowerCase()));
QualityOfProtection.AUTHENTICATION.name().toLowerCase());
if (QualityOfProtection.INTEGRITY.name().toLowerCase()
.equals(rpcProtection)) {
saslQOP = QualityOfProtection.INTEGRITY;
} else if (QualityOfProtection.PRIVACY.name().toLowerCase().equals(
rpcProtection)) {
saslQOP = QualityOfProtection.PRIVACY;
}
SaslUtil.SASL_PROPS.put(Sasl.QOP, saslQOP.getSaslQop());
SaslUtil.SASL_PROPS.put(Sasl.SERVER_AUTH, "true");
} }
public static <T extends TokenIdentifier> T getIdentifier(String id, public static <T extends TokenIdentifier> T getIdentifier(String id,

View File

@ -38,6 +38,7 @@ import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextOutputCallback; import javax.security.auth.callback.TextOutputCallback;
import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.Sasl;
import javax.security.sasl.RealmCallback; import javax.security.sasl.RealmCallback;
import javax.security.sasl.RealmChoiceCallback; import javax.security.sasl.RealmChoiceCallback;
import javax.security.sasl.SaslClient; import javax.security.sasl.SaslClient;
@ -75,6 +76,23 @@ public class TestHBaseSaslRpcClient {
Logger.getRootLogger().setLevel(Level.DEBUG); Logger.getRootLogger().setLevel(Level.DEBUG);
} }
@Test
public void testSaslQOPNotEmpty() throws Exception {
// default QOP is authentication
new HBaseSaslRpcClient(AuthMethod.KERBEROS, createTokenMock(), "principal/host@DOMAIN.COM", false);
assertTrue(SaslUtil.SASL_PROPS.get(Sasl.QOP).equals(SaslUtil.QualityOfProtection.AUTHENTICATION.getSaslQop()));
// check with specific QOPs
new HBaseSaslRpcClient(AuthMethod.KERBEROS, createTokenMock(), "principal/host@DOMAIN.COM", false, "authentication");
assertTrue(SaslUtil.SASL_PROPS.get(Sasl.QOP).equals(SaslUtil.QualityOfProtection.AUTHENTICATION.getSaslQop()));
new HBaseSaslRpcClient(AuthMethod.KERBEROS, createTokenMock(), "principal/host@DOMAIN.COM", false, "privacy");
assertTrue(SaslUtil.SASL_PROPS.get(Sasl.QOP).equals(SaslUtil.QualityOfProtection.PRIVACY.getSaslQop()));
new HBaseSaslRpcClient(AuthMethod.KERBEROS, createTokenMock(), "principal/host@DOMAIN.COM", false, "integrity");
assertTrue(SaslUtil.SASL_PROPS.get(Sasl.QOP).equals(SaslUtil.QualityOfProtection.INTEGRITY.getSaslQop()));
}
@Test @Test
public void testSaslClientCallbackHandler() throws UnsupportedCallbackException { public void testSaslClientCallbackHandler() throws UnsupportedCallbackException {
final Token<? extends TokenIdentifier> token = createTokenMock(); final Token<? extends TokenIdentifier> token = createTokenMock();