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  package org.apache.hadoop.hbase.security.access;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.util.List;
24  
25  import org.apache.hadoop.conf.Configuration;
26  import org.apache.hadoop.hbase.HBaseTestingUtility;
27  import org.apache.hadoop.hbase.HConstants;
28  import org.apache.hadoop.hbase.MediumTests;
29  import org.apache.hadoop.hbase.NamespaceDescriptor;
30  import org.apache.hadoop.hbase.client.Get;
31  import org.apache.hadoop.hbase.client.HTable;
32  import org.apache.hadoop.hbase.client.Result;
33  import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
34  import org.apache.hadoop.hbase.coprocessor.ObserverContext;
35  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
36  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
37  import org.apache.hadoop.hbase.security.User;
38  import org.apache.hadoop.hbase.security.access.Permission.Action;
39  import org.apache.hadoop.hbase.util.Bytes;
40  
41  import org.junit.AfterClass;
42  import org.junit.BeforeClass;
43  import org.junit.Test;
44  import org.junit.experimental.categories.Category;
45  
46  import com.google.common.collect.ListMultimap;
47  import com.google.protobuf.BlockingRpcChannel;
48  
49  @Category(MediumTests.class)
50  public class TestNamespaceCommands extends SecureTestUtil {
51    private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
52    private static String TestNamespace = "ns1";
53    private static Configuration conf;
54    private static MasterCoprocessorEnvironment CP_ENV;
55    private static AccessController ACCESS_CONTROLLER;
56    
57    // user with all permissions
58    private static User SUPERUSER;
59    // user with rw permissions
60    private static User USER_RW;
61    // user with create table permissions alone
62    private static User USER_CREATE;
63    // user with permission on namespace for testing all operations.
64    private static User USER_NSP_WRITE;
65    
66    @BeforeClass
67    public static void beforeClass() throws Exception {
68      conf = UTIL.getConfiguration();
69      enableSecurity(conf);
70  
71      SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
72      USER_RW = User.createUserForTesting(conf, "rw_user", new String[0]);
73      USER_CREATE = User.createUserForTesting(conf, "create_user", new String[0]);
74      USER_NSP_WRITE = User.createUserForTesting(conf, "namespace_write", new String[0]);
75  
76      UTIL.startMiniCluster();
77      // Wait for the ACL table to become available
78      UTIL.waitTableAvailable(AccessControlLists.ACL_TABLE_NAME.getName(), 30 * 1000);
79  
80      ACCESS_CONTROLLER = (AccessController) UTIL.getMiniHBaseCluster().getMaster()
81        .getCoprocessorHost()
82          .findCoprocessor(AccessController.class.getName());
83  
84      UTIL.getHBaseAdmin().createNamespace(NamespaceDescriptor.create(TestNamespace).build());
85  
86      grantOnNamespace(UTIL, USER_NSP_WRITE.getShortName(),
87        TestNamespace, Permission.Action.WRITE);
88    }
89    
90    @AfterClass
91    public static void afterClass() throws Exception {
92      UTIL.getHBaseAdmin().deleteNamespace(TestNamespace);
93      UTIL.shutdownMiniCluster();
94    }
95  
96    @Test
97    public void testAclTableEntries() throws Exception {
98      String userTestNamespace = "userTestNsp";
99      HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
100     try {
101       // Grant and check state in ACL table
102       grantOnNamespace(UTIL, userTestNamespace, TestNamespace,
103         Permission.Action.WRITE);
104 
105       Result result = acl.get(new Get(Bytes.toBytes(userTestNamespace)));
106       assertTrue(result != null);
107       ListMultimap<String, TablePermission> perms =
108           AccessControlLists.getNamespacePermissions(conf, TestNamespace);
109       assertEquals(2, perms.size());
110       List<TablePermission> namespacePerms = perms.get(userTestNamespace);
111       assertTrue(perms.containsKey(userTestNamespace));
112       assertEquals(1, namespacePerms.size());
113       assertEquals(TestNamespace,
114         namespacePerms.get(0).getNamespace());
115       assertEquals(null, namespacePerms.get(0).getFamily());
116       assertEquals(null, namespacePerms.get(0).getQualifier());
117       assertEquals(1, namespacePerms.get(0).getActions().length);
118       assertEquals(Permission.Action.WRITE, namespacePerms.get(0).getActions()[0]);
119 
120       // Revoke and check state in ACL table
121       revokeFromNamespace(UTIL, userTestNamespace, TestNamespace,
122         Permission.Action.WRITE);
123 
124       perms = AccessControlLists.getNamespacePermissions(conf, TestNamespace);
125       assertEquals(1, perms.size());
126     } finally {
127       acl.close();
128     }
129   }
130   
131   @Test
132   public void testModifyNamespace() throws Exception {
133     AccessTestAction modifyNamespace = new AccessTestAction() {
134       public Object run() throws Exception {
135         ACCESS_CONTROLLER.preModifyNamespace(ObserverContext.createAndPrepare(CP_ENV, null),
136           NamespaceDescriptor.create(TestNamespace).addConfiguration("abc", "156").build());
137         return null;
138       }
139     };
140     // verify that superuser or hbase admin can modify namespaces.
141     verifyAllowed(modifyNamespace, SUPERUSER);
142     // all others should be denied
143     verifyDenied(modifyNamespace, USER_NSP_WRITE, USER_CREATE, USER_RW);
144   }
145   
146   @Test
147   public void testGrantRevoke() throws Exception{
148     final String testUser = "testUser";
149 
150     // Test if client API actions are authorized
151 
152     AccessTestAction grantAction = new AccessTestAction() {
153       public Object run() throws Exception {
154         HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
155         try {
156           BlockingRpcChannel service =
157               acl.coprocessorService(HConstants.EMPTY_START_ROW);
158           AccessControlService.BlockingInterface protocol =
159             AccessControlService.newBlockingStub(service);
160           ProtobufUtil.grant(protocol, testUser, TestNamespace, Action.WRITE);
161         } finally {
162           acl.close();
163         }
164         return null;
165       }
166     };
167 
168     AccessTestAction revokeAction = new AccessTestAction() {
169       public Object run() throws Exception {
170         HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
171         try {
172           BlockingRpcChannel service =
173               acl.coprocessorService(HConstants.EMPTY_START_ROW);
174           AccessControlService.BlockingInterface protocol =
175             AccessControlService.newBlockingStub(service);
176           ProtobufUtil.revoke(protocol, testUser, TestNamespace, Action.WRITE);
177         } finally {
178           acl.close();
179         }
180         return null;
181       }
182     };
183 
184     // Only HBase super user should be able to grant and revoke permissions to
185     // namespaces
186     verifyAllowed(grantAction, SUPERUSER);
187     verifyDenied(grantAction, USER_CREATE, USER_RW);
188     verifyAllowed(revokeAction, SUPERUSER);
189     verifyDenied(revokeAction, USER_CREATE, USER_RW);    
190   }
191 }