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:
parent
c278e40239
commit
868e9b6431
|
@ -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
|
||||
|
|
|
@ -38,13 +38,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 =
|
||||
|
@ -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 class ProxyUsers {
|
|||
// remove all existing stuff
|
||||
proxyGroups.clear();
|
||||
proxyHosts.clear();
|
||||
proxyUsers.clear();
|
||||
proxyServers.clear();
|
||||
|
||||
// get all the new keys for groups
|
||||
String regex = CONF_HADOOP_PROXYUSER_RE+"[^.]*\\"+CONF_GROUPS;
|
||||
// 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
|
||||
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()));
|
||||
|
@ -104,6 +116,16 @@ 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
|
||||
*
|
||||
|
@ -141,28 +163,41 @@ public class ProxyUsers {
|
|||
if (user.getRealUser() == null) {
|
||||
return;
|
||||
}
|
||||
boolean groupAuthorized = false;
|
||||
boolean userAuthorized = false;
|
||||
boolean ipAuthorized = false;
|
||||
UserGroupInformation superUser = user.getRealUser();
|
||||
|
||||
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 (!userAuthorized) {
|
||||
Collection<String> allowedUserGroups = proxyGroups.get(
|
||||
getProxySuperuserGroupConfKey(superUser.getShortUserName()));
|
||||
|
||||
if (isWildcardList(allowedUserGroups)) {
|
||||
groupAuthorized = true;
|
||||
userAuthorized = true;
|
||||
} else if (allowedUserGroups != null && !allowedUserGroups.isEmpty()) {
|
||||
for (String group : user.getGroupNames()) {
|
||||
if (allowedUserGroups.contains(group)) {
|
||||
groupAuthorized = true;
|
||||
userAuthorized = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!groupAuthorized) {
|
||||
if (!userAuthorized) {
|
||||
throw new AuthorizationException("User: " + superUser.getUserName()
|
||||
+ " is not allowed to impersonate " + user.getUserName());
|
||||
}
|
||||
}
|
||||
|
||||
Collection<String> ipList = proxyHosts.get(
|
||||
getProxySuperuserIpConfKey(superUser.getShortUserName()));
|
||||
|
@ -183,7 +218,7 @@ public class ProxyUsers {
|
|||
}
|
||||
}
|
||||
}
|
||||
if(!ipAuthorized) {
|
||||
if (!ipAuthorized) {
|
||||
throw new AuthorizationException("Unauthorized connection for super-user: "
|
||||
+ superUser.getUserName() + " from IP " + remoteAddress);
|
||||
}
|
||||
|
@ -213,6 +248,11 @@ public class ProxyUsers {
|
|||
(list.contains("*"));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static Map<String, Collection<String>> getProxyUsers() {
|
||||
return proxyUsers;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static Map<String, Collection<String>> getProxyGroups() {
|
||||
return proxyGroups;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -30,6 +30,7 @@ import static org.junit.Assert.*;
|
|||
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 =
|
||||
|
@ -70,6 +71,40 @@ public class TestProxyUsers {
|
|||
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();
|
||||
|
@ -104,6 +139,40 @@ public class TestProxyUsers {
|
|||
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() {
|
||||
Configuration conf = new Configuration();
|
||||
|
@ -193,7 +262,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue