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.rsgroup; 019 020import static org.apache.hadoop.hbase.AuthUtil.toGroupEntry; 021import static org.junit.Assert.assertEquals; 022import static org.junit.Assert.fail; 023 024import java.io.IOException; 025import java.util.Optional; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.hbase.HBaseClassTestRule; 028import org.apache.hadoop.hbase.HBaseTestingUtil; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.TableNotFoundException; 031import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 032import org.apache.hadoop.hbase.client.Connection; 033import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 034import org.apache.hadoop.hbase.ipc.RpcServer; 035import org.apache.hadoop.hbase.master.HMaster; 036import org.apache.hadoop.hbase.security.User; 037import org.apache.hadoop.hbase.security.UserProvider; 038import org.apache.hadoop.hbase.security.access.AccessChecker; 039import org.apache.hadoop.hbase.security.access.AccessControlClient; 040import org.apache.hadoop.hbase.security.access.Permission; 041import org.apache.hadoop.hbase.security.access.PermissionStorage; 042import org.apache.hadoop.hbase.security.access.SecureTestUtil; 043import org.apache.hadoop.hbase.testclassification.MediumTests; 044import org.apache.hadoop.hbase.testclassification.SecurityTests; 045import org.apache.hadoop.hbase.util.Bytes; 046import org.junit.AfterClass; 047import org.junit.BeforeClass; 048import org.junit.ClassRule; 049import org.junit.Test; 050import org.junit.experimental.categories.Category; 051import org.slf4j.Logger; 052import org.slf4j.LoggerFactory; 053 054/** 055 * Performs authorization checks for rsgroup operations, according to different levels of authorized 056 * users. 057 */ 058@Category({ SecurityTests.class, MediumTests.class }) 059public class TestRSGroupsWithACL extends SecureTestUtil { 060 061 @ClassRule 062 public static final HBaseClassTestRule CLASS_RULE = 063 HBaseClassTestRule.forClass(TestRSGroupsWithACL.class); 064 065 private static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsWithACL.class); 066 private static TableName TEST_TABLE = TableName.valueOf("testtable1"); 067 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 068 private static Configuration conf; 069 070 private static Connection systemUserConnection; 071 // user with all permissions 072 private static User SUPERUSER; 073 // user granted with all global permission 074 private static User USER_ADMIN; 075 // user with rw permissions on column family. 076 private static User USER_RW; 077 // user with read-only permissions 078 private static User USER_RO; 079 // user is table owner. will have all permissions on table 080 private static User USER_OWNER; 081 // user with create table permissions alone 082 private static User USER_CREATE; 083 // user with no permissions 084 private static User USER_NONE; 085 086 private static final String GROUP_ADMIN = "group_admin"; 087 private static final String GROUP_CREATE = "group_create"; 088 private static final String GROUP_READ = "group_read"; 089 private static final String GROUP_WRITE = "group_write"; 090 091 private static User USER_GROUP_ADMIN; 092 private static User USER_GROUP_CREATE; 093 private static User USER_GROUP_READ; 094 private static User USER_GROUP_WRITE; 095 096 private static byte[] TEST_FAMILY = Bytes.toBytes("f1"); 097 private static HMaster master; 098 private static AccessChecker accessChecker; 099 private static UserProvider userProvider; 100 101 @BeforeClass 102 public static void setupBeforeClass() throws Exception { 103 // setup configuration 104 conf = TEST_UTIL.getConfiguration(); 105 // Enable security 106 enableSecurity(conf); 107 // Verify enableSecurity sets up what we require 108 verifyConfiguration(conf); 109 // Enable rsgroup 110 RSGroupUtil.enableRSGroup(conf); 111 112 TEST_UTIL.startMiniCluster(); 113 // Wait for the ACL table to become available 114 TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME); 115 TEST_UTIL.waitUntilAllRegionsAssigned(RSGroupInfoManagerImpl.RSGROUP_TABLE_NAME); 116 TEST_UTIL.waitUntilNoRegionsInTransition(); 117 118 // create a set of test users 119 SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); 120 USER_ADMIN = User.createUserForTesting(conf, "admin2", new String[0]); 121 USER_RW = User.createUserForTesting(conf, "rwuser", new String[0]); 122 USER_RO = User.createUserForTesting(conf, "rouser", new String[0]); 123 USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]); 124 USER_CREATE = User.createUserForTesting(conf, "tbl_create", new String[0]); 125 USER_NONE = User.createUserForTesting(conf, "nouser", new String[0]); 126 127 USER_GROUP_ADMIN = 128 User.createUserForTesting(conf, "user_group_admin", new String[] { GROUP_ADMIN }); 129 USER_GROUP_CREATE = 130 User.createUserForTesting(conf, "user_group_create", new String[] { GROUP_CREATE }); 131 USER_GROUP_READ = 132 User.createUserForTesting(conf, "user_group_read", new String[] { GROUP_READ }); 133 USER_GROUP_WRITE = 134 User.createUserForTesting(conf, "user_group_write", new String[] { GROUP_WRITE }); 135 136 // Grant table creation permission to USER_OWNER 137 grantGlobal(TEST_UTIL, USER_OWNER.getShortName(), Permission.Action.CREATE); 138 139 systemUserConnection = TEST_UTIL.getConnection(); 140 setUpTableAndUserPermissions(); 141 master = TEST_UTIL.getHBaseCluster().getMaster(); 142 accessChecker = master.getAccessChecker(); 143 userProvider = UserProvider.instantiate(TEST_UTIL.getConfiguration()); 144 } 145 146 private void checkPermission(String request) throws IOException { 147 accessChecker.requirePermission(getActiveUser(), request, null, Permission.Action.ADMIN); 148 } 149 150 private User getActiveUser() throws IOException { 151 // for non-rpc handling, fallback to system user 152 Optional<User> optionalUser = RpcServer.getRequestUser(); 153 if (optionalUser.isPresent()) { 154 return optionalUser.get(); 155 } 156 return userProvider.getCurrent(); 157 } 158 159 private static void setUpTableAndUserPermissions() throws Exception { 160 TableDescriptorBuilder tableBuilder = TableDescriptorBuilder.newBuilder(TEST_TABLE); 161 ColumnFamilyDescriptorBuilder cfd = ColumnFamilyDescriptorBuilder.newBuilder(TEST_FAMILY); 162 cfd.setMaxVersions(100); 163 tableBuilder.setColumnFamily(cfd.build()); 164 createTable(TEST_UTIL, USER_OWNER, tableBuilder.build(), new byte[][] { Bytes.toBytes("s") }); 165 166 // Set up initial grants 167 grantGlobal(TEST_UTIL, USER_ADMIN.getShortName(), Permission.Action.ADMIN, 168 Permission.Action.CREATE, Permission.Action.READ, Permission.Action.WRITE); 169 170 grantOnTable(TEST_UTIL, USER_RW.getShortName(), TEST_TABLE, TEST_FAMILY, null, 171 Permission.Action.READ, Permission.Action.WRITE); 172 173 // USER_CREATE is USER_RW plus CREATE permissions 174 grantOnTable(TEST_UTIL, USER_CREATE.getShortName(), TEST_TABLE, null, null, 175 Permission.Action.CREATE, Permission.Action.READ, Permission.Action.WRITE); 176 177 grantOnTable(TEST_UTIL, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null, 178 Permission.Action.READ); 179 180 grantGlobal(TEST_UTIL, toGroupEntry(GROUP_ADMIN), Permission.Action.ADMIN); 181 grantGlobal(TEST_UTIL, toGroupEntry(GROUP_CREATE), Permission.Action.CREATE); 182 grantGlobal(TEST_UTIL, toGroupEntry(GROUP_READ), Permission.Action.READ); 183 grantGlobal(TEST_UTIL, toGroupEntry(GROUP_WRITE), Permission.Action.WRITE); 184 185 assertEquals(4, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size()); 186 try { 187 assertEquals(4, 188 AccessControlClient.getUserPermissions(systemUserConnection, TEST_TABLE.toString()).size()); 189 } catch (AssertionError e) { 190 fail(e.getMessage()); 191 } catch (Throwable e) { 192 LOG.error("error during call of AccessControlClient.getUserPermissions. ", e); 193 } 194 } 195 196 private static void cleanUp() throws Exception { 197 // Clean the _acl_ table 198 try { 199 deleteTable(TEST_UTIL, TEST_TABLE); 200 } catch (TableNotFoundException ex) { 201 // Test deleted the table, no problem 202 LOG.info("Test deleted table " + TEST_TABLE); 203 } 204 // Verify all table/namespace permissions are erased 205 assertEquals(0, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size()); 206 assertEquals(0, 207 PermissionStorage.getNamespacePermissions(conf, TEST_TABLE.getNamespaceAsString()).size()); 208 } 209 210 @AfterClass 211 public static void tearDownAfterClass() throws Exception { 212 cleanUp(); 213 TEST_UTIL.shutdownMiniCluster(); 214 } 215 216 @Test 217 public void testGetRSGroupInfo() throws Exception { 218 AccessTestAction action = () -> { 219 checkPermission("getRSGroupInfo"); 220 return null; 221 }; 222 223 validateAdminPermissions(action); 224 } 225 226 @Test 227 public void testGetRSGroupInfoOfTable() throws Exception { 228 AccessTestAction action = () -> { 229 checkPermission("getRSGroupInfoOfTable"); 230 return null; 231 }; 232 233 validateAdminPermissions(action); 234 } 235 236 @Test 237 public void testMoveServers() throws Exception { 238 AccessTestAction action = () -> { 239 checkPermission("moveServers"); 240 return null; 241 }; 242 243 validateAdminPermissions(action); 244 } 245 246 @Test 247 public void testMoveTables() throws Exception { 248 AccessTestAction action = () -> { 249 checkPermission("moveTables"); 250 return null; 251 }; 252 253 validateAdminPermissions(action); 254 } 255 256 @Test 257 public void testAddRSGroup() throws Exception { 258 AccessTestAction action = () -> { 259 checkPermission("addRSGroup"); 260 return null; 261 }; 262 263 validateAdminPermissions(action); 264 } 265 266 @Test 267 public void testRemoveRSGroup() throws Exception { 268 AccessTestAction action = () -> { 269 checkPermission("removeRSGroup"); 270 return null; 271 }; 272 273 validateAdminPermissions(action); 274 } 275 276 @Test 277 public void testBalanceRSGroup() throws Exception { 278 AccessTestAction action = () -> { 279 checkPermission("balanceRSGroup"); 280 return null; 281 }; 282 283 validateAdminPermissions(action); 284 } 285 286 @Test 287 public void testListRSGroup() throws Exception { 288 AccessTestAction action = () -> { 289 checkPermission("listRSGroup"); 290 return null; 291 }; 292 293 validateAdminPermissions(action); 294 } 295 296 @Test 297 public void testGetRSGroupInfoOfServer() throws Exception { 298 AccessTestAction action = () -> { 299 checkPermission("getRSGroupInfoOfServer"); 300 return null; 301 }; 302 303 validateAdminPermissions(action); 304 } 305 306 @Test 307 public void testMoveServersAndTables() throws Exception { 308 AccessTestAction action = () -> { 309 checkPermission("moveServersAndTables"); 310 return null; 311 }; 312 313 validateAdminPermissions(action); 314 } 315 316 @Test 317 public void testRemoveServers() throws Exception { 318 AccessTestAction action = () -> { 319 checkPermission("removeServers"); 320 return null; 321 }; 322 323 validateAdminPermissions(action); 324 } 325 326 @Test 327 public void testRenameRSGroup() throws Exception { 328 AccessTestAction action = () -> { 329 checkPermission("renameRSGroup"); 330 return null; 331 }; 332 333 validateAdminPermissions(action); 334 } 335 336 @Test 337 public void testUpdateRSGroupConfig() throws Exception { 338 AccessTestAction action = () -> { 339 checkPermission("updateRSGroupConfig"); 340 return null; 341 }; 342 343 validateAdminPermissions(action); 344 } 345 346 private void validateAdminPermissions(AccessTestAction action) throws Exception { 347 verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN); 348 verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ, 349 USER_GROUP_WRITE, USER_GROUP_CREATE); 350 } 351}