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.fail;
23  
24  import java.io.IOException;
25  import java.lang.reflect.UndeclaredThrowableException;
26  import java.security.PrivilegedActionException;
27  import java.security.PrivilegedExceptionAction;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.concurrent.Callable;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.hadoop.conf.Configuration;
35  import org.apache.hadoop.hbase.Coprocessor;
36  import org.apache.hadoop.hbase.HBaseTestingUtility;
37  import org.apache.hadoop.hbase.HConstants;
38  import org.apache.hadoop.hbase.MiniHBaseCluster;
39  import org.apache.hadoop.hbase.NamespaceDescriptor;
40  import org.apache.hadoop.hbase.TableName;
41  import org.apache.hadoop.hbase.Waiter.Predicate;
42  import org.apache.hadoop.hbase.client.Connection;
43  import org.apache.hadoop.hbase.client.ConnectionFactory;
44  import org.apache.hadoop.hbase.client.HTable;
45  import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException;
46  import org.apache.hadoop.hbase.client.Table;
47  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
48  import org.apache.hadoop.hbase.io.hfile.HFile;
49  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
50  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
51  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
52  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.CheckPermissionsRequest;
53  import org.apache.hadoop.hbase.regionserver.HRegion;
54  import org.apache.hadoop.hbase.security.AccessDeniedException;
55  import org.apache.hadoop.hbase.security.User;
56  import org.apache.hadoop.hbase.security.access.Permission.Action;
57  import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
58  
59  import com.google.common.collect.Lists;
60  import com.google.common.collect.Maps;
61  import com.google.protobuf.BlockingRpcChannel;
62  import com.google.protobuf.ServiceException;
63  
64  /**
65   * Utility methods for testing security
66   */
67  public class SecureTestUtil {
68    
69    private static final Log LOG = LogFactory.getLog(SecureTestUtil.class);
70    private static final int WAIT_TIME = 10000;
71  
72    public static void configureSuperuser(Configuration conf) throws IOException {
73      // The secure minicluster creates separate service principals based on the
74      // current user's name, one for each slave. We need to add all of these to
75      // the superuser list or security won't function properly. We expect the
76      // HBase service account(s) to have superuser privilege.
77      String currentUser = User.getCurrent().getName();
78      StringBuffer sb = new StringBuffer();
79      sb.append("admin,");
80      sb.append(currentUser);
81      // Assumes we won't ever have a minicluster with more than 5 slaves
82      for (int i = 0; i < 5; i++) {
83        sb.append(',');
84        sb.append(currentUser); sb.append(".hfs."); sb.append(i);
85      }
86      conf.set("hbase.superuser", sb.toString());
87    }
88  
89    public static void enableSecurity(Configuration conf) throws IOException {
90      conf.set("hadoop.security.authorization", "false");
91      conf.set("hadoop.security.authentication", "simple");
92      conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, AccessController.class.getName());
93      conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, AccessController.class.getName() +
94        "," + SecureBulkLoadEndpoint.class.getName());
95      conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, AccessController.class.getName());
96      // Need HFile V3 for tags for security features
97      conf.setInt(HFile.FORMAT_VERSION_KEY, 3);
98      configureSuperuser(conf);
99    }
100 
101   public static void verifyConfiguration(Configuration conf) {
102     if (!(conf.get(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY).contains(
103         AccessController.class.getName())
104         && conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY).contains(
105             AccessController.class.getName()) && conf.get(
106         CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY).contains(
107         AccessController.class.getName()))) {
108       throw new RuntimeException("AccessController is missing from a system coprocessor list");
109     }
110     if (conf.getInt(HFile.FORMAT_VERSION_KEY, 2) < HFile.MIN_FORMAT_VERSION_WITH_TAGS) {
111       throw new RuntimeException("Post 0.96 security features require HFile version >= 3");
112     }
113   }
114 
115   public static void checkTablePerms(Configuration conf, TableName table, byte[] family, byte[] column,
116       Permission.Action... actions) throws IOException {
117     Permission[] perms = new Permission[actions.length];
118     for (int i = 0; i < actions.length; i++) {
119       perms[i] = new TablePermission(table, family, column, actions[i]);
120     }
121 
122     checkTablePerms(conf, table, perms);
123   }
124 
125   public static void checkTablePerms(Configuration conf, TableName table, Permission... perms)
126   throws IOException {
127     CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
128     for (Permission p : perms) {
129       request.addPermission(ProtobufUtil.toPermission(p));
130     }
131     try (Connection connection = ConnectionFactory.createConnection(conf)) {
132       try (Table acl = connection.getTable(table)) {
133         AccessControlService.BlockingInterface protocol =
134             AccessControlService.newBlockingStub(acl.coprocessorService(new byte[0]));
135         try {
136           protocol.checkPermissions(null, request.build());
137         } catch (ServiceException se) {
138           ProtobufUtil.toIOException(se);
139         }
140       }
141     }
142   }
143 
144   /**
145    * An AccessTestAction performs an action that will be examined to confirm
146    * the results conform to expected access rights.
147    * <p>
148    * To indicate an action was allowed, return null or a non empty list of
149    * KeyValues.
150    * <p>
151    * To indicate the action was not allowed, either throw an AccessDeniedException
152    * or return an empty list of KeyValues.
153    */
154   static interface AccessTestAction extends PrivilegedExceptionAction<Object> { }
155 
156   /** This fails only in case of ADE or empty list for any of the actions. */
157   public static void verifyAllowed(User user, AccessTestAction... actions) throws Exception {
158     for (AccessTestAction action : actions) {
159       try {
160         Object obj = user.runAs(action);
161         if (obj != null && obj instanceof List<?>) {
162           List<?> results = (List<?>) obj;
163           if (results != null && results.isEmpty()) {
164             fail("Empty non null results from action for user '" + user.getShortName() + "'");
165           }
166         }
167       } catch (AccessDeniedException ade) {
168         fail("Expected action to pass for user '" + user.getShortName() + "' but was denied");
169       }
170     }
171   }
172 
173   /** This fails only in case of ADE or empty list for any of the users. */
174   public static void verifyAllowed(AccessTestAction action, User... users) throws Exception {
175     for (User user : users) {
176       verifyAllowed(user, action);
177     }
178   }
179 
180   public static void verifyAllowed(User user, AccessTestAction action, int count) throws Exception {
181     try {
182       Object obj = user.runAs(action);
183       if (obj != null && obj instanceof List<?>) {
184         List<?> results = (List<?>) obj;
185         if (results != null && results.isEmpty()) {
186           fail("Empty non null results from action for user '" + user.getShortName() + "'");
187         }
188         assertEquals(count, results.size());
189       }
190     } catch (AccessDeniedException ade) {
191       fail("Expected action to pass for user '" + user.getShortName() + "' but was denied");
192     }
193   }
194 
195   /** This passes only in case of ADE for all users. */
196   public static void verifyDenied(AccessTestAction action, User... users) throws Exception {
197     for (User user : users) {
198       verifyDenied(user, action);
199     }
200   }
201 
202   /** This passes only in case of empty list for all users. */
203   public static void verifyIfEmptyList(AccessTestAction action, User... users) throws Exception {
204     for (User user : users) {
205       try {
206         Object obj = user.runAs(action);
207         if (obj != null && obj instanceof List<?>) {
208           List<?> results = (List<?>) obj;
209           if (results != null && !results.isEmpty()) {
210             fail("Unexpected action results: " +  results + " for user '"
211                 + user.getShortName() + "'");
212           }
213         } else {
214           fail("Unexpected results for user '" + user.getShortName() + "'");
215         }
216       } catch (AccessDeniedException ade) {
217         fail("Expected action to pass for user '" + user.getShortName() + "' but was denied");
218       }
219     }
220   }
221 
222   /** This passes only in case of null for all users. */
223   public static void verifyIfNull(AccessTestAction  action, User... users) throws Exception {
224     for (User user : users) {
225       try {
226         Object obj = user.runAs(action);
227         if (obj != null) {
228           fail("Non null results from action for user '" + user.getShortName() + "'");
229         }
230       } catch (AccessDeniedException ade) {
231         fail("Expected action to pass for user '" + user.getShortName() + "' but was denied");
232       }
233     }
234   }
235 
236   /** This passes only in case of ADE for all actions. */
237   public static void verifyDenied(User user, AccessTestAction... actions) throws Exception {
238     for (AccessTestAction action : actions) {
239       try {
240         user.runAs(action);
241         fail("Expected exception was not thrown for user '" + user.getShortName() + "'");
242       } catch (IOException e) {
243         boolean isAccessDeniedException = false;
244         if(e instanceof RetriesExhaustedWithDetailsException) {
245           // in case of batch operations, and put, the client assembles a
246           // RetriesExhaustedWithDetailsException instead of throwing an
247           // AccessDeniedException
248           for(Throwable ex : ((RetriesExhaustedWithDetailsException) e).getCauses()) {
249             if (ex instanceof AccessDeniedException) {
250               isAccessDeniedException = true;
251               break;
252             }
253           }
254         }
255         else {
256           // For doBulkLoad calls AccessDeniedException
257           // is buried in the stack trace
258           Throwable ex = e;
259           do {
260             if (ex instanceof AccessDeniedException) {
261               isAccessDeniedException = true;
262               break;
263             }
264           } while((ex = ex.getCause()) != null);
265         }
266         if (!isAccessDeniedException) {
267           fail("Expected exception was not thrown for user '" + user.getShortName() + "'");
268         }
269       } catch (UndeclaredThrowableException ute) {
270         // TODO why we get a PrivilegedActionException, which is unexpected?
271         Throwable ex = ute.getUndeclaredThrowable();
272         if (ex instanceof PrivilegedActionException) {
273           ex = ((PrivilegedActionException) ex).getException();
274         }
275         if (ex instanceof ServiceException) {
276           ServiceException se = (ServiceException)ex;
277           if (se.getCause() != null && se.getCause() instanceof AccessDeniedException) {
278             // expected result
279             return;
280           }
281         }
282         fail("Expected exception was not thrown for user '" + user.getShortName() + "'");
283       }
284     }
285   }
286 
287   private static List<AccessController> getAccessControllers(MiniHBaseCluster cluster) {
288     List<AccessController> result = Lists.newArrayList();
289     for (RegionServerThread t: cluster.getLiveRegionServerThreads()) {
290       for (HRegion region: t.getRegionServer().getOnlineRegionsLocalContext()) {
291         Coprocessor cp = region.getCoprocessorHost()
292           .findCoprocessor(AccessController.class.getName());
293         if (cp != null) {
294           result.add((AccessController)cp);
295         }
296       }
297     }
298     return result;
299   }
300 
301   private static Map<AccessController,Long> getAuthManagerMTimes(MiniHBaseCluster cluster) {
302     Map<AccessController,Long> result = Maps.newHashMap();
303     for (AccessController ac: getAccessControllers(cluster)) {
304       result.put(ac, ac.getAuthManager().getMTime());
305     }
306     return result;
307   }
308 
309   @SuppressWarnings("rawtypes")
310   private static void updateACLs(final HBaseTestingUtility util, Callable c) throws Exception {
311     // Get the current mtimes for all access controllers
312     final Map<AccessController,Long> oldMTimes = getAuthManagerMTimes(util.getHBaseCluster());
313 
314     // Run the update action
315     c.call();
316 
317     // Wait until mtimes for all access controllers have incremented
318     util.waitFor(WAIT_TIME, 100, new Predicate<IOException>() {
319       @Override
320       public boolean evaluate() throws IOException {
321         Map<AccessController,Long> mtimes = getAuthManagerMTimes(util.getHBaseCluster());
322         for (Map.Entry<AccessController,Long> e: mtimes.entrySet()) {
323           if (!oldMTimes.containsKey(e.getKey())) {
324             LOG.error("Snapshot of AccessController state does not include instance on region " +
325               e.getKey().getRegion().getRegionNameAsString());
326             // Error out the predicate, we will try again
327             return false;
328           }
329           long old = oldMTimes.get(e.getKey());
330           long now = e.getValue();
331           if (now <= old) {
332             LOG.info("AccessController on region " +
333               e.getKey().getRegion().getRegionNameAsString() + " has not updated: mtime=" +
334               now);
335             return false;
336           }
337         }
338         return true;
339       }
340     });
341   }
342 
343   /**
344    * Grant permissions globally to the given user. Will wait until all active
345    * AccessController instances have updated their permissions caches or will
346    * throw an exception upon timeout (10 seconds).
347    */
348   public static void grantGlobal(final HBaseTestingUtility util, final String user,
349       final Permission.Action... actions) throws Exception {
350     SecureTestUtil.updateACLs(util, new Callable<Void>() {
351       @Override
352       public Void call() throws Exception {
353         try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) {
354           try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
355             BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
356             AccessControlService.BlockingInterface protocol =
357                 AccessControlService.newBlockingStub(service);
358             ProtobufUtil.grant(protocol, user, actions);
359           }
360         }
361         return null;
362       }
363     });
364   }
365 
366   /**
367    * Revoke permissions globally from the given user. Will wait until all active
368    * AccessController instances have updated their permissions caches or will
369    * throw an exception upon timeout (10 seconds).
370    */
371   public static void revokeGlobal(final HBaseTestingUtility util, final String user,
372       final Permission.Action... actions) throws Exception {
373     SecureTestUtil.updateACLs(util, new Callable<Void>() {
374       @Override
375       public Void call() throws Exception {
376         try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) {
377           try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
378             BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
379             AccessControlService.BlockingInterface protocol =
380                 AccessControlService.newBlockingStub(service);
381             ProtobufUtil.revoke(protocol, user, actions);
382           }
383         }
384         return null;
385       }
386     });
387   }
388 
389   /**
390    * Grant permissions on a namespace to the given user. Will wait until all active
391    * AccessController instances have updated their permissions caches or will
392    * throw an exception upon timeout (10 seconds).
393    */
394   public static void grantOnNamespace(final HBaseTestingUtility util, final String user,
395       final String namespace, final Permission.Action... actions) throws Exception {
396     SecureTestUtil.updateACLs(util, new Callable<Void>() {
397       @Override
398       public Void call() throws Exception {
399         try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) {
400           try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
401             BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
402             AccessControlService.BlockingInterface protocol =
403                 AccessControlService.newBlockingStub(service);
404             ProtobufUtil.grant(protocol, user, namespace, actions);
405           }
406         }
407         return null;
408       }
409     });
410   }
411 
412   /**
413    * Grant permissions on a namespace to the given user using AccessControl Client.
414    * Will wait until all active AccessController instances have updated their permissions caches
415    * or will throw an exception upon timeout (10 seconds).
416    */
417   public static void grantOnNamespaceUsingAccessControlClient(final HBaseTestingUtility util,
418       final Configuration conf, final String user, final String namespace,
419       final Permission.Action... actions) throws Exception {
420     SecureTestUtil.updateACLs(util, new Callable<Void>() {
421       @Override
422       public Void call() throws Exception {
423         try {
424           AccessControlClient.grant(conf, namespace, user, actions);
425         } catch (Throwable t) {
426           t.printStackTrace();
427         }
428         return null;
429       }
430     });
431   }
432 
433   /**
434    * Grant permissions on a namespace to the given user using AccessControl Client.
435    * Will wait until all active AccessController instances have updated their permissions caches
436    * or will throw an exception upon timeout (10 seconds).
437    */
438   public static void grantOnNamespaceUsingAccessControlClient(final HBaseTestingUtility util,
439       final Connection connection, final String user, final String namespace,
440       final Permission.Action... actions) throws Exception {
441     SecureTestUtil.updateACLs(util, new Callable<Void>() {
442       @Override
443       public Void call() throws Exception {
444         try {
445           AccessControlClient.grant(connection, namespace, user, actions);
446         } catch (Throwable t) {
447           t.printStackTrace();
448         }
449         return null;
450       }
451     });
452   }
453 
454   /**
455    * Revoke permissions on a namespace from the given user using AccessControl Client.
456    * Will wait until all active AccessController instances have updated their permissions caches
457    * or will throw an exception upon timeout (10 seconds).
458    */
459   public static void revokeFromNamespaceUsingAccessControlClient(final HBaseTestingUtility util,
460       final Connection connection, final String user, final String namespace,
461       final Permission.Action... actions) throws Exception {
462     SecureTestUtil.updateACLs(util, new Callable<Void>() {
463       @Override
464       public Void call() throws Exception {
465         try {
466           AccessControlClient.revoke(connection, namespace, user, actions);
467         } catch (Throwable t) {
468           t.printStackTrace();
469         }
470         return null;
471       }
472     });
473   }
474 
475   /**
476    * Revoke permissions on a namespace from the given user. Will wait until all active
477    * AccessController instances have updated their permissions caches or will
478    * throw an exception upon timeout (10 seconds).
479    */
480   public static void revokeFromNamespace(final HBaseTestingUtility util, final String user,
481       final String namespace, final Permission.Action... actions) throws Exception {
482     SecureTestUtil.updateACLs(util, new Callable<Void>() {
483       @Override
484       public Void call() throws Exception {
485         try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) {
486           try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
487             BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
488             AccessControlService.BlockingInterface protocol =
489                 AccessControlService.newBlockingStub(service);
490             ProtobufUtil.revoke(protocol, user, namespace, actions);
491           }
492         }
493         return null;
494       }
495     });
496   }
497 
498   /**
499    * Grant permissions on a table to the given user. Will wait until all active
500    * AccessController instances have updated their permissions caches or will
501    * throw an exception upon timeout (10 seconds).
502    */
503   public static void grantOnTable(final HBaseTestingUtility util, final String user,
504       final TableName table, final byte[] family, final byte[] qualifier,
505       final Permission.Action... actions) throws Exception {
506     SecureTestUtil.updateACLs(util, new Callable<Void>() {
507       @Override
508       public Void call() throws Exception {
509         try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) {
510           try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
511             BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
512             AccessControlService.BlockingInterface protocol =
513                 AccessControlService.newBlockingStub(service);
514             ProtobufUtil.grant(protocol, user, table, family, qualifier, actions);
515           }
516         }
517         return null;
518       }
519     });
520   }
521 
522   /**
523    * Grant permissions on a table to the given user using AccessControlClient. Will wait until all
524    * active AccessController instances have updated their permissions caches or will
525    * throw an exception upon timeout (10 seconds).
526    */
527   public static void grantOnTableUsingAccessControlClient(final HBaseTestingUtility util,
528       final Connection connection, final String user, final TableName table, final byte[] family,
529       final byte[] qualifier, final Permission.Action... actions) throws Exception {
530     SecureTestUtil.updateACLs(util, new Callable<Void>() {
531       @Override
532       public Void call() throws Exception {
533         try {
534           AccessControlClient.grant(connection, table, user, family, qualifier, actions);
535         } catch (Throwable t) {
536           t.printStackTrace();
537         }
538         return null;
539       }
540     });
541   }
542 
543   /**
544    * Grant global permissions to the given user using AccessControlClient. Will wait until all
545    * active AccessController instances have updated their permissions caches or will
546    * throw an exception upon timeout (10 seconds).
547    */
548   public static void grantGlobalUsingAccessControlClient(final HBaseTestingUtility util,
549       final Connection connection, final String user, final Permission.Action... actions)
550       throws Exception {
551     SecureTestUtil.updateACLs(util, new Callable<Void>() {
552       @Override
553       public Void call() throws Exception {
554         try {
555           AccessControlClient.grant(connection, user, actions);
556         } catch (Throwable t) {
557           t.printStackTrace();
558         }
559         return null;
560       }
561     });
562   }
563 
564   /**
565    * Revoke permissions on a table from the given user. Will wait until all active
566    * AccessController instances have updated their permissions caches or will
567    * throw an exception upon timeout (10 seconds).
568    */
569   public static void revokeFromTable(final HBaseTestingUtility util, final String user,
570       final TableName table, final byte[] family, final byte[] qualifier,
571       final Permission.Action... actions) throws Exception {
572     SecureTestUtil.updateACLs(util, new Callable<Void>() {
573       @Override
574       public Void call() throws Exception {
575         try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) {
576           try (Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) {
577             BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
578             AccessControlService.BlockingInterface protocol =
579                 AccessControlService.newBlockingStub(service);
580             ProtobufUtil.revoke(protocol, user, table, family, qualifier, actions);
581           }
582         }
583         return null;
584       }
585     });
586   }
587 
588   /**
589    * Revoke permissions on a table from the given user using AccessControlClient. Will wait until
590    * all active AccessController instances have updated their permissions caches or will
591    * throw an exception upon timeout (10 seconds).
592    */
593   public static void revokeFromTableUsingAccessControlClient(final HBaseTestingUtility util,
594       final Connection connection, final String user, final TableName table, final byte[] family,
595       final byte[] qualifier, final Permission.Action... actions) throws Exception {
596     SecureTestUtil.updateACLs(util, new Callable<Void>() {
597       @Override
598       public Void call() throws Exception {
599         try {
600           AccessControlClient.revoke(connection, table, user, family, qualifier, actions);
601         } catch (Throwable t) {
602           t.printStackTrace();
603         }
604         return null;
605       }
606     });
607   }
608 
609   /**
610    * Revoke global permissions from the given user using AccessControlClient. Will wait until
611    * all active AccessController instances have updated their permissions caches or will
612    * throw an exception upon timeout (10 seconds).
613    */
614   public static void revokeGlobalUsingAccessControlClient(final HBaseTestingUtility util,
615       final Connection connection, final String user,final Permission.Action... actions)
616       throws Exception {
617     SecureTestUtil.updateACLs(util, new Callable<Void>() {
618       @Override
619       public Void call() throws Exception {
620         try {
621           AccessControlClient.revoke(connection, user, actions);
622         } catch (Throwable t) {
623           t.printStackTrace();
624         }
625         return null;
626       }
627     });
628   }
629 
630   public static void createNamespace(HBaseTestingUtility testUtil, NamespaceDescriptor nsDesc)
631       throws Exception {
632     testUtil.getHBaseAdmin().createNamespace(nsDesc);
633   }
634 
635   public static void deleteNamespace(HBaseTestingUtility testUtil, String namespace)
636       throws Exception {
637     testUtil.getHBaseAdmin().deleteNamespace(namespace);
638   }
639 
640   public static String convertToNamespace(String namespace) {
641     return AccessControlLists.NAMESPACE_PREFIX + namespace;
642   }
643 
644   public static String convertToGroup(String group) {
645     return AccessControlLists.GROUP_PREFIX + group;
646   }
647 
648   public void checkGlobalPerms(HBaseTestingUtility testUtil, Permission.Action... actions)
649       throws IOException {
650     Permission[] perms = new Permission[actions.length];
651     for (int i = 0; i < actions.length; i++) {
652       perms[i] = new Permission(actions[i]);
653     }
654     CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
655     for (Action a : actions) {
656       request.addPermission(AccessControlProtos.Permission.newBuilder()
657           .setType(AccessControlProtos.Permission.Type.Global)
658           .setGlobalPermission(
659               AccessControlProtos.GlobalPermission.newBuilder()
660                   .addAction(ProtobufUtil.toPermissionAction(a)).build()));
661     }
662     HTable acl = new HTable(testUtil.getConfiguration(), AccessControlLists.ACL_TABLE_NAME);
663     try {
664       BlockingRpcChannel channel = acl.coprocessorService(new byte[0]);
665       AccessControlService.BlockingInterface protocol =
666         AccessControlService.newBlockingStub(channel);
667       try {
668         protocol.checkPermissions(null, request.build());
669       } catch (ServiceException se) {
670         ProtobufUtil.toIOException(se);
671       }
672     } finally {
673       acl.close();
674     }
675   }
676 
677   public void checkTablePerms(HBaseTestingUtility testUtil, TableName table, byte[] family,
678       byte[] column, Permission.Action... actions) throws IOException {
679     Permission[] perms = new Permission[actions.length];
680     for (int i = 0; i < actions.length; i++) {
681       perms[i] = new TablePermission(table, family, column, actions[i]);
682     }
683     checkTablePerms(testUtil, table, perms);
684   }
685 
686   public void checkTablePerms(HBaseTestingUtility testUtil, TableName table, Permission... perms)
687       throws IOException {
688     CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
689     for (Permission p : perms) {
690       request.addPermission(ProtobufUtil.toPermission(p));
691     }
692     HTable acl = new HTable(testUtil.getConfiguration(), table);
693     try {
694       AccessControlService.BlockingInterface protocol =
695         AccessControlService.newBlockingStub(acl.coprocessorService(new byte[0]));
696       try {
697         protocol.checkPermissions(null, request.build());
698       } catch (ServiceException se) {
699         ProtobufUtil.toIOException(se);
700       }
701     } finally {
702       acl.close();
703     }
704   }
705 
706 }