Author: boryas
Date: Tue Apr 13 23:01:43 2010
New Revision: 933810
URL: http://svn.apache.org/viewvc?rev=933810&view=rev
Log:
HADOOP-6580. UGI should contain authentication method.
Modified:
hadoop/common/trunk/CHANGES.txt
hadoop/common/trunk/src/java/org/apache/hadoop/ipc/Server.java
hadoop/common/trunk/src/java/org/apache/hadoop/security/SaslRpcServer.java
hadoop/common/trunk/src/java/org/apache/hadoop/security/User.java
hadoop/common/trunk/src/java/org/apache/hadoop/security/UserGroupInformation.java
hadoop/common/trunk/src/test/core/org/apache/hadoop/ipc/TestSaslRPC.java
hadoop/common/trunk/src/test/core/org/apache/hadoop/security/TestUserGroupInformation.java
Modified: hadoop/common/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/hadoop/common/trunk/CHANGES.txt?rev=933810&r1=933809&r2=933810&view=diff
==============================================================================
--- hadoop/common/trunk/CHANGES.txt (original)
+++ hadoop/common/trunk/CHANGES.txt Tue Apr 13 23:01:43 2010
@@ -68,6 +68,8 @@ Trunk (unreleased changes)
HADOOP-6586. Log authentication and authorization failures and successes
for RPC (boryas)
+ HADOOP-6580. UGI should contain authentication method. (jnp via boryas)
+
IMPROVEMENTS
HADOOP-6283. Improve the exception messages thrown by
Modified: hadoop/common/trunk/src/java/org/apache/hadoop/ipc/Server.java
URL:
http://svn.apache.org/viewvc/hadoop/common/trunk/src/java/org/apache/hadoop/ipc/Server.java?rev=933810&r1=933809&r2=933810&view=diff
==============================================================================
--- hadoop/common/trunk/src/java/org/apache/hadoop/ipc/Server.java (original)
+++ hadoop/common/trunk/src/java/org/apache/hadoop/ipc/Server.java Tue Apr 13
23:01:43 2010
@@ -72,6 +72,7 @@ import org.apache.hadoop.security.SaslRp
import org.apache.hadoop.security.SaslRpcServer.SaslStatus;
import org.apache.hadoop.security.SaslRpcServer.SaslDigestCallbackHandler;
import org.apache.hadoop.security.SaslRpcServer.SaslGssCallbackHandler;
+import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authorize.ProxyUsers;
import org.apache.hadoop.security.authorize.AuthorizationException;
@@ -1084,18 +1085,32 @@ public abstract class Server {
UserGroupInformation protocolUser = header.getUgi();
if (!useSasl) {
user = protocolUser;
- } else if ((protocolUser != null)
- && (!protocolUser.getUserName().equals(user.getUserName()))) {
- if (authMethod == AuthMethod.DIGEST) {
- // Not allowed to doAs if token authentication is used
- throw new AccessControlException("Authenticated user (" + user
- + ") doesn't match what the client claims to be (" + protocolUser
- + ")");
- } else {
- //Effective user can be different from authenticated user
- //for simple auth or kerberos auth
- user = UserGroupInformation.createProxyUser(protocolUser
- .getUserName(), user);
+ if (user != null) {
+ user.setAuthenticationMethod(AuthMethod.SIMPLE.authenticationMethod);
+ }
+ } else {
+ // user is authenticated
+ user.setAuthenticationMethod(authMethod.authenticationMethod);
+ //Now we check if this is a proxy user case. If the protocol user is
+ //different from the 'user', it is a proxy user scenario. However,
+ //this is not allowed if user authenticated with DIGEST.
+ if ((protocolUser != null)
+ && (!protocolUser.getUserName().equals(user.getUserName()))) {
+ if (authMethod == AuthMethod.DIGEST) {
+ // Not allowed to doAs if token authentication is used
+ throw new AccessControlException("Authenticated user (" + user
+ + ") doesn't match what the client claims to be ("
+ + protocolUser + ")");
+ } else {
+ // Effective user can be different from authenticated user
+ // for simple auth or kerberos auth
+ // The user is the real user. Now we create a proxy user
+ UserGroupInformation realUser = user;
+ user = UserGroupInformation.createProxyUser(protocolUser
+ .getUserName(), realUser);
+ // Now the user is a proxy user, set Authentication method Proxy.
+ user.setAuthenticationMethod(AuthenticationMethod.PROXY);
+ }
}
}
}
Modified:
hadoop/common/trunk/src/java/org/apache/hadoop/security/SaslRpcServer.java
URL:
http://svn.apache.org/viewvc/hadoop/common/trunk/src/java/org/apache/hadoop/security/SaslRpcServer.java?rev=933810&r1=933809&r2=933810&view=diff
==============================================================================
--- hadoop/common/trunk/src/java/org/apache/hadoop/security/SaslRpcServer.java
(original)
+++ hadoop/common/trunk/src/java/org/apache/hadoop/security/SaslRpcServer.java
Tue Apr 13 23:01:43 2010
@@ -41,6 +41,7 @@ import org.apache.commons.logging.LogFac
import org.apache.hadoop.ipc.Server;
import org.apache.hadoop.security.token.SecretManager;
import org.apache.hadoop.security.token.TokenIdentifier;
+import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
import org.apache.hadoop.security.token.SecretManager.InvalidToken;
/**
@@ -102,17 +103,20 @@ public class SaslRpcServer {
/** Authentication method */
public static enum AuthMethod {
- SIMPLE((byte) 80, ""), // no authentication
- KERBEROS((byte) 81, "GSSAPI"), // SASL Kerberos authentication
- DIGEST((byte) 82, "DIGEST-MD5"); // SASL DIGEST-MD5 authentication
+ SIMPLE((byte) 80, "", AuthenticationMethod.SIMPLE),
+ KERBEROS((byte) 81, "GSSAPI", AuthenticationMethod.KERBEROS),
+ DIGEST((byte) 82, "DIGEST-MD5", AuthenticationMethod.TOKEN);
/** The code for this method. */
public final byte code;
public final String mechanismName;
+ public final AuthenticationMethod authenticationMethod;
- private AuthMethod(byte code, String mechanismName) {
+ private AuthMethod(byte code, String mechanismName,
+ AuthenticationMethod authMethod) {
this.code = code;
this.mechanismName = mechanismName;
+ this.authenticationMethod = authMethod;
}
private static final int FIRST_CODE = values()[0].code;
Modified: hadoop/common/trunk/src/java/org/apache/hadoop/security/User.java
URL:
http://svn.apache.org/viewvc/hadoop/common/trunk/src/java/org/apache/hadoop/security/User.java?rev=933810&r1=933809&r2=933810&view=diff
==============================================================================
--- hadoop/common/trunk/src/java/org/apache/hadoop/security/User.java (original)
+++ hadoop/common/trunk/src/java/org/apache/hadoop/security/User.java Tue Apr
13 23:01:43 2010
@@ -19,6 +19,8 @@ package org.apache.hadoop.security;
import java.security.Principal;
+import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
+
/**
* Save the full and short name of the user as a principal. This allows us to
* have a single type that we always look for when picking up user names.
@@ -26,8 +28,13 @@ import java.security.Principal;
class User implements Principal {
private final String fullName;
private final String shortName;
+ private AuthenticationMethod authMethod = null;
public User(String name) {
+ this(name, null);
+ }
+
+ public User(String name, AuthenticationMethod authMethod) {
fullName = name;
int atIdx = name.indexOf('@');
if (atIdx == -1) {
@@ -40,6 +47,7 @@ class User implements Principal {
shortName = name.substring(0, slashIdx);
}
}
+ this.authMethod = authMethod;
}
/**
@@ -65,7 +73,7 @@ class User implements Principal {
} else if (o == null || getClass() != o.getClass()) {
return false;
} else {
- return fullName.equals(((User) o).fullName);
+ return ((fullName.equals(((User) o).fullName)) && (authMethod == ((User)
o).authMethod));
}
}
@@ -78,4 +86,12 @@ class User implements Principal {
public String toString() {
return fullName;
}
+
+ public void setAuthenticationMethod(AuthenticationMethod authMethod) {
+ this.authMethod = authMethod;
+ }
+
+ public AuthenticationMethod getAuthenticationMethod() {
+ return authMethod;
+ }
}
Modified:
hadoop/common/trunk/src/java/org/apache/hadoop/security/UserGroupInformation.java
URL:
http://svn.apache.org/viewvc/hadoop/common/trunk/src/java/org/apache/hadoop/security/UserGroupInformation.java?rev=933810&r1=933809&r2=933810&view=diff
==============================================================================
---
hadoop/common/trunk/src/java/org/apache/hadoop/security/UserGroupInformation.java
(original)
+++
hadoop/common/trunk/src/java/org/apache/hadoop/security/UserGroupInformation.java
Tue Apr 13 23:01:43 2010
@@ -51,6 +51,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.SaslRpcServer.AuthMethod;
import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.security.token.TokenIdentifier;
@@ -470,6 +471,15 @@ public class UserGroupInformation {
return new UserGroupInformation(subject);
}
+ public static enum AuthenticationMethod {
+ SIMPLE,
+ KERBEROS,
+ TOKEN,
+ CERTIFICATE,
+ KERBEROS_SSL,
+ PROXY;
+ }
+
/* Create a proxy user using username of the effective user and the ugi of
the
* real user.
*
@@ -650,6 +660,30 @@ public class UserGroupInformation {
}
/**
+ * Sets the authentication method in the subject
+ *
+ * @param authMethod
+ */
+ public synchronized
+ void setAuthenticationMethod(AuthenticationMethod authMethod) {
+ for (User p : subject.getPrincipals(User.class)) {
+ p.setAuthenticationMethod(authMethod);
+ }
+ }
+
+ /**
+ * Get the authentication method from the subject
+ *
+ * @return AuthenticationMethod in the subject, null if not present.
+ */
+ public synchronized AuthenticationMethod getAuthenticationMethod() {
+ for (User p: subject.getPrincipals(User.class)) {
+ return p.getAuthenticationMethod();
+ }
+ return null;
+ }
+
+ /**
* Compare the subjects to see if they are equal to each other.
*/
@Override
Modified:
hadoop/common/trunk/src/test/core/org/apache/hadoop/ipc/TestSaslRPC.java
URL:
http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/core/org/apache/hadoop/ipc/TestSaslRPC.java?rev=933810&r1=933809&r2=933810&view=diff
==============================================================================
--- hadoop/common/trunk/src/test/core/org/apache/hadoop/ipc/TestSaslRPC.java
(original)
+++ hadoop/common/trunk/src/test/core/org/apache/hadoop/ipc/TestSaslRPC.java
Tue Apr 13 23:01:43 2010
@@ -25,8 +25,11 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.net.InetSocketAddress;
+import java.security.PrivilegedExceptionAction;
import java.util.Collection;
+import junit.framework.Assert;
+
import org.apache.commons.logging.*;
import org.apache.commons.logging.impl.Log4JLogger;
@@ -44,6 +47,7 @@ import org.apache.hadoop.security.SaslIn
import org.apache.hadoop.security.SaslRpcClient;
import org.apache.hadoop.security.SaslRpcServer;
import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
import org.apache.log4j.Level;
import org.junit.Test;
@@ -161,10 +165,14 @@ public class TestSaslRPC {
@KerberosInfo(SERVER_PRINCIPAL_KEY)
@TokenInfo(TestTokenSelector.class)
public interface TestSaslProtocol extends TestRPC.TestProtocol {
+ public AuthenticationMethod getAuthMethod() throws IOException;
}
public static class TestSaslImpl extends TestRPC.TestImpl implements
TestSaslProtocol {
+ public AuthenticationMethod getAuthMethod() throws IOException {
+ return UserGroupInformation.getCurrentUser().getAuthenticationMethod();
+ }
}
@Test
@@ -258,6 +266,43 @@ public class TestSaslRPC {
}
}
+ @Test
+ public void testDigestAuthMethod() throws Exception {
+ TestTokenSecretManager sm = new TestTokenSecretManager();
+ Server server = RPC.getServer(TestSaslProtocol.class,
+ new TestSaslImpl(), ADDRESS, 0, 5, true, conf, sm);
+ server.start();
+
+ final UserGroupInformation current = UserGroupInformation.getCurrentUser();
+ final InetSocketAddress addr = NetUtils.getConnectAddress(server);
+ TestTokenIdentifier tokenId = new TestTokenIdentifier(new Text(current
+ .getUserName()));
+ Token<TestTokenIdentifier> token = new Token<TestTokenIdentifier>(tokenId,
+ sm);
+ Text host = new Text(addr.getAddress().getHostAddress() + ":"
+ + addr.getPort());
+ token.setService(host);
+ LOG.info("Service IP address for token is " + host);
+ current.addToken(token);
+
+ current.doAs(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws IOException {
+ TestSaslProtocol proxy = null;
+ try {
+ proxy = (TestSaslProtocol) RPC.getProxy(TestSaslProtocol.class,
+ TestSaslProtocol.versionID, addr, conf);
+ Assert.assertEquals(AuthenticationMethod.TOKEN,
proxy.getAuthMethod());
+ } finally {
+ if (proxy != null) {
+ RPC.stopProxy(proxy);
+ }
+ }
+ return null;
+ }
+ });
+ server.stop();
+ }
+
public static void main(String[] args) throws Exception {
System.out.println("Testing Kerberos authentication over RPC");
if (args.length != 2) {
Modified:
hadoop/common/trunk/src/test/core/org/apache/hadoop/security/TestUserGroupInformation.java
URL:
http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/core/org/apache/hadoop/security/TestUserGroupInformation.java?rev=933810&r1=933809&r2=933810&view=diff
==============================================================================
---
hadoop/common/trunk/src/test/core/org/apache/hadoop/security/TestUserGroupInformation.java
(original)
+++
hadoop/common/trunk/src/test/core/org/apache/hadoop/security/TestUserGroupInformation.java
Tue Apr 13 23:01:43 2010
@@ -27,13 +27,15 @@ import static org.mockito.Mockito.mock;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import org.apache.hadoop.conf.Configuration;
+import junit.framework.Assert;
+
+import org.apache.hadoop.security.SaslRpcServer.AuthMethod;
+import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.security.token.TokenIdentifier;
import org.junit.Test;
@@ -212,4 +214,51 @@ public class TestUserGroupInformation {
assertTrue(otherSet.contains(t1));
assertTrue(otherSet.contains(t2));
}
+
+ @Test
+ public void testUGIAuthMethod() throws Exception {
+ final UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
+ final AuthenticationMethod am = AuthenticationMethod.KERBEROS;
+ ugi.setAuthenticationMethod(am);
+ Assert.assertEquals(am, ugi.getAuthenticationMethod());
+ ugi.doAs(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws IOException {
+ Assert.assertEquals(am, UserGroupInformation.getCurrentUser()
+ .getAuthenticationMethod());
+ return null;
+ }
+ });
+ }
+
+ @Test
+ public void testUGIAuthMethodInRealUser() throws Exception {
+ final UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
+ UserGroupInformation proxyUgi = UserGroupInformation.createProxyUser(
+ "proxy", ugi);
+ final AuthenticationMethod am = AuthenticationMethod.KERBEROS;
+ ugi.setAuthenticationMethod(am);
+ Assert.assertEquals(am, ugi.getAuthenticationMethod());
+ Assert.assertEquals(null, proxyUgi.getAuthenticationMethod());
+ proxyUgi.setAuthenticationMethod(AuthenticationMethod.PROXY);
+ proxyUgi.doAs(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws IOException {
+ Assert.assertEquals(AuthenticationMethod.PROXY, UserGroupInformation
+ .getCurrentUser().getAuthenticationMethod());
+ Assert.assertEquals(am, UserGroupInformation.getCurrentUser()
+ .getRealUser().getAuthenticationMethod());
+ return null;
+ }
+ });
+ UserGroupInformation proxyUgi2 = UserGroupInformation.createProxyUser(
+ "proxy", ugi);
+ proxyUgi2.setAuthenticationMethod(AuthenticationMethod.PROXY);
+ Assert.assertEquals(proxyUgi, proxyUgi2);
+ // Equality should work if authMethod is null
+ UserGroupInformation realugi = UserGroupInformation.getCurrentUser();
+ UserGroupInformation proxyUgi3 = UserGroupInformation.createProxyUser(
+ "proxyAnother", realugi);
+ UserGroupInformation proxyUgi4 = UserGroupInformation.createProxyUser(
+ "proxyAnother", realugi);
+ Assert.assertEquals(proxyUgi3, proxyUgi4);
+ }
}