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