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.createTable(TEST_TABLE2, TEST_FAMILY);
113 }
114
115 @AfterClass
116 public static void afterClass() throws Exception {
117 UTIL.shutdownMiniCluster();
118 }
119
120 @After
121 public void tearDown() throws Exception {
122 Configuration conf = UTIL.getConfiguration();
123 try (Connection connection = ConnectionFactory.createConnection(conf);
124 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
125 AccessControlLists.removeTablePermissions(conf, TEST_TABLE, table);
126 AccessControlLists.removeTablePermissions(conf, TEST_TABLE2, table);
127 AccessControlLists.removeTablePermissions(conf, AccessControlLists.ACL_TABLE_NAME, table);
128 }
129 }
130
131
132
133
134
135 @Test
136 public void testMigration() throws DeserializationException {
137 Configuration conf = UTIL.getConfiguration();
138 ListMultimap<String,TablePermission> permissions = createPermissions();
139 byte [] bytes = writePermissionsAsBytes(permissions, conf);
140 AccessControlLists.readPermissions(bytes, conf);
141 }
142
143
144
145
146
147
148 public static byte[] writePermissionsAsBytes(ListMultimap<String,? extends Permission> perms,
149 Configuration conf) {
150 try {
151 ByteArrayOutputStream bos = new ByteArrayOutputStream();
152 writePermissions(new DataOutputStream(bos), perms, conf);
153 return bos.toByteArray();
154 } catch (IOException ioe) {
155
156 throw new RuntimeException("Error serializing permissions", ioe);
157 }
158 }
159
160
161
162
163
164
165
166
167
168 public static void writePermissions(DataOutput out,
169 ListMultimap<String,? extends Permission> perms, Configuration conf)
170 throws IOException {
171 Set<String> keys = perms.keySet();
172 out.writeInt(keys.size());
173 for (String key : keys) {
174 Text.writeString(out, key);
175 HbaseObjectWritableFor96Migration.writeObject(out, perms.get(key), List.class, conf);
176 }
177 }
178
179
180 @Test
181 public void testBasicWrite() throws Exception {
182 Configuration conf = UTIL.getConfiguration();
183 try (Connection connection = ConnectionFactory.createConnection(conf);
184 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
185
186 AccessControlLists.addUserPermission(conf,
187 new UserPermission(Bytes.toBytes("george"), TEST_TABLE, null, (byte[])null,
188 UserPermission.Action.READ, UserPermission.Action.WRITE), table);
189 AccessControlLists.addUserPermission(conf,
190 new UserPermission(Bytes.toBytes("hubert"), TEST_TABLE, null, (byte[])null,
191 UserPermission.Action.READ), table);
192 AccessControlLists.addUserPermission(conf,
193 new UserPermission(Bytes.toBytes("humphrey"),
194 TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER,
195 UserPermission.Action.READ), table);
196 }
197
198 ListMultimap<String,TablePermission> perms =
199 AccessControlLists.getTablePermissions(conf, TEST_TABLE);
200 List<TablePermission> userPerms = perms.get("george");
201 assertNotNull("Should have permissions for george", userPerms);
202 assertEquals("Should have 1 permission for george", 1, userPerms.size());
203 TablePermission permission = userPerms.get(0);
204 assertEquals("Permission should be for " + TEST_TABLE,
205 TEST_TABLE, permission.getTableName());
206 assertNull("Column family should be empty", permission.getFamily());
207
208
209 assertNotNull(permission.getActions());
210 assertEquals(2, permission.getActions().length);
211 List<TablePermission.Action> actions = Arrays.asList(permission.getActions());
212 assertTrue(actions.contains(TablePermission.Action.READ));
213 assertTrue(actions.contains(TablePermission.Action.WRITE));
214
215 userPerms = perms.get("hubert");
216 assertNotNull("Should have permissions for hubert", userPerms);
217 assertEquals("Should have 1 permission for hubert", 1, userPerms.size());
218 permission = userPerms.get(0);
219 assertEquals("Permission should be for " + TEST_TABLE,
220 TEST_TABLE, permission.getTableName());
221 assertNull("Column family should be empty", permission.getFamily());
222
223
224 assertNotNull(permission.getActions());
225 assertEquals(1, permission.getActions().length);
226 actions = Arrays.asList(permission.getActions());
227 assertTrue(actions.contains(TablePermission.Action.READ));
228 assertFalse(actions.contains(TablePermission.Action.WRITE));
229
230 userPerms = perms.get("humphrey");
231 assertNotNull("Should have permissions for humphrey", userPerms);
232 assertEquals("Should have 1 permission for humphrey", 1, userPerms.size());
233 permission = userPerms.get(0);
234 assertEquals("Permission should be for " + TEST_TABLE,
235 TEST_TABLE, permission.getTableName());
236 assertTrue("Permission should be for family " + Bytes.toString(TEST_FAMILY),
237 Bytes.equals(TEST_FAMILY, permission.getFamily()));
238 assertTrue("Permission should be for qualifier " + Bytes.toString(TEST_QUALIFIER),
239 Bytes.equals(TEST_QUALIFIER, permission.getQualifier()));
240
241
242 assertNotNull(permission.getActions());
243 assertEquals(1, permission.getActions().length);
244 actions = Arrays.asList(permission.getActions());
245 assertTrue(actions.contains(TablePermission.Action.READ));
246 assertFalse(actions.contains(TablePermission.Action.WRITE));
247
248
249 try (Connection connection = ConnectionFactory.createConnection(conf);
250 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
251 AccessControlLists.addUserPermission(conf,
252 new UserPermission(Bytes.toBytes("hubert"), TEST_TABLE2, null, (byte[])null,
253 TablePermission.Action.READ, TablePermission.Action.WRITE), table);
254 }
255
256 Map<byte[], ListMultimap<String,TablePermission>> allPerms =
257 AccessControlLists.loadAll(conf);
258 assertEquals("Full permission map should have entries for both test tables",
259 2, allPerms.size());
260
261 userPerms = allPerms.get(TEST_TABLE.getName()).get("hubert");
262 assertNotNull(userPerms);
263 assertEquals(1, userPerms.size());
264 permission = userPerms.get(0);
265 assertEquals(TEST_TABLE, permission.getTableName());
266 assertEquals(1, permission.getActions().length);
267 assertEquals(TablePermission.Action.READ, permission.getActions()[0]);
268
269 userPerms = allPerms.get(TEST_TABLE2.getName()).get("hubert");
270 assertNotNull(userPerms);
271 assertEquals(1, userPerms.size());
272 permission = userPerms.get(0);
273 assertEquals(TEST_TABLE2, permission.getTableName());
274 assertEquals(2, permission.getActions().length);
275 actions = Arrays.asList(permission.getActions());
276 assertTrue(actions.contains(TablePermission.Action.READ));
277 assertTrue(actions.contains(TablePermission.Action.WRITE));
278 }
279
280 @Test
281 public void testPersistence() throws Exception {
282 Configuration conf = UTIL.getConfiguration();
283 try (Connection connection = ConnectionFactory.createConnection(conf);
284 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
285 AccessControlLists.addUserPermission(conf,
286 new UserPermission(Bytes.toBytes("albert"), TEST_TABLE, null,
287 (byte[])null, TablePermission.Action.READ), table);
288 AccessControlLists.addUserPermission(conf,
289 new UserPermission(Bytes.toBytes("betty"), TEST_TABLE, null,
290 (byte[])null, TablePermission.Action.READ,
291 TablePermission.Action.WRITE), table);
292 AccessControlLists.addUserPermission(conf,
293 new UserPermission(Bytes.toBytes("clark"),
294 TEST_TABLE, TEST_FAMILY,
295 TablePermission.Action.READ), table);
296 AccessControlLists.addUserPermission(conf,
297 new UserPermission(Bytes.toBytes("dwight"),
298 TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER,
299 TablePermission.Action.WRITE), table);
300 }
301
302 ListMultimap<String,TablePermission> preperms =
303 AccessControlLists.getTablePermissions(conf, TEST_TABLE);
304
305 Table table = new HTable(conf, TEST_TABLE);
306 table.put(new Put(Bytes.toBytes("row1"))
307 .add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes("v1")));
308 table.put(new Put(Bytes.toBytes("row2"))
309 .add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes("v2")));
310 Admin admin = UTIL.getHBaseAdmin();
311 admin.split(TEST_TABLE);
312
313
314 Thread.sleep(10000);
315
316 ListMultimap<String,TablePermission> postperms =
317 AccessControlLists.getTablePermissions(conf, TEST_TABLE);
318
319 checkMultimapEqual(preperms, postperms);
320 }
321
322 @Test
323 public void testSerialization() throws Exception {
324 Configuration conf = UTIL.getConfiguration();
325 ListMultimap<String,TablePermission> permissions = createPermissions();
326 byte[] permsData = AccessControlLists.writePermissionsAsBytes(permissions, conf);
327
328 ListMultimap<String, TablePermission> copy =
329 AccessControlLists.readPermissions(permsData, conf);
330
331 checkMultimapEqual(permissions, copy);
332 }
333
334 private ListMultimap<String,TablePermission> createPermissions() {
335 ListMultimap<String,TablePermission> permissions = ArrayListMultimap.create();
336 permissions.put("george", new TablePermission(TEST_TABLE, null,
337 TablePermission.Action.READ));
338 permissions.put("george", new TablePermission(TEST_TABLE, TEST_FAMILY,
339 TablePermission.Action.WRITE));
340 permissions.put("george", new TablePermission(TEST_TABLE2, null,
341 TablePermission.Action.READ));
342 permissions.put("hubert", new TablePermission(TEST_TABLE2, null,
343 TablePermission.Action.READ, TablePermission.Action.WRITE));
344 permissions.put("bruce",new TablePermission(TEST_NAMESPACE,
345 TablePermission.Action.READ));
346 return permissions;
347 }
348
349 public void checkMultimapEqual(ListMultimap<String,TablePermission> first,
350 ListMultimap<String,TablePermission> second) {
351 assertEquals(first.size(), second.size());
352 for (String key : first.keySet()) {
353 List<TablePermission> firstPerms = first.get(key);
354 List<TablePermission> secondPerms = second.get(key);
355 assertNotNull(secondPerms);
356 assertEquals(firstPerms.size(), secondPerms.size());
357 LOG.info("First permissions: "+firstPerms.toString());
358 LOG.info("Second permissions: "+secondPerms.toString());
359 for (TablePermission p : firstPerms) {
360 assertTrue("Permission "+p.toString()+" not found", secondPerms.contains(p));
361 }
362 }
363 }
364
365 @Test
366 public void testEquals() throws Exception {
367 TablePermission p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
368 TablePermission p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
369 assertTrue(p1.equals(p2));
370 assertTrue(p2.equals(p1));
371
372 p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ, TablePermission.Action.WRITE);
373 p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.WRITE, TablePermission.Action.READ);
374 assertTrue(p1.equals(p2));
375 assertTrue(p2.equals(p1));
376
377 p1 = new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.READ, TablePermission.Action.WRITE);
378 p2 = new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.WRITE, TablePermission.Action.READ);
379 assertTrue(p1.equals(p2));
380 assertTrue(p2.equals(p1));
381
382 p1 = new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER, TablePermission.Action.READ, TablePermission.Action.WRITE);
383 p2 = new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER, TablePermission.Action.WRITE, TablePermission.Action.READ);
384 assertTrue(p1.equals(p2));
385 assertTrue(p2.equals(p1));
386
387 p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
388 p2 = new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.READ);
389 assertFalse(p1.equals(p2));
390 assertFalse(p2.equals(p1));
391
392 p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
393 p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.WRITE);
394 assertFalse(p1.equals(p2));
395 assertFalse(p2.equals(p1));
396 p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ, TablePermission.Action.WRITE);
397 assertFalse(p1.equals(p2));
398 assertFalse(p2.equals(p1));
399
400 p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
401 p2 = new TablePermission(TEST_TABLE2, null, TablePermission.Action.READ);
402 assertFalse(p1.equals(p2));
403 assertFalse(p2.equals(p1));
404
405 p2 = new TablePermission(TEST_TABLE, null);
406 assertFalse(p1.equals(p2));
407 assertFalse(p2.equals(p1));
408
409 p1 = new TablePermission(TEST_NAMESPACE, TablePermission.Action.READ);
410 p2 = new TablePermission(TEST_NAMESPACE, TablePermission.Action.READ);
411 assertEquals(p1, p2);
412
413 p1 = new TablePermission(TEST_NAMESPACE, TablePermission.Action.READ);
414 p2 = new TablePermission(TEST_NAMESPACE2, TablePermission.Action.READ);
415 assertFalse(p1.equals(p2));
416 assertFalse(p2.equals(p1));
417 }
418
419 @Test
420 public void testGlobalPermission() throws Exception {
421 Configuration conf = UTIL.getConfiguration();
422
423
424 try (Connection connection = ConnectionFactory.createConnection(conf);
425 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
426 AccessControlLists.addUserPermission(conf,
427 new UserPermission(Bytes.toBytes("user1"),
428 Permission.Action.READ, Permission.Action.WRITE), table);
429 AccessControlLists.addUserPermission(conf,
430 new UserPermission(Bytes.toBytes("user2"),
431 Permission.Action.CREATE), table);
432 AccessControlLists.addUserPermission(conf,
433 new UserPermission(Bytes.toBytes("user3"),
434 Permission.Action.ADMIN, Permission.Action.READ, Permission.Action.CREATE), table);
435 }
436 ListMultimap<String,TablePermission> perms = AccessControlLists.getTablePermissions(conf, null);
437 List<TablePermission> user1Perms = perms.get("user1");
438 assertEquals("Should have 1 permission for user1", 1, user1Perms.size());
439 assertEquals("user1 should have WRITE permission",
440 new Permission.Action[] { Permission.Action.READ, Permission.Action.WRITE },
441 user1Perms.get(0).getActions());
442
443 List<TablePermission> user2Perms = perms.get("user2");
444 assertEquals("Should have 1 permission for user2", 1, user2Perms.size());
445 assertEquals("user2 should have CREATE permission",
446 new Permission.Action[] { Permission.Action.CREATE },
447 user2Perms.get(0).getActions());
448
449 List<TablePermission> user3Perms = perms.get("user3");
450 assertEquals("Should have 1 permission for user3", 1, user3Perms.size());
451 assertEquals("user3 should have ADMIN, READ, CREATE permission",
452 new Permission.Action[] {
453 Permission.Action.READ, Permission.Action.CREATE, Permission.Action.ADMIN,
454 },
455 user3Perms.get(0).getActions());
456 }
457
458 @Test
459 public void testAuthManager() throws Exception {
460 Configuration conf = UTIL.getConfiguration();
461
462
463
464 TableAuthManager authManager = TableAuthManager.getOrCreate(ZKW, conf);
465
466 User currentUser = User.getCurrent();
467 assertTrue(authManager.authorize(currentUser, Permission.Action.ADMIN));
468 try (Connection connection = ConnectionFactory.createConnection(conf);
469 Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
470 for (int i=1; i<=50; i++) {
471 AccessControlLists.addUserPermission(conf, new UserPermission(Bytes.toBytes("testauth"+i),
472 Permission.Action.ADMIN, Permission.Action.READ, Permission.Action.WRITE), table);
473
474 assertTrue("Failed current user auth check on iter "+i,
475 authManager.authorize(currentUser, Permission.Action.ADMIN));
476 }
477 }
478 }
479 }