1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.security.access;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.fail;
22 import java.io.IOException;
23 import java.security.PrivilegedExceptionAction;
24 import java.util.HashMap;
25 import java.util.Map;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.hadoop.conf.Configuration;
29 import org.apache.hadoop.hbase.AuthUtil;
30 import org.apache.hadoop.hbase.Coprocessor;
31 import org.apache.hadoop.hbase.HBaseTestingUtility;
32 import org.apache.hadoop.hbase.HColumnDescriptor;
33 import org.apache.hadoop.hbase.HTableDescriptor;
34 import org.apache.hadoop.hbase.TableNameTestRule;
35 import org.apache.hadoop.hbase.TableNotFoundException;
36 import org.apache.hadoop.hbase.client.Connection;
37 import org.apache.hadoop.hbase.client.ConnectionFactory;
38 import org.apache.hadoop.hbase.client.Delete;
39 import org.apache.hadoop.hbase.client.Get;
40 import org.apache.hadoop.hbase.client.Increment;
41 import org.apache.hadoop.hbase.client.Put;
42 import org.apache.hadoop.hbase.client.Table;
43 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
44 import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
45 import org.apache.hadoop.hbase.security.User;
46 import org.apache.hadoop.hbase.security.access.Permission.Action;
47 import org.apache.hadoop.hbase.testclassification.MediumTests;
48 import org.apache.hadoop.hbase.util.Bytes;
49 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
50 import org.apache.hadoop.hbase.util.Threads;
51 import org.apache.log4j.Level;
52 import org.apache.log4j.Logger;
53 import org.junit.After;
54 import org.junit.AfterClass;
55 import org.junit.Before;
56 import org.junit.BeforeClass;
57 import org.junit.Rule;
58 import org.junit.Test;
59 import org.junit.experimental.categories.Category;
60
61 @Category(MediumTests.class)
62 public class TestCellACLWithMultipleVersions extends SecureTestUtil {
63 private static final Log LOG = LogFactory.getLog(TestCellACLWithMultipleVersions.class);
64
65 static {
66 Logger.getLogger(AccessController.class).setLevel(Level.TRACE);
67 Logger.getLogger(AccessControlFilter.class).setLevel(Level.TRACE);
68 Logger.getLogger(TableAuthManager.class).setLevel(Level.TRACE);
69 }
70
71 @Rule
72 public TableNameTestRule testTable = new TableNameTestRule();
73 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
74 private static final byte[] TEST_FAMILY1 = Bytes.toBytes("f1");
75 private static final byte[] TEST_FAMILY2 = Bytes.toBytes("f2");
76 private static final byte[] TEST_ROW = Bytes.toBytes("cellpermtest");
77 private static final byte[] TEST_Q1 = Bytes.toBytes("q1");
78 private static final byte[] TEST_Q2 = Bytes.toBytes("q2");
79 private static final byte[] ZERO = Bytes.toBytes(0L);
80 private static final byte[] ONE = Bytes.toBytes(1L);
81 private static final byte[] TWO = Bytes.toBytes(2L);
82
83 private static Configuration conf;
84
85 private static final String GROUP = "group";
86 private static User GROUP_USER;
87 private static User USER_OWNER;
88 private static User USER_OTHER;
89 private static User USER_OTHER2;
90
91 private static String[] usersAndGroups;
92
93 @BeforeClass
94 public static void setupBeforeClass() throws Exception {
95
96 conf = TEST_UTIL.getConfiguration();
97
98 enableSecurity(conf);
99
100 verifyConfiguration(conf);
101
102
103 conf.setBoolean(AccessControlConstants.CF_ATTRIBUTE_EARLY_OUT, false);
104
105 TEST_UTIL.startMiniCluster();
106 MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster()
107 .getMasterCoprocessorHost();
108 cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
109 AccessController ac = (AccessController)
110 cpHost.findCoprocessor(AccessController.class.getName());
111 cpHost.createEnvironment(AccessController.class, ac, Coprocessor.PRIORITY_HIGHEST, 1, conf);
112 RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0)
113 .getRegionServerCoprocessorHost();
114 rsHost.createEnvironment(AccessController.class, ac, Coprocessor.PRIORITY_HIGHEST, 1, conf);
115
116
117 TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME);
118
119
120 USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
121 USER_OTHER = User.createUserForTesting(conf, "other", new String[0]);
122 USER_OTHER2 = User.createUserForTesting(conf, "other2", new String[0]);
123 GROUP_USER = User.createUserForTesting(conf, "group_user", new String[] { GROUP });
124
125 usersAndGroups = new String[] { USER_OTHER.getShortName(), AuthUtil.toGroupEntry(GROUP) };
126 }
127
128 @AfterClass
129 public static void tearDownAfterClass() throws Exception {
130 TEST_UTIL.shutdownMiniCluster();
131 }
132
133 @Before
134 public void setUp() throws Exception {
135 HTableDescriptor htd = new HTableDescriptor(testTable.getTableName());
136 HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY1);
137 hcd.setMaxVersions(4);
138 htd.setOwner(USER_OWNER);
139 htd.addFamily(hcd);
140 hcd = new HColumnDescriptor(TEST_FAMILY2);
141 hcd.setMaxVersions(4);
142 htd.setOwner(USER_OWNER);
143 htd.addFamily(hcd);
144
145 TEST_UTIL.createTable(htd, new byte[][] { Bytes.toBytes("s") });
146 TEST_UTIL.waitUntilAllRegionsAssigned(testTable.getTableName());
147 LOG.info("Sleeping a second because of HBASE-12581");
148 Threads.sleep(1000);
149 }
150
151 @Test
152 public void testCellPermissionwithVersions() throws Exception {
153
154
155 final Map<String, Permission> writePerms = prepareCellPermissions(usersAndGroups, Action.WRITE);
156 final Map<String, Permission> readPerms = prepareCellPermissions(usersAndGroups, Action.READ);
157 verifyAllowed(new AccessTestAction() {
158 @Override
159 public Object run() throws Exception {
160 try(Connection conn = ConnectionFactory.createConnection(conf);
161 Table t = conn.getTable(testTable.getTableName())) {
162 Put p;
163
164 p = new Put(TEST_ROW).add(TEST_FAMILY1, TEST_Q1, ZERO);
165 p.setACL(writePerms);
166 t.put(p);
167
168 p = new Put(TEST_ROW).add(TEST_FAMILY1, TEST_Q1, ZERO);
169 p.setACL(readPerms);
170 t.put(p);
171 p = new Put(TEST_ROW).add(TEST_FAMILY1, TEST_Q1, ZERO);
172 p.setACL(writePerms);
173 t.put(p);
174 p = new Put(TEST_ROW).add(TEST_FAMILY1, TEST_Q1, ZERO);
175 p.setACL(readPerms);
176 t.put(p);
177 p = new Put(TEST_ROW).add(TEST_FAMILY1, TEST_Q1, ZERO);
178 p.setACL(writePerms);
179 t.put(p);
180 }
181 return null;
182 }
183 }, USER_OWNER);
184
185
186
187 AccessTestAction getQ1 = new AccessTestAction() {
188 @Override
189 public Object run() throws Exception {
190 Get get = new Get(TEST_ROW);
191 get.setMaxVersions(10);
192 try(Connection conn = ConnectionFactory.createConnection(conf);
193 Table t = conn.getTable(testTable.getTableName())) {
194 return t.get(get).listCells();
195 }
196 }
197 };
198
199 AccessTestAction get2 = new AccessTestAction() {
200 @Override
201 public Object run() throws Exception {
202 Get get = new Get(TEST_ROW);
203 get.setMaxVersions(10);
204 try(Connection conn = ConnectionFactory.createConnection(conf);
205 Table t = conn.getTable(testTable.getTableName())) {
206 return t.get(get).listCells();
207 }
208 }
209 };
210
211
212 verifyAllowed(GROUP_USER, getQ1, 2);
213 verifyAllowed(USER_OTHER, getQ1, 2);
214
215
216
217 verifyAllowed(new AccessTestAction() {
218 @Override
219 public Object run() throws Exception {
220 try(Connection conn = ConnectionFactory.createConnection(conf);
221 Table t = conn.getTable(testTable.getTableName())) {
222 Put p;
223 p = new Put(TEST_ROW).add(TEST_FAMILY1, TEST_Q1, ZERO);
224 p.setACL(writePerms);
225 t.put(p);
226 p = new Put(TEST_ROW).add(TEST_FAMILY1, TEST_Q1, ZERO);
227 p.setACL(readPerms);
228 t.put(p);
229 p = new Put(TEST_ROW).add(TEST_FAMILY1, TEST_Q1, ZERO);
230 p.setACL(writePerms);
231 t.put(p);
232 }
233 return null;
234 }
235 }, USER_OWNER);
236
237
238 verifyAllowed(USER_OTHER, get2, 1);
239 verifyAllowed(GROUP_USER, get2, 1);
240 }
241
242 private Map<String, Permission> prepareCellPermissions(String[] users, Action... action) {
243 Map<String, Permission> perms = new HashMap<String, Permission>(2);
244 for (String user : users) {
245 perms.put(user, new Permission(action));
246 }
247 return perms;
248 }
249
250 @Test
251 public void testCellPermissionsWithDeleteMutipleVersions() throws Exception {
252
253 final byte[] TEST_ROW1 = Bytes.toBytes("r1");
254 final byte[] TEST_ROW2 = Bytes.toBytes("r2");
255 final byte[] TEST_Q1 = Bytes.toBytes("q1");
256 final byte[] TEST_Q2 = Bytes.toBytes("q2");
257 final byte[] ZERO = Bytes.toBytes(0L);
258
259
260 final User user1 = User.createUserForTesting(conf, "user1", new String[0]);
261 final User user2 = User.createUserForTesting(conf, "user2", new String[0]);
262
263 verifyAllowed(new AccessTestAction() {
264 @Override
265 public Object run() throws Exception {
266 try (Connection connection = ConnectionFactory.createConnection(conf)) {
267 try (Table t = connection.getTable(testTable.getTableName())) {
268
269 Put p = new Put(TEST_ROW1);
270 p.add(TEST_FAMILY1, TEST_Q1, ZERO);
271 p.add(TEST_FAMILY1, TEST_Q2, ZERO);
272 p.setACL(user1.getShortName(), new Permission(Permission.Action.READ,
273 Permission.Action.WRITE));
274 t.put(p);
275
276 p = new Put(TEST_ROW2);
277 p.add(TEST_FAMILY1, TEST_Q1, ZERO);
278 p.add(TEST_FAMILY1, TEST_Q2, ZERO);
279 p.setACL(user1.getShortName(), new Permission(Permission.Action.READ,
280 Permission.Action.WRITE));
281 t.put(p);
282 }
283 }
284 return null;
285 }
286 }, USER_OWNER);
287
288 verifyAllowed(new AccessTestAction() {
289 @Override
290 public Object run() throws Exception {
291 try (Connection connection = ConnectionFactory.createConnection(conf)) {
292 try (Table t = connection.getTable(testTable.getTableName())) {
293
294 Put p = new Put(TEST_ROW1);
295 p.add(TEST_FAMILY1, TEST_Q1, ZERO);
296 p.add(TEST_FAMILY1, TEST_Q2, ZERO);
297 Map<String, Permission> perms =
298 prepareCellPermissions(new String[] { user1.getShortName(), user2.getShortName(),
299 AuthUtil.toGroupEntry(GROUP) }, Action.READ, Action.WRITE);
300 p.setACL(perms);
301 t.put(p);
302
303 p = new Put(TEST_ROW2);
304 p.add(TEST_FAMILY1, TEST_Q1, ZERO);
305 p.add(TEST_FAMILY1, TEST_Q2, ZERO);
306 p.setACL(perms);
307 t.put(p);
308 }
309 }
310 return null;
311 }
312 }, user1);
313
314
315
316 user1.runAs(new PrivilegedExceptionAction<Void>() {
317 @Override
318 public Void run() throws Exception {
319 try (Connection connection = ConnectionFactory.createConnection(conf)) {
320 try (Table t = connection.getTable(testTable.getTableName())) {
321 Delete d = new Delete(TEST_ROW1);
322 d.deleteColumns(TEST_FAMILY1, TEST_Q1);
323 d.deleteColumns(TEST_FAMILY1, TEST_Q2);
324 t.delete(d);
325 }
326 }
327 return null;
328 }
329 });
330
331
332 verifyUserDeniedForDeleteMultipleVersions(user2, TEST_ROW2, TEST_Q1, TEST_Q2);
333
334
335
336 verifyUserDeniedForDeleteMultipleVersions(GROUP_USER, TEST_ROW2, TEST_Q1, TEST_Q2);
337
338
339 user1.runAs(new PrivilegedExceptionAction<Void>() {
340 @Override
341 public Void run() throws Exception {
342 try (Connection connection = ConnectionFactory.createConnection(conf)) {
343 try (Table t = connection.getTable(testTable.getTableName())) {
344 Delete d = new Delete(TEST_ROW2);
345 d.deleteFamily(TEST_FAMILY1);
346 t.delete(d);
347 }
348 }
349 return null;
350 }
351 });
352 }
353
354 private void verifyUserDeniedForDeleteMultipleVersions(final User user, final byte[] row,
355 final byte[] q1, final byte[] q2) throws IOException, InterruptedException {
356 user.runAs(new PrivilegedExceptionAction<Void>() {
357 @Override
358 public Void run() throws Exception {
359 try (Connection connection = ConnectionFactory.createConnection(conf)) {
360 try (Table t = connection.getTable(testTable.getTableName())) {
361 Delete d = new Delete(row);
362 d.addColumns(TEST_FAMILY1, q1);
363 d.addColumns(TEST_FAMILY1, q2);
364 t.delete(d);
365 fail(user.getShortName() + " should not be allowed to delete the row");
366 } catch (Exception e) {
367
368 }
369 }
370 return null;
371 }
372 });
373 }
374
375
376 @Test
377 public void testDeleteWithFutureTimestamp() throws Exception {
378
379
380 verifyAllowed(new AccessTestAction() {
381 @Override
382 public Object run() throws Exception {
383 try (Connection connection = ConnectionFactory.createConnection(conf)) {
384 try (Table t = connection.getTable(testTable.getTableName())) {
385
386 Put p = new Put(TEST_ROW).add(TEST_FAMILY1, TEST_Q2, ONE);
387 Map<String, Permission> readAndWritePerms =
388 prepareCellPermissions(usersAndGroups, Action.READ, Action.WRITE);
389 p.setACL(readAndWritePerms);
390 t.put(p);
391 p = new Put(TEST_ROW).add(TEST_FAMILY2, TEST_Q2, ONE);
392 p.setACL(readAndWritePerms);
393 t.put(p);
394 LOG.info("Stored at current time");
395
396 p = new Put(TEST_ROW).add(TEST_FAMILY1, TEST_Q1,
397 EnvironmentEdgeManager.currentTime() + 1000000, ZERO);
398 p.setACL(prepareCellPermissions(new String[]{ USER_OTHER.getShortName(),
399 AuthUtil.toGroupEntry(GROUP)}, Action.READ));
400 t.put(p);
401 }
402 }
403 return null;
404 }
405 }, USER_OWNER);
406
407
408
409 AccessTestAction getQ1 = new AccessTestAction() {
410 @Override
411 public Object run() throws Exception {
412 Get get = new Get(TEST_ROW).addColumn(TEST_FAMILY1, TEST_Q1);
413 try (Connection connection = ConnectionFactory.createConnection(conf)) {
414 try (Table t = connection.getTable(testTable.getTableName())) {
415 return t.get(get).listCells();
416 }
417 }
418 }
419 };
420
421 AccessTestAction getQ2 = new AccessTestAction() {
422 @Override
423 public Object run() throws Exception {
424 Get get = new Get(TEST_ROW).addColumn(TEST_FAMILY1, TEST_Q2);
425 try (Connection connection = ConnectionFactory.createConnection(conf)) {
426 try (Table t = connection.getTable(testTable.getTableName())) {
427 return t.get(get).listCells();
428 }
429 }
430 }
431 };
432
433 verifyAllowed(getQ1, USER_OWNER, USER_OTHER, GROUP_USER);
434 verifyAllowed(getQ2, USER_OWNER, USER_OTHER, GROUP_USER);
435
436
437
438
439 AccessTestAction deleteFamily1 = getDeleteFamilyAction(TEST_FAMILY1);
440 AccessTestAction deleteFamily2 = getDeleteFamilyAction(TEST_FAMILY2);
441
442 verifyAllowed(deleteFamily1, USER_OTHER);
443 verifyAllowed(deleteFamily2, GROUP_USER);
444
445
446
447 verifyAllowed(getQ1, USER_OWNER, USER_OTHER,GROUP_USER);
448
449
450
451 verifyIfNull(getQ2, USER_OTHER, GROUP_USER);
452 }
453
454 private AccessTestAction getDeleteFamilyAction(final byte[] fam) {
455 AccessTestAction deleteFamilyAction = new AccessTestAction() {
456 @Override
457 public Object run() throws Exception {
458 Delete delete = new Delete(TEST_ROW).addFamily(fam);
459 try (Connection connection = ConnectionFactory.createConnection(conf)) {
460 try (Table t = connection.getTable(testTable.getTableName())) {
461 t.delete(delete);
462 }
463 }
464 return null;
465 }
466 };
467 return deleteFamilyAction;
468 }
469
470 @Test
471 public void testCellPermissionsWithDeleteWithUserTs() throws Exception {
472 USER_OWNER.runAs(new AccessTestAction() {
473 @Override
474 public Object run() throws Exception {
475 try (Connection connection = ConnectionFactory.createConnection(conf)) {
476 try (Table t = connection.getTable(testTable.getTableName())) {
477
478 Put p = new Put(TEST_ROW);
479 p.add(TEST_FAMILY1, TEST_Q1, 123L, ZERO);
480 p.add(TEST_FAMILY1, TEST_Q2, 123L, ZERO);
481 p.setACL(prepareCellPermissions(
482 new String[] { USER_OTHER.getShortName(), AuthUtil.toGroupEntry(GROUP),
483 USER_OTHER2.getShortName() }, Permission.Action.READ, Permission.Action.WRITE));
484 t.put(p);
485
486
487 p = new Put(TEST_ROW);
488 p.add(TEST_FAMILY1, TEST_Q1, 125L, ONE);
489 p.add(TEST_FAMILY1, TEST_Q2, 125L, ONE);
490 p.setACL(prepareCellPermissions(
491 new String[] { USER_OTHER.getShortName(), AuthUtil.toGroupEntry(GROUP) },
492 Action.READ, Action.WRITE));
493 t.put(p);
494
495
496 p = new Put(TEST_ROW);
497 p.add(TEST_FAMILY1, TEST_Q1, 127L, TWO);
498 p.add(TEST_FAMILY1, TEST_Q2, 127L, TWO);
499 p.setACL(prepareCellPermissions(
500 new String[] { USER_OTHER.getShortName(), AuthUtil.toGroupEntry(GROUP) },
501 Action.READ, Action.WRITE));
502 t.put(p);
503
504 return null;
505 }
506 }
507 }
508 });
509
510
511 USER_OTHER2.runAs(new AccessTestAction() {
512 @Override
513 public Object run() throws Exception {
514 try (Connection connection = ConnectionFactory.createConnection(conf)) {
515 try (Table t = connection.getTable(testTable.getTableName())) {
516 Delete d = new Delete(TEST_ROW, 124L);
517 d.deleteColumns(TEST_FAMILY1, TEST_Q1);
518 t.delete(d);
519 }
520 }
521 return null;
522 }
523 });
524
525
526 USER_OTHER2.runAs(new AccessTestAction() {
527 @Override
528 public Object run() throws Exception {
529 try (Connection connection = ConnectionFactory.createConnection(conf)) {
530 try (Table t = connection.getTable(testTable.getTableName())) {
531 Delete d = new Delete(TEST_ROW);
532 d.deleteColumns(TEST_FAMILY1, TEST_Q2, 124L);
533 t.delete(d);
534 }
535 }
536 return null;
537 }
538 });
539 }
540
541 @Test
542 public void testCellPermissionsWithDeleteExactVersion() throws Exception {
543 final byte[] TEST_ROW1 = Bytes.toBytes("r1");
544 final byte[] TEST_Q1 = Bytes.toBytes("q1");
545 final byte[] TEST_Q2 = Bytes.toBytes("q2");
546 final byte[] ZERO = Bytes.toBytes(0L);
547
548 final User user1 = User.createUserForTesting(conf, "user1", new String[0]);
549 final User user2 = User.createUserForTesting(conf, "user2", new String[0]);
550
551 verifyAllowed(new AccessTestAction() {
552 @Override
553 public Object run() throws Exception {
554 try (Connection connection = ConnectionFactory.createConnection(conf)) {
555 try (Table t = connection.getTable(testTable.getTableName())) {
556 Map<String, Permission> permsU1andOwner =
557 prepareCellPermissions(
558 new String[] { user1.getShortName(), USER_OWNER.getShortName() }, Action.READ,
559 Action.WRITE);
560 Map<String, Permission> permsU2andGUandOwner =
561 prepareCellPermissions(
562 new String[] { user2.getShortName(), AuthUtil.toGroupEntry(GROUP),
563 USER_OWNER.getShortName() }, Action.READ, Action.WRITE);
564 Put p = new Put(TEST_ROW1);
565 p.add(TEST_FAMILY1, TEST_Q1, 123, ZERO);
566 p.setACL(permsU1andOwner);
567 t.put(p);
568 p = new Put(TEST_ROW1);
569 p.add(TEST_FAMILY1, TEST_Q2, 123, ZERO);
570 p.setACL(permsU2andGUandOwner);
571 t.put(p);
572 p = new Put(TEST_ROW1);
573 p.add(TEST_FAMILY2, TEST_Q1, 123, ZERO);
574 p.add(TEST_FAMILY2, TEST_Q2, 123, ZERO);
575 p.setACL(permsU2andGUandOwner);
576 t.put(p);
577
578 p = new Put(TEST_ROW1);
579 p.add(TEST_FAMILY2, TEST_Q1, 125, ZERO);
580 p.add(TEST_FAMILY2, TEST_Q2, 125, ZERO);
581 p.setACL(permsU1andOwner);
582 t.put(p);
583
584 p = new Put(TEST_ROW1);
585 p.add(TEST_FAMILY1, TEST_Q1, 127, ZERO);
586 p.setACL(permsU2andGUandOwner);
587 t.put(p);
588 p = new Put(TEST_ROW1);
589 p.add(TEST_FAMILY1, TEST_Q2, 127, ZERO);
590 p.setACL(permsU1andOwner);
591 t.put(p);
592 p = new Put(TEST_ROW1);
593 p.add(TEST_FAMILY2, TEST_Q1, 129, ZERO);
594 p.add(TEST_FAMILY2, TEST_Q2, 129, ZERO);
595 p.setACL(permsU1andOwner);
596 t.put(p);
597 }
598 }
599 return null;
600 }
601 }, USER_OWNER);
602
603
604
605 user1.runAs(new PrivilegedExceptionAction<Void>() {
606 @Override
607 public Void run() throws Exception {
608 try (Connection connection = ConnectionFactory.createConnection(conf)) {
609 try (Table t = connection.getTable(testTable.getTableName())) {
610 Delete d = new Delete(TEST_ROW1);
611 d.deleteColumn(TEST_FAMILY1, TEST_Q1, 123);
612 d.deleteColumn(TEST_FAMILY1, TEST_Q2);
613 d.deleteFamilyVersion(TEST_FAMILY2, 125);
614 t.delete(d);
615 }
616 }
617 return null;
618 }
619 });
620
621 verifyUserDeniedForDeleteExactVersion(user2, TEST_ROW1, TEST_Q1, TEST_Q2);
622 verifyUserDeniedForDeleteExactVersion(GROUP_USER, TEST_ROW1, TEST_Q1, TEST_Q2);
623 }
624
625 private void verifyUserDeniedForDeleteExactVersion(final User user, final byte[] row,
626 final byte[] q1, final byte[] q2) throws IOException, InterruptedException {
627 user.runAs(new PrivilegedExceptionAction<Void>() {
628 @Override
629 public Void run() throws Exception {
630 try (Connection connection = ConnectionFactory.createConnection(conf)) {
631 try (Table t = connection.getTable(testTable.getTableName())) {
632 Delete d = new Delete(row, 127);
633 d.addColumns(TEST_FAMILY1, q1);
634 d.addColumns(TEST_FAMILY1, q2);
635 d.addFamily(TEST_FAMILY2, 129);
636 t.delete(d);
637 fail(user.getShortName() + " can not do the delete");
638 } catch (Exception e) {
639
640 }
641 }
642 return null;
643 }
644 });
645 }
646
647 @Test
648 public void testCellPermissionsForIncrementWithMultipleVersions() throws Exception {
649 final byte[] TEST_ROW1 = Bytes.toBytes("r1");
650 final byte[] TEST_Q1 = Bytes.toBytes("q1");
651 final byte[] TEST_Q2 = Bytes.toBytes("q2");
652 final byte[] ZERO = Bytes.toBytes(0L);
653
654 final User user1 = User.createUserForTesting(conf, "user1", new String[0]);
655 final User user2 = User.createUserForTesting(conf, "user2", new String[0]);
656
657 verifyAllowed(new AccessTestAction() {
658 @Override
659 public Object run() throws Exception {
660 try (Connection connection = ConnectionFactory.createConnection(conf)) {
661 try (Table t = connection.getTable(testTable.getTableName())) {
662 Map<String, Permission> permsU1andOwner =
663 prepareCellPermissions(
664 new String[] { user1.getShortName(), USER_OWNER.getShortName() }, Action.READ,
665 Action.WRITE);
666 Map<String, Permission> permsU2andGUandOwner =
667 prepareCellPermissions(
668 new String[] { user2.getShortName(), AuthUtil.toGroupEntry(GROUP),
669 USER_OWNER.getShortName() }, Action.READ, Action.WRITE);
670 Put p = new Put(TEST_ROW1);
671 p.add(TEST_FAMILY1, TEST_Q1, 123, ZERO);
672 p.setACL(permsU1andOwner);
673 t.put(p);
674 p = new Put(TEST_ROW1);
675 p.add(TEST_FAMILY1, TEST_Q2, 123, ZERO);
676 p.setACL(permsU2andGUandOwner);
677 t.put(p);
678
679 p = new Put(TEST_ROW1);
680 p.add(TEST_FAMILY1, TEST_Q1, 127, ZERO);
681 p.setACL(permsU2andGUandOwner);
682 t.put(p);
683 p = new Put(TEST_ROW1);
684 p.add(TEST_FAMILY1, TEST_Q2, 127, ZERO);
685 p.setACL(permsU1andOwner);
686 t.put(p);
687 }
688 }
689 return null;
690 }
691 }, USER_OWNER);
692
693
694 user1.runAs(new PrivilegedExceptionAction<Void>() {
695 @Override
696 public Void run() throws Exception {
697 try (Connection connection = ConnectionFactory.createConnection(conf)) {
698 try (Table t = connection.getTable(testTable.getTableName())) {
699 Increment inc = new Increment(TEST_ROW1);
700 inc.setTimeRange(0, 123);
701 inc.addColumn(TEST_FAMILY1, TEST_Q1, 2L);
702 t.increment(inc);
703 t.incrementColumnValue(TEST_ROW1, TEST_FAMILY1, TEST_Q2, 1L);
704 }
705 }
706 return null;
707 }
708 });
709
710 verifyUserDeniedForIncrementMultipleVersions(user2, TEST_ROW1, TEST_Q2);
711 verifyUserDeniedForIncrementMultipleVersions(GROUP_USER, TEST_ROW1, TEST_Q2);
712 }
713
714 private void verifyUserDeniedForIncrementMultipleVersions(final User user, final byte[] row,
715 final byte[] q1) throws IOException, InterruptedException {
716 user.runAs(new PrivilegedExceptionAction<Void>() {
717 @Override
718 public Void run() throws Exception {
719 try (Connection connection = ConnectionFactory.createConnection(conf)) {
720 try (Table t = connection.getTable(testTable.getTableName())) {
721 Increment inc = new Increment(row);
722 inc.setTimeRange(0, 127);
723 inc.addColumn(TEST_FAMILY1, q1, 2L);
724 t.increment(inc);
725 fail(user.getShortName() + " cannot do the increment.");
726 } catch (Exception e) {
727
728 }
729 }
730 return null;
731 }
732 });
733 }
734
735 @Test
736 public void testCellPermissionsForPutWithMultipleVersions() throws Exception {
737 final byte[] TEST_ROW1 = Bytes.toBytes("r1");
738 final byte[] TEST_Q1 = Bytes.toBytes("q1");
739 final byte[] TEST_Q2 = Bytes.toBytes("q2");
740 final byte[] ZERO = Bytes.toBytes(0L);
741
742 final User user1 = User.createUserForTesting(conf, "user1", new String[0]);
743 final User user2 = User.createUserForTesting(conf, "user2", new String[0]);
744
745 verifyAllowed(new AccessTestAction() {
746 @Override
747 public Object run() throws Exception {
748 try (Connection connection = ConnectionFactory.createConnection(conf)) {
749 try (Table t = connection.getTable(testTable.getTableName())) {
750 Map<String, Permission> permsU1andOwner =
751 prepareCellPermissions(
752 new String[] { user1.getShortName(), USER_OWNER.getShortName() }, Action.READ,
753 Action.WRITE);
754 Map<String, Permission> permsU2andGUandOwner =
755 prepareCellPermissions(
756 new String[] { user1.getShortName(), AuthUtil.toGroupEntry(GROUP),
757 USER_OWNER.getShortName() }, Action.READ, Action.WRITE);
758 permsU2andGUandOwner.put(user2.getShortName(), new Permission(Permission.Action.READ,
759 Permission.Action.WRITE));
760 permsU2andGUandOwner.put(USER_OWNER.getShortName(),
761 new Permission(Permission.Action.READ, Permission.Action.WRITE));
762 Put p = new Put(TEST_ROW1);
763 p.add(TEST_FAMILY1, TEST_Q1, 123, ZERO);
764 p.setACL(permsU1andOwner);
765 t.put(p);
766 p = new Put(TEST_ROW1);
767 p.add(TEST_FAMILY1, TEST_Q2, 123, ZERO);
768 p.setACL(permsU2andGUandOwner);
769 t.put(p);
770
771 p = new Put(TEST_ROW1);
772 p.add(TEST_FAMILY1, TEST_Q1, 127, ZERO);
773 p.setACL(permsU2andGUandOwner);
774 t.put(p);
775 p = new Put(TEST_ROW1);
776 p.add(TEST_FAMILY1, TEST_Q2, 127, ZERO);
777 p.setACL(permsU1andOwner);
778 t.put(p);
779 }
780 }
781 return null;
782 }
783 }, USER_OWNER);
784
785
786
787
788 user1.runAs(new PrivilegedExceptionAction<Void>() {
789 @Override
790 public Void run() throws Exception {
791 try (Connection connection = ConnectionFactory.createConnection(conf)) {
792 try (Table t = connection.getTable(testTable.getTableName())) {
793 Put p = new Put(TEST_ROW1);
794 p.add(TEST_FAMILY1, TEST_Q1, 125, ZERO);
795 p.add(TEST_FAMILY1, TEST_Q2, ZERO);
796 p.setACL(user2.getShortName(), new Permission(Permission.Action.READ,
797 Permission.Action.WRITE));
798 t.put(p);
799 }
800 }
801 return null;
802 }
803 });
804
805 verifyUserDeniedForPutMultipleVersions(user2, TEST_ROW1, TEST_Q1, TEST_Q2, ZERO);
806 verifyUserDeniedForPutMultipleVersions(GROUP_USER, TEST_ROW1, TEST_Q1, TEST_Q2, ZERO);
807 }
808
809 private void verifyUserDeniedForPutMultipleVersions(final User user, final byte[] row,
810 final byte[] q1, final byte[] q2, final byte[] value) throws IOException,
811 InterruptedException {
812 user.runAs(new PrivilegedExceptionAction<Void>() {
813 @Override
814 public Void run() throws Exception {
815 try (Connection connection = ConnectionFactory.createConnection(conf)) {
816 try (Table t = connection.getTable(testTable.getTableName())) {
817 Put p = new Put(row);
818
819 p.addColumn(TEST_FAMILY1, q1, 124, value);
820 p.addColumn(TEST_FAMILY1, q2, value);
821 t.put(p);
822 fail(user.getShortName() + " cannot do the put.");
823 } catch (Exception e) {
824
825 }
826 }
827 return null;
828 }
829 });
830 }
831
832 @Test
833 public void testCellPermissionsForCheckAndDelete() throws Exception {
834 final byte[] TEST_ROW1 = Bytes.toBytes("r1");
835 final byte[] TEST_Q3 = Bytes.toBytes("q3");
836 final byte[] ZERO = Bytes.toBytes(0L);
837
838 final User user1 = User.createUserForTesting(conf, "user1", new String[0]);
839 final User user2 = User.createUserForTesting(conf, "user2", new String[0]);
840
841 verifyAllowed(new AccessTestAction() {
842 @Override
843 public Object run() throws Exception {
844 try (Connection connection = ConnectionFactory.createConnection(conf)) {
845 try (Table t = connection.getTable(testTable.getTableName())) {
846 Map<String, Permission> permsU1andOwner =
847 prepareCellPermissions(
848 new String[] { user1.getShortName(), USER_OWNER.getShortName() }, Action.READ,
849 Action.WRITE);
850 Map<String, Permission> permsU1andU2andGUandOwner =
851 prepareCellPermissions(new String[] { user1.getShortName(), user2.getShortName(),
852 AuthUtil.toGroupEntry(GROUP), USER_OWNER.getShortName() }, Action.READ,
853 Action.WRITE);
854 Map<String, Permission> permsU1_U2andGU =
855 prepareCellPermissions(new String[] { user1.getShortName(), user2.getShortName(),
856 AuthUtil.toGroupEntry(GROUP) }, Action.READ, Action.WRITE);
857
858 Put p = new Put(TEST_ROW1);
859 p.add(TEST_FAMILY1, TEST_Q1, 120, ZERO);
860 p.add(TEST_FAMILY1, TEST_Q2, 120, ZERO);
861 p.add(TEST_FAMILY1, TEST_Q3, 120, ZERO);
862 p.setACL(permsU1andU2andGUandOwner);
863 t.put(p);
864
865 p = new Put(TEST_ROW1);
866 p.add(TEST_FAMILY1, TEST_Q1, 123, ZERO);
867 p.add(TEST_FAMILY1, TEST_Q2, 123, ZERO);
868 p.add(TEST_FAMILY1, TEST_Q3, 123, ZERO);
869 p.setACL(permsU1andOwner);
870 t.put(p);
871
872 p = new Put(TEST_ROW1);
873 p.add(TEST_FAMILY1, TEST_Q1, 127, ZERO);
874 p.setACL(permsU1_U2andGU);
875 t.put(p);
876
877 p = new Put(TEST_ROW1);
878 p.add(TEST_FAMILY1, TEST_Q2, 127, ZERO);
879 p.setACL(user2.getShortName(), new Permission(Permission.Action.READ));
880 t.put(p);
881
882 p = new Put(TEST_ROW1);
883 p.addColumn(TEST_FAMILY1, TEST_Q3, 127, ZERO);
884 p.setACL(AuthUtil.toGroupEntry(GROUP), new Permission(Permission.Action.READ));
885 t.put(p);
886 }
887 }
888 return null;
889 }
890 }, USER_OWNER);
891
892
893
894 user1.runAs(new PrivilegedExceptionAction<Void>() {
895 @Override
896 public Void run() throws Exception {
897 try (Connection connection = ConnectionFactory.createConnection(conf)) {
898 try (Table t = connection.getTable(testTable.getTableName())) {
899 Delete d = new Delete(TEST_ROW1);
900 d.deleteColumns(TEST_FAMILY1, TEST_Q1, 120);
901 t.checkAndDelete(TEST_ROW1, TEST_FAMILY1, TEST_Q1, ZERO, d);
902 }
903 }
904 return null;
905 }
906 });
907
908
909 verifyUserDeniedForCheckAndDelete(user2, TEST_ROW1, ZERO);
910
911
912
913
914 verifyUserDeniedForCheckAndDelete(GROUP_USER, TEST_ROW1, ZERO);
915
916
917
918
919 verifyUserAllowedforCheckAndDelete(user2, TEST_ROW1, TEST_Q2, ZERO);
920
921
922
923
924
925 verifyUserAllowedforCheckAndDelete(GROUP_USER, TEST_ROW1, TEST_Q3, ZERO);
926 }
927
928 private void verifyUserAllowedforCheckAndDelete(final User user, final byte[] row,
929 final byte[] q1, final byte[] value) throws IOException, InterruptedException {
930 user.runAs(new PrivilegedExceptionAction<Void>() {
931 @Override
932 public Void run() throws Exception {
933 try (Connection connection = ConnectionFactory.createConnection(conf)) {
934 try (Table t = connection.getTable(testTable.getTableName())) {
935 Delete d = new Delete(row);
936 d.addColumn(TEST_FAMILY1, q1, 120);
937 t.checkAndDelete(row, TEST_FAMILY1, q1, value, d);
938 }
939 }
940 return null;
941 }
942 });
943 }
944
945 private void verifyUserDeniedForCheckAndDelete(final User user, final byte[] row,
946 final byte[] value) throws IOException, InterruptedException {
947 user.runAs(new PrivilegedExceptionAction<Void>() {
948 @Override
949 public Void run() throws Exception {
950 try (Connection connection = ConnectionFactory.createConnection(conf)) {
951 try (Table t = connection.getTable(testTable.getTableName())) {
952 Delete d = new Delete(row);
953 d.addColumns(TEST_FAMILY1, TEST_Q1);
954 t.checkAndDelete(row, TEST_FAMILY1, TEST_Q1, value, d);
955 fail(user.getShortName() + " should not be allowed to do checkAndDelete");
956 } catch (Exception e) {
957 }
958 }
959 return null;
960 }
961 });
962 }
963
964 @After
965 public void tearDown() throws Exception {
966
967 try {
968 TEST_UTIL.deleteTable(testTable.getTableName());
969 } catch (TableNotFoundException ex) {
970
971 LOG.info("Test deleted table " + testTable.getTableName());
972 }
973 assertEquals(0, AccessControlLists.getTablePermissions(conf, testTable.getTableName()).size());
974 }
975 }