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.HBaseTestingUtil; 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 HBaseTestingUtil UTIL = new HBaseTestingUtil(); 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 = TableName.valueOf("perms_test"); 079 080 @BeforeClass 081 public static void beforeClass() throws Exception { 082 // setup configuration 083 Configuration conf = UTIL.getConfiguration(); 084 SecureTestUtil.enableSecurity(conf); 085 086 // start minicluster 087 UTIL.startMiniCluster(); 088 AUTH_A = new AuthManager(conf); 089 AUTH_B = new AuthManager(conf); 090 WATCHER_A = new ZKPermissionWatcher( 091 new ZKWatcher(conf, "TestZKPermissionsWatcher_1", ABORTABLE), AUTH_A, conf); 092 WATCHER_B = new ZKPermissionWatcher( 093 new ZKWatcher(conf, "TestZKPermissionsWatcher_2", ABORTABLE), AUTH_B, conf); 094 WATCHER_A.start(); 095 WATCHER_B.start(); 096 } 097 098 @AfterClass 099 public static void afterClass() throws Exception { 100 WATCHER_A.close(); 101 WATCHER_B.close(); 102 UTIL.shutdownMiniCluster(); 103 } 104 105 @Test 106 public void testPermissionsWatcher() throws Exception { 107 Configuration conf = UTIL.getConfiguration(); 108 User george = User.createUserForTesting(conf, "george", new String[] {}); 109 User hubert = User.createUserForTesting(conf, "hubert", new String[] {}); 110 111 assertFalse(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 112 assertFalse(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 113 assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 114 assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 115 116 assertFalse(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 117 assertFalse(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 118 assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 119 assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 120 121 // update ACL: george RW 122 List<UserPermission> acl = new ArrayList<>(1); 123 acl.add(new UserPermission(george.getShortName(), Permission.newBuilder(TEST_TABLE) 124 .withActions(Permission.Action.READ, Permission.Action.WRITE).build())); 125 ListMultimap<String, UserPermission> multimap = ArrayListMultimap.create(); 126 multimap.putAll(george.getShortName(), acl); 127 byte[] serialized = PermissionStorage.writePermissionsAsBytes(multimap, conf); 128 WATCHER_A.writeToZookeeper(TEST_TABLE.getName(), serialized); 129 final long mtimeB = AUTH_B.getMTime(); 130 // Wait for the update to propagate 131 UTIL.waitFor(10000, 100, new Predicate<Exception>() { 132 @Override 133 public boolean evaluate() throws Exception { 134 return AUTH_B.getMTime() > mtimeB; 135 } 136 }); 137 Thread.sleep(1000); 138 139 // check it 140 assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 141 assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 142 assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 143 assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 144 assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 145 assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 146 assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 147 assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 148 149 // update ACL: hubert R 150 List<UserPermission> acl2 = new ArrayList<>(1); 151 acl2.add(new UserPermission(hubert.getShortName(), 152 Permission.newBuilder(TEST_TABLE).withActions(TablePermission.Action.READ).build())); 153 final long mtimeA = AUTH_A.getMTime(); 154 multimap.putAll(hubert.getShortName(), acl2); 155 byte[] serialized2 = PermissionStorage.writePermissionsAsBytes(multimap, conf); 156 WATCHER_B.writeToZookeeper(TEST_TABLE.getName(), serialized2); 157 // Wait for the update to propagate 158 UTIL.waitFor(10000, 100, new Predicate<Exception>() { 159 @Override 160 public boolean evaluate() throws Exception { 161 return AUTH_A.getMTime() > mtimeA; 162 } 163 }); 164 Thread.sleep(1000); 165 166 // check it 167 assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 168 assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 169 assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ)); 170 assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE)); 171 assertTrue(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 172 assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 173 assertTrue(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ)); 174 assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE)); 175 } 176}