1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.security.access;
19
20 import static org.apache.hadoop.hbase.AuthUtil.toGroupEntry;
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertTrue;
25 import java.util.Arrays;
26 import java.util.List;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.hbase.Coprocessor;
32 import org.apache.hadoop.hbase.HBaseTestingUtility;
33 import org.apache.hadoop.hbase.HColumnDescriptor;
34 import org.apache.hadoop.hbase.HConstants;
35 import org.apache.hadoop.hbase.HTableDescriptor;
36 import org.apache.hadoop.hbase.NamespaceDescriptor;
37 import org.apache.hadoop.hbase.TableName;
38 import org.apache.hadoop.hbase.TableNameTestRule;
39 import org.apache.hadoop.hbase.TableNotFoundException;
40 import org.apache.hadoop.hbase.client.Admin;
41 import org.apache.hadoop.hbase.client.Connection;
42 import org.apache.hadoop.hbase.client.ConnectionFactory;
43 import org.apache.hadoop.hbase.client.Put;
44 import org.apache.hadoop.hbase.client.Result;
45 import org.apache.hadoop.hbase.client.ResultScanner;
46 import org.apache.hadoop.hbase.client.Scan;
47 import org.apache.hadoop.hbase.client.Table;
48 import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
49 import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
50 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
51 import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
52 import org.apache.hadoop.hbase.security.User;
53 import org.apache.hadoop.hbase.security.access.Permission.Action;
54 import org.apache.hadoop.hbase.testclassification.LargeTests;
55 import org.apache.hadoop.hbase.util.Bytes;
56 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
57 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
58 import org.junit.After;
59 import org.junit.AfterClass;
60 import org.junit.Before;
61 import org.junit.BeforeClass;
62 import org.junit.Rule;
63 import org.junit.Test;
64 import org.junit.experimental.categories.Category;
65
66 @Category(LargeTests.class)
67 public class TestAccessController2 extends SecureTestUtil {
68 private static final Log LOG = LogFactory.getLog(TestAccessController2.class);
69
70 private static final byte[] TEST_ROW = Bytes.toBytes("test");
71 private static final byte[] TEST_FAMILY = Bytes.toBytes("f");
72 private static final byte[] TEST_QUALIFIER = Bytes.toBytes("q");
73 private static final byte[] TEST_VALUE = Bytes.toBytes("value");
74
75 private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
76 private static Configuration conf;
77
78
79
80
81 private static Connection systemUserConnection;
82
83 private final static byte[] Q1 = Bytes.toBytes("q1");
84 private final static byte[] value1 = Bytes.toBytes("value1");
85
86 private static byte[] TEST_FAMILY_2 = Bytes.toBytes("f2");
87 private static byte[] TEST_ROW_2 = Bytes.toBytes("r2");
88 private final static byte[] Q2 = Bytes.toBytes("q2");
89 private final static byte[] value2 = Bytes.toBytes("value2");
90
91 private static byte[] TEST_ROW_3 = Bytes.toBytes("r3");
92
93 private static final String TESTGROUP_1 = "testgroup_1";
94 private static final String TESTGROUP_2 = "testgroup_2";
95
96 private static User TESTGROUP1_USER1;
97 private static User TESTGROUP2_USER1;
98
99 @Rule
100 public TableNameTestRule testTable = new TableNameTestRule();
101 private String namespace = "testNamespace";
102 private String tname = namespace + ":testtable1";
103 private TableName tableName = TableName.valueOf(tname);
104 private static String TESTGROUP_1_NAME;
105
106 @BeforeClass
107 public static void setupBeforeClass() throws Exception {
108 conf = TEST_UTIL.getConfiguration();
109
110 conf.setInt(HConstants.REGION_SERVER_HIGH_PRIORITY_HANDLER_COUNT, 10);
111
112 enableSecurity(conf);
113
114 verifyConfiguration(conf);
115 TEST_UTIL.startMiniCluster();
116
117 TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME);
118
119 TESTGROUP_1_NAME = toGroupEntry(TESTGROUP_1);
120 TESTGROUP1_USER1 =
121 User.createUserForTesting(conf, "testgroup1_user1", new String[] { TESTGROUP_1 });
122 TESTGROUP2_USER1 =
123 User.createUserForTesting(conf, "testgroup2_user2", new String[] { TESTGROUP_2 });
124
125 systemUserConnection = ConnectionFactory.createConnection(conf);
126 }
127
128 @Before
129 public void setUp() throws Exception {
130 createNamespace(TEST_UTIL, NamespaceDescriptor.create(namespace).build());
131 try (Table table = createTable(TEST_UTIL, tableName,
132 new byte[][] { TEST_FAMILY, TEST_FAMILY_2 })) {
133 TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
134
135
136 table.put(Arrays.asList(new Put(TEST_ROW).addColumn(TEST_FAMILY, Q1, value1),
137 new Put(TEST_ROW_2).addColumn(TEST_FAMILY, Q2, value2),
138 new Put(TEST_ROW_3).addColumn(TEST_FAMILY_2, Q1, value1)));
139 }
140
141 assertEquals(1, AccessControlLists.getTablePermissions(conf, tableName).size());
142 try {
143 assertEquals(1, AccessControlClient.getUserPermissions(systemUserConnection, tableName.toString())
144 .size());
145 } catch (Throwable e) {
146 LOG.error("Error during call of AccessControlClient.getUserPermissions. ", e);
147 }
148 }
149
150 @AfterClass
151 public static void tearDownAfterClass() throws Exception {
152 systemUserConnection.close();
153 TEST_UTIL.shutdownMiniCluster();
154 }
155
156 @After
157 public void tearDown() throws Exception {
158
159 try {
160 deleteTable(TEST_UTIL, tableName);
161 } catch (TableNotFoundException ex) {
162
163 LOG.info("Test deleted table " + tableName);
164 }
165 deleteNamespace(TEST_UTIL, namespace);
166
167 assertEquals(0, AccessControlLists.getTablePermissions(conf, tableName).size());
168 assertEquals(0, AccessControlLists.getNamespacePermissions(conf, namespace).size());
169 }
170
171 @Test (timeout=180000)
172 public void testCreateWithCorrectOwner() throws Exception {
173
174 final User testUser = User.createUserForTesting(TEST_UTIL.getConfiguration(), "TestUser",
175 new String[0]);
176
177 SecureTestUtil.grantGlobal(TEST_UTIL, testUser.getShortName(), Action.CREATE);
178 verifyAllowed(new AccessTestAction() {
179 @Override
180 public Object run() throws Exception {
181 HTableDescriptor desc = new HTableDescriptor(testTable.getTableName());
182 desc.addFamily(new HColumnDescriptor(TEST_FAMILY));
183 try (Connection connection =
184 ConnectionFactory.createConnection(TEST_UTIL.getConfiguration(), testUser)) {
185 try (Admin admin = connection.getAdmin()) {
186 createTable(TEST_UTIL, admin, desc);
187 }
188 }
189 return null;
190 }
191 }, testUser);
192 TEST_UTIL.waitTableAvailable(testTable.getTableName());
193
194
195 List<TablePermission> perms =
196 AccessControlLists.getTablePermissions(conf, testTable.getTableName())
197 .get(testUser.getShortName());
198 assertNotNull(perms);
199 assertFalse(perms.isEmpty());
200
201 assertTrue(perms.get(0).implies(Permission.Action.READ));
202 assertTrue(perms.get(0).implies(Permission.Action.WRITE));
203 assertTrue(perms.get(0).implies(Permission.Action.EXEC));
204 assertTrue(perms.get(0).implies(Permission.Action.CREATE));
205 assertTrue(perms.get(0).implies(Permission.Action.ADMIN));
206 }
207
208 @Test (timeout=180000)
209 public void testCreateTableWithGroupPermissions() throws Exception {
210 grantGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.CREATE);
211 try {
212 AccessTestAction createAction = new AccessTestAction() {
213 @Override
214 public Object run() throws Exception {
215 HTableDescriptor desc = new HTableDescriptor(testTable.getTableName());
216 desc.addFamily(new HColumnDescriptor(TEST_FAMILY));
217 try (Connection connection =
218 ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) {
219 try (Admin admin = connection.getAdmin()) {
220 admin.createTable(desc);
221 }
222 }
223 return null;
224 }
225 };
226 verifyAllowed(createAction, TESTGROUP1_USER1);
227 verifyDenied(createAction, TESTGROUP2_USER1);
228 } finally {
229 revokeGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.CREATE);
230 }
231 }
232
233 @Test (timeout=180000)
234 public void testACLTableAccess() throws Exception {
235 final Configuration conf = TEST_UTIL.getConfiguration();
236
237
238 User superUser = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
239
240
241 User globalRead = User.createUserForTesting(conf, "globalRead", new String[0]);
242 User globalWrite = User.createUserForTesting(conf, "globalWrite", new String[0]);
243 User globalCreate = User.createUserForTesting(conf, "globalCreate", new String[0]);
244 User globalAdmin = User.createUserForTesting(conf, "globalAdmin", new String[0]);
245 SecureTestUtil.grantGlobal(TEST_UTIL, globalRead.getShortName(), Action.READ);
246 SecureTestUtil.grantGlobal(TEST_UTIL, globalWrite.getShortName(), Action.WRITE);
247 SecureTestUtil.grantGlobal(TEST_UTIL, globalCreate.getShortName(), Action.CREATE);
248 SecureTestUtil.grantGlobal(TEST_UTIL, globalAdmin.getShortName(), Action.ADMIN);
249
250
251 User nsRead = User.createUserForTesting(conf, "nsRead", new String[0]);
252 User nsWrite = User.createUserForTesting(conf, "nsWrite", new String[0]);
253 User nsCreate = User.createUserForTesting(conf, "nsCreate", new String[0]);
254 User nsAdmin = User.createUserForTesting(conf, "nsAdmin", new String[0]);
255 SecureTestUtil.grantOnNamespace(TEST_UTIL, nsRead.getShortName(),
256 testTable.getTableName().getNamespaceAsString(), Action.READ);
257 SecureTestUtil.grantOnNamespace(TEST_UTIL, nsWrite.getShortName(),
258 testTable.getTableName().getNamespaceAsString(), Action.WRITE);
259 SecureTestUtil.grantOnNamespace(TEST_UTIL, nsCreate.getShortName(),
260 testTable.getTableName().getNamespaceAsString(), Action.CREATE);
261 SecureTestUtil.grantOnNamespace(TEST_UTIL, nsAdmin.getShortName(),
262 testTable.getTableName().getNamespaceAsString(), Action.ADMIN);
263
264
265 User tableRead = User.createUserForTesting(conf, "tableRead", new String[0]);
266 User tableWrite = User.createUserForTesting(conf, "tableWrite", new String[0]);
267 User tableCreate = User.createUserForTesting(conf, "tableCreate", new String[0]);
268 User tableAdmin = User.createUserForTesting(conf, "tableAdmin", new String[0]);
269 SecureTestUtil.grantOnTable(TEST_UTIL, tableRead.getShortName(),
270 testTable.getTableName(), null, null, Action.READ);
271 SecureTestUtil.grantOnTable(TEST_UTIL, tableWrite.getShortName(),
272 testTable.getTableName(), null, null, Action.WRITE);
273 SecureTestUtil.grantOnTable(TEST_UTIL, tableCreate.getShortName(),
274 testTable.getTableName(), null, null, Action.CREATE);
275 SecureTestUtil.grantOnTable(TEST_UTIL, tableAdmin.getShortName(),
276 testTable.getTableName(), null, null, Action.ADMIN);
277
278 grantGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.WRITE);
279 try {
280
281
282 AccessTestAction writeAction = new AccessTestAction() {
283 @Override
284 public Object run() throws Exception {
285 try (Connection conn = ConnectionFactory.createConnection(conf);
286 Table t = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) {
287 t.put(new Put(TEST_ROW).addColumn(AccessControlLists.ACL_LIST_FAMILY, TEST_QUALIFIER,
288 TEST_VALUE));
289 return null;
290 } finally {
291 }
292 }
293 };
294
295
296
297 verifyDenied(writeAction, globalAdmin, globalCreate, globalRead, TESTGROUP2_USER1);
298 verifyDenied(writeAction, nsAdmin, nsCreate, nsRead, nsWrite);
299 verifyDenied(writeAction, tableAdmin, tableCreate, tableRead, tableWrite);
300 verifyAllowed(writeAction, superUser, globalWrite, TESTGROUP1_USER1);
301 } finally {
302 revokeGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.WRITE);
303 }
304
305 grantGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.READ);
306 try {
307
308
309 AccessTestAction scanAction = new AccessTestAction() {
310 @Override
311 public Object run() throws Exception {
312 try (Connection conn = ConnectionFactory.createConnection(conf);
313 Table t = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) {
314 ResultScanner s = t.getScanner(new Scan());
315 try {
316 for (Result r = s.next(); r != null; r = s.next()) {
317
318 }
319 } finally {
320 s.close();
321 }
322 return null;
323 }
324 }
325 };
326
327
328
329 verifyDenied(scanAction, globalAdmin, globalCreate, globalWrite, TESTGROUP2_USER1);
330 verifyDenied(scanAction, nsCreate, nsAdmin, nsRead, nsWrite);
331 verifyDenied(scanAction, tableCreate, tableAdmin, tableRead, tableWrite);
332 verifyAllowed(scanAction, superUser, globalRead, TESTGROUP1_USER1);
333 } finally {
334 revokeGlobal(TEST_UTIL, TESTGROUP_1_NAME, Action.READ);
335 }
336 }
337
338
339
340
341 @Test(timeout = 300000)
342 public void testPostGrantAndRevokeScanAction() throws Exception {
343 AccessTestAction scanTableActionForGroupWithTableLevelAccess = new AccessTestAction() {
344 @Override
345 public Void run() throws Exception {
346 try (Connection connection = ConnectionFactory.createConnection(conf);
347 Table table = connection.getTable(tableName);) {
348 Scan s1 = new Scan();
349 try (ResultScanner scanner1 = table.getScanner(s1);) {
350 Result[] next1 = scanner1.next(5);
351 assertTrue("User having table level access should be able to scan all "
352 + "the data in the table.", next1.length == 3);
353 }
354 }
355 return null;
356 }
357 };
358
359 AccessTestAction scanTableActionForGroupWithFamilyLevelAccess = new AccessTestAction() {
360 @Override
361 public Void run() throws Exception {
362 try (Connection connection = ConnectionFactory.createConnection(conf);
363 Table table = connection.getTable(tableName);) {
364 Scan s1 = new Scan();
365 try (ResultScanner scanner1 = table.getScanner(s1);) {
366 Result[] next1 = scanner1.next(5);
367 assertTrue("User having column family level access should be able to scan all "
368 + "the data belonging to that family.", next1.length == 2);
369 }
370 }
371 return null;
372 }
373 };
374
375 AccessTestAction scanFamilyActionForGroupWithFamilyLevelAccess = new AccessTestAction() {
376 @Override
377 public Void run() throws Exception {
378 try (Connection connection = ConnectionFactory.createConnection(conf);
379 Table table = connection.getTable(tableName);) {
380 Scan s1 = new Scan();
381 s1.addFamily(TEST_FAMILY_2);
382 try (ResultScanner scanner1 = table.getScanner(s1);) {
383 scanner1.next();
384 }
385 }
386 return null;
387 }
388 };
389
390 AccessTestAction scanTableActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
391 @Override
392 public Void run() throws Exception {
393 try (Connection connection = ConnectionFactory.createConnection(conf);
394 Table table = connection.getTable(tableName);) {
395 Scan s1 = new Scan();
396 try (ResultScanner scanner1 = table.getScanner(s1);) {
397 Result[] next1 = scanner1.next(5);
398 assertTrue("User having column qualifier level access should be able to scan "
399 + "that column family qualifier data.", next1.length == 1);
400 }
401 }
402 return null;
403 }
404 };
405
406 AccessTestAction scanFamilyActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
407 @Override
408 public Void run() throws Exception {
409 try (Connection connection = ConnectionFactory.createConnection(conf);
410 Table table = connection.getTable(tableName);) {
411 Scan s1 = new Scan();
412 s1.addFamily(TEST_FAMILY_2);
413 try (ResultScanner scanner1 = table.getScanner(s1);) {
414 scanner1.next();
415 }
416 }
417 return null;
418 }
419 };
420
421 AccessTestAction scanQualifierActionForGroupWithQualifierLevelAccess = new AccessTestAction() {
422 @Override
423 public Void run() throws Exception {
424 try (Connection connection = ConnectionFactory.createConnection(conf);
425 Table table = connection.getTable(tableName);) {
426 Scan s1 = new Scan();
427 s1.addColumn(TEST_FAMILY, Q2);
428 try (ResultScanner scanner1 = table.getScanner(s1);) {
429 scanner1.next();
430 }
431 }
432 return null;
433 }
434 };
435
436
437
438 grantOnTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, null, null, Action.READ);
439 verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithTableLevelAccess);
440 verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithTableLevelAccess);
441
442
443 revokeFromTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, null, null);
444 verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithTableLevelAccess);
445
446
447
448 grantOnTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, null,
449 Permission.Action.READ);
450 verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithFamilyLevelAccess);
451 verifyDenied(TESTGROUP1_USER1, scanFamilyActionForGroupWithFamilyLevelAccess);
452 verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithFamilyLevelAccess);
453 verifyDenied(TESTGROUP2_USER1, scanFamilyActionForGroupWithFamilyLevelAccess);
454
455
456
457 revokeFromTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, null);
458 verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithFamilyLevelAccess);
459
460
461
462 grantOnTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, Q1, Action.READ);
463 verifyAllowed(TESTGROUP1_USER1, scanTableActionForGroupWithQualifierLevelAccess);
464 verifyDenied(TESTGROUP1_USER1, scanFamilyActionForGroupWithQualifierLevelAccess);
465 verifyDenied(TESTGROUP1_USER1, scanQualifierActionForGroupWithQualifierLevelAccess);
466 verifyDenied(TESTGROUP2_USER1, scanTableActionForGroupWithQualifierLevelAccess);
467 verifyDenied(TESTGROUP2_USER1, scanFamilyActionForGroupWithQualifierLevelAccess);
468 verifyDenied(TESTGROUP2_USER1, scanQualifierActionForGroupWithQualifierLevelAccess);
469
470
471
472 revokeFromTable(TEST_UTIL, TESTGROUP_1_NAME, tableName, TEST_FAMILY, Q1);
473 verifyDenied(TESTGROUP1_USER1, scanTableActionForGroupWithQualifierLevelAccess);
474 }
475
476 public static class MyAccessController extends AccessController {
477 }
478
479 @Test (timeout=180000)
480 public void testCoprocessorLoading() throws Exception {
481 MasterCoprocessorHost cpHost =
482 TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterCoprocessorHost();
483 cpHost.load(MyAccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
484 AccessController ACCESS_CONTROLLER = (AccessController) cpHost.findCoprocessor(
485 MyAccessController.class.getName());
486 MasterCoprocessorEnvironment CP_ENV = cpHost.createEnvironment(
487 MyAccessController.class, ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf);
488 RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0)
489 .getRegionServerCoprocessorHost();
490 RegionServerCoprocessorEnvironment RSCP_ENV = rsHost.createEnvironment(
491 MyAccessController.class, ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf);
492 }
493
494 @Test (timeout=180000)
495 public void testACLZNodeDeletion() throws Exception {
496 String baseAclZNode = "/hbase/acl/";
497 String ns = "testACLZNodeDeletionNamespace";
498 NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build();
499 createNamespace(TEST_UTIL, desc);
500
501 final TableName table = TableName.valueOf(ns, "testACLZNodeDeletionTable");
502 final byte[] family = Bytes.toBytes("f1");
503 HTableDescriptor htd = new HTableDescriptor(table);
504 htd.addFamily(new HColumnDescriptor(family));
505 createTable(TEST_UTIL, htd);
506 TEST_UTIL.waitUntilAllRegionsAssigned(htd.getTableName());
507
508
509 grantOnNamespace(TEST_UTIL, TESTGROUP1_USER1.getShortName(), ns, Action.ADMIN);
510 ZooKeeperWatcher zkw = TEST_UTIL.getMiniHBaseCluster().getMaster().getZooKeeper();
511 assertTrue("The acl znode for table should exist", ZKUtil.checkExists(zkw, baseAclZNode +
512 table.getNameAsString()) != -1);
513 assertTrue("The acl znode for namespace should exist", ZKUtil.checkExists(zkw, baseAclZNode +
514 convertToNamespace(ns)) != -1);
515
516 revokeFromNamespace(TEST_UTIL, TESTGROUP1_USER1.getShortName(), ns, Action.ADMIN);
517 deleteTable(TEST_UTIL, table);
518 deleteNamespace(TEST_UTIL, ns);
519
520 assertTrue("The acl znode for table should have been deleted",
521 ZKUtil.checkExists(zkw, baseAclZNode + table.getNameAsString()) == -1);
522 assertTrue( "The acl znode for namespace should have been deleted",
523 ZKUtil.checkExists(zkw, baseAclZNode + convertToNamespace(ns)) == -1);
524 }
525 }