blob: fe00949e3c895c07e9c526863996eb47d8e2980d [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.security.authorize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
import org.apache.hadoop.security.Groups;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.util.NativeCodeLoader;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
@InterfaceStability.Evolving
public class TestAccessControlList {
private static final Logger LOG =
LoggerFactory.getLogger(TestAccessControlList.class);
/**
* Test the netgroups (groups in ACL rules that start with @)
*
* This is a manual test because it requires:
* - host setup
* - native code compiled
* - specify the group mapping class
*
* Host setup:
*
* /etc/nsswitch.conf should have a line like this:
* netgroup: files
*
* /etc/netgroup should be (the whole file):
* lasVegas (,elvis,)
* memphis (,elvis,) (,jerryLeeLewis,)
*
* To run this test:
*
* export JAVA_HOME='path/to/java'
* ant \
* -Dtestcase=TestAccessControlList \
* -Dtest.output=yes \
* -DTestAccessControlListGroupMapping=$className \
* compile-native test
*
* where $className is one of the classes that provide group
* mapping services, i.e. classes that implement
* GroupMappingServiceProvider interface, at this time:
* - org.apache.hadoop.security.JniBasedUnixGroupsNetgroupMapping
* - org.apache.hadoop.security.ShellBasedUnixGroupsNetgroupMapping
*
*/
@Test
public void testNetgroups() throws Exception {
if(!NativeCodeLoader.isNativeCodeLoaded()) {
LOG.info("Not testing netgroups, " +
"this test only runs when native code is compiled");
return;
}
String groupMappingClassName =
System.getProperty("TestAccessControlListGroupMapping");
if(groupMappingClassName == null) {
LOG.info("Not testing netgroups, no group mapping class specified, " +
"use -DTestAccessControlListGroupMapping=$className to specify " +
"group mapping class (must implement GroupMappingServiceProvider " +
"interface and support netgroups)");
return;
}
LOG.info("Testing netgroups using: " + groupMappingClassName);
Configuration conf = new Configuration();
conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_GROUP_MAPPING,
groupMappingClassName);
Groups groups = Groups.getUserToGroupsMappingService(conf);
AccessControlList acl;
// create these ACLs to populate groups cache
acl = new AccessControlList("ja my"); // plain
acl = new AccessControlList("sinatra ratpack,@lasVegas"); // netgroup
acl = new AccessControlList(" somegroup,@someNetgroup"); // no user
// this ACL will be used for testing ACLs
acl = new AccessControlList("carlPerkins ratpack,@lasVegas");
acl.addGroup("@memphis");
// validate the netgroups before and after rehresh to make
// sure refresh works correctly
validateNetgroups(groups, acl);
groups.refresh();
validateNetgroups(groups, acl);
}
/**
* Validate the netgroups, both group membership and ACL
* functionality
*
* Note: assumes a specific acl setup done by testNetgroups
*
* @param groups group to user mapping service
* @param acl ACL set up in a specific way, see testNetgroups
*/
private void validateNetgroups(Groups groups,
AccessControlList acl) throws Exception {
// check that the netgroups are working
List<String> elvisGroups = groups.getGroups("elvis");
assertTrue(elvisGroups.contains("@lasVegas"));
assertTrue(elvisGroups.contains("@memphis"));
List<String> jerryLeeLewisGroups = groups.getGroups("jerryLeeLewis");
assertTrue(jerryLeeLewisGroups.contains("@memphis"));
// allowed because his netgroup is in ACL
UserGroupInformation elvis =
UserGroupInformation.createRemoteUser("elvis");
assertUserAllowed(elvis, acl);
// allowed because he's in ACL
UserGroupInformation carlPerkins =
UserGroupInformation.createRemoteUser("carlPerkins");
assertUserAllowed(carlPerkins, acl);
// not allowed because he's not in ACL and has no netgroups
UserGroupInformation littleRichard =
UserGroupInformation.createRemoteUser("littleRichard");
assertUserNotAllowed(littleRichard, acl);
}
@Test
public void testWildCardAccessControlList() throws Exception {
AccessControlList acl;
acl = new AccessControlList("*");
assertTrue(acl.isAllAllowed());
acl = new AccessControlList(" * ");
assertTrue(acl.isAllAllowed());
acl = new AccessControlList(" *");
assertTrue(acl.isAllAllowed());
acl = new AccessControlList("* ");
assertTrue(acl.isAllAllowed());
}
// Check if AccessControlList.toString() works as expected.
// Also validate if getAclString() for various cases.
@Test
public void testAclString() {
AccessControlList acl;
acl = new AccessControlList("*");
assertEquals("All users are allowed", acl.toString());
validateGetAclString(acl);
acl = new AccessControlList(" ");
assertEquals("No users are allowed", acl.toString());
acl = new AccessControlList("user1,user2");
assertEquals("Users [user1, user2] are allowed", acl.toString());
validateGetAclString(acl);
acl = new AccessControlList("user1,user2 ");// with space
assertEquals("Users [user1, user2] are allowed", acl.toString());
validateGetAclString(acl);
acl = new AccessControlList(" group1,group2");
assertTrue(acl.toString().equals(
"Members of the groups [group1, group2] are allowed"));
validateGetAclString(acl);
acl = new AccessControlList("user1,user2 group1,group2");
assertTrue(acl.toString().equals(
"Users [user1, user2] and " +
"members of the groups [group1, group2] are allowed"));
validateGetAclString(acl);
}
// Validates if getAclString() is working as expected. i.e. if we can build
// a new ACL instance from the value returned by getAclString().
private void validateGetAclString(AccessControlList acl) {
assertTrue(acl.toString().equals(
new AccessControlList(acl.getAclString()).toString()));
}
@Test
public void testAccessControlList() throws Exception {
AccessControlList acl;
Collection<String> users;
Collection<String> groups;
acl = new AccessControlList("drwho tardis");
users = acl.getUsers();
assertEquals(users.size(), 1);
assertEquals(users.iterator().next(), "drwho");
groups = acl.getGroups();
assertEquals(groups.size(), 1);
assertEquals(groups.iterator().next(), "tardis");
acl = new AccessControlList("drwho");
users = acl.getUsers();
assertEquals(users.size(), 1);
assertEquals(users.iterator().next(), "drwho");
groups = acl.getGroups();
assertEquals(groups.size(), 0);
acl = new AccessControlList("drwho ");
users = acl.getUsers();
assertEquals(users.size(), 1);
assertEquals(users.iterator().next(), "drwho");
groups = acl.getGroups();
assertEquals(groups.size(), 0);
acl = new AccessControlList(" tardis");
users = acl.getUsers();
assertEquals(users.size(), 0);
groups = acl.getGroups();
assertEquals(groups.size(), 1);
assertEquals(groups.iterator().next(), "tardis");
Iterator<String> iter;
acl = new AccessControlList("drwho,joe tardis, users");
users = acl.getUsers();
assertEquals(users.size(), 2);
iter = users.iterator();
assertEquals(iter.next(), "drwho");
assertEquals(iter.next(), "joe");
groups = acl.getGroups();
assertEquals(groups.size(), 2);
iter = groups.iterator();
assertEquals(iter.next(), "tardis");
assertEquals(iter.next(), "users");
}
/**
* Test addUser/Group and removeUser/Group api.
*/
@Test
public void testAddRemoveAPI() {
AccessControlList acl;
Collection<String> users;
Collection<String> groups;
acl = new AccessControlList(" ");
assertEquals(0, acl.getUsers().size());
assertEquals(0, acl.getGroups().size());
assertEquals(" ", acl.getAclString());
acl.addUser("drwho");
users = acl.getUsers();
assertEquals(users.size(), 1);
assertEquals(users.iterator().next(), "drwho");
assertEquals("drwho ", acl.getAclString());
acl.addGroup("tardis");
groups = acl.getGroups();
assertEquals(groups.size(), 1);
assertEquals(groups.iterator().next(), "tardis");
assertEquals("drwho tardis", acl.getAclString());
acl.addUser("joe");
acl.addGroup("users");
users = acl.getUsers();
assertEquals(users.size(), 2);
Iterator<String> iter = users.iterator();
assertEquals(iter.next(), "drwho");
assertEquals(iter.next(), "joe");
groups = acl.getGroups();
assertEquals(groups.size(), 2);
iter = groups.iterator();
assertEquals(iter.next(), "tardis");
assertEquals(iter.next(), "users");
assertEquals("drwho,joe tardis,users", acl.getAclString());
acl.removeUser("joe");
acl.removeGroup("users");
users = acl.getUsers();
assertEquals(users.size(), 1);
assertFalse(users.contains("joe"));
groups = acl.getGroups();
assertEquals(groups.size(), 1);
assertFalse(groups.contains("users"));
assertEquals("drwho tardis", acl.getAclString());
acl.removeGroup("tardis");
groups = acl.getGroups();
assertEquals(0, groups.size());
assertFalse(groups.contains("tardis"));
assertEquals("drwho ", acl.getAclString());
acl.removeUser("drwho");
assertEquals(0, users.size());
assertFalse(users.contains("drwho"));
assertEquals(0, acl.getGroups().size());
assertEquals(0, acl.getUsers().size());
assertEquals(" ", acl.getAclString());
}
/**
* Tests adding/removing wild card as the user/group.
*/
@Test
public void testAddRemoveWildCard() {
AccessControlList acl = new AccessControlList("drwho tardis");
Throwable th = null;
try {
acl.addUser(" * ");
} catch (Throwable t) {
th = t;
}
assertNotNull(th);
assertTrue(th instanceof IllegalArgumentException);
th = null;
try {
acl.addGroup(" * ");
} catch (Throwable t) {
th = t;
}
assertNotNull(th);
assertTrue(th instanceof IllegalArgumentException);
th = null;
try {
acl.removeUser(" * ");
} catch (Throwable t) {
th = t;
}
assertNotNull(th);
assertTrue(th instanceof IllegalArgumentException);
th = null;
try {
acl.removeGroup(" * ");
} catch (Throwable t) {
th = t;
}
assertNotNull(th);
assertTrue(th instanceof IllegalArgumentException);
}
/**
* Tests adding user/group to an wild card acl.
*/
@Test
public void testAddRemoveToWildCardACL() {
AccessControlList acl = new AccessControlList(" * ");
assertTrue(acl.isAllAllowed());
UserGroupInformation drwho =
UserGroupInformation.createUserForTesting("drwho@APACHE.ORG",
new String[] { "aliens" });
UserGroupInformation drwho2 =
UserGroupInformation.createUserForTesting("drwho2@APACHE.ORG",
new String[] { "tardis" });
acl.addUser("drwho");
assertTrue(acl.isAllAllowed());
assertFalse(acl.getAclString().contains("drwho"));
acl.addGroup("tardis");
assertTrue(acl.isAllAllowed());
assertFalse(acl.getAclString().contains("tardis"));
acl.removeUser("drwho");
assertTrue(acl.isAllAllowed());
assertUserAllowed(drwho, acl);
acl.removeGroup("tardis");
assertTrue(acl.isAllAllowed());
assertUserAllowed(drwho2, acl);
}
/**
* Verify the method isUserAllowed()
*/
@Test
public void testIsUserAllowed() {
AccessControlList acl;
UserGroupInformation drwho =
UserGroupInformation.createUserForTesting("drwho@APACHE.ORG",
new String[] { "aliens", "humanoids", "timelord" });
UserGroupInformation susan =
UserGroupInformation.createUserForTesting("susan@APACHE.ORG",
new String[] { "aliens", "humanoids", "timelord" });
UserGroupInformation barbara =
UserGroupInformation.createUserForTesting("barbara@APACHE.ORG",
new String[] { "humans", "teachers" });
UserGroupInformation ian =
UserGroupInformation.createUserForTesting("ian@APACHE.ORG",
new String[] { "humans", "teachers" });
acl = new AccessControlList("drwho humanoids");
assertUserAllowed(drwho, acl);
assertUserAllowed(susan, acl);
assertUserNotAllowed(barbara, acl);
assertUserNotAllowed(ian, acl);
acl = new AccessControlList("drwho");
assertUserAllowed(drwho, acl);
assertUserNotAllowed(susan, acl);
assertUserNotAllowed(barbara, acl);
assertUserNotAllowed(ian, acl);
acl = new AccessControlList("drwho ");
assertUserAllowed(drwho, acl);
assertUserNotAllowed(susan, acl);
assertUserNotAllowed(barbara, acl);
assertUserNotAllowed(ian, acl);
acl = new AccessControlList(" humanoids");
assertUserAllowed(drwho, acl);
assertUserAllowed(susan, acl);
assertUserNotAllowed(barbara, acl);
assertUserNotAllowed(ian, acl);
acl = new AccessControlList("drwho,ian aliens,teachers");
assertUserAllowed(drwho, acl);
assertUserAllowed(susan, acl);
assertUserAllowed(barbara, acl);
assertUserAllowed(ian, acl);
acl = new AccessControlList("");
UserGroupInformation spyUser = spy(drwho);
acl.isUserAllowed(spyUser);
verify(spyUser, never()).getGroupNames();
}
private void assertUserAllowed(UserGroupInformation ugi,
AccessControlList acl) {
assertTrue("User " + ugi + " is not granted the access-control!!",
acl.isUserAllowed(ugi));
}
private void assertUserNotAllowed(UserGroupInformation ugi,
AccessControlList acl) {
assertFalse("User " + ugi
+ " is incorrectly granted the access-control!!",
acl.isUserAllowed(ugi));
}
}