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