HADOOP-10467: Merging r1593162 from trunk to branch-2.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1593164 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Arpit Agarwal 2014-05-08 00:46:14 +00:00
parent c278e40239
commit 868e9b6431
4 changed files with 151 additions and 23 deletions

View File

@ -42,6 +42,9 @@ Release 2.5.0 - UNRELEASED
HADOOP-10556. Add toLowerCase support to auth_to_local rules
for service name. (tucu)
HADOOP-10467. Enable proxyuser specification to support list of users in
addition to list of groups (Benoy Antony via Arpit Agarwal)
OPTIMIZATIONS
BUG FIXES

View File

@ -38,13 +38,16 @@
public class ProxyUsers {
private static final String CONF_HOSTS = ".hosts";
private static final String CONF_USERS = ".users";
private static final String CONF_GROUPS = ".groups";
private static final String CONF_HADOOP_PROXYUSER = "hadoop.proxyuser.";
private static final String CONF_HADOOP_PROXYUSER_RE = "hadoop\\.proxyuser\\.";
public static final String CONF_HADOOP_PROXYSERVERS = "hadoop.proxyservers";
private static boolean init = false;
// list of groups and hosts per proxyuser
//list of users, groups and hosts per proxyuser
private static Map<String, Collection<String>> proxyUsers =
new HashMap<String, Collection<String>>();
private static Map<String, Collection<String>> proxyGroups =
new HashMap<String, Collection<String>>();
private static Map<String, Collection<String>> proxyHosts =
@ -53,7 +56,7 @@ public class ProxyUsers {
new HashSet<String>();
/**
* reread the conf and get new values for "hadoop.proxyuser.*.groups/hosts"
* reread the conf and get new values for "hadoop.proxyuser.*.groups/users/hosts"
*/
public static void refreshSuperUserGroupsConfiguration() {
//load server side configuration;
@ -69,11 +72,20 @@ public static synchronized void refreshSuperUserGroupsConfiguration(Configuratio
// remove all existing stuff
proxyGroups.clear();
proxyHosts.clear();
proxyUsers.clear();
proxyServers.clear();
// get all the new keys for users
String regex = CONF_HADOOP_PROXYUSER_RE+"[^.]*\\"+CONF_USERS;
Map<String,String> allMatchKeys = conf.getValByRegex(regex);
for(Entry<String, String> entry : allMatchKeys.entrySet()) {
Collection<String> users = StringUtils.getTrimmedStringCollection(entry.getValue());
proxyUsers.put(entry.getKey(), users);
}
// get all the new keys for groups
String regex = CONF_HADOOP_PROXYUSER_RE+"[^.]*\\"+CONF_GROUPS;
Map<String,String> allMatchKeys = conf.getValByRegex(regex);
regex = CONF_HADOOP_PROXYUSER_RE+"[^.]*\\"+CONF_GROUPS;
allMatchKeys = conf.getValByRegex(regex);
for(Entry<String, String> entry : allMatchKeys.entrySet()) {
proxyGroups.put(entry.getKey(),
StringUtils.getTrimmedStringCollection(entry.getValue()));
@ -103,7 +115,17 @@ public static synchronized boolean isProxyServer(String remoteAddr) {
}
return proxyServers.contains(remoteAddr);
}
/**
* Returns configuration key for effective users allowed for a superuser
*
* @param userName name of the superuser
* @return configuration key for superuser users
*/
public static String getProxySuperuserUserConfKey(String userName) {
return ProxyUsers.CONF_HADOOP_PROXYUSER+userName+ProxyUsers.CONF_USERS;
}
/**
* Returns configuration key for effective user groups allowed for a superuser
*
@ -141,27 +163,40 @@ public static synchronized void authorize(UserGroupInformation user,
if (user.getRealUser() == null) {
return;
}
boolean groupAuthorized = false;
boolean userAuthorized = false;
boolean ipAuthorized = false;
UserGroupInformation superUser = user.getRealUser();
Collection<String> allowedUserGroups = proxyGroups.get(
getProxySuperuserGroupConfKey(superUser.getShortUserName()));
if (isWildcardList(allowedUserGroups)) {
groupAuthorized = true;
} else if (allowedUserGroups != null && !allowedUserGroups.isEmpty()) {
for (String group : user.getGroupNames()) {
if (allowedUserGroups.contains(group)) {
groupAuthorized = true;
break;
}
Collection<String> allowedUsers = proxyUsers.get(
getProxySuperuserUserConfKey(superUser.getShortUserName()));
if (isWildcardList(allowedUsers)) {
userAuthorized = true;
} else if (allowedUsers != null && !allowedUsers.isEmpty()) {
if (allowedUsers.contains(user.getShortUserName())) {
userAuthorized = true;
}
}
if (!groupAuthorized) {
throw new AuthorizationException("User: " + superUser.getUserName()
+ " is not allowed to impersonate " + user.getUserName());
if (!userAuthorized) {
Collection<String> allowedUserGroups = proxyGroups.get(
getProxySuperuserGroupConfKey(superUser.getShortUserName()));
if (isWildcardList(allowedUserGroups)) {
userAuthorized = true;
} else if (allowedUserGroups != null && !allowedUserGroups.isEmpty()) {
for (String group : user.getGroupNames()) {
if (allowedUserGroups.contains(group)) {
userAuthorized = true;
break;
}
}
}
if (!userAuthorized) {
throw new AuthorizationException("User: " + superUser.getUserName()
+ " is not allowed to impersonate " + user.getUserName());
}
}
Collection<String> ipList = proxyHosts.get(
@ -183,7 +218,7 @@ public static synchronized void authorize(UserGroupInformation user,
}
}
}
if(!ipAuthorized) {
if (!ipAuthorized) {
throw new AuthorizationException("Unauthorized connection for super-user: "
+ superUser.getUserName() + " from IP " + remoteAddress);
}
@ -212,6 +247,11 @@ private static boolean isWildcardList(Collection<String> list) {
(list.size() == 1) &&
(list.contains("*"));
}
@VisibleForTesting
public static Map<String, Collection<String>> getProxyUsers() {
return proxyUsers;
}
@VisibleForTesting
public static Map<String, Collection<String>> getProxyGroups() {

View File

@ -203,7 +203,9 @@ KVNO Timestamp Principal
Some products such as Apache Oozie which access the services of Hadoop
on behalf of end users need to be able to impersonate end users.
You can configure proxy user using properties
<<<hadoop.proxyuser.${superuser}.hosts>>> and <<<hadoop.proxyuser.${superuser}.groups>>>.
<<<hadoop.proxyuser.${superuser}.hosts>>> along with either or both of
<<<hadoop.proxyuser.${superuser}.groups>>>
and <<<hadoop.proxyuser.${superuser}.users>>>.
For example, by specifying as below in core-site.xml,
user named <<<oozie>>> accessing from any host
@ -220,6 +222,20 @@ KVNO Timestamp Principal
</property>
----
User named <<<oozie>>> accessing from any host
can impersonate user1 and user2 by specifying as below in core-site.xml.
----
<property>
<name>hadoop.proxyuser.oozie.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.oozie.users</name>
<value>user1,user2</value>
</property>
----
** Secure DataNode
Because the data transfer protocol of DataNode

View File

@ -30,6 +30,7 @@
public class TestProxyUsers {
private static final String REAL_USER_NAME = "proxier";
private static final String PROXY_USER_NAME = "proxied_user";
private static final String AUTHORIZED_PROXY_USER_NAME = "authorized_proxied_user";
private static final String[] GROUP_NAMES =
new String[] { "foo_group" };
private static final String[] OTHER_GROUP_NAMES =
@ -69,7 +70,41 @@ public void testProxyUsers() throws Exception {
// From bad IP
assertNotAuthorized(proxyUserUgi, "1.2.3.5");
}
@Test
public void testProxyUsersWithUserConf() throws Exception {
Configuration conf = new Configuration();
conf.set(
ProxyUsers.getProxySuperuserUserConfKey(REAL_USER_NAME),
StringUtils.join(",", Arrays.asList(AUTHORIZED_PROXY_USER_NAME)));
conf.set(
ProxyUsers.getProxySuperuserIpConfKey(REAL_USER_NAME),
PROXY_IP);
ProxyUsers.refreshSuperUserGroupsConfiguration(conf);
// First try proxying a user that's allowed
UserGroupInformation realUserUgi = UserGroupInformation
.createRemoteUser(REAL_USER_NAME);
UserGroupInformation proxyUserUgi = UserGroupInformation.createProxyUserForTesting(
AUTHORIZED_PROXY_USER_NAME, realUserUgi, GROUP_NAMES);
// From good IP
assertAuthorized(proxyUserUgi, "1.2.3.4");
// From bad IP
assertNotAuthorized(proxyUserUgi, "1.2.3.5");
// Now try proxying a user that's not allowed
realUserUgi = UserGroupInformation.createRemoteUser(REAL_USER_NAME);
proxyUserUgi = UserGroupInformation.createProxyUserForTesting(
PROXY_USER_NAME, realUserUgi, GROUP_NAMES);
// From good IP
assertNotAuthorized(proxyUserUgi, "1.2.3.4");
// From bad IP
assertNotAuthorized(proxyUserUgi, "1.2.3.5");
}
@Test
public void testWildcardGroup() {
Configuration conf = new Configuration();
@ -103,6 +138,40 @@ public void testWildcardGroup() {
// From bad IP
assertNotAuthorized(proxyUserUgi, "1.2.3.5");
}
@Test
public void testWildcardUser() {
Configuration conf = new Configuration();
conf.set(
ProxyUsers.getProxySuperuserUserConfKey(REAL_USER_NAME),
"*");
conf.set(
ProxyUsers.getProxySuperuserIpConfKey(REAL_USER_NAME),
PROXY_IP);
ProxyUsers.refreshSuperUserGroupsConfiguration(conf);
// First try proxying a user that's allowed
UserGroupInformation realUserUgi = UserGroupInformation
.createRemoteUser(REAL_USER_NAME);
UserGroupInformation proxyUserUgi = UserGroupInformation.createProxyUserForTesting(
AUTHORIZED_PROXY_USER_NAME, realUserUgi, GROUP_NAMES);
// From good IP
assertAuthorized(proxyUserUgi, "1.2.3.4");
// From bad IP
assertNotAuthorized(proxyUserUgi, "1.2.3.5");
// Now try proxying a different user (just to make sure we aren't getting spill over
// from the other test case!)
realUserUgi = UserGroupInformation.createRemoteUser(REAL_USER_NAME);
proxyUserUgi = UserGroupInformation.createProxyUserForTesting(
PROXY_USER_NAME, realUserUgi, OTHER_GROUP_NAMES);
// From good IP
assertAuthorized(proxyUserUgi, "1.2.3.4");
// From bad IP
assertNotAuthorized(proxyUserUgi, "1.2.3.5");
}
@Test
public void testWildcardIP() {
@ -193,7 +262,7 @@ private void assertAuthorized(UserGroupInformation proxyUgi, String host) {
try {
ProxyUsers.authorize(proxyUgi, host);
} catch (AuthorizationException e) {
fail("Did not allowed authorization of " + proxyUgi + " from " + host);
fail("Did not allow authorization of " + proxyUgi + " from " + host);
}
}
}