001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.rsgroup;
019
020import static org.apache.hadoop.hbase.AuthUtil.toGroupEntry;
021import static org.junit.Assert.assertEquals;
022import static org.junit.Assert.assertTrue;
023import static org.junit.Assert.fail;
024
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.hbase.HBaseClassTestRule;
027import org.apache.hadoop.hbase.HBaseTestingUtility;
028import org.apache.hadoop.hbase.HConstants;
029import org.apache.hadoop.hbase.TableName;
030import org.apache.hadoop.hbase.TableNotFoundException;
031import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
032import org.apache.hadoop.hbase.client.Connection;
033import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
034import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
035import org.apache.hadoop.hbase.security.User;
036import org.apache.hadoop.hbase.security.access.AccessControlClient;
037import org.apache.hadoop.hbase.security.access.AccessControlLists;
038import org.apache.hadoop.hbase.security.access.Permission;
039import org.apache.hadoop.hbase.security.access.SecureTestUtil;
040import org.apache.hadoop.hbase.security.access.TableAuthManager;
041import org.apache.hadoop.hbase.testclassification.MediumTests;
042import org.apache.hadoop.hbase.testclassification.SecurityTests;
043import org.apache.hadoop.hbase.util.Bytes;
044import org.junit.AfterClass;
045import org.junit.BeforeClass;
046import org.junit.ClassRule;
047import org.junit.Test;
048import org.junit.experimental.categories.Category;
049import org.slf4j.Logger;
050import org.slf4j.LoggerFactory;
051
052/**
053 * Performs authorization checks for rsgroup operations, according to different
054 * levels of authorized users.
055 */
056@Category({SecurityTests.class, MediumTests.class})
057public class TestRSGroupsWithACL extends SecureTestUtil{
058
059  @ClassRule
060  public static final HBaseClassTestRule CLASS_RULE =
061      HBaseClassTestRule.forClass(TestRSGroupsWithACL.class);
062
063  private static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsWithACL.class);
064  private static TableName TEST_TABLE = TableName.valueOf("testtable1");
065  private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
066  private static Configuration conf;
067
068  private static Connection systemUserConnection;
069  // user with all permissions
070  private static User SUPERUSER;
071  // user granted with all global permission
072  private static User USER_ADMIN;
073  // user with rw permissions on column family.
074  private static User USER_RW;
075  // user with read-only permissions
076  private static User USER_RO;
077  // user is table owner. will have all permissions on table
078  private static User USER_OWNER;
079  // user with create table permissions alone
080  private static User USER_CREATE;
081  // user with no permissions
082  private static User USER_NONE;
083
084  private static final String GROUP_ADMIN = "group_admin";
085  private static final String GROUP_CREATE = "group_create";
086  private static final String GROUP_READ = "group_read";
087  private static final String GROUP_WRITE = "group_write";
088
089  private static User USER_GROUP_ADMIN;
090  private static User USER_GROUP_CREATE;
091  private static User USER_GROUP_READ;
092  private static User USER_GROUP_WRITE;
093
094  private static byte[] TEST_FAMILY = Bytes.toBytes("f1");
095
096  private static RSGroupAdminEndpoint rsGroupAdminEndpoint;
097
098  @BeforeClass
099  public static void setupBeforeClass() throws Exception {
100    // setup configuration
101    conf = TEST_UTIL.getConfiguration();
102    conf.set(HConstants.HBASE_MASTER_LOADBALANCER_CLASS,
103        RSGroupBasedLoadBalancer.class.getName());
104    // Enable security
105    enableSecurity(conf);
106    // Verify enableSecurity sets up what we require
107    verifyConfiguration(conf);
108    // Enable rsgroup
109    configureRSGroupAdminEndpoint(conf);
110
111    TEST_UTIL.startMiniCluster();
112    rsGroupAdminEndpoint = (RSGroupAdminEndpoint) TEST_UTIL.getMiniHBaseCluster().getMaster().
113        getMasterCoprocessorHost().findCoprocessor(RSGroupAdminEndpoint.class.getName());
114    // Wait for the ACL table to become available
115    TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME);
116
117    // create a set of test users
118    SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
119    USER_ADMIN = User.createUserForTesting(conf, "admin2", new String[0]);
120    USER_RW = User.createUserForTesting(conf, "rwuser", new String[0]);
121    USER_RO = User.createUserForTesting(conf, "rouser", new String[0]);
122    USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
123    USER_CREATE = User.createUserForTesting(conf, "tbl_create", new String[0]);
124    USER_NONE = User.createUserForTesting(conf, "nouser", new String[0]);
125
126    USER_GROUP_ADMIN =
127        User.createUserForTesting(conf, "user_group_admin", new String[] { GROUP_ADMIN });
128    USER_GROUP_CREATE =
129        User.createUserForTesting(conf, "user_group_create", new String[] { GROUP_CREATE });
130    USER_GROUP_READ =
131        User.createUserForTesting(conf, "user_group_read", new String[] { GROUP_READ });
132    USER_GROUP_WRITE =
133        User.createUserForTesting(conf, "user_group_write", new String[] { GROUP_WRITE });
134
135    systemUserConnection = TEST_UTIL.getConnection();
136    setUpTableAndUserPermissions();
137  }
138
139  private static void setUpTableAndUserPermissions() throws Exception {
140    TableDescriptorBuilder tableBuilder = TableDescriptorBuilder.newBuilder(TEST_TABLE);
141    ColumnFamilyDescriptorBuilder cfd = ColumnFamilyDescriptorBuilder.newBuilder(TEST_FAMILY);
142    cfd.setMaxVersions(100);
143    tableBuilder.setColumnFamily(cfd.build());
144    tableBuilder.setValue(TableDescriptorBuilder.OWNER, USER_OWNER.getShortName());
145    createTable(TEST_UTIL, tableBuilder.build(),
146        new byte[][] { Bytes.toBytes("s") });
147
148    // Set up initial grants
149    grantGlobal(TEST_UTIL, USER_ADMIN.getShortName(),
150        Permission.Action.ADMIN,
151        Permission.Action.CREATE,
152        Permission.Action.READ,
153        Permission.Action.WRITE);
154
155    grantOnTable(TEST_UTIL, USER_RW.getShortName(),
156        TEST_TABLE, TEST_FAMILY, null,
157        Permission.Action.READ,
158        Permission.Action.WRITE);
159
160    // USER_CREATE is USER_RW plus CREATE permissions
161    grantOnTable(TEST_UTIL, USER_CREATE.getShortName(),
162        TEST_TABLE, null, null,
163        Permission.Action.CREATE,
164        Permission.Action.READ,
165        Permission.Action.WRITE);
166
167    grantOnTable(TEST_UTIL, USER_RO.getShortName(),
168        TEST_TABLE, TEST_FAMILY, null,
169        Permission.Action.READ);
170
171    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_ADMIN), Permission.Action.ADMIN);
172    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_CREATE), Permission.Action.CREATE);
173    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_READ), Permission.Action.READ);
174    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_WRITE), Permission.Action.WRITE);
175
176    assertEquals(4, AccessControlLists.getTablePermissions(conf, TEST_TABLE).size());
177    try {
178      assertEquals(4, AccessControlClient.getUserPermissions(systemUserConnection,
179          TEST_TABLE.toString()).size());
180    } catch (Throwable e) {
181      LOG.error("error during call of AccessControlClient.getUserPermissions. ", e);
182      fail("error during call of AccessControlClient.getUserPermissions.");
183    }
184  }
185
186  private static void cleanUp() throws Exception {
187    // Clean the _acl_ table
188    try {
189      deleteTable(TEST_UTIL, TEST_TABLE);
190    } catch (TableNotFoundException ex) {
191      // Test deleted the table, no problem
192      LOG.info("Test deleted table " + TEST_TABLE);
193    }
194    // Verify all table/namespace permissions are erased
195    assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE).size());
196    assertEquals(0, AccessControlLists.getNamespacePermissions(conf,
197            TEST_TABLE.getNamespaceAsString()).size());
198  }
199
200  @AfterClass
201  public static void tearDownAfterClass() throws Exception {
202    cleanUp();
203    TEST_UTIL.shutdownMiniCluster();
204    int total = TableAuthManager.getTotalRefCount();
205    assertTrue("Unexpected reference count: " + total, total == 0);
206  }
207
208  private static void configureRSGroupAdminEndpoint(Configuration conf) {
209    String currentCoprocessors = conf.get(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY);
210    String coprocessors = RSGroupAdminEndpoint.class.getName();
211    if (currentCoprocessors != null) {
212      coprocessors += "," + currentCoprocessors;
213    }
214    conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, coprocessors);
215    conf.set(HConstants.HBASE_MASTER_LOADBALANCER_CLASS,
216        RSGroupBasedLoadBalancer.class.getName());
217  }
218
219  @Test
220  public void testGetRSGroupInfo() throws Exception {
221    AccessTestAction action = () -> {
222      rsGroupAdminEndpoint.checkPermission("getRSGroupInfo");
223      return null;
224    };
225
226    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
227    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
228        USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
229  }
230
231  @Test
232  public void testGetRSGroupInfoOfTable() throws Exception {
233    AccessTestAction action = () -> {
234      rsGroupAdminEndpoint.checkPermission("getRSGroupInfoOfTable");
235      return null;
236    };
237
238    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
239    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
240        USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
241  }
242
243  @Test
244  public void testMoveServers() throws Exception {
245    AccessTestAction action = () -> {
246      rsGroupAdminEndpoint.checkPermission("moveServers");
247      return null;
248    };
249
250    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
251    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
252        USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
253  }
254
255  @Test
256  public void testMoveTables() throws Exception {
257    AccessTestAction action = () -> {
258      rsGroupAdminEndpoint.checkPermission("moveTables");
259      return null;
260    };
261
262    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
263    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
264        USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
265  }
266
267  @Test
268  public void testAddRSGroup() throws Exception {
269    AccessTestAction action = () -> {
270      rsGroupAdminEndpoint.checkPermission("addRSGroup");
271      return null;
272    };
273
274    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
275    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
276        USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
277  }
278
279  @Test
280  public void testRemoveRSGroup() throws Exception {
281    AccessTestAction action = () -> {
282      rsGroupAdminEndpoint.checkPermission("removeRSGroup");
283      return null;
284    };
285
286    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
287    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
288        USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
289  }
290
291  @Test
292  public void testBalanceRSGroup() throws Exception {
293    AccessTestAction action = () -> {
294      rsGroupAdminEndpoint.checkPermission("balanceRSGroup");
295      return null;
296    };
297
298    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
299    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
300        USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
301  }
302
303  @Test
304  public void testListRSGroup() throws Exception {
305    AccessTestAction action = () -> {
306      rsGroupAdminEndpoint.checkPermission("listRSGroup");
307      return null;
308    };
309
310    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
311    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
312        USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
313  }
314
315  @Test
316  public void testGetRSGroupInfoOfServer() throws Exception {
317    AccessTestAction action = () -> {
318      rsGroupAdminEndpoint.checkPermission("getRSGroupInfoOfServer");
319      return null;
320    };
321
322    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
323    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
324        USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
325  }
326
327  @Test
328  public void testMoveServersAndTables() throws Exception {
329    AccessTestAction action = () -> {
330      rsGroupAdminEndpoint.checkPermission("moveServersAndTables");
331      return null;
332    };
333
334    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
335    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO,
336        USER_NONE, USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
337  }
338}