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