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