View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.security.access;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertTrue;
24  import static org.junit.Assert.fail;
25  
26  import java.io.IOException;
27  import java.lang.reflect.UndeclaredThrowableException;
28  import java.security.PrivilegedActionException;
29  import java.security.PrivilegedExceptionAction;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.NavigableMap;
33  
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  import org.apache.hadoop.conf.Configuration;
37  import org.apache.hadoop.fs.FileStatus;
38  import org.apache.hadoop.fs.FileSystem;
39  import org.apache.hadoop.fs.Path;
40  import org.apache.hadoop.fs.permission.FsPermission;
41  import org.apache.hadoop.hbase.Coprocessor;
42  import org.apache.hadoop.hbase.TableName;
43  import org.apache.hadoop.hbase.HBaseTestingUtility;
44  import org.apache.hadoop.hbase.HColumnDescriptor;
45  import org.apache.hadoop.hbase.HConstants;
46  import org.apache.hadoop.hbase.HRegionInfo;
47  import org.apache.hadoop.hbase.HTableDescriptor;
48  import org.apache.hadoop.hbase.KeyValue;
49  import org.apache.hadoop.hbase.LargeTests;
50  import org.apache.hadoop.hbase.MiniHBaseCluster;
51  import org.apache.hadoop.hbase.ServerName;
52  import org.apache.hadoop.hbase.TableNotFoundException;
53  import org.apache.hadoop.hbase.client.Append;
54  import org.apache.hadoop.hbase.client.Delete;
55  import org.apache.hadoop.hbase.client.Get;
56  import org.apache.hadoop.hbase.client.HBaseAdmin;
57  import org.apache.hadoop.hbase.client.HTable;
58  import org.apache.hadoop.hbase.client.Increment;
59  import org.apache.hadoop.hbase.client.Put;
60  import org.apache.hadoop.hbase.client.Result;
61  import org.apache.hadoop.hbase.client.ResultScanner;
62  import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException;
63  import org.apache.hadoop.hbase.client.Scan;
64  import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
65  import org.apache.hadoop.hbase.coprocessor.ObserverContext;
66  import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
67  import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
68  import org.apache.hadoop.hbase.io.hfile.CacheConfig;
69  import org.apache.hadoop.hbase.io.hfile.HFile;
70  import org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles;
71  import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
72  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
73  import org.apache.hadoop.hbase.protobuf.RequestConverter;
74  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
75  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
76  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.CheckPermissionsRequest;
77  import org.apache.hadoop.hbase.regionserver.HRegion;
78  import org.apache.hadoop.hbase.regionserver.HRegionServer;
79  import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
80  import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
81  import org.apache.hadoop.hbase.regionserver.ScanType;
82  import org.apache.hadoop.hbase.security.AccessDeniedException;
83  import org.apache.hadoop.hbase.security.User;
84  import org.apache.hadoop.hbase.security.access.Permission.Action;
85  import org.apache.hadoop.hbase.util.Bytes;
86  import org.apache.hadoop.hbase.util.JVMClusterUtil;
87  import org.apache.hadoop.hbase.util.TestTableName;
88  
89  import org.junit.After;
90  import org.junit.AfterClass;
91  import org.junit.Before;
92  import org.junit.BeforeClass;
93  import org.junit.Rule;
94  import org.junit.Test;
95  import org.junit.experimental.categories.Category;
96  
97  import com.google.protobuf.BlockingRpcChannel;
98  import com.google.protobuf.ServiceException;
99  
100 /**
101  * Performs authorization checks for common operations, according to different
102  * levels of authorized users.
103  */
104 @Category(LargeTests.class)
105 @SuppressWarnings("rawtypes")
106 public class TestAccessController extends SecureTestUtil {
107   private static final Log LOG = LogFactory.getLog(TestAccessController.class);
108   @Rule public TestTableName TEST_TABLE = new TestTableName();
109   private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
110   private static Configuration conf;
111 
112   // user with all permissions
113   private static User SUPERUSER;
114   // user granted with all global permission
115   private static User USER_ADMIN;
116   // user with rw permissions on column family.
117   private static User USER_RW;
118   // user with read-only permissions
119   private static User USER_RO;
120   // user is table owner. will have all permissions on table
121   private static User USER_OWNER;
122   // user with create table permissions alone
123   private static User USER_CREATE;
124   // user with no permissions
125   private static User USER_NONE;
126 
127   private static TableName TEST_TABLE2 =
128       TableName.valueOf("testtable2");
129   private static byte[] TEST_FAMILY = Bytes.toBytes("f1");
130 
131   private static MasterCoprocessorEnvironment CP_ENV;
132   private static AccessController ACCESS_CONTROLLER;
133   private static RegionServerCoprocessorEnvironment RSCP_ENV;
134   private RegionCoprocessorEnvironment RCP_ENV;
135 
136   @BeforeClass
137   public static void setupBeforeClass() throws Exception {
138     // setup configuration
139     conf = TEST_UTIL.getConfiguration();
140     conf.set("hbase.master.hfilecleaner.plugins",
141       "org.apache.hadoop.hbase.master.cleaner.HFileLinkCleaner," +
142       "org.apache.hadoop.hbase.master.snapshot.SnapshotHFileCleaner");
143     conf.set("hbase.master.logcleaner.plugins",
144       "org.apache.hadoop.hbase.master.snapshot.SnapshotLogCleaner");
145     SecureTestUtil.enableSecurity(conf);
146 
147     TEST_UTIL.startMiniCluster();
148     MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster().getCoprocessorHost();
149     cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
150     ACCESS_CONTROLLER = (AccessController) cpHost.findCoprocessor(AccessController.class.getName());
151     CP_ENV = cpHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER,
152       Coprocessor.PRIORITY_HIGHEST, 1, conf);
153     RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0)
154         .getCoprocessorHost();
155     RSCP_ENV = rsHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER,
156       Coprocessor.PRIORITY_HIGHEST, 1, conf);
157 
158     // Wait for the ACL table to become available
159     TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME.getName());
160 
161     // create a set of test users
162     SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
163     USER_ADMIN = User.createUserForTesting(conf, "admin2", new String[0]);
164     USER_RW = User.createUserForTesting(conf, "rwuser", new String[0]);
165     USER_RO = User.createUserForTesting(conf, "rouser", new String[0]);
166     USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
167     USER_CREATE = User.createUserForTesting(conf, "tbl_create", new String[0]);
168     USER_NONE = User.createUserForTesting(conf, "nouser", new String[0]);
169   }
170 
171   @AfterClass
172   public static void tearDownAfterClass() throws Exception {
173     TEST_UTIL.shutdownMiniCluster();
174   }
175 
176   @Before
177   public void setUp() throws Exception {
178     // Create the test table (owner added to the _acl_ table)
179     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
180     HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName());
181     htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
182     htd.setOwner(USER_OWNER);
183     admin.createTable(htd);
184     TEST_UTIL.waitTableEnabled(TEST_TABLE.getTableName().getName());
185 
186     HRegion region = TEST_UTIL.getHBaseCluster().getRegions(TEST_TABLE.getTableName()).get(0);
187     RegionCoprocessorHost rcpHost = region.getCoprocessorHost();
188     RCP_ENV = rcpHost.createEnvironment(AccessController.class, ACCESS_CONTROLLER,
189       Coprocessor.PRIORITY_HIGHEST, 1, conf);
190 
191     // initilize access control
192     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
193     try {
194       BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getTableName().getName());
195       AccessControlService.BlockingInterface protocol =
196         AccessControlService.newBlockingStub(service);
197 
198       protocol.grant(null, RequestConverter.buildGrantRequest(USER_ADMIN.getShortName(),
199         AccessControlProtos.Permission.Action.ADMIN,
200         AccessControlProtos.Permission.Action.CREATE,
201         AccessControlProtos.Permission.Action.READ,
202         AccessControlProtos.Permission.Action.WRITE));
203 
204       protocol.grant(null, RequestConverter.buildGrantRequest(USER_RW.getShortName(),
205         TEST_TABLE.getTableName(), TEST_FAMILY, null,
206         AccessControlProtos.Permission.Action.READ,
207         AccessControlProtos.Permission.Action.WRITE));
208 
209       // USER_CREATE is USER_RW plus CREATE permissions
210       protocol.grant(null, RequestConverter.buildGrantRequest(USER_CREATE.getShortName(),
211         TEST_TABLE.getTableName(), null, null,
212         AccessControlProtos.Permission.Action.CREATE,
213         AccessControlProtos.Permission.Action.READ,
214         AccessControlProtos.Permission.Action.WRITE));
215 
216       protocol.grant(null, RequestConverter.buildGrantRequest(USER_RO.getShortName(), TEST_TABLE.getTableName(),
217         TEST_FAMILY, null, AccessControlProtos.Permission.Action.READ));
218 
219       assertEquals(4, AccessControlLists.getTablePermissions(conf, TEST_TABLE.getTableName()).size());
220     } finally {
221       acl.close();
222     }
223   }
224 
225   @After
226   public void tearDown() throws Exception {
227     // Clean the _acl_ table
228     try {
229       TEST_UTIL.deleteTable(TEST_TABLE.getTableName());
230     } catch (TableNotFoundException ex) {
231       // Test deleted the table, no problem
232       LOG.info("Test deleted table " + TEST_TABLE.getTableName());
233     }
234     assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE.getTableName()).size());
235   }
236 
237   public void verifyAllowed(PrivilegedExceptionAction action, User... users) throws Exception {
238     for (User user : users) {
239       verifyAllowed(user, action);
240     }
241   }
242 
243   public void verifyDenied(User user, PrivilegedExceptionAction... actions) throws Exception {
244     for (PrivilegedExceptionAction action : actions) {
245       try {
246         user.runAs(action);
247         fail("Expected AccessDeniedException for user '" + user.getShortName() + "'");
248       } catch (IOException e) {
249         boolean isAccessDeniedException = false;
250         if(e instanceof RetriesExhaustedWithDetailsException) {
251           // in case of batch operations, and put, the client assembles a
252           // RetriesExhaustedWithDetailsException instead of throwing an
253           // AccessDeniedException
254           for(Throwable ex : ((RetriesExhaustedWithDetailsException) e).getCauses()) {
255             if (ex instanceof AccessDeniedException) {
256               isAccessDeniedException = true;
257               break;
258             }
259           }
260         }
261         else {
262           // For doBulkLoad calls AccessDeniedException
263           // is buried in the stack trace
264           Throwable ex = e;
265           do {
266             if (ex instanceof AccessDeniedException) {
267               isAccessDeniedException = true;
268               break;
269             }
270           } while((ex = ex.getCause()) != null);
271         }
272         if (!isAccessDeniedException) {
273           fail("Not receiving AccessDeniedException for user '" + user.getShortName() + "'");
274         }
275       } catch (UndeclaredThrowableException ute) {
276         // TODO why we get a PrivilegedActionException, which is unexpected?
277         Throwable ex = ute.getUndeclaredThrowable();
278         if (ex instanceof PrivilegedActionException) {
279           ex = ((PrivilegedActionException) ex).getException();
280         }
281         if (ex instanceof ServiceException) {
282           ServiceException se = (ServiceException)ex;
283           if (se.getCause() != null && se.getCause() instanceof AccessDeniedException) {
284             // expected result
285             return;
286           }
287         }
288         fail("Not receiving AccessDeniedException for user '" + user.getShortName() + "'");
289       }
290     }
291   }
292 
293   public void verifyDenied(PrivilegedExceptionAction action, User... users) throws Exception {
294     for (User user : users) {
295       verifyDenied(user, action);
296     }
297   }
298 
299   @Test
300   public void testTableCreate() throws Exception {
301     PrivilegedExceptionAction createTable = new PrivilegedExceptionAction() {
302       public Object run() throws Exception {
303         HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("testnewtable"));
304         htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
305         ACCESS_CONTROLLER.preCreateTable(ObserverContext.createAndPrepare(CP_ENV, null), htd, null);
306         return null;
307       }
308     };
309 
310     // verify that superuser can create tables
311     verifyAllowed(createTable, SUPERUSER, USER_ADMIN);
312 
313     // all others should be denied
314     verifyDenied(createTable, USER_CREATE, USER_RW, USER_RO, USER_NONE);
315   }
316 
317   @Test
318   public void testTableModify() throws Exception {
319     PrivilegedExceptionAction modifyTable = new PrivilegedExceptionAction() {
320       public Object run() throws Exception {
321         HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName());
322         htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
323         htd.addFamily(new HColumnDescriptor("fam_" + User.getCurrent().getShortName()));
324         ACCESS_CONTROLLER.preModifyTable(ObserverContext.createAndPrepare(CP_ENV, null),
325           TEST_TABLE.getTableName(), htd);
326         return null;
327       }
328     };
329 
330     verifyAllowed(modifyTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
331     verifyDenied(modifyTable, USER_RW, USER_RO, USER_NONE);
332   }
333 
334   @Test
335   public void testTableDelete() throws Exception {
336     PrivilegedExceptionAction deleteTable = new PrivilegedExceptionAction() {
337       public Object run() throws Exception {
338         ACCESS_CONTROLLER
339             .preDeleteTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName());
340         return null;
341       }
342     };
343 
344     verifyAllowed(deleteTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
345     verifyDenied(deleteTable, USER_RW, USER_RO, USER_NONE);
346   }
347 
348   @Test
349   public void testAddColumn() throws Exception {
350     final HColumnDescriptor hcd = new HColumnDescriptor("fam_new");
351     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
352       public Object run() throws Exception {
353         ACCESS_CONTROLLER.preAddColumn(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName(),
354           hcd);
355         return null;
356       }
357     };
358 
359     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
360     verifyDenied(action, USER_RW, USER_RO, USER_NONE);
361   }
362 
363   @Test
364   public void testModifyColumn() throws Exception {
365     final HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
366     hcd.setMaxVersions(10);
367     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
368       public Object run() throws Exception {
369         ACCESS_CONTROLLER.preModifyColumn(ObserverContext.createAndPrepare(CP_ENV, null),
370           TEST_TABLE.getTableName(), hcd);
371         return null;
372       }
373     };
374 
375     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
376     verifyDenied(action, USER_RW, USER_RO, USER_NONE);
377   }
378 
379   @Test
380   public void testDeleteColumn() throws Exception {
381     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
382       public Object run() throws Exception {
383         ACCESS_CONTROLLER.preDeleteColumn(ObserverContext.createAndPrepare(CP_ENV, null),
384           TEST_TABLE.getTableName(), TEST_FAMILY);
385         return null;
386       }
387     };
388 
389     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
390     verifyDenied(action, USER_RW, USER_RO, USER_NONE);
391   }
392 
393   @Test
394   public void testTableDisable() throws Exception {
395     PrivilegedExceptionAction disableTable = new PrivilegedExceptionAction() {
396       public Object run() throws Exception {
397         ACCESS_CONTROLLER.preDisableTable(ObserverContext.createAndPrepare(CP_ENV, null),
398           TEST_TABLE.getTableName());
399         return null;
400       }
401     };
402 
403     PrivilegedExceptionAction disableAclTable = new PrivilegedExceptionAction() {
404       public Object run() throws Exception {
405         ACCESS_CONTROLLER.preDisableTable(ObserverContext.createAndPrepare(CP_ENV, null),
406             AccessControlLists.ACL_TABLE_NAME);
407         return null;
408       }
409     };
410 
411     verifyAllowed(disableTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
412     verifyDenied(disableTable, USER_RW, USER_RO, USER_NONE);
413 
414     // No user should be allowed to disable _acl_ table
415     verifyDenied(disableAclTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER, USER_RW, USER_RO);
416   }
417 
418   @Test
419   public void testTableEnable() throws Exception {
420     PrivilegedExceptionAction enableTable = new PrivilegedExceptionAction() {
421       public Object run() throws Exception {
422         ACCESS_CONTROLLER
423             .preEnableTable(ObserverContext.createAndPrepare(CP_ENV, null), TEST_TABLE.getTableName());
424         return null;
425       }
426     };
427 
428     verifyAllowed(enableTable, SUPERUSER, USER_ADMIN, USER_CREATE, USER_OWNER);
429     verifyDenied(enableTable, USER_RW, USER_RO, USER_NONE);
430   }
431 
432   @Test
433   public void testMove() throws Exception {
434     Map<HRegionInfo, ServerName> regions;
435     HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName());
436     try {
437       regions = table.getRegionLocations();
438     } finally {
439       table.close();
440     }
441     final Map.Entry<HRegionInfo, ServerName> firstRegion = regions.entrySet().iterator().next();
442     final ServerName server = TEST_UTIL.getHBaseCluster().getRegionServer(0).getServerName();
443     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
444       public Object run() throws Exception {
445         ACCESS_CONTROLLER.preMove(ObserverContext.createAndPrepare(CP_ENV, null),
446           firstRegion.getKey(), server, server);
447         return null;
448       }
449     };
450 
451     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
452     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
453   }
454 
455   @Test
456   public void testAssign() throws Exception {
457     Map<HRegionInfo, ServerName> regions;
458     HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName());
459     try {
460       regions = table.getRegionLocations();
461     } finally {
462       table.close();
463     }
464     final Map.Entry<HRegionInfo, ServerName> firstRegion = regions.entrySet().iterator().next();
465 
466     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
467       public Object run() throws Exception {
468         ACCESS_CONTROLLER.preAssign(ObserverContext.createAndPrepare(CP_ENV, null),
469           firstRegion.getKey());
470         return null;
471       }
472     };
473 
474     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
475     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
476   }
477 
478   @Test
479   public void testUnassign() throws Exception {
480     Map<HRegionInfo, ServerName> regions;
481     HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName());
482     try {
483       regions = table.getRegionLocations();
484     } finally {
485       table.close();
486     }
487     final Map.Entry<HRegionInfo, ServerName> firstRegion = regions.entrySet().iterator().next();
488 
489     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
490       public Object run() throws Exception {
491         ACCESS_CONTROLLER.preUnassign(ObserverContext.createAndPrepare(CP_ENV, null),
492           firstRegion.getKey(), false);
493         return null;
494       }
495     };
496 
497     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
498     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
499   }
500 
501   @Test
502   public void testRegionOffline() throws Exception {
503     Map<HRegionInfo, ServerName> regions;
504     HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName());
505     try {
506       regions = table.getRegionLocations();
507     } finally {
508       table.close();
509     }
510     final Map.Entry<HRegionInfo, ServerName> firstRegion = regions.entrySet().iterator().next();
511 
512     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
513       public Object run() throws Exception {
514         ACCESS_CONTROLLER.preRegionOffline(ObserverContext.createAndPrepare(CP_ENV, null),
515           firstRegion.getKey());
516         return null;
517       }
518     };
519 
520     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
521     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
522   }
523 
524   @Test
525   public void testBalance() throws Exception {
526     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
527       public Object run() throws Exception {
528         ACCESS_CONTROLLER.preBalance(ObserverContext.createAndPrepare(CP_ENV, null));
529         return null;
530       }
531     };
532 
533     verifyAllowed(action, SUPERUSER, USER_ADMIN);
534     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
535   }
536 
537   @Test
538   public void testBalanceSwitch() throws Exception {
539     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
540       public Object run() throws Exception {
541         ACCESS_CONTROLLER.preBalanceSwitch(ObserverContext.createAndPrepare(CP_ENV, null), true);
542         return null;
543       }
544     };
545 
546     verifyAllowed(action, SUPERUSER, USER_ADMIN);
547     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
548   }
549 
550   @Test
551   public void testShutdown() throws Exception {
552     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
553       public Object run() throws Exception {
554         ACCESS_CONTROLLER.preShutdown(ObserverContext.createAndPrepare(CP_ENV, null));
555         return null;
556       }
557     };
558 
559     verifyAllowed(action, SUPERUSER, USER_ADMIN);
560     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
561   }
562 
563   @Test
564   public void testStopMaster() throws Exception {
565     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
566       public Object run() throws Exception {
567         ACCESS_CONTROLLER.preStopMaster(ObserverContext.createAndPrepare(CP_ENV, null));
568         return null;
569       }
570     };
571 
572     verifyAllowed(action, SUPERUSER, USER_ADMIN);
573     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
574   }
575 
576   private void verifyWrite(PrivilegedExceptionAction action) throws Exception {
577     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW);
578     verifyDenied(action, USER_NONE, USER_RO);
579   }
580 
581   @Test
582   public void testSplit() throws Exception {
583     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
584       public Object run() throws Exception {
585         ACCESS_CONTROLLER.preSplit(ObserverContext.createAndPrepare(RCP_ENV, null));
586         return null;
587       }
588     };
589 
590     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
591     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
592   }
593 
594   @Test
595   public void testSplitWithSplitRow() throws Exception {
596     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
597       public Object run() throws Exception {
598         ACCESS_CONTROLLER.preSplit(
599             ObserverContext.createAndPrepare(RCP_ENV, null),
600             Bytes.toBytes("row2"));
601         return null;
602       }
603     };
604 
605     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
606     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
607   }
608 
609 
610   @Test
611   public void testFlush() throws Exception {
612     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
613       public Object run() throws Exception {
614         ACCESS_CONTROLLER.preFlush(ObserverContext.createAndPrepare(RCP_ENV, null));
615         return null;
616       }
617     };
618 
619     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
620     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
621   }
622 
623   @Test
624   public void testCompact() throws Exception {
625     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
626       public Object run() throws Exception {
627         ACCESS_CONTROLLER.preCompact(ObserverContext.createAndPrepare(RCP_ENV, null), null, null,
628           ScanType.COMPACT_RETAIN_DELETES);
629         return null;
630       }
631     };
632 
633     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
634     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
635   }
636 
637   @Test
638   public void testPreCompactSelection() throws Exception {
639     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
640       public Object run() throws Exception {
641         ACCESS_CONTROLLER.preCompactSelection(ObserverContext.createAndPrepare(RCP_ENV, null), null, null);
642         return null;
643       }
644     };
645 
646     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER);
647     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE);
648   }
649 
650   private void verifyRead(PrivilegedExceptionAction action) throws Exception {
651     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW, USER_RO);
652     verifyDenied(action, USER_NONE);
653   }
654 
655   private void verifyReadWrite(PrivilegedExceptionAction action) throws Exception {
656     verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW);
657     verifyDenied(action, USER_NONE, USER_RO);
658   }
659 
660   @Test
661   public void testRead() throws Exception {
662     // get action
663     PrivilegedExceptionAction getAction = new PrivilegedExceptionAction() {
664       public Object run() throws Exception {
665         Get g = new Get(Bytes.toBytes("random_row"));
666         g.addFamily(TEST_FAMILY);
667         HTable t = new HTable(conf, TEST_TABLE.getTableName());
668         try {
669           t.get(g);
670         } finally {
671           t.close();
672         }
673         return null;
674       }
675     };
676     verifyRead(getAction);
677 
678     // action for scanning
679     PrivilegedExceptionAction scanAction = new PrivilegedExceptionAction() {
680       public Object run() throws Exception {
681         Scan s = new Scan();
682         s.addFamily(TEST_FAMILY);
683 
684         HTable table = new HTable(conf, TEST_TABLE.getTableName());
685         try {
686           ResultScanner scanner = table.getScanner(s);
687           try {
688             for (Result r = scanner.next(); r != null; r = scanner.next()) {
689               // do nothing
690             }
691           } catch (IOException e) {
692           } finally {
693             scanner.close();
694           }
695         } finally {
696           table.close();
697         }
698         return null;
699       }
700     };
701     verifyRead(scanAction);
702   }
703 
704   @Test
705   // test put, delete, increment
706   public void testWrite() throws Exception {
707     // put action
708     PrivilegedExceptionAction putAction = new PrivilegedExceptionAction() {
709       public Object run() throws Exception {
710         Put p = new Put(Bytes.toBytes("random_row"));
711         p.add(TEST_FAMILY, Bytes.toBytes("Qualifier"), Bytes.toBytes(1));
712         HTable t = new HTable(conf, TEST_TABLE.getTableName());
713         try {
714           t.put(p);
715         } finally {
716           t.close();
717         }
718         return null;
719       }
720     };
721     verifyWrite(putAction);
722 
723     // delete action
724     PrivilegedExceptionAction deleteAction = new PrivilegedExceptionAction() {
725       public Object run() throws Exception {
726         Delete d = new Delete(Bytes.toBytes("random_row"));
727         d.deleteFamily(TEST_FAMILY);
728         HTable t = new HTable(conf, TEST_TABLE.getTableName());
729         try {
730           t.delete(d);
731         } finally {
732           t.close();
733         }
734         return null;
735       }
736     };
737     verifyWrite(deleteAction);
738 
739     // increment action
740     PrivilegedExceptionAction incrementAction = new PrivilegedExceptionAction() {
741       public Object run() throws Exception {
742         Increment inc = new Increment(Bytes.toBytes("random_row"));
743         inc.addColumn(TEST_FAMILY, Bytes.toBytes("Qualifier"), 1);
744         HTable t = new HTable(conf, TEST_TABLE.getTableName());
745         try {
746           t.increment(inc);
747         } finally {
748           t.close();
749         }
750         return null;
751       }
752     };
753     verifyWrite(incrementAction);
754   }
755 
756   @Test
757   public void testReadWrite() throws Exception {
758     // action for checkAndDelete
759     PrivilegedExceptionAction checkAndDeleteAction = new PrivilegedExceptionAction() {
760       public Object run() throws Exception {
761         Delete d = new Delete(Bytes.toBytes("random_row"));
762         d.deleteFamily(TEST_FAMILY);
763         HTable t = new HTable(conf, TEST_TABLE.getTableName());
764         try {
765           t.checkAndDelete(Bytes.toBytes("random_row"), TEST_FAMILY, Bytes.toBytes("q"),
766             Bytes.toBytes("test_value"), d);
767         } finally {
768           t.close();
769         }
770         return null;
771       }
772     };
773     verifyReadWrite(checkAndDeleteAction);
774 
775     // action for checkAndPut()
776     PrivilegedExceptionAction checkAndPut = new PrivilegedExceptionAction() {
777       public Object run() throws Exception {
778         Put p = new Put(Bytes.toBytes("random_row"));
779         p.add(TEST_FAMILY, Bytes.toBytes("Qualifier"), Bytes.toBytes(1));
780         HTable t = new HTable(conf, TEST_TABLE.getTableName());
781         try {
782           t.checkAndPut(Bytes.toBytes("random_row"), TEST_FAMILY, Bytes.toBytes("q"),
783            Bytes.toBytes("test_value"), p);
784         } finally {
785           t.close();
786         }
787         return null;
788       }
789     };
790     verifyReadWrite(checkAndPut);
791   }
792 
793   @Test
794   public void testBulkLoad() throws Exception {
795     FileSystem fs = TEST_UTIL.getTestFileSystem();
796     final Path dir = TEST_UTIL.getDataTestDir("testBulkLoad");
797     fs.mkdirs(dir);
798     //need to make it globally writable
799     //so users creating HFiles have write permissions
800     fs.setPermission(dir, FsPermission.valueOf("-rwxrwxrwx"));
801 
802     PrivilegedExceptionAction bulkLoadAction = new PrivilegedExceptionAction() {
803       public Object run() throws Exception {
804         int numRows = 3;
805 
806         //Making the assumption that the test table won't split between the range
807         byte[][][] hfileRanges = {{{(byte)0}, {(byte)9}}};
808 
809         Path bulkLoadBasePath = new Path(dir, new Path(User.getCurrent().getName()));
810         new BulkLoadHelper(bulkLoadBasePath)
811             .bulkLoadHFile(TEST_TABLE.getTableName(), TEST_FAMILY, Bytes.toBytes("q"), hfileRanges, numRows);
812 
813         return null;
814       }
815     };
816 
817     // User performing bulk loads must have privilege to read table metadata
818     // (ADMIN or CREATE)
819     verifyAllowed(bulkLoadAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE);
820     verifyDenied(bulkLoadAction, USER_RW, USER_NONE, USER_RO);
821 
822     // Reinit after the bulk upload
823     TEST_UTIL.getHBaseAdmin().disableTable(TEST_TABLE.getTableName());
824     TEST_UTIL.getHBaseAdmin().enableTable(TEST_TABLE.getTableName());
825   }
826 
827   public class BulkLoadHelper {
828     private final FileSystem fs;
829     private final Path loadPath;
830     private final Configuration conf;
831 
832     public BulkLoadHelper(Path loadPath) throws IOException {
833       fs = TEST_UTIL.getTestFileSystem();
834       conf = TEST_UTIL.getConfiguration();
835       loadPath = loadPath.makeQualified(fs);
836       this.loadPath = loadPath;
837     }
838 
839     private void createHFile(Path path,
840         byte[] family, byte[] qualifier,
841         byte[] startKey, byte[] endKey, int numRows) throws IOException {
842 
843       HFile.Writer writer = null;
844       long now = System.currentTimeMillis();
845       try {
846         writer = HFile.getWriterFactory(conf, new CacheConfig(conf))
847             .withPath(fs, path)
848             .withComparator(KeyValue.KEY_COMPARATOR)
849             .create();
850         // subtract 2 since numRows doesn't include boundary keys
851         for (byte[] key : Bytes.iterateOnSplits(startKey, endKey, true, numRows-2)) {
852           KeyValue kv = new KeyValue(key, family, qualifier, now, key);
853           writer.append(kv);
854         }
855       } finally {
856         if(writer != null)
857           writer.close();
858       }
859     }
860 
861     private void bulkLoadHFile(
862         TableName tableName,
863         byte[] family,
864         byte[] qualifier,
865         byte[][][] hfileRanges,
866         int numRowsPerRange) throws Exception {
867 
868       Path familyDir = new Path(loadPath, Bytes.toString(family));
869       fs.mkdirs(familyDir);
870       int hfileIdx = 0;
871       for (byte[][] range : hfileRanges) {
872         byte[] from = range[0];
873         byte[] to = range[1];
874         createHFile(new Path(familyDir, "hfile_"+(hfileIdx++)),
875             family, qualifier, from, to, numRowsPerRange);
876       }
877       //set global read so RegionServer can move it
878       setPermission(loadPath, FsPermission.valueOf("-rwxrwxrwx"));
879 
880       HTable table = new HTable(conf, tableName);
881       try {
882         HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
883         TEST_UTIL.waitTableEnabled(admin, tableName.getName());
884         LoadIncrementalHFiles loader = new LoadIncrementalHFiles(conf);
885         loader.doBulkLoad(loadPath, table);
886       } finally {
887         table.close();
888       }
889     }
890 
891     public void setPermission(Path dir, FsPermission perm) throws IOException {
892       if(!fs.getFileStatus(dir).isDir()) {
893         fs.setPermission(dir,perm);
894       }
895       else {
896         for(FileStatus el : fs.listStatus(dir)) {
897           fs.setPermission(el.getPath(), perm);
898           setPermission(el.getPath() , perm);
899         }
900       }
901     }
902   }
903 
904   @Test
905   public void testAppend() throws Exception {
906 
907     PrivilegedExceptionAction appendAction = new PrivilegedExceptionAction() {
908       public Object run() throws Exception {
909         byte[] row = Bytes.toBytes("random_row");
910         byte[] qualifier = Bytes.toBytes("q");
911         Put put = new Put(row);
912         put.add(TEST_FAMILY, qualifier, Bytes.toBytes(1));
913         Append append = new Append(row);
914         append.add(TEST_FAMILY, qualifier, Bytes.toBytes(2));
915         HTable t = new HTable(conf, TEST_TABLE.getTableName());
916         try {
917           t.put(put);
918           t.append(append);
919         } finally {
920           t.close();
921         }
922         return null;
923       }
924     };
925 
926     verifyAllowed(appendAction, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_RW);
927     verifyDenied(appendAction, USER_RO, USER_NONE);
928   }
929 
930   @Test
931   public void testGrantRevoke() throws Exception {
932 
933     PrivilegedExceptionAction grantAction = new PrivilegedExceptionAction() {
934       public Object run() throws Exception {
935         HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
936         try {
937           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getTableName().getName());
938           AccessControlService.BlockingInterface protocol =
939             AccessControlService.newBlockingStub(service);
940           ProtobufUtil.grant(protocol, USER_RO.getShortName(), TEST_TABLE.getTableName(),
941             TEST_FAMILY, null, Action.READ);
942         } finally {
943           acl.close();
944         }
945         return null;
946       }
947     };
948 
949     PrivilegedExceptionAction revokeAction = new PrivilegedExceptionAction() {
950       public Object run() throws Exception {
951         HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
952         try {
953           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getTableName().getName());
954           AccessControlService.BlockingInterface protocol =
955             AccessControlService.newBlockingStub(service);
956           ProtobufUtil.revoke(protocol, USER_RO.getShortName(), TEST_TABLE.getTableName(),
957             TEST_FAMILY, null, Action.READ);
958         } finally {
959           acl.close();
960         }
961         return null;
962       }
963     };
964 
965     PrivilegedExceptionAction getPermissionsAction = new PrivilegedExceptionAction() {
966       public Object run() throws Exception {
967         HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
968         try {
969           BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getTableName().getName());
970           AccessControlService.BlockingInterface protocol =
971             AccessControlService.newBlockingStub(service);
972           ProtobufUtil.getUserPermissions(protocol, TEST_TABLE.getTableName());
973         } finally {
974           acl.close();
975         }
976         return null;
977       }
978     };
979 
980     verifyAllowed(grantAction, SUPERUSER, USER_ADMIN, USER_OWNER);
981     verifyDenied(grantAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
982 
983     verifyAllowed(revokeAction, SUPERUSER, USER_ADMIN, USER_OWNER);
984     verifyDenied(revokeAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
985 
986     verifyAllowed(getPermissionsAction, SUPERUSER, USER_ADMIN, USER_OWNER);
987     verifyDenied(getPermissionsAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
988   }
989 
990   @Test
991   public void testPostGrantRevoke() throws Exception {
992     final TableName tableName =
993         TableName.valueOf("TempTable");
994     final byte[] family1 = Bytes.toBytes("f1");
995     final byte[] family2 = Bytes.toBytes("f2");
996     final byte[] qualifier = Bytes.toBytes("q");
997 
998     // create table
999     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
1000     if (admin.tableExists(tableName)) {
1001       admin.disableTable(tableName);
1002       admin.deleteTable(tableName);
1003     }
1004     HTableDescriptor htd = new HTableDescriptor(tableName);
1005     htd.addFamily(new HColumnDescriptor(family1));
1006     htd.addFamily(new HColumnDescriptor(family2));
1007     admin.createTable(htd);
1008 
1009     // create temp users
1010     User tblUser = User
1011         .createUserForTesting(TEST_UTIL.getConfiguration(), "tbluser", new String[0]);
1012     User gblUser = User
1013         .createUserForTesting(TEST_UTIL.getConfiguration(), "gbluser", new String[0]);
1014 
1015     // prepare actions:
1016     PrivilegedExceptionAction putActionAll = new PrivilegedExceptionAction() {
1017       public Object run() throws Exception {
1018         Put p = new Put(Bytes.toBytes("a"));
1019         p.add(family1, qualifier, Bytes.toBytes("v1"));
1020         p.add(family2, qualifier, Bytes.toBytes("v2"));
1021         HTable t = new HTable(conf, tableName);
1022         try {
1023           t.put(p);
1024         } finally {
1025           t.close();
1026         }
1027         return null;
1028       }
1029     };
1030     PrivilegedExceptionAction putAction1 = new PrivilegedExceptionAction() {
1031       public Object run() throws Exception {
1032         Put p = new Put(Bytes.toBytes("a"));
1033         p.add(family1, qualifier, Bytes.toBytes("v1"));
1034         HTable t = new HTable(conf, tableName);
1035         try {
1036           t.put(p);
1037         } finally {
1038           t.close();
1039         }
1040         return null;
1041       }
1042     };
1043     PrivilegedExceptionAction putAction2 = new PrivilegedExceptionAction() {
1044       public Object run() throws Exception {
1045         Put p = new Put(Bytes.toBytes("a"));
1046         p.add(family2, qualifier, Bytes.toBytes("v2"));
1047         HTable t = new HTable(conf, tableName);
1048         try {
1049           t.put(p);
1050         } finally {
1051           t.close();
1052         }
1053         return null;
1054       }
1055     };
1056     PrivilegedExceptionAction getActionAll = new PrivilegedExceptionAction() {
1057       public Object run() throws Exception {
1058         Get g = new Get(Bytes.toBytes("random_row"));
1059         g.addFamily(family1);
1060         g.addFamily(family2);
1061         HTable t = new HTable(conf, tableName);
1062         try {
1063           t.get(g);
1064         } finally {
1065           t.close();
1066         }
1067         return null;
1068       }
1069     };
1070     PrivilegedExceptionAction getAction1 = new PrivilegedExceptionAction() {
1071       public Object run() throws Exception {
1072         Get g = new Get(Bytes.toBytes("random_row"));
1073         g.addFamily(family1);
1074         HTable t = new HTable(conf, tableName);
1075         try {
1076           t.get(g);
1077         } finally {
1078           t.close();
1079         }
1080         return null;
1081       }
1082     };
1083     PrivilegedExceptionAction getAction2 = new PrivilegedExceptionAction() {
1084       public Object run() throws Exception {
1085         Get g = new Get(Bytes.toBytes("random_row"));
1086         g.addFamily(family2);
1087         HTable t = new HTable(conf, tableName);
1088         try {
1089           t.get(g);
1090         } finally {
1091           t.close();
1092         }
1093         return null;
1094       }
1095     };
1096     PrivilegedExceptionAction deleteActionAll = new PrivilegedExceptionAction() {
1097       public Object run() throws Exception {
1098         Delete d = new Delete(Bytes.toBytes("random_row"));
1099         d.deleteFamily(family1);
1100         d.deleteFamily(family2);
1101         HTable t = new HTable(conf, tableName);
1102         try {
1103           t.delete(d);
1104         } finally {
1105           t.close();
1106         }
1107         return null;
1108       }
1109     };
1110     PrivilegedExceptionAction deleteAction1 = new PrivilegedExceptionAction() {
1111       public Object run() throws Exception {
1112         Delete d = new Delete(Bytes.toBytes("random_row"));
1113         d.deleteFamily(family1);
1114         HTable t = new HTable(conf, tableName);
1115         try {
1116           t.delete(d);
1117         } finally {
1118           t.close();
1119         }
1120         return null;
1121       }
1122     };
1123     PrivilegedExceptionAction deleteAction2 = new PrivilegedExceptionAction() {
1124       public Object run() throws Exception {
1125         Delete d = new Delete(Bytes.toBytes("random_row"));
1126         d.deleteFamily(family2);
1127         HTable t = new HTable(conf, tableName);
1128         try {
1129           t.delete(d);
1130         } finally {
1131           t.close();
1132         }
1133         return null;
1134       }
1135     };
1136 
1137     // initial check:
1138     verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1139     verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1140     verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1141 
1142     verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1143     verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1144     verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1145 
1146     // grant table read permission
1147     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1148     try {
1149       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1150       AccessControlService.BlockingInterface protocol =
1151         AccessControlService.newBlockingStub(service);
1152       ProtobufUtil.grant(protocol, tblUser.getShortName(),
1153         tableName, null, null, Permission.Action.READ);
1154       ProtobufUtil.grant(protocol, gblUser.getShortName(),
1155           Permission.Action.READ);
1156     } finally {
1157       acl.close();
1158     }
1159 
1160     Thread.sleep(100);
1161     // check
1162     verifyAllowed(tblUser, getActionAll, getAction1, getAction2);
1163     verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1164     verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1165 
1166     verifyAllowed(gblUser, getActionAll, getAction1, getAction2);
1167     verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1168     verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1169 
1170     // grant table write permission
1171     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1172     try {
1173       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1174       AccessControlService.BlockingInterface protocol =
1175         AccessControlService.newBlockingStub(service);
1176       ProtobufUtil.grant(protocol, tblUser.getShortName(),
1177         tableName, null, null, Permission.Action.WRITE);
1178       ProtobufUtil.grant(protocol, gblUser.getShortName(),
1179           Permission.Action.WRITE);
1180     } finally {
1181       acl.close();
1182     }
1183 
1184     Thread.sleep(100);
1185 
1186     verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1187     verifyAllowed(tblUser, putActionAll, putAction1, putAction2);
1188     verifyAllowed(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1189 
1190     verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1191     verifyAllowed(gblUser, putActionAll, putAction1, putAction2);
1192     verifyAllowed(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1193 
1194     // revoke table permission
1195     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1196     try {
1197       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1198       AccessControlService.BlockingInterface protocol =
1199         AccessControlService.newBlockingStub(service);
1200       ProtobufUtil.grant(protocol, tblUser.getShortName(), tableName, null, null,
1201         Permission.Action.READ, Permission.Action.WRITE);
1202       ProtobufUtil.revoke(protocol, tblUser.getShortName(), tableName, null, null);
1203       ProtobufUtil.revoke(protocol, gblUser.getShortName());
1204     } finally {
1205       acl.close();
1206     }
1207 
1208     Thread.sleep(100);
1209 
1210     verifyDenied(tblUser, getActionAll, getAction1, getAction2);
1211     verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1212     verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1213 
1214     verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1215     verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1216     verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1217 
1218     // grant column family read permission
1219     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1220     try {
1221       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1222       AccessControlService.BlockingInterface protocol =
1223         AccessControlService.newBlockingStub(service);
1224       ProtobufUtil.grant(protocol, tblUser.getShortName(),
1225         tableName, family1, null, Permission.Action.READ);
1226       ProtobufUtil.grant(protocol, gblUser.getShortName(),
1227           Permission.Action.READ);
1228     } finally {
1229       acl.close();
1230     }
1231 
1232     Thread.sleep(100);
1233 
1234     // Access should be denied for family2
1235     verifyAllowed(tblUser, getActionAll, getAction1);
1236     verifyDenied(tblUser, getAction2);
1237     verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1238     verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1239 
1240     verifyAllowed(gblUser, getActionAll, getAction1, getAction2);
1241     verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1242     verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1243 
1244     // grant column family write permission
1245     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1246     try {
1247       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1248       AccessControlService.BlockingInterface protocol =
1249         AccessControlService.newBlockingStub(service);
1250       ProtobufUtil.grant(protocol, tblUser.getShortName(),
1251         tableName, family2, null, Permission.Action.WRITE);
1252       ProtobufUtil.grant(protocol, gblUser.getShortName(),
1253           Permission.Action.WRITE);
1254     } finally {
1255       acl.close();
1256     }
1257 
1258     Thread.sleep(100);
1259 
1260     // READ from family1, WRITE to family2 are allowed
1261     verifyAllowed(tblUser, getActionAll, getAction1);
1262     verifyAllowed(tblUser, putAction2, deleteAction2);
1263     verifyDenied(tblUser, getAction2);
1264     verifyDenied(tblUser, putActionAll, putAction1);
1265     verifyDenied(tblUser, deleteActionAll, deleteAction1);
1266 
1267     verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1268     verifyAllowed(gblUser, putActionAll, putAction1, putAction2);
1269     verifyAllowed(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1270 
1271     // revoke column family permission
1272     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1273     try {
1274       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1275       AccessControlService.BlockingInterface protocol =
1276         AccessControlService.newBlockingStub(service);
1277       ProtobufUtil.revoke(protocol, tblUser.getShortName(), tableName, family2, null);
1278       ProtobufUtil.revoke(protocol, gblUser.getShortName());
1279     } finally {
1280       acl.close();
1281     }
1282 
1283     Thread.sleep(100);
1284 
1285     // Revoke on family2 should not have impact on family1 permissions
1286     verifyAllowed(tblUser, getActionAll, getAction1);
1287     verifyDenied(tblUser, getAction2);
1288     verifyDenied(tblUser, putActionAll, putAction1, putAction2);
1289     verifyDenied(tblUser, deleteActionAll, deleteAction1, deleteAction2);
1290 
1291     // Should not have access as global permissions are completely revoked
1292     verifyDenied(gblUser, getActionAll, getAction1, getAction2);
1293     verifyDenied(gblUser, putActionAll, putAction1, putAction2);
1294     verifyDenied(gblUser, deleteActionAll, deleteAction1, deleteAction2);
1295 
1296     // delete table
1297     admin.disableTable(tableName);
1298     admin.deleteTable(tableName);
1299   }
1300 
1301   private boolean hasFoundUserPermission(UserPermission userPermission, List<UserPermission> perms) {
1302     return perms.contains(userPermission);
1303   }
1304 
1305   @Test
1306   public void testPostGrantRevokeAtQualifierLevel() throws Exception {
1307     final TableName tableName =
1308         TableName.valueOf("testGrantRevokeAtQualifierLevel");
1309     final byte[] family1 = Bytes.toBytes("f1");
1310     final byte[] family2 = Bytes.toBytes("f2");
1311     final byte[] qualifier = Bytes.toBytes("q");
1312 
1313     // create table
1314     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
1315     if (admin.tableExists(tableName)) {
1316       admin.disableTable(tableName);
1317       admin.deleteTable(tableName);
1318     }
1319     HTableDescriptor htd = new HTableDescriptor(tableName);
1320     htd.addFamily(new HColumnDescriptor(family1));
1321     htd.addFamily(new HColumnDescriptor(family2));
1322     admin.createTable(htd);
1323 
1324     // create temp users
1325     User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "user", new String[0]);
1326 
1327     PrivilegedExceptionAction getQualifierAction = new PrivilegedExceptionAction() {
1328       public Object run() throws Exception {
1329         Get g = new Get(Bytes.toBytes("random_row"));
1330         g.addColumn(family1, qualifier);
1331         HTable t = new HTable(conf, tableName);
1332         try {
1333           t.get(g);
1334         } finally {
1335           t.close();
1336         }
1337         return null;
1338       }
1339     };
1340     PrivilegedExceptionAction putQualifierAction = new PrivilegedExceptionAction() {
1341       public Object run() throws Exception {
1342         Put p = new Put(Bytes.toBytes("random_row"));
1343         p.add(family1, qualifier, Bytes.toBytes("v1"));
1344         HTable t = new HTable(conf, tableName);
1345         try {
1346           t.put(p);
1347         } finally {
1348           t.close();
1349         }
1350         return null;
1351       }
1352     };
1353     PrivilegedExceptionAction deleteQualifierAction = new PrivilegedExceptionAction() {
1354       public Object run() throws Exception {
1355         Delete d = new Delete(Bytes.toBytes("random_row"));
1356         d.deleteColumn(family1, qualifier);
1357         // d.deleteFamily(family1);
1358         HTable t = new HTable(conf, tableName);
1359         try {
1360           t.delete(d);
1361         } finally {
1362           t.close();
1363         }
1364         return null;
1365       }
1366     };
1367 
1368     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1369     try {
1370       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1371       AccessControlService.BlockingInterface protocol =
1372         AccessControlService.newBlockingStub(service);
1373       ProtobufUtil.revoke(protocol, user.getShortName(), tableName, family1, null);
1374     } finally {
1375       acl.close();
1376     }
1377 
1378     Thread.sleep(100);
1379 
1380     verifyDenied(user, getQualifierAction);
1381     verifyDenied(user, putQualifierAction);
1382     verifyDenied(user, deleteQualifierAction);
1383 
1384     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1385     try {
1386       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1387       AccessControlService.BlockingInterface protocol =
1388         AccessControlService.newBlockingStub(service);
1389       ProtobufUtil.grant(protocol, user.getShortName(),
1390         tableName, family1, qualifier, Permission.Action.READ);
1391     } finally {
1392       acl.close();
1393     }
1394 
1395     Thread.sleep(100);
1396 
1397     verifyAllowed(user, getQualifierAction);
1398     verifyDenied(user, putQualifierAction);
1399     verifyDenied(user, deleteQualifierAction);
1400 
1401     // only grant write permission
1402     // TODO: comment this portion after HBASE-3583
1403     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1404     try {
1405       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1406       AccessControlService.BlockingInterface protocol =
1407         AccessControlService.newBlockingStub(service);
1408       ProtobufUtil.grant(protocol, user.getShortName(),
1409         tableName, family1, qualifier, Permission.Action.WRITE);
1410     } finally {
1411       acl.close();
1412     }
1413 
1414     Thread.sleep(100);
1415 
1416     verifyDenied(user, getQualifierAction);
1417     verifyAllowed(user, putQualifierAction);
1418     verifyAllowed(user, deleteQualifierAction);
1419 
1420     // grant both read and write permission.
1421     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1422     try {
1423       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1424       AccessControlService.BlockingInterface protocol =
1425         AccessControlService.newBlockingStub(service);
1426       ProtobufUtil.grant(protocol, user.getShortName(),
1427         tableName, family1, qualifier,
1428           Permission.Action.READ, Permission.Action.WRITE);
1429     } finally {
1430       acl.close();
1431     }
1432 
1433     Thread.sleep(100);
1434 
1435     verifyAllowed(user, getQualifierAction);
1436     verifyAllowed(user, putQualifierAction);
1437     verifyAllowed(user, deleteQualifierAction);
1438 
1439     // revoke family level permission won't impact column level.
1440     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1441     try {
1442       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1443       AccessControlService.BlockingInterface protocol =
1444         AccessControlService.newBlockingStub(service);
1445       ProtobufUtil.revoke(protocol, user.getShortName(),
1446         tableName, family1, qualifier);
1447     } finally {
1448       acl.close();
1449     }
1450 
1451     Thread.sleep(100);
1452 
1453     verifyDenied(user, getQualifierAction);
1454     verifyDenied(user, putQualifierAction);
1455     verifyDenied(user, deleteQualifierAction);
1456 
1457     // delete table
1458     admin.disableTable(tableName);
1459     admin.deleteTable(tableName);
1460   }
1461 
1462   @Test
1463   public void testPermissionList() throws Exception {
1464     final TableName tableName =
1465         TableName.valueOf("testPermissionList");
1466     final byte[] family1 = Bytes.toBytes("f1");
1467     final byte[] family2 = Bytes.toBytes("f2");
1468     final byte[] qualifier = Bytes.toBytes("q");
1469 
1470     // create table
1471     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
1472     if (admin.tableExists(tableName)) {
1473       admin.disableTable(tableName);
1474       admin.deleteTable(tableName);
1475     }
1476     HTableDescriptor htd = new HTableDescriptor(tableName);
1477     htd.addFamily(new HColumnDescriptor(family1));
1478     htd.addFamily(new HColumnDescriptor(family2));
1479     htd.setOwner(USER_OWNER);
1480     admin.createTable(htd);
1481 
1482     List<UserPermission> perms;
1483 
1484     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1485     try {
1486       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1487       AccessControlService.BlockingInterface protocol =
1488         AccessControlService.newBlockingStub(service);
1489       perms = ProtobufUtil.getUserPermissions(protocol, tableName);
1490     } finally {
1491       acl.close();
1492     }
1493 
1494     UserPermission ownerperm = new UserPermission(
1495       Bytes.toBytes(USER_OWNER.getName()), tableName, null, Action.values());
1496     assertTrue("Owner should have all permissions on table",
1497       hasFoundUserPermission(ownerperm, perms));
1498 
1499     User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "user", new String[0]);
1500     byte[] userName = Bytes.toBytes(user.getShortName());
1501 
1502     UserPermission up = new UserPermission(userName,
1503       tableName, family1, qualifier, Permission.Action.READ);
1504     assertFalse("User should not be granted permission: " + up.toString(),
1505       hasFoundUserPermission(up, perms));
1506 
1507     // grant read permission
1508     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1509     try {
1510       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1511       AccessControlService.BlockingInterface protocol =
1512         AccessControlService.newBlockingStub(service);
1513       ProtobufUtil.grant(protocol, user.getShortName(),
1514         tableName, family1, qualifier, Permission.Action.READ);
1515       perms = ProtobufUtil.getUserPermissions(protocol, tableName);
1516     } finally {
1517       acl.close();
1518     }
1519 
1520     UserPermission upToVerify = new UserPermission(
1521       userName, tableName, family1, qualifier, Permission.Action.READ);
1522     assertTrue("User should be granted permission: " + upToVerify.toString(),
1523       hasFoundUserPermission(upToVerify, perms));
1524 
1525     upToVerify = new UserPermission(
1526       userName, tableName, family1, qualifier, Permission.Action.WRITE);
1527     assertFalse("User should not be granted permission: " + upToVerify.toString(),
1528       hasFoundUserPermission(upToVerify, perms));
1529 
1530     // grant read+write
1531     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1532     try {
1533       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1534       AccessControlService.BlockingInterface protocol =
1535         AccessControlService.newBlockingStub(service);
1536       ProtobufUtil.grant(protocol, user.getShortName(),
1537         tableName, family1, qualifier,
1538           Permission.Action.WRITE, Permission.Action.READ);
1539       perms = ProtobufUtil.getUserPermissions(protocol, tableName);
1540     } finally {
1541       acl.close();
1542     }
1543 
1544     upToVerify = new UserPermission(userName, tableName, family1,
1545       qualifier, Permission.Action.WRITE, Permission.Action.READ);
1546     assertTrue("User should be granted permission: " + upToVerify.toString(),
1547       hasFoundUserPermission(upToVerify, perms));
1548 
1549     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1550     try {
1551       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1552       AccessControlService.BlockingInterface protocol =
1553         AccessControlService.newBlockingStub(service);
1554       ProtobufUtil.revoke(protocol, user.getShortName(), tableName, family1, qualifier,
1555         Permission.Action.WRITE, Permission.Action.READ);
1556       perms = ProtobufUtil.getUserPermissions(protocol, tableName);
1557     } finally {
1558       acl.close();
1559     }
1560 
1561     assertFalse("User should not be granted permission: " + upToVerify.toString(),
1562       hasFoundUserPermission(upToVerify, perms));
1563 
1564     // disable table before modification
1565     admin.disableTable(tableName);
1566 
1567     User newOwner = User.createUserForTesting(conf, "new_owner", new String[] {});
1568     htd.setOwner(newOwner);
1569     admin.modifyTable(tableName, htd);
1570 
1571     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1572     try {
1573       BlockingRpcChannel service = acl.coprocessorService(tableName.getName());
1574       AccessControlService.BlockingInterface protocol =
1575         AccessControlService.newBlockingStub(service);
1576       perms = ProtobufUtil.getUserPermissions(protocol, tableName);
1577     } finally {
1578       acl.close();
1579     }
1580 
1581     UserPermission newOwnerperm = new UserPermission(
1582       Bytes.toBytes(newOwner.getName()), tableName, null, Action.values());
1583     assertTrue("New owner should have all permissions on table",
1584       hasFoundUserPermission(newOwnerperm, perms));
1585 
1586     // delete table
1587     admin.deleteTable(tableName);
1588   }
1589 
1590   @Test
1591   public void testGlobalPermissionList() throws Exception {
1592     List<UserPermission> perms;
1593     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1594     try {
1595       BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
1596       AccessControlService.BlockingInterface protocol =
1597         AccessControlService.newBlockingStub(service);
1598       perms = ProtobufUtil.getUserPermissions(protocol);
1599     } finally {
1600       acl.close();
1601     }
1602     UserPermission adminPerm = new UserPermission(Bytes.toBytes(USER_ADMIN.getShortName()),
1603       AccessControlLists.ACL_TABLE_NAME, null, null, Bytes.toBytes("ACRW"));
1604     assertTrue("Only user admin has permission on table _acl_ per setup",
1605       perms.size() == 1 && hasFoundUserPermission(adminPerm, perms));
1606   }
1607 
1608   /** global operations */
1609   private void verifyGlobal(PrivilegedExceptionAction<?> action) throws Exception {
1610     verifyAllowed(action, SUPERUSER);
1611 
1612     verifyDenied(action, USER_CREATE, USER_RW, USER_NONE, USER_RO);
1613   }
1614 
1615   public void checkGlobalPerms(Permission.Action... actions) throws IOException {
1616     Permission[] perms = new Permission[actions.length];
1617     for (int i = 0; i < actions.length; i++) {
1618       perms[i] = new Permission(actions[i]);
1619     }
1620     CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
1621     for (Action a : actions) {
1622       request.addPermission(AccessControlProtos.Permission.newBuilder()
1623           .setType(AccessControlProtos.Permission.Type.Global)
1624           .setGlobalPermission(
1625               AccessControlProtos.GlobalPermission.newBuilder()
1626                   .addAction(ProtobufUtil.toPermissionAction(a)).build()));
1627     }
1628     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1629     try {
1630       BlockingRpcChannel channel = acl.coprocessorService(new byte[0]);
1631       AccessControlService.BlockingInterface protocol =
1632         AccessControlService.newBlockingStub(channel);
1633       try {
1634         protocol.checkPermissions(null, request.build());
1635       } catch (ServiceException se) {
1636         ProtobufUtil.toIOException(se);
1637       }
1638     } finally {
1639       acl.close();
1640     }
1641   }
1642 
1643   public void checkTablePerms(TableName table, byte[] family, byte[] column,
1644       Permission.Action... actions) throws IOException {
1645     Permission[] perms = new Permission[actions.length];
1646     for (int i = 0; i < actions.length; i++) {
1647       perms[i] = new TablePermission(table, family, column, actions[i]);
1648     }
1649 
1650     checkTablePerms(table, perms);
1651   }
1652 
1653   public void checkTablePerms(TableName table, Permission... perms) throws IOException {
1654     CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
1655     for (Permission p : perms) {
1656       request.addPermission(ProtobufUtil.toPermission(p));
1657     }
1658     HTable acl = new HTable(conf, table);
1659     try {
1660       AccessControlService.BlockingInterface protocol =
1661         AccessControlService.newBlockingStub(acl.coprocessorService(new byte[0]));
1662       try {
1663         protocol.checkPermissions(null, request.build());
1664       } catch (ServiceException se) {
1665         ProtobufUtil.toIOException(se);
1666       }
1667     } finally {
1668       acl.close();
1669     }
1670   }
1671 
1672   @Test
1673   public void testCheckPermissions() throws Exception {
1674     // --------------------------------------
1675     // test global permissions
1676     PrivilegedExceptionAction<Void> globalAdmin = new PrivilegedExceptionAction<Void>() {
1677       @Override
1678       public Void run() throws Exception {
1679         checkGlobalPerms(Permission.Action.ADMIN);
1680         return null;
1681       }
1682     };
1683     // verify that only superuser can admin
1684     verifyGlobal(globalAdmin);
1685 
1686     // --------------------------------------
1687     // test multiple permissions
1688     PrivilegedExceptionAction<Void> globalReadWrite = new PrivilegedExceptionAction<Void>() {
1689       @Override
1690       public Void run() throws Exception {
1691         checkGlobalPerms(Permission.Action.READ, Permission.Action.WRITE);
1692         return null;
1693       }
1694     };
1695 
1696     verifyGlobal(globalReadWrite);
1697 
1698     // --------------------------------------
1699     // table/column/qualifier level permissions
1700     final byte[] TEST_Q1 = Bytes.toBytes("q1");
1701     final byte[] TEST_Q2 = Bytes.toBytes("q2");
1702 
1703     User userTable = User.createUserForTesting(conf, "user_check_perms_table", new String[0]);
1704     User userColumn = User.createUserForTesting(conf, "user_check_perms_family", new String[0]);
1705     User userQualifier = User.createUserForTesting(conf, "user_check_perms_q", new String[0]);
1706 
1707     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1708     try {
1709       BlockingRpcChannel channel = acl.coprocessorService(new byte[0]);
1710       AccessControlService.BlockingInterface protocol =
1711         AccessControlService.newBlockingStub(channel);
1712       ProtobufUtil.grant(protocol, userTable.getShortName(),
1713         TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
1714       ProtobufUtil.grant(protocol, userColumn.getShortName(),
1715         TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ);
1716       ProtobufUtil.grant(protocol, userQualifier.getShortName(),
1717         TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1, Permission.Action.READ);
1718     } finally {
1719       acl.close();
1720     }
1721 
1722     PrivilegedExceptionAction<Void> tableRead = new PrivilegedExceptionAction<Void>() {
1723       @Override
1724       public Void run() throws Exception {
1725         checkTablePerms(TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
1726         return null;
1727       }
1728     };
1729 
1730     PrivilegedExceptionAction<Void> columnRead = new PrivilegedExceptionAction<Void>() {
1731       @Override
1732       public Void run() throws Exception {
1733         checkTablePerms(TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ);
1734         return null;
1735       }
1736     };
1737 
1738     PrivilegedExceptionAction<Void> qualifierRead = new PrivilegedExceptionAction<Void>() {
1739       @Override
1740       public Void run() throws Exception {
1741         checkTablePerms(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1, Permission.Action.READ);
1742         return null;
1743       }
1744     };
1745 
1746     PrivilegedExceptionAction<Void> multiQualifierRead = new PrivilegedExceptionAction<Void>() {
1747       @Override
1748       public Void run() throws Exception {
1749         checkTablePerms(TEST_TABLE.getTableName(), new Permission[] {
1750             new TablePermission(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q1, Permission.Action.READ),
1751             new TablePermission(TEST_TABLE.getTableName(), TEST_FAMILY, TEST_Q2, Permission.Action.READ), });
1752         return null;
1753       }
1754     };
1755 
1756     PrivilegedExceptionAction<Void> globalAndTableRead = new PrivilegedExceptionAction<Void>() {
1757       @Override
1758       public Void run() throws Exception {
1759         checkTablePerms(TEST_TABLE.getTableName(), new Permission[] { new Permission(Permission.Action.READ),
1760             new TablePermission(TEST_TABLE.getTableName(), null, (byte[]) null, Permission.Action.READ), });
1761         return null;
1762       }
1763     };
1764 
1765     PrivilegedExceptionAction<Void> noCheck = new PrivilegedExceptionAction<Void>() {
1766       @Override
1767       public Void run() throws Exception {
1768         checkTablePerms(TEST_TABLE.getTableName(), new Permission[0]);
1769         return null;
1770       }
1771     };
1772 
1773     verifyAllowed(tableRead, SUPERUSER, userTable);
1774     verifyDenied(tableRead, userColumn, userQualifier);
1775 
1776     verifyAllowed(columnRead, SUPERUSER, userTable, userColumn);
1777     verifyDenied(columnRead, userQualifier);
1778 
1779     verifyAllowed(qualifierRead, SUPERUSER, userTable, userColumn, userQualifier);
1780 
1781     verifyAllowed(multiQualifierRead, SUPERUSER, userTable, userColumn);
1782     verifyDenied(multiQualifierRead, userQualifier);
1783 
1784     verifyAllowed(globalAndTableRead, SUPERUSER);
1785     verifyDenied(globalAndTableRead, userTable, userColumn, userQualifier);
1786 
1787     verifyAllowed(noCheck, SUPERUSER, userTable, userColumn, userQualifier);
1788 
1789     // --------------------------------------
1790     // test family level multiple permissions
1791     PrivilegedExceptionAction<Void> familyReadWrite = new PrivilegedExceptionAction<Void>() {
1792       @Override
1793       public Void run() throws Exception {
1794         checkTablePerms(TEST_TABLE.getTableName(), TEST_FAMILY, null, Permission.Action.READ,
1795           Permission.Action.WRITE);
1796         return null;
1797       }
1798     };
1799 
1800     verifyAllowed(familyReadWrite, SUPERUSER, USER_OWNER, USER_CREATE, USER_RW);
1801     verifyDenied(familyReadWrite, USER_NONE, USER_RO);
1802 
1803     // --------------------------------------
1804     // check for wrong table region
1805     CheckPermissionsRequest checkRequest = CheckPermissionsRequest.newBuilder()
1806       .addPermission(AccessControlProtos.Permission.newBuilder()
1807           .setType(AccessControlProtos.Permission.Type.Table)
1808           .setTablePermission(
1809               AccessControlProtos.TablePermission.newBuilder()
1810                   .setTableName(ProtobufUtil.toProtoTableName(TEST_TABLE.getTableName()))
1811                   .addAction(AccessControlProtos.Permission.Action.CREATE))
1812       ).build();
1813     acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1814     try {
1815       BlockingRpcChannel channel = acl.coprocessorService(new byte[0]);
1816       AccessControlService.BlockingInterface protocol =
1817         AccessControlService.newBlockingStub(channel);
1818       try {
1819         // but ask for TablePermissions for TEST_TABLE
1820         protocol.checkPermissions(null, checkRequest);
1821         fail("this should have thrown CoprocessorException");
1822       } catch (ServiceException ex) {
1823         // expected
1824       }
1825     } finally {
1826       acl.close();
1827     }
1828   }
1829 
1830   @Test
1831   public void testStopRegionServer() throws Exception {
1832     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
1833       public Object run() throws Exception {
1834         ACCESS_CONTROLLER.preStopRegionServer(ObserverContext.createAndPrepare(RSCP_ENV, null));
1835         return null;
1836       }
1837     };
1838 
1839     verifyAllowed(action, SUPERUSER, USER_ADMIN);
1840     verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE);
1841   }
1842 
1843   @Test
1844   public void testOpenRegion() throws Exception {
1845     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
1846       public Object run() throws Exception {
1847         ACCESS_CONTROLLER.preOpen(ObserverContext.createAndPrepare(RCP_ENV, null));
1848         return null;
1849       }
1850     };
1851 
1852     verifyAllowed(action, SUPERUSER, USER_ADMIN);
1853     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1854   }
1855 
1856   @Test
1857   public void testCloseRegion() throws Exception {
1858     PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
1859       public Object run() throws Exception {
1860         ACCESS_CONTROLLER.preClose(ObserverContext.createAndPrepare(RCP_ENV, null), false);
1861         return null;
1862       }
1863     };
1864 
1865     verifyAllowed(action, SUPERUSER, USER_ADMIN);
1866     verifyDenied(action, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1867   }
1868 
1869   @Test
1870   public void testSnapshot() throws Exception {
1871     PrivilegedExceptionAction snapshotAction = new PrivilegedExceptionAction() {
1872       public Object run() throws Exception {
1873         ACCESS_CONTROLLER.preSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
1874           null, null);
1875         return null;
1876       }
1877     };
1878 
1879     PrivilegedExceptionAction deleteAction = new PrivilegedExceptionAction() {
1880       public Object run() throws Exception {
1881         ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
1882           null);
1883         return null;
1884       }
1885     };
1886 
1887     PrivilegedExceptionAction restoreAction = new PrivilegedExceptionAction() {
1888       public Object run() throws Exception {
1889         ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
1890           null, null);
1891         return null;
1892       }
1893     };
1894 
1895     PrivilegedExceptionAction cloneAction = new PrivilegedExceptionAction() {
1896       public Object run() throws Exception {
1897         ACCESS_CONTROLLER.preCloneSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
1898           null, null);
1899         return null;
1900       }
1901     };
1902 
1903     verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN);
1904     verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1905 
1906     verifyAllowed(cloneAction, SUPERUSER, USER_ADMIN);
1907     verifyDenied(deleteAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1908 
1909     verifyAllowed(restoreAction, SUPERUSER, USER_ADMIN);
1910     verifyDenied(restoreAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1911 
1912     verifyAllowed(deleteAction, SUPERUSER, USER_ADMIN);
1913     verifyDenied(cloneAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
1914   }
1915 
1916   @Test
1917   public void testGlobalAuthorizationForNewRegisteredRS() throws Exception {
1918     LOG.debug("Test for global authorization for a new registered RegionServer.");
1919     MiniHBaseCluster hbaseCluster = TEST_UTIL.getHBaseCluster();
1920 
1921     // Since each RegionServer running on different user, add global
1922     // permissions for the new user.
1923     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
1924     try {
1925       BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getTableName().getName());
1926       AccessControlService.BlockingInterface protocol =
1927         AccessControlService.newBlockingStub(service);
1928       String currentUser = User.getCurrent().getShortName();
1929       // User name for the new RegionServer we plan to add.
1930       String activeUserForNewRs = currentUser + ".hfs."
1931           + hbaseCluster.getLiveRegionServerThreads().size();
1932       ProtobufUtil.grant(protocol, activeUserForNewRs,
1933         Permission.Action.ADMIN, Permission.Action.CREATE,
1934         Permission.Action.READ, Permission.Action.WRITE);
1935     } finally {
1936       acl.close();
1937     }
1938     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
1939     HTableDescriptor htd = new HTableDescriptor(TEST_TABLE2);
1940     htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
1941     admin.createTable(htd);
1942 
1943     // Starting a new RegionServer.
1944     JVMClusterUtil.RegionServerThread newRsThread = hbaseCluster
1945         .startRegionServer();
1946     final HRegionServer newRs = newRsThread.getRegionServer();
1947 
1948     // Move region to the new RegionServer.
1949     HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE2);
1950     try {
1951       NavigableMap<HRegionInfo, ServerName> regions = table
1952           .getRegionLocations();
1953       final Map.Entry<HRegionInfo, ServerName> firstRegion = regions.entrySet()
1954           .iterator().next();
1955 
1956       PrivilegedExceptionAction moveAction = new PrivilegedExceptionAction() {
1957         public Object run() throws Exception {
1958           HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
1959           admin.move(firstRegion.getKey().getEncodedNameAsBytes(),
1960               Bytes.toBytes(newRs.getServerName().getServerName()));
1961           return null;
1962         }
1963       };
1964       SUPERUSER.runAs(moveAction);
1965 
1966       final int RETRIES_LIMIT = 10;
1967       int retries = 0;
1968       while (newRs.getOnlineRegions(TEST_TABLE2).size() < 1 && retries < RETRIES_LIMIT) {
1969         LOG.debug("Waiting for region to be opened. Already retried " + retries
1970             + " times.");
1971         try {
1972           Thread.sleep(1000);
1973         } catch (InterruptedException e) {
1974         }
1975         retries++;
1976         if (retries == RETRIES_LIMIT - 1) {
1977           fail("Retry exhaust for waiting region to be opened.");
1978         }
1979       }
1980       // Verify write permission for user "admin2" who has the global
1981       // permissions.
1982       PrivilegedExceptionAction putAction = new PrivilegedExceptionAction() {
1983         public Object run() throws Exception {
1984           HTable table = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE2);
1985           Put put = new Put(Bytes.toBytes("test"));
1986           put.add(TEST_FAMILY, Bytes.toBytes("qual"), Bytes.toBytes("value"));
1987           table.put(put);
1988           return null;
1989         }
1990       };
1991       USER_ADMIN.runAs(putAction);
1992     } finally {
1993       table.close();
1994     }
1995   }
1996 
1997   @Test
1998   public void testTableDescriptorsEnumeration() throws Exception {
1999     User TABLE_ADMIN = User.createUserForTesting(conf, "UserA", new String[0]);
2000 
2001     // Grant TABLE ADMIN privs
2002     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
2003     try {
2004       BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getTableName().getName());
2005       AccessControlService.BlockingInterface protocol =
2006         AccessControlService.newBlockingStub(service);
2007       ProtobufUtil.grant(protocol, TABLE_ADMIN.getShortName(), TEST_TABLE.getTableName(),
2008         null, null, Permission.Action.ADMIN);
2009     } finally {
2010       acl.close();
2011     }
2012 
2013     PrivilegedExceptionAction listTablesAction = new PrivilegedExceptionAction() {
2014       public Object run() throws Exception {
2015         HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
2016         try {
2017           admin.listTables();
2018         } finally {
2019           admin.close();
2020         }
2021         return null;
2022       }
2023     };
2024 
2025     PrivilegedExceptionAction getTableDescAction = new PrivilegedExceptionAction() {
2026       public Object run() throws Exception {
2027         HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
2028         try {
2029           admin.getTableDescriptor(TEST_TABLE.getTableName());
2030         } finally {
2031           admin.close();
2032         }
2033         return null;
2034       }
2035     };
2036 
2037     verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN);
2038     verifyDenied(listTablesAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, TABLE_ADMIN);
2039 
2040     verifyAllowed(getTableDescAction, SUPERUSER, USER_ADMIN, USER_CREATE, TABLE_ADMIN);
2041     verifyDenied(getTableDescAction, USER_RW, USER_RO, USER_NONE);
2042   }
2043 
2044   @Test
2045   public void testTableDeletion() throws Exception {
2046     User TABLE_ADMIN = User.createUserForTesting(conf, "TestUser", new String[0]);
2047 
2048     // Grant TABLE ADMIN privs
2049     HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
2050     try {
2051       BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getTableName().getName());
2052       AccessControlService.BlockingInterface protocol =
2053         AccessControlService.newBlockingStub(service);
2054       ProtobufUtil.grant(protocol, TABLE_ADMIN.getShortName(), TEST_TABLE.getTableName(),
2055         null, null, Permission.Action.ADMIN);
2056     } finally {
2057       acl.close();
2058     }
2059 
2060     PrivilegedExceptionAction deleteTableAction = new PrivilegedExceptionAction() {
2061       public Object run() throws Exception {
2062         HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
2063         try {
2064           admin.disableTable(TEST_TABLE.getTableName());
2065           admin.deleteTable(TEST_TABLE.getTableName());
2066         } finally {
2067           admin.close();
2068         }
2069         return null;
2070       }
2071     };
2072 
2073     verifyDenied(deleteTableAction, USER_RW, USER_RO, USER_NONE);
2074     verifyAllowed(deleteTableAction, TABLE_ADMIN);
2075   }
2076 
2077 }