001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.security.access; 019 020import static org.junit.Assert.assertFalse; 021import static org.junit.Assert.assertTrue; 022 023import java.util.ArrayList; 024import java.util.List; 025import java.util.concurrent.atomic.AtomicBoolean; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.hbase.Abortable; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseTestingUtility; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.Waiter.Predicate; 032import org.apache.hadoop.hbase.security.User; 033import org.apache.hadoop.hbase.testclassification.MediumTests; 034import org.apache.hadoop.hbase.testclassification.SecurityTests; 035import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 036import org.junit.AfterClass; 037import org.junit.BeforeClass; 038import org.junit.ClassRule; 039import org.junit.Test; 040import org.junit.experimental.categories.Category; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap; 045import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap; 046 047/** 048 * Test the reading and writing of access permissions to and from zookeeper. 049 */ 050@Category({SecurityTests.class, MediumTests.class}) 051public class TestZKPermissionWatcher { 052 053 @ClassRule 054 public static final HBaseClassTestRule CLASS_RULE = 055 HBaseClassTestRule.forClass(TestZKPermissionWatcher.class); 056 057 private static final Logger LOG = LoggerFactory.getLogger(TestZKPermissionWatcher.class); 058 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); 059 private static AuthManager AUTH_A; 060 private static AuthManager AUTH_B; 061 private static ZKPermissionWatcher WATCHER_A; 062 private static ZKPermissionWatcher WATCHER_B; 063 private final static Abortable ABORTABLE = new Abortable() { 064 private final AtomicBoolean abort = new AtomicBoolean(false); 065 066 @Override 067 public void abort(String why, Throwable e) { 068 LOG.info(why, e); 069 abort.set(true); 070 } 071 072 @Override 073 public boolean isAborted() { 074 return abort.get(); 075 } 076 }; 077 078 private static TableName TEST_TABLE = 079 TableName.valueOf("perms_test"); 080 081 @BeforeClass 082 public static void beforeClass() throws Exception { 083 // setup configuration 084 Configuration conf = UTIL.getConfiguration(); 085 SecureTestUtil.enableSecurity(conf); 086 087 // start minicluster 088 UTIL.startMiniCluster(); 089 AUTH_A = new AuthManager(conf); 090 AUTH_B = new AuthManager(conf); 091 WATCHER_A = new ZKPermissionWatcher( 092 new ZKWatcher(conf, "TestZKPermissionsWatcher_1", ABORTABLE), AUTH_A, conf); 093 WATCHER_B = new ZKPermissionWatcher( 094 new ZKWatcher(conf, "TestZKPermissionsWatcher_2", ABORTABLE), AUTH_B, conf); 095 WATCHER_A.start(); 096 WATCHER_B.start(); 097 } 098 099 @AfterClass 100 public static void afterClass() throws Exception { 101 WATCHER_A.close(); 102 WATCHER_B.close(); 103 UTIL.shutdownMiniCluster(); 104 } 105 106 @Test 107 public void testPermissionsWatcher() throws Exception { 108 Configuration conf = UTIL.getConfiguration(); 109 User george = User.createUserForTesting(conf, "george", new String[] { }); 110 User hubert = User.createUserForTesting(conf, "hubert", new String[] { }); 111 112 assertFalse(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 113 assertFalse(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 114 assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 115 assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 116 117 assertFalse(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 118 assertFalse(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 119 assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 120 assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 121 122 // update ACL: george RW 123 List<UserPermission> acl = new ArrayList<>(1); 124 acl.add(new UserPermission(george.getShortName(), Permission.newBuilder(TEST_TABLE) 125 .withActions(Permission.Action.READ, Permission.Action.WRITE).build())); 126 ListMultimap<String, UserPermission> multimap = ArrayListMultimap.create(); 127 multimap.putAll(george.getShortName(), acl); 128 byte[] serialized = PermissionStorage.writePermissionsAsBytes(multimap, conf); 129 WATCHER_A.writeToZookeeper(TEST_TABLE.getName(), serialized); 130 final long mtimeB = AUTH_B.getMTime(); 131 // Wait for the update to propagate 132 UTIL.waitFor(10000, 100, new Predicate<Exception>() { 133 @Override 134 public boolean evaluate() throws Exception { 135 return AUTH_B.getMTime() > mtimeB; 136 } 137 }); 138 Thread.sleep(1000); 139 140 // check it 141 assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 142 assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 143 assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 144 assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 145 assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 146 assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 147 assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 148 assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 149 150 // update ACL: hubert R 151 List<UserPermission> acl2 = new ArrayList<>(1); 152 acl2.add(new UserPermission(hubert.getShortName(), 153 Permission.newBuilder(TEST_TABLE).withActions(TablePermission.Action.READ).build())); 154 final long mtimeA = AUTH_A.getMTime(); 155 multimap.putAll(hubert.getShortName(), acl2); 156 byte[] serialized2 = PermissionStorage.writePermissionsAsBytes(multimap, conf); 157 WATCHER_B.writeToZookeeper(TEST_TABLE.getName(), serialized2); 158 // Wait for the update to propagate 159 UTIL.waitFor(10000, 100, new Predicate<Exception>() { 160 @Override 161 public boolean evaluate() throws Exception { 162 return AUTH_A.getMTime() > mtimeA; 163 } 164 }); 165 Thread.sleep(1000); 166 167 // check it 168 assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 169 assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 170 assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 171 assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 172 assertTrue(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 173 assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 174 assertTrue(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 175 assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 176 } 177}