merge -c 1512380 FIXES: HADOOP-9789. Support server advertised kerberos principals (daryn)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1512381 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Daryn Sharp 2013-08-09 16:30:10 +00:00
parent d90f3fbdbf
commit 02aa997ba2
4 changed files with 43 additions and 33 deletions

View File

@ -65,6 +65,8 @@ Release 2.1.1-beta - UNRELEASED
HADOOP-9672. Upgrade Avro dependency to 1.7.4. (sandy via kihwal) HADOOP-9672. Upgrade Avro dependency to 1.7.4. (sandy via kihwal)
HADOOP-9789. Support server advertised kerberos principals (daryn)
OPTIMIZATIONS OPTIMIZATIONS
BUG FIXES BUG FIXES

View File

@ -33,6 +33,7 @@ import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern;
import javax.security.auth.callback.Callback; import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.CallbackHandler;
@ -51,6 +52,7 @@ import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.GlobPattern;
import org.apache.hadoop.ipc.ProtobufRpcEngine.RpcRequestMessageWrapper; import org.apache.hadoop.ipc.ProtobufRpcEngine.RpcRequestMessageWrapper;
import org.apache.hadoop.ipc.ProtobufRpcEngine.RpcResponseMessageWrapper; import org.apache.hadoop.ipc.ProtobufRpcEngine.RpcResponseMessageWrapper;
import org.apache.hadoop.ipc.RPC.RpcKind; import org.apache.hadoop.ipc.RPC.RpcKind;
@ -280,9 +282,8 @@ public class SaslRpcClient {
* @return String of the server's principal * @return String of the server's principal
* @throws IOException - error determining configured principal * @throws IOException - error determining configured principal
*/ */
@VisibleForTesting
// try to get the configured principal for the remote server String getServerPrincipal(SaslAuth authType) throws IOException {
private String getServerPrincipal(SaslAuth authType) throws IOException {
KerberosInfo krbInfo = SecurityUtil.getKerberosInfo(protocol, conf); KerberosInfo krbInfo = SecurityUtil.getKerberosInfo(protocol, conf);
LOG.debug("Get kerberos info proto:"+protocol+" info:"+krbInfo); LOG.debug("Get kerberos info proto:"+protocol+" info:"+krbInfo);
if (krbInfo == null) { // protocol has no support for kerberos if (krbInfo == null) { // protocol has no support for kerberos
@ -294,28 +295,37 @@ public class SaslRpcClient {
"Can't obtain server Kerberos config key from protocol=" "Can't obtain server Kerberos config key from protocol="
+ protocol.getCanonicalName()); + protocol.getCanonicalName());
} }
// construct the expected principal from the config // construct server advertised principal for comparision
String confPrincipal = SecurityUtil.getServerPrincipal( String serverPrincipal = new KerberosPrincipal(
conf.get(serverKey), serverAddr.getAddress()); authType.getProtocol() + "/" + authType.getServerId()).getName();
if (confPrincipal == null || confPrincipal.isEmpty()) { boolean isPrincipalValid = false;
throw new IllegalArgumentException(
"Failed to specify server's Kerberos principal name"); // use the pattern if defined
String serverKeyPattern = conf.get(serverKey + ".pattern");
if (serverKeyPattern != null && !serverKeyPattern.isEmpty()) {
Pattern pattern = GlobPattern.compile(serverKeyPattern);
isPrincipalValid = pattern.matcher(serverPrincipal).matches();
} else {
// check that the server advertised principal matches our conf
String confPrincipal = SecurityUtil.getServerPrincipal(
conf.get(serverKey), serverAddr.getAddress());
if (confPrincipal == null || confPrincipal.isEmpty()) {
throw new IllegalArgumentException(
"Failed to specify server's Kerberos principal name");
}
KerberosName name = new KerberosName(confPrincipal);
if (name.getHostName() == null) {
throw new IllegalArgumentException(
"Kerberos principal name does NOT have the expected hostname part: "
+ confPrincipal);
}
isPrincipalValid = serverPrincipal.equals(confPrincipal);
} }
// ensure it looks like a host-based service principal if (!isPrincipalValid) {
KerberosName name = new KerberosName(confPrincipal);
if (name.getHostName() == null) {
throw new IllegalArgumentException(
"Kerberos principal name does NOT have the expected hostname part: "
+ confPrincipal);
}
// check that the server advertised principal matches our conf
KerberosPrincipal serverPrincipal = new KerberosPrincipal(
authType.getProtocol() + "/" + authType.getServerId());
if (!serverPrincipal.getName().equals(confPrincipal)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Server has invalid Kerberos principal: " + serverPrincipal); "Server has invalid Kerberos principal: " + serverPrincipal);
} }
return confPrincipal; return serverPrincipal;
} }

View File

@ -47,7 +47,6 @@ import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.Server; import org.apache.hadoop.ipc.Server;
import org.apache.hadoop.ipc.Server.Connection; import org.apache.hadoop.ipc.Server.Connection;
import org.apache.hadoop.security.authentication.util.KerberosName;
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;
import org.apache.hadoop.security.token.SecretManager.InvalidToken; import org.apache.hadoop.security.token.SecretManager.InvalidToken;
@ -104,12 +103,12 @@ public class SaslRpcServer {
String fullName = UserGroupInformation.getCurrentUser().getUserName(); String fullName = UserGroupInformation.getCurrentUser().getUserName();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Kerberos principal name is " + fullName); LOG.debug("Kerberos principal name is " + fullName);
KerberosName krbName = new KerberosName(fullName); // don't use KerberosName because we don't want auth_to_local
serverId = krbName.getHostName(); String[] parts = fullName.split("[/@]", 2);
if (serverId == null) { protocol = parts[0];
serverId = ""; // should verify service host is present here rather than in create()
} // but lazy tests are using a UGI that isn't a SPN...
protocol = krbName.getServiceName(); serverId = (parts.length < 2) ? "" : parts[1];
break; break;
} }
default: default:

View File

@ -824,14 +824,13 @@ public class TestSaslRPC {
final AuthMethod serverAuth, final AuthMethod serverAuth,
final UseToken tokenType) throws Exception { final UseToken tokenType) throws Exception {
String currentUser = UserGroupInformation.getCurrentUser().getUserName();
final Configuration serverConf = new Configuration(conf); final Configuration serverConf = new Configuration(conf);
serverConf.set(HADOOP_SECURITY_AUTHENTICATION, serverAuth.toString()); serverConf.set(HADOOP_SECURITY_AUTHENTICATION, serverAuth.toString());
UserGroupInformation.setConfiguration(serverConf); UserGroupInformation.setConfiguration(serverConf);
final UserGroupInformation serverUgi = final UserGroupInformation serverUgi = (serverAuth == KERBEROS)
UserGroupInformation.createRemoteUser(currentUser + "-SERVER/localhost@NONE"); ? UserGroupInformation.createRemoteUser("server/localhost@NONE")
: UserGroupInformation.createRemoteUser("server");
serverUgi.setAuthenticationMethod(serverAuth); serverUgi.setAuthenticationMethod(serverAuth);
final TestTokenSecretManager sm = new TestTokenSecretManager(); final TestTokenSecretManager sm = new TestTokenSecretManager();
@ -866,7 +865,7 @@ public class TestSaslRPC {
UserGroupInformation.setConfiguration(clientConf); UserGroupInformation.setConfiguration(clientConf);
final UserGroupInformation clientUgi = final UserGroupInformation clientUgi =
UserGroupInformation.createRemoteUser(currentUser + "-CLIENT"); UserGroupInformation.createRemoteUser("client");
clientUgi.setAuthenticationMethod(clientAuth); clientUgi.setAuthenticationMethod(clientAuth);
final InetSocketAddress addr = NetUtils.getConnectAddress(server); final InetSocketAddress addr = NetUtils.getConnectAddress(server);