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.fail;
22  
23  import java.io.IOException;
24  import java.lang.reflect.UndeclaredThrowableException;
25  import java.security.PrivilegedActionException;
26  import java.security.PrivilegedExceptionAction;
27  
28  import org.apache.hadoop.conf.Configuration;
29  import org.apache.hadoop.hbase.TableName;
30  import org.apache.hadoop.hbase.client.HTable;
31  import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException;
32  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
33  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
34  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.CheckPermissionsRequest;
35  import org.apache.hadoop.hbase.security.AccessDeniedException;
36  import org.apache.hadoop.hbase.security.User;
37  
38  import com.google.protobuf.ServiceException;
39  
40  /**
41   * Utility methods for testing security
42   */
43  public class SecureTestUtil {
44    public static void enableSecurity(Configuration conf) throws IOException {
45      conf.set("hadoop.security.authorization", "false");
46      conf.set("hadoop.security.authentication", "simple");
47      conf.set("hbase.coprocessor.master.classes", AccessController.class.getName());
48      conf.set("hbase.coprocessor.region.classes", AccessController.class.getName()+
49          ","+SecureBulkLoadEndpoint.class.getName());
50      // add the process running user to superusers
51      String currentUser = User.getCurrent().getName();
52      conf.set("hbase.superuser", "admin,"+currentUser);
53    }
54    
55    public void verifyAllowed(User user, PrivilegedExceptionAction... actions) throws Exception {
56      for (PrivilegedExceptionAction action : actions) {
57        try {
58          user.runAs(action);
59        } catch (AccessDeniedException ade) {
60          fail("Expected action to pass for user '" + user.getShortName() + "' but was denied");
61        }
62      }
63    }
64  
65    public void verifyAllowed(PrivilegedExceptionAction action, User... users) throws Exception {
66      for (User user : users) {
67        verifyAllowed(user, action);
68      }
69    }
70  
71    public void verifyDenied(User user, PrivilegedExceptionAction... actions) throws Exception {
72      for (PrivilegedExceptionAction action : actions) {
73        try {
74          user.runAs(action);
75          fail("Expected AccessDeniedException for user '" + user.getShortName() + "'");
76        } catch (IOException e) {
77          boolean isAccessDeniedException = false;
78          if(e instanceof RetriesExhaustedWithDetailsException) {
79            // in case of batch operations, and put, the client assembles a
80            // RetriesExhaustedWithDetailsException instead of throwing an
81            // AccessDeniedException
82            for(Throwable ex : ((RetriesExhaustedWithDetailsException) e).getCauses()) {
83              if (ex instanceof AccessDeniedException) {
84                isAccessDeniedException = true;
85                break;
86              }
87            }
88          }
89          else {
90            // For doBulkLoad calls AccessDeniedException
91            // is buried in the stack trace
92            Throwable ex = e;
93            do {
94              if (ex instanceof AccessDeniedException) {
95                isAccessDeniedException = true;
96                break;
97              }
98            } while((ex = ex.getCause()) != null);
99          }
100         if (!isAccessDeniedException) {
101           fail("Not receiving AccessDeniedException for user '" + user.getShortName() + "'");
102         }
103       } catch (UndeclaredThrowableException ute) {
104         // TODO why we get a PrivilegedActionException, which is unexpected?
105         Throwable ex = ute.getUndeclaredThrowable();
106         if (ex instanceof PrivilegedActionException) {
107           ex = ((PrivilegedActionException) ex).getException();
108         }
109         if (ex instanceof ServiceException) {
110           ServiceException se = (ServiceException)ex;
111           if (se.getCause() != null && se.getCause() instanceof AccessDeniedException) {
112             // expected result
113             return;
114           }
115         }
116         fail("Not receiving AccessDeniedException for user '" + user.getShortName() + "'");
117       }
118     }
119   }
120 
121   public void verifyDenied(PrivilegedExceptionAction action, User... users) throws Exception {
122     for (User user : users) {
123       verifyDenied(user, action);
124     }
125   }
126   
127   public void checkTablePerms(Configuration conf, byte[] table, byte[] family, byte[] column,
128       Permission.Action... actions) throws IOException {
129     Permission[] perms = new Permission[actions.length];
130     for (int i = 0; i < actions.length; i++) {
131       perms[i] = new TablePermission(TableName.valueOf(table), family, column, actions[i]);
132     }
133 
134     checkTablePerms(conf, table, perms);
135   }
136 
137   public void checkTablePerms(Configuration conf, byte[] table, Permission... perms) throws IOException {
138     CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
139     for (Permission p : perms) {
140       request.addPermission(ProtobufUtil.toPermission(p));
141     }
142     HTable acl = new HTable(conf, table);
143     try {
144       AccessControlService.BlockingInterface protocol =
145         AccessControlService.newBlockingStub(acl.coprocessorService(new byte[0]));
146       try {
147         protocol.checkPermissions(null, request.build());
148       } catch (ServiceException se) {
149         ProtobufUtil.toIOException(se);
150       }
151     } finally {
152       acl.close();
153     }
154   }
155 }