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