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