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