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