HADOOP-10467. Enable proxyuser specification to support list of users in addition to list of groups. (Contributed bt Benoy Antony)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1593162 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Arpit Agarwal 2014-05-08 00:45:32 +00:00
parent 838aeee2e5
commit 1ff694081f
4 changed files with 151 additions and 23 deletions

View File

@ -374,6 +374,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

@ -40,13 +40,16 @@ import com.google.common.annotations.VisibleForTesting;
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 =
@ -55,7 +58,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;
@ -71,11 +74,20 @@ public class ProxyUsers {
// 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()) {
Collection<String> groups = StringUtils.getTrimmedStringCollection(entry.getValue());
proxyGroups.put(entry.getKey(), groups );
@ -108,7 +120,17 @@ public class ProxyUsers {
}
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
*
@ -146,27 +168,40 @@ public class ProxyUsers {
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(
@ -188,7 +223,7 @@ public class ProxyUsers {
}
}
}
if(!ipAuthorized) {
if (!ipAuthorized) {
throw new AuthorizationException("Unauthorized connection for super-user: "
+ superUser.getUserName() + " from IP " + remoteAddress);
}
@ -217,6 +252,11 @@ public class ProxyUsers {
(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

@ -39,6 +39,7 @@ public class TestProxyUsers {
LogFactory.getLog(TestProxyUsers.class);
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[] NETGROUP_NAMES =
@ -158,7 +159,41 @@ public class TestProxyUsers {
// 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();
@ -192,6 +227,40 @@ public class TestProxyUsers {
// 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() {
@ -282,7 +351,7 @@ public class TestProxyUsers {
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);
}
}
}