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