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