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