HADOOP-15836. Review of AccessControlList. Contributed by BELUGA BEHR.
This commit is contained in:
parent
e2cecb681e
commit
00254d7b8c
@ -20,11 +20,13 @@
|
|||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.Set;
|
||||||
import java.util.List;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
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;
|
||||||
@ -34,7 +36,6 @@
|
|||||||
import org.apache.hadoop.io.WritableFactory;
|
import org.apache.hadoop.io.WritableFactory;
|
||||||
import org.apache.hadoop.security.Groups;
|
import org.apache.hadoop.security.Groups;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing a configured access control list.
|
* Class representing a configured access control list.
|
||||||
@ -57,9 +58,9 @@ public class AccessControlList implements Writable {
|
|||||||
private static final int INITIAL_CAPACITY = 256;
|
private static final int INITIAL_CAPACITY = 256;
|
||||||
|
|
||||||
// Set of users who are granted access.
|
// Set of users who are granted access.
|
||||||
private Collection<String> users;
|
private final Set<String> users = new TreeSet<>();
|
||||||
// Set of groups which are granted access
|
// Set of groups which are granted access
|
||||||
private Collection<String> groups;
|
private final Set<String> groups = new TreeSet<>();
|
||||||
// Whether all users are granted access.
|
// Whether all users are granted access.
|
||||||
private boolean allAllowed;
|
private boolean allAllowed;
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ public AccessControlList(String aclString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new ACL from String representation of users and groups
|
* Construct a new ACL from String representation of users and groups.
|
||||||
*
|
*
|
||||||
* The arguments are comma separated lists
|
* The arguments are comma separated lists
|
||||||
*
|
*
|
||||||
@ -103,38 +104,39 @@ public AccessControlList(String users, String groups) {
|
|||||||
* @param aclString build ACL from array of Strings
|
* @param aclString build ACL from array of Strings
|
||||||
*/
|
*/
|
||||||
private void buildACL(String[] userGroupStrings) {
|
private void buildACL(String[] userGroupStrings) {
|
||||||
users = new HashSet<String>();
|
|
||||||
groups = new HashSet<String>();
|
|
||||||
for (String aclPart : userGroupStrings) {
|
for (String aclPart : userGroupStrings) {
|
||||||
if (aclPart != null && isWildCardACLValue(aclPart)) {
|
if (aclPart != null && isWildCardACLValue(aclPart)) {
|
||||||
allAllowed = true;
|
allAllowed = true;
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!allAllowed) {
|
|
||||||
if (userGroupStrings.length >= 1 && userGroupStrings[0] != null) {
|
if (userGroupStrings.length >= 1 && userGroupStrings[0] != null) {
|
||||||
users = StringUtils.getTrimmedStringCollection(userGroupStrings[0]);
|
String[] userList = userGroupStrings[0].split(",");
|
||||||
|
for (String user : userList) {
|
||||||
|
if (StringUtils.isNotBlank(user)) {
|
||||||
|
users.add(user.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userGroupStrings.length == 2 && userGroupStrings[1] != null) {
|
if (userGroupStrings.length == 2 && userGroupStrings[1] != null) {
|
||||||
groups = StringUtils.getTrimmedStringCollection(userGroupStrings[1]);
|
String[] groupList = userGroupStrings[1].split(",");
|
||||||
groupsMapping.cacheGroupsAdd(new LinkedList<String>(groups));
|
for (String group : groupList) {
|
||||||
|
if (StringUtils.isNotBlank(group)) {
|
||||||
|
groups.add(group.trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
groupsMapping.cacheGroupsAdd(new ArrayList<>(groups));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether ACL string contains wildcard
|
* Checks whether ACL string contains wildcard.
|
||||||
*
|
*
|
||||||
* @param aclString check this ACL string for wildcard
|
* @param aclString check this ACL string for wildcard
|
||||||
* @return true if ACL string contains wildcard false otherwise
|
* @return true if ACL string contains wildcard false otherwise
|
||||||
*/
|
*/
|
||||||
private boolean isWildCardACLValue(String aclString) {
|
private boolean isWildCardACLValue(String aclString) {
|
||||||
if (aclString.contains(WILDCARD_ACL_VALUE) &&
|
return WILDCARD_ACL_VALUE.equals(aclString.trim());
|
||||||
aclString.trim().equals(WILDCARD_ACL_VALUE)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllAllowed() {
|
public boolean isAllAllowed() {
|
||||||
@ -144,8 +146,7 @@ public boolean isAllAllowed() {
|
|||||||
/**
|
/**
|
||||||
* Add user to the names of users allowed for this service.
|
* Add user to the names of users allowed for this service.
|
||||||
*
|
*
|
||||||
* @param user
|
* @param user The user name
|
||||||
* The user name
|
|
||||||
*/
|
*/
|
||||||
public void addUser(String user) {
|
public void addUser(String user) {
|
||||||
if (isWildCardACLValue(user)) {
|
if (isWildCardACLValue(user)) {
|
||||||
@ -159,17 +160,15 @@ public void addUser(String user) {
|
|||||||
/**
|
/**
|
||||||
* Add group to the names of groups allowed for this service.
|
* Add group to the names of groups allowed for this service.
|
||||||
*
|
*
|
||||||
* @param group
|
* @param group The group name
|
||||||
* The group name
|
|
||||||
*/
|
*/
|
||||||
public void addGroup(String group) {
|
public void addGroup(String group) {
|
||||||
if (isWildCardACLValue(group)) {
|
if (isWildCardACLValue(group)) {
|
||||||
throw new IllegalArgumentException("Group " + group + " can not be added");
|
throw new IllegalArgumentException(
|
||||||
|
"Group " + group + " can not be added");
|
||||||
}
|
}
|
||||||
if (!isAllAllowed()) {
|
if (!isAllAllowed()) {
|
||||||
List<String> groupsList = new LinkedList<String>();
|
groupsMapping.cacheGroupsAdd(Collections.singletonList(group));
|
||||||
groupsList.add(group);
|
|
||||||
groupsMapping.cacheGroupsAdd(groupsList);
|
|
||||||
groups.add(group);
|
groups.add(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,8 +176,7 @@ public void addGroup(String group) {
|
|||||||
/**
|
/**
|
||||||
* Remove user from the names of users allowed for this service.
|
* Remove user from the names of users allowed for this service.
|
||||||
*
|
*
|
||||||
* @param user
|
* @param user The user name
|
||||||
* The user name
|
|
||||||
*/
|
*/
|
||||||
public void removeUser(String user) {
|
public void removeUser(String user) {
|
||||||
if (isWildCardACLValue(user)) {
|
if (isWildCardACLValue(user)) {
|
||||||
@ -192,13 +190,12 @@ public void removeUser(String user) {
|
|||||||
/**
|
/**
|
||||||
* Remove group from the names of groups allowed for this service.
|
* Remove group from the names of groups allowed for this service.
|
||||||
*
|
*
|
||||||
* @param group
|
* @param group The group name
|
||||||
* The group name
|
|
||||||
*/
|
*/
|
||||||
public void removeGroup(String group) {
|
public void removeGroup(String group) {
|
||||||
if (isWildCardACLValue(group)) {
|
if (isWildCardACLValue(group)) {
|
||||||
throw new IllegalArgumentException("Group " + group
|
throw new IllegalArgumentException(
|
||||||
+ " can not be removed");
|
"Group " + group + " can not be removed");
|
||||||
}
|
}
|
||||||
if (!isAllAllowed()) {
|
if (!isAllAllowed()) {
|
||||||
groups.remove(group);
|
groups.remove(group);
|
||||||
@ -207,18 +204,20 @@ public void removeGroup(String group) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the names of users allowed for this service.
|
* Get the names of users allowed for this service.
|
||||||
* @return the set of user names. the set must not be modified.
|
*
|
||||||
|
* @return an unmodifiable set of user names in alphabetic order.
|
||||||
*/
|
*/
|
||||||
public Collection<String> getUsers() {
|
public Collection<String> getUsers() {
|
||||||
return users;
|
return Collections.unmodifiableSet(users);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the names of user groups allowed for this service.
|
* Get the names of user groups allowed for this service.
|
||||||
* @return the set of group names. the set must not be modified.
|
*
|
||||||
|
* @return an unmodifiable set of group names in alphabetic order.
|
||||||
*/
|
*/
|
||||||
public Collection<String> getGroups() {
|
public Collection<String> getGroups() {
|
||||||
return groups;
|
return Collections.unmodifiableSet(groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -230,7 +229,8 @@ public Collection<String> getGroups() {
|
|||||||
public final boolean isUserInList(UserGroupInformation ugi) {
|
public final boolean isUserInList(UserGroupInformation ugi) {
|
||||||
if (allAllowed || users.contains(ugi.getShortUserName())) {
|
if (allAllowed || users.contains(ugi.getShortUserName())) {
|
||||||
return true;
|
return true;
|
||||||
} else if (!groups.isEmpty()) {
|
}
|
||||||
|
if (!groups.isEmpty()) {
|
||||||
for (String group : ugi.getGroups()) {
|
for (String group : ugi.getGroups()) {
|
||||||
if (groups.contains(group)) {
|
if (groups.contains(group)) {
|
||||||
return true;
|
return true;
|
||||||
@ -326,7 +326,7 @@ public void readFields(DataInput in) throws IOException {
|
|||||||
* @return comma separated list of users
|
* @return comma separated list of users
|
||||||
*/
|
*/
|
||||||
private String getUsersString() {
|
private String getUsersString() {
|
||||||
return getString(users);
|
return String.join(",", users);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -335,26 +335,6 @@ private String getUsersString() {
|
|||||||
* @return comma separated list of groups
|
* @return comma separated list of groups
|
||||||
*/
|
*/
|
||||||
private String getGroupsString() {
|
private String getGroupsString() {
|
||||||
return getString(groups);
|
return String.join(",", groups);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns comma-separated concatenated single String of all strings of
|
|
||||||
* the given set
|
|
||||||
*
|
|
||||||
* @param strings set of strings to concatenate
|
|
||||||
*/
|
|
||||||
private String getString(Collection<String> strings) {
|
|
||||||
StringBuilder sb = new StringBuilder(INITIAL_CAPACITY);
|
|
||||||
boolean first = true;
|
|
||||||
for(String str: strings) {
|
|
||||||
if (!first) {
|
|
||||||
sb.append(",");
|
|
||||||
} else {
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
sb.append(str);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
@ -37,9 +39,7 @@
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static org.mockito.Mockito.never;
|
import com.google.common.collect.Iterables;
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
|
@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
|
||||||
@InterfaceStability.Evolving
|
@InterfaceStability.Evolving
|
||||||
@ -202,14 +202,14 @@ public void testAclString() {
|
|||||||
validateGetAclString(acl);
|
validateGetAclString(acl);
|
||||||
|
|
||||||
acl = new AccessControlList(" group1,group2");
|
acl = new AccessControlList(" group1,group2");
|
||||||
assertTrue(acl.toString().equals(
|
assertEquals("Members of the groups [group1, group2] are allowed",
|
||||||
"Members of the groups [group1, group2] are allowed"));
|
acl.toString());
|
||||||
validateGetAclString(acl);
|
validateGetAclString(acl);
|
||||||
|
|
||||||
acl = new AccessControlList("user1,user2 group1,group2");
|
acl = new AccessControlList("user1,user2 group1,group2");
|
||||||
assertTrue(acl.toString().equals(
|
assertEquals("Users [user1, user2] and members of the groups "
|
||||||
"Users [user1, user2] and " +
|
+ "[group1, group2] are allowed", acl.toString());
|
||||||
"members of the groups [group1, group2] are allowed"));
|
|
||||||
validateGetAclString(acl);
|
validateGetAclString(acl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,45 +228,42 @@ public void testAccessControlList() throws Exception {
|
|||||||
|
|
||||||
acl = new AccessControlList("drwho tardis");
|
acl = new AccessControlList("drwho tardis");
|
||||||
users = acl.getUsers();
|
users = acl.getUsers();
|
||||||
assertEquals(users.size(), 1);
|
assertEquals(1, users.size());
|
||||||
assertEquals(users.iterator().next(), "drwho");
|
assertEquals("drwho", Iterables.getOnlyElement(users));
|
||||||
groups = acl.getGroups();
|
groups = acl.getGroups();
|
||||||
assertEquals(groups.size(), 1);
|
assertEquals(1, groups.size());
|
||||||
assertEquals(groups.iterator().next(), "tardis");
|
assertEquals("tardis", Iterables.getOnlyElement(groups));
|
||||||
|
|
||||||
acl = new AccessControlList("drwho");
|
acl = new AccessControlList("drwho");
|
||||||
users = acl.getUsers();
|
users = acl.getUsers();
|
||||||
assertEquals(users.size(), 1);
|
assertEquals(1, users.size());
|
||||||
assertEquals(users.iterator().next(), "drwho");
|
assertEquals("drwho", Iterables.getOnlyElement(users));
|
||||||
groups = acl.getGroups();
|
groups = acl.getGroups();
|
||||||
assertEquals(groups.size(), 0);
|
assertEquals(0, groups.size());
|
||||||
|
|
||||||
acl = new AccessControlList("drwho ");
|
acl = new AccessControlList("drwho ");
|
||||||
users = acl.getUsers();
|
users = acl.getUsers();
|
||||||
assertEquals(users.size(), 1);
|
assertEquals(1, users.size());
|
||||||
assertEquals(users.iterator().next(), "drwho");
|
assertEquals("drwho", Iterables.getOnlyElement(users));
|
||||||
groups = acl.getGroups();
|
groups = acl.getGroups();
|
||||||
assertEquals(groups.size(), 0);
|
assertEquals(0, groups.size());
|
||||||
|
|
||||||
acl = new AccessControlList(" tardis");
|
acl = new AccessControlList(" tardis");
|
||||||
users = acl.getUsers();
|
users = acl.getUsers();
|
||||||
assertEquals(users.size(), 0);
|
assertEquals(0, users.size());
|
||||||
groups = acl.getGroups();
|
groups = acl.getGroups();
|
||||||
assertEquals(groups.size(), 1);
|
assertEquals(1, groups.size());
|
||||||
assertEquals(groups.iterator().next(), "tardis");
|
assertEquals("tardis", Iterables.getOnlyElement(groups));
|
||||||
|
|
||||||
Iterator<String> iter;
|
|
||||||
acl = new AccessControlList("drwho,joe tardis, users");
|
acl = new AccessControlList("drwho,joe tardis, users");
|
||||||
users = acl.getUsers();
|
users = acl.getUsers();
|
||||||
assertEquals(users.size(), 2);
|
assertEquals(2, users.size());
|
||||||
iter = users.iterator();
|
assertTrue(users.contains("drwho"));
|
||||||
assertEquals(iter.next(), "drwho");
|
assertTrue(users.contains("joe"));
|
||||||
assertEquals(iter.next(), "joe");
|
|
||||||
groups = acl.getGroups();
|
groups = acl.getGroups();
|
||||||
assertEquals(groups.size(), 2);
|
assertEquals(2, groups.size());
|
||||||
iter = groups.iterator();
|
assertTrue(groups.contains("tardis"));
|
||||||
assertEquals(iter.next(), "tardis");
|
assertTrue(groups.contains("users"));
|
||||||
assertEquals(iter.next(), "users");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -284,49 +281,45 @@ public void testAddRemoveAPI() {
|
|||||||
|
|
||||||
acl.addUser("drwho");
|
acl.addUser("drwho");
|
||||||
users = acl.getUsers();
|
users = acl.getUsers();
|
||||||
assertEquals(users.size(), 1);
|
assertEquals(1, users.size());
|
||||||
assertEquals(users.iterator().next(), "drwho");
|
assertEquals("drwho", Iterables.getOnlyElement(users));
|
||||||
assertEquals("drwho ", acl.getAclString());
|
assertEquals("drwho ", acl.getAclString());
|
||||||
|
|
||||||
acl.addGroup("tardis");
|
acl.addGroup("tardis");
|
||||||
groups = acl.getGroups();
|
groups = acl.getGroups();
|
||||||
assertEquals(groups.size(), 1);
|
assertEquals(1, groups.size());
|
||||||
assertEquals(groups.iterator().next(), "tardis");
|
assertEquals("tardis", Iterables.getOnlyElement(groups));
|
||||||
assertEquals("drwho tardis", acl.getAclString());
|
assertEquals("drwho tardis", acl.getAclString());
|
||||||
|
|
||||||
acl.addUser("joe");
|
acl.addUser("joe");
|
||||||
acl.addGroup("users");
|
acl.addGroup("users");
|
||||||
users = acl.getUsers();
|
users = acl.getUsers();
|
||||||
assertEquals(users.size(), 2);
|
assertEquals(2, users.size());
|
||||||
Iterator<String> iter = users.iterator();
|
assertTrue(users.contains("drwho"));
|
||||||
assertEquals(iter.next(), "drwho");
|
assertTrue(users.contains("joe"));
|
||||||
assertEquals(iter.next(), "joe");
|
|
||||||
groups = acl.getGroups();
|
groups = acl.getGroups();
|
||||||
assertEquals(groups.size(), 2);
|
assertEquals(2, groups.size());
|
||||||
iter = groups.iterator();
|
assertTrue(groups.contains("tardis"));
|
||||||
assertEquals(iter.next(), "tardis");
|
assertTrue(groups.contains("users"));
|
||||||
assertEquals(iter.next(), "users");
|
|
||||||
assertEquals("drwho,joe tardis,users", acl.getAclString());
|
|
||||||
|
|
||||||
acl.removeUser("joe");
|
acl.removeUser("joe");
|
||||||
acl.removeGroup("users");
|
acl.removeGroup("users");
|
||||||
users = acl.getUsers();
|
users = acl.getUsers();
|
||||||
assertEquals(users.size(), 1);
|
assertEquals(1, users.size());
|
||||||
assertFalse(users.contains("joe"));
|
assertEquals("drwho", Iterables.getOnlyElement(users));
|
||||||
groups = acl.getGroups();
|
groups = acl.getGroups();
|
||||||
assertEquals(groups.size(), 1);
|
assertEquals(1, groups.size());
|
||||||
assertFalse(groups.contains("users"));
|
assertEquals("tardis", Iterables.getOnlyElement(groups));
|
||||||
assertEquals("drwho tardis", acl.getAclString());
|
assertEquals("drwho tardis", acl.getAclString());
|
||||||
|
|
||||||
acl.removeGroup("tardis");
|
acl.removeGroup("tardis");
|
||||||
groups = acl.getGroups();
|
groups = acl.getGroups();
|
||||||
assertEquals(0, groups.size());
|
assertEquals(0, groups.size());
|
||||||
assertFalse(groups.contains("tardis"));
|
|
||||||
assertEquals("drwho ", acl.getAclString());
|
assertEquals("drwho ", acl.getAclString());
|
||||||
|
|
||||||
acl.removeUser("drwho");
|
acl.removeUser("drwho");
|
||||||
assertEquals(0, users.size());
|
assertEquals(0, users.size());
|
||||||
assertFalse(users.contains("drwho"));
|
|
||||||
assertEquals(0, acl.getGroups().size());
|
assertEquals(0, acl.getGroups().size());
|
||||||
assertEquals(0, acl.getUsers().size());
|
assertEquals(0, acl.getUsers().size());
|
||||||
assertEquals(" ", acl.getAclString());
|
assertEquals(" ", acl.getAclString());
|
||||||
|
Loading…
Reference in New Issue
Block a user