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