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.coprocessor.CoprocessorHost;
33  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
34  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
35  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.CheckPermissionsRequest;
36  import org.apache.hadoop.hbase.security.AccessDeniedException;
37  import org.apache.hadoop.hbase.security.User;
38  
39  import com.google.protobuf.ServiceException;
40  
41  /**
42   * Utility methods for testing security
43   */
44  public class SecureTestUtil {
45    public static void enableSecurity(Configuration conf) throws IOException {
46      conf.set("hadoop.security.authorization", "false");
47      conf.set("hadoop.security.authentication", "simple");
48      conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, AccessController.class.getName());
49      conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, AccessController.class.getName() +
50        "," + SecureBulkLoadEndpoint.class.getName());
51      conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, AccessController.class.getName());
52      // The secure minicluster creates separate service principals based on the
53      // current user's name, one for each slave. We need to add all of these to
54      // the superuser list or security won't function properly. We expect the
55      // HBase service account(s) to have superuser privilege.
56      String currentUser = User.getCurrent().getName();
57      StringBuffer sb = new StringBuffer();
58      sb.append("admin,");
59      sb.append(currentUser);
60      // Assumes we won't ever have a minicluster with more than 5 slaves
61      for (int i = 0; i < 5; i++) {
62        sb.append(',');
63        sb.append(currentUser); sb.append(".hfs."); sb.append(i);
64      }
65      conf.set("hbase.superuser", sb.toString());
66    }
67    
68    public void verifyAllowed(User user, PrivilegedExceptionAction... actions) throws Exception {
69      for (PrivilegedExceptionAction action : actions) {
70        try {
71          user.runAs(action);
72        } catch (AccessDeniedException ade) {
73          fail("Expected action to pass for user '" + user.getShortName() + "' but was denied");
74        }
75      }
76    }
77  
78    public void verifyAllowed(PrivilegedExceptionAction action, User... users) throws Exception {
79      for (User user : users) {
80        verifyAllowed(user, action);
81      }
82    }
83  
84    public void verifyDenied(User user, PrivilegedExceptionAction... actions) throws Exception {
85      for (PrivilegedExceptionAction action : actions) {
86        try {
87          user.runAs(action);
88          fail("Expected AccessDeniedException for user '" + user.getShortName() + "'");
89        } catch (IOException e) {
90          boolean isAccessDeniedException = false;
91          if(e instanceof RetriesExhaustedWithDetailsException) {
92            // in case of batch operations, and put, the client assembles a
93            // RetriesExhaustedWithDetailsException instead of throwing an
94            // AccessDeniedException
95            for(Throwable ex : ((RetriesExhaustedWithDetailsException) e).getCauses()) {
96              if (ex instanceof AccessDeniedException) {
97                isAccessDeniedException = true;
98                break;
99              }
100           }
101         }
102         else {
103           // For doBulkLoad calls AccessDeniedException
104           // is buried in the stack trace
105           Throwable ex = e;
106           do {
107             if (ex instanceof AccessDeniedException) {
108               isAccessDeniedException = true;
109               break;
110             }
111           } while((ex = ex.getCause()) != null);
112         }
113         if (!isAccessDeniedException) {
114           fail("Not receiving AccessDeniedException for user '" + user.getShortName() + "'");
115         }
116       } catch (UndeclaredThrowableException ute) {
117         // TODO why we get a PrivilegedActionException, which is unexpected?
118         Throwable ex = ute.getUndeclaredThrowable();
119         if (ex instanceof PrivilegedActionException) {
120           ex = ((PrivilegedActionException) ex).getException();
121         }
122         if (ex instanceof ServiceException) {
123           ServiceException se = (ServiceException)ex;
124           if (se.getCause() != null && se.getCause() instanceof AccessDeniedException) {
125             // expected result
126             return;
127           }
128         }
129         fail("Not receiving AccessDeniedException for user '" + user.getShortName() + "'");
130       }
131     }
132   }
133 
134   public void verifyDenied(PrivilegedExceptionAction action, User... users) throws Exception {
135     for (User user : users) {
136       verifyDenied(user, action);
137     }
138   }
139   
140   public void checkTablePerms(Configuration conf, byte[] table, byte[] family, byte[] column,
141       Permission.Action... actions) throws IOException {
142     Permission[] perms = new Permission[actions.length];
143     for (int i = 0; i < actions.length; i++) {
144       perms[i] = new TablePermission(TableName.valueOf(table), family, column, actions[i]);
145     }
146 
147     checkTablePerms(conf, table, perms);
148   }
149 
150   public void checkTablePerms(Configuration conf, byte[] table, Permission... perms) throws IOException {
151     CheckPermissionsRequest.Builder request = CheckPermissionsRequest.newBuilder();
152     for (Permission p : perms) {
153       request.addPermission(ProtobufUtil.toPermission(p));
154     }
155     HTable acl = new HTable(conf, table);
156     try {
157       AccessControlService.BlockingInterface protocol =
158         AccessControlService.newBlockingStub(acl.coprocessorService(new byte[0]));
159       try {
160         protocol.checkPermissions(null, request.build());
161       } catch (ServiceException se) {
162         ProtobufUtil.toIOException(se);
163       }
164     } finally {
165       acl.close();
166     }
167   }
168 }