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