| /** |
| * 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 java.util.Iterator; |
| import java.util.Set; |
| import java.util.List; |
| |
| import org.junit.Test; |
| import org.junit.Before; |
| 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 static org.junit.Assume.assumeTrue; |
| |
| import org.apache.hadoop.classification.InterfaceAudience; |
| import org.apache.hadoop.classification.InterfaceStability; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.hadoop.fs.CommonConfigurationKeysPublic; |
| import org.apache.hadoop.util.NativeCodeLoader; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.security.Groups; |
| import org.apache.hadoop.security.UserGroupInformation; |
| import org.apache.hadoop.security.authorize.AccessControlList; |
| |
| @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"}) |
| @InterfaceStability.Evolving |
| public class TestAccessControlList { |
| |
| private static final Log LOG = |
| LogFactory.getLog(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 becuase 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("*"); |
| assertTrue(acl.toString().equals("All users are allowed")); |
| validateGetAclString(acl); |
| |
| acl = new AccessControlList(" "); |
| assertTrue(acl.toString().equals("No users are allowed")); |
| |
| acl = new AccessControlList("user1,user2"); |
| assertTrue(acl.toString().equals("Users [user1, user2] are allowed")); |
| validateGetAclString(acl); |
| |
| acl = new AccessControlList("user1,user2 ");// with space |
| assertTrue(acl.toString().equals("Users [user1, user2] are allowed")); |
| 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; |
| Set<String> users; |
| Set<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; |
| Set<String> users; |
| Set<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); |
| } |
| |
| 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)); |
| } |
| } |