1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.security.access;
20
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.assertNull;
25 import static org.junit.Assert.assertTrue;
26
27 import java.io.ByteArrayOutputStream;
28 import java.io.DataOutput;
29 import java.io.DataOutputStream;
30 import java.io.IOException;
31 import java.util.Arrays;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.concurrent.atomic.AtomicBoolean;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.hadoop.conf.Configuration;
40 import org.apache.hadoop.hbase.Abortable;
41 import org.apache.hadoop.hbase.TableName;
42 import org.apache.hadoop.hbase.client.Admin;
43 import org.apache.hadoop.hbase.client.Connection;
44 import org.apache.hadoop.hbase.client.ConnectionFactory;
45 import org.apache.hadoop.hbase.client.Table;
46 import org.apache.hadoop.hbase.exceptions.DeserializationException;
47 import org.apache.hadoop.hbase.HBaseTestingUtility;
48 import org.apache.hadoop.hbase.security.access.Permission.Action;
49 import org.apache.hadoop.hbase.testclassification.LargeTests;
50 import org.apache.hadoop.hbase.client.HTable;
51 import org.apache.hadoop.hbase.client.Put;
52 import org.apache.hadoop.hbase.security.User;
53 import org.apache.hadoop.hbase.util.Bytes;
54 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
55 import org.apache.hadoop.io.Text;
56 import org.junit.After;
57 import org.junit.AfterClass;
58 import org.junit.BeforeClass;
59 import org.junit.Test;
60 import org.junit.experimental.categories.Category;
61
62 import com.google.common.collect.ArrayListMultimap;
63 import com.google.common.collect.ListMultimap;
64
65
66
67
68 @Category(LargeTests.class)
69 public class TestTablePermissions {
70 private static final Log LOG = LogFactory.getLog(TestTablePermissions.class);
71 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
72 private static ZooKeeperWatcher ZKW;
73 private final static Abortable ABORTABLE = new Abortable() {
74 private final AtomicBoolean abort = new AtomicBoolean(false);
75
76 @Override
77 public void abort(String why, Throwable e) {
78 LOG.info(why, e);
79 abort.set(true);
80 }
81
82 @Override
83 public boolean isAborted() {
84 return abort.get();
85 }
86 };
87
88 private static String TEST_NAMESPACE = "perms_test_ns";
89 private static String TEST_NAMESPACE2 = "perms_test_ns2";
90 private static TableName TEST_TABLE =
91 TableName.valueOf("perms_test");
92 private static TableName TEST_TABLE2 =
93 TableName.valueOf("perms_test2");
94 private static byte[] TEST_FAMILY = Bytes.toBytes("f1");
95 private static byte[] TEST_QUALIFIER = Bytes.toBytes("col1");
96
97 @BeforeClass
98 public static void beforeClass() throws Exception {
99
100 Configuration conf = UTIL.getConfiguration();
101 SecureTestUtil.enableSecurity(conf);
102
103 UTIL.startMiniCluster();
104
105
106 UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME);
107
108 ZKW = new ZooKeeperWatcher(UTIL.getConfiguration(),
109 "TestTablePermissions", ABORTABLE);
110
111 UTIL.createTable(TEST_TABLE, TEST_FAMILY);
112 UTIL.waitUntilAllRegionsAssigned(TEST_TABLE);
113 UTIL.createTable(TEST_TABLE2, TEST_FAMILY);
114 UTIL.waitUntilAllRegionsAssigned(TEST_TABLE2);
115 }
116
117 @AfterClass
118 public static void afterClass() throws Exception {
119 UTIL.shutdownMiniCluster();
120 }
121
122 @After
123 public void tearDown() throws Exception {
124 Configuration conf = UTIL.getConfiguration();
125 try (Connection connection = ConnectionFactory.createConnection(conf);
126 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
127 AccessControlLists.removeTablePermissions(conf, TEST_TABLE, table);
128 AccessControlLists.removeTablePermissions(conf, TEST_TABLE2, table);
129 AccessControlLists.removeTablePermissions(conf, AccessControlLists.ACL_TABLE_NAME, table);
130 }
131 }
132
133
134
135
136
137 @Test
138 public void testMigration() throws DeserializationException {
139 Configuration conf = UTIL.getConfiguration();
140 ListMultimap<String,TablePermission> permissions = createPermissions();
141 byte [] bytes = writePermissionsAsBytes(permissions, conf);
142 AccessControlLists.readPermissions(bytes, conf);
143 }
144
145
146
147
148
149
150 public static byte[] writePermissionsAsBytes(ListMultimap<String,? extends Permission> perms,
151 Configuration conf) {
152 try {
153 ByteArrayOutputStream bos = new ByteArrayOutputStream();
154 writePermissions(new DataOutputStream(bos), perms, conf);
155 return bos.toByteArray();
156 } catch (IOException ioe) {
157
158 throw new RuntimeException("Error serializing permissions", ioe);
159 }
160 }
161
162
163
164
165
166
167
168
169
170 public static void writePermissions(DataOutput out,
171 ListMultimap<String,? extends Permission> perms, Configuration conf)
172 throws IOException {
173 Set<String> keys = perms.keySet();
174 out.writeInt(keys.size());
175 for (String key : keys) {
176 Text.writeString(out, key);
177 HbaseObjectWritableFor96Migration.writeObject(out, perms.get(key), List.class, conf);
178 }
179 }
180
181
182 @Test
183 public void testBasicWrite() throws Exception {
184 Configuration conf = UTIL.getConfiguration();
185 try (Connection connection = ConnectionFactory.createConnection(conf);
186 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
187
188 AccessControlLists.addUserPermission(conf,
189 new UserPermission(Bytes.toBytes("george"), TEST_TABLE, null, (byte[])null,
190 UserPermission.Action.READ, UserPermission.Action.WRITE), table);
191 AccessControlLists.addUserPermission(conf,
192 new UserPermission(Bytes.toBytes("hubert"), TEST_TABLE, null, (byte[])null,
193 UserPermission.Action.READ), table);
194 AccessControlLists.addUserPermission(conf,
195 new UserPermission(Bytes.toBytes("humphrey"),
196 TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER,
197 UserPermission.Action.READ), table);
198 }
199
200 ListMultimap<String,TablePermission> perms =
201 AccessControlLists.getTablePermissions(conf, TEST_TABLE);
202 List<TablePermission> userPerms = perms.get("george");
203 assertNotNull("Should have permissions for george", userPerms);
204 assertEquals("Should have 1 permission for george", 1, userPerms.size());
205 TablePermission permission = userPerms.get(0);
206 assertEquals("Permission should be for " + TEST_TABLE,
207 TEST_TABLE, permission.getTableName());
208 assertNull("Column family should be empty", permission.getFamily());
209
210
211 assertNotNull(permission.getActions());
212 assertEquals(2, permission.getActions().length);
213 List<TablePermission.Action> actions = Arrays.asList(permission.getActions());
214 assertTrue(actions.contains(TablePermission.Action.READ));
215 assertTrue(actions.contains(TablePermission.Action.WRITE));
216
217 userPerms = perms.get("hubert");
218 assertNotNull("Should have permissions for hubert", userPerms);
219 assertEquals("Should have 1 permission for hubert", 1, userPerms.size());
220 permission = userPerms.get(0);
221 assertEquals("Permission should be for " + TEST_TABLE,
222 TEST_TABLE, permission.getTableName());
223 assertNull("Column family should be empty", permission.getFamily());
224
225
226 assertNotNull(permission.getActions());
227 assertEquals(1, permission.getActions().length);
228 actions = Arrays.asList(permission.getActions());
229 assertTrue(actions.contains(TablePermission.Action.READ));
230 assertFalse(actions.contains(TablePermission.Action.WRITE));
231
232 userPerms = perms.get("humphrey");
233 assertNotNull("Should have permissions for humphrey", userPerms);
234 assertEquals("Should have 1 permission for humphrey", 1, userPerms.size());
235 permission = userPerms.get(0);
236 assertEquals("Permission should be for " + TEST_TABLE,
237 TEST_TABLE, permission.getTableName());
238 assertTrue("Permission should be for family " + Bytes.toString(TEST_FAMILY),
239 Bytes.equals(TEST_FAMILY, permission.getFamily()));
240 assertTrue("Permission should be for qualifier " + Bytes.toString(TEST_QUALIFIER),
241 Bytes.equals(TEST_QUALIFIER, permission.getQualifier()));
242
243
244 assertNotNull(permission.getActions());
245 assertEquals(1, permission.getActions().length);
246 actions = Arrays.asList(permission.getActions());
247 assertTrue(actions.contains(TablePermission.Action.READ));
248 assertFalse(actions.contains(TablePermission.Action.WRITE));
249
250
251 try (Connection connection = ConnectionFactory.createConnection(conf);
252 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
253 AccessControlLists.addUserPermission(conf,
254 new UserPermission(Bytes.toBytes("hubert"), TEST_TABLE2, null, (byte[])null,
255 TablePermission.Action.READ, TablePermission.Action.WRITE), table);
256 }
257
258 Map<byte[], ListMultimap<String,TablePermission>> allPerms =
259 AccessControlLists.loadAll(conf);
260 assertEquals("Full permission map should have entries for both test tables",
261 2, allPerms.size());
262
263 userPerms = allPerms.get(TEST_TABLE.getName()).get("hubert");
264 assertNotNull(userPerms);
265 assertEquals(1, userPerms.size());
266 permission = userPerms.get(0);
267 assertEquals(TEST_TABLE, permission.getTableName());
268 assertEquals(1, permission.getActions().length);
269 assertEquals(TablePermission.Action.READ, permission.getActions()[0]);
270
271 userPerms = allPerms.get(TEST_TABLE2.getName()).get("hubert");
272 assertNotNull(userPerms);
273 assertEquals(1, userPerms.size());
274 permission = userPerms.get(0);
275 assertEquals(TEST_TABLE2, permission.getTableName());
276 assertEquals(2, permission.getActions().length);
277 actions = Arrays.asList(permission.getActions());
278 assertTrue(actions.contains(TablePermission.Action.READ));
279 assertTrue(actions.contains(TablePermission.Action.WRITE));
280 }
281
282 @Test
283 public void testPersistence() throws Exception {
284 Configuration conf = UTIL.getConfiguration();
285 try (Connection connection = ConnectionFactory.createConnection(conf);
286 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
287 AccessControlLists.addUserPermission(conf,
288 new UserPermission(Bytes.toBytes("albert"), TEST_TABLE, null,
289 (byte[])null, TablePermission.Action.READ), table);
290 AccessControlLists.addUserPermission(conf,
291 new UserPermission(Bytes.toBytes("betty"), TEST_TABLE, null,
292 (byte[])null, TablePermission.Action.READ,
293 TablePermission.Action.WRITE), table);
294 AccessControlLists.addUserPermission(conf,
295 new UserPermission(Bytes.toBytes("clark"),
296 TEST_TABLE, TEST_FAMILY,
297 TablePermission.Action.READ), table);
298 AccessControlLists.addUserPermission(conf,
299 new UserPermission(Bytes.toBytes("dwight"),
300 TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER,
301 TablePermission.Action.WRITE), table);
302 }
303
304 ListMultimap<String,TablePermission> preperms =
305 AccessControlLists.getTablePermissions(conf, TEST_TABLE);
306
307 Table table = new HTable(conf, TEST_TABLE);
308 table.put(new Put(Bytes.toBytes("row1"))
309 .add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes("v1")));
310 table.put(new Put(Bytes.toBytes("row2"))
311 .add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes("v2")));
312 Admin admin = UTIL.getHBaseAdmin();
313 admin.split(TEST_TABLE);
314
315
316 Thread.sleep(10000);
317
318 ListMultimap<String,TablePermission> postperms =
319 AccessControlLists.getTablePermissions(conf, TEST_TABLE);
320
321 checkMultimapEqual(preperms, postperms);
322 }
323
324 @Test
325 public void testSerialization() throws Exception {
326 Configuration conf = UTIL.getConfiguration();
327 ListMultimap<String,TablePermission> permissions = createPermissions();
328 byte[] permsData = AccessControlLists.writePermissionsAsBytes(permissions, conf);
329
330 ListMultimap<String, TablePermission> copy =
331 AccessControlLists.readPermissions(permsData, conf);
332
333 checkMultimapEqual(permissions, copy);
334 }
335
336 private ListMultimap<String,TablePermission> createPermissions() {
337 ListMultimap<String,TablePermission> permissions = ArrayListMultimap.create();
338 permissions.put("george", new TablePermission(TEST_TABLE, null,
339 TablePermission.Action.READ));
340 permissions.put("george", new TablePermission(TEST_TABLE, TEST_FAMILY,
341 TablePermission.Action.WRITE));
342 permissions.put("george", new TablePermission(TEST_TABLE2, null,
343 TablePermission.Action.READ));
344 permissions.put("hubert", new TablePermission(TEST_TABLE2, null,
345 TablePermission.Action.READ, TablePermission.Action.WRITE));
346 permissions.put("bruce",new TablePermission(TEST_NAMESPACE,
347 TablePermission.Action.READ));
348 return permissions;
349 }
350
351 public void checkMultimapEqual(ListMultimap<String,TablePermission> first,
352 ListMultimap<String,TablePermission> second) {
353 assertEquals(first.size(), second.size());
354 for (String key : first.keySet()) {
355 List<TablePermission> firstPerms = first.get(key);
356 List<TablePermission> secondPerms = second.get(key);
357 assertNotNull(secondPerms);
358 assertEquals(firstPerms.size(), secondPerms.size());
359 LOG.info("First permissions: "+firstPerms.toString());
360 LOG.info("Second permissions: "+secondPerms.toString());
361 for (TablePermission p : firstPerms) {
362 assertTrue("Permission "+p.toString()+" not found", secondPerms.contains(p));
363 }
364 }
365 }
366
367 @Test
368 public void testEquals() throws Exception {
369 TablePermission p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
370 TablePermission p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
371 assertTrue(p1.equals(p2));
372 assertTrue(p2.equals(p1));
373
374 p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ, TablePermission.Action.WRITE);
375 p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.WRITE, TablePermission.Action.READ);
376 assertTrue(p1.equals(p2));
377 assertTrue(p2.equals(p1));
378
379 p1 = new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.READ, TablePermission.Action.WRITE);
380 p2 = new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.WRITE, TablePermission.Action.READ);
381 assertTrue(p1.equals(p2));
382 assertTrue(p2.equals(p1));
383
384 p1 = new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER, TablePermission.Action.READ, TablePermission.Action.WRITE);
385 p2 = new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER, TablePermission.Action.WRITE, TablePermission.Action.READ);
386 assertTrue(p1.equals(p2));
387 assertTrue(p2.equals(p1));
388
389 p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
390 p2 = new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.READ);
391 assertFalse(p1.equals(p2));
392 assertFalse(p2.equals(p1));
393
394 p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
395 p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.WRITE);
396 assertFalse(p1.equals(p2));
397 assertFalse(p2.equals(p1));
398 p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ, TablePermission.Action.WRITE);
399 assertFalse(p1.equals(p2));
400 assertFalse(p2.equals(p1));
401
402 p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
403 p2 = new TablePermission(TEST_TABLE2, null, TablePermission.Action.READ);
404 assertFalse(p1.equals(p2));
405 assertFalse(p2.equals(p1));
406
407 p2 = new TablePermission(TEST_TABLE, null);
408 assertFalse(p1.equals(p2));
409 assertFalse(p2.equals(p1));
410
411 p1 = new TablePermission(TEST_NAMESPACE, TablePermission.Action.READ);
412 p2 = new TablePermission(TEST_NAMESPACE, TablePermission.Action.READ);
413 assertEquals(p1, p2);
414
415 p1 = new TablePermission(TEST_NAMESPACE, TablePermission.Action.READ);
416 p2 = new TablePermission(TEST_NAMESPACE2, TablePermission.Action.READ);
417 assertFalse(p1.equals(p2));
418 assertFalse(p2.equals(p1));
419 }
420
421 @Test
422 public void testGlobalPermission() throws Exception {
423 Configuration conf = UTIL.getConfiguration();
424
425
426 try (Connection connection = ConnectionFactory.createConnection(conf);
427 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
428 AccessControlLists.addUserPermission(conf,
429 new UserPermission(Bytes.toBytes("user1"),
430 Permission.Action.READ, Permission.Action.WRITE), table);
431 AccessControlLists.addUserPermission(conf,
432 new UserPermission(Bytes.toBytes("user2"),
433 Permission.Action.CREATE), table);
434 AccessControlLists.addUserPermission(conf,
435 new UserPermission(Bytes.toBytes("user3"),
436 Permission.Action.ADMIN, Permission.Action.READ, Permission.Action.CREATE), table);
437 }
438 ListMultimap<String,TablePermission> perms = AccessControlLists.getTablePermissions(conf, null);
439 List<TablePermission> user1Perms = perms.get("user1");
440 assertEquals("Should have 1 permission for user1", 1, user1Perms.size());
441 assertEquals("user1 should have WRITE permission",
442 new Permission.Action[] { Permission.Action.READ, Permission.Action.WRITE },
443 user1Perms.get(0).getActions());
444
445 List<TablePermission> user2Perms = perms.get("user2");
446 assertEquals("Should have 1 permission for user2", 1, user2Perms.size());
447 assertEquals("user2 should have CREATE permission",
448 new Permission.Action[] { Permission.Action.CREATE },
449 user2Perms.get(0).getActions());
450
451 List<TablePermission> user3Perms = perms.get("user3");
452 assertEquals("Should have 1 permission for user3", 1, user3Perms.size());
453 assertEquals("user3 should have ADMIN, READ, CREATE permission",
454 new Permission.Action[] {
455 Permission.Action.READ, Permission.Action.CREATE, Permission.Action.ADMIN,
456 },
457 user3Perms.get(0).getActions());
458 }
459
460 @Test
461 public void testAuthManager() throws Exception {
462 Configuration conf = UTIL.getConfiguration();
463
464
465
466 TableAuthManager authManager = TableAuthManager.getOrCreate(ZKW, conf);
467
468 User currentUser = User.getCurrent();
469 assertTrue(authManager.authorize(currentUser, Permission.Action.ADMIN));
470 try (Connection connection = ConnectionFactory.createConnection(conf);
471 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
472 for (int i=1; i<=50; i++) {
473 AccessControlLists.addUserPermission(conf, new UserPermission(Bytes.toBytes("testauth"+i),
474 Permission.Action.ADMIN, Permission.Action.READ, Permission.Action.WRITE), table);
475
476 assertTrue("Failed current user auth check on iter "+i,
477 authManager.authorize(currentUser, Permission.Action.ADMIN));
478 }
479 }
480 }
481 }