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.fail;
023
024import org.apache.hadoop.conf.Configuration;
025import org.apache.hadoop.hbase.HBaseClassTestRule;
026import org.apache.hadoop.hbase.HBaseTestingUtility;
027import org.apache.hadoop.hbase.HConstants;
028import org.apache.hadoop.hbase.TableName;
029import org.apache.hadoop.hbase.TableNotFoundException;
030import org.apache.hadoop.hbase.Waiter.Predicate;
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.master.HMaster;
036import org.apache.hadoop.hbase.security.User;
037import org.apache.hadoop.hbase.security.access.AccessControlClient;
038import org.apache.hadoop.hbase.security.access.Permission;
039import org.apache.hadoop.hbase.security.access.PermissionStorage;
040import org.apache.hadoop.hbase.security.access.SecureTestUtil;
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 levels of authorized
054 * 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, RSGroupBasedLoadBalancer.class.getName());
103    // Enable security
104    enableSecurity(conf);
105    // Verify enableSecurity sets up what we require
106    verifyConfiguration(conf);
107    // Enable rsgroup
108    configureRSGroupAdminEndpoint(conf);
109
110    TEST_UTIL.startMiniCluster();
111
112    HMaster master = TEST_UTIL.getHBaseCluster().getMaster();
113    TEST_UTIL.waitFor(60000, (Predicate<Exception>) () -> master.isInitialized()
114      && ((RSGroupBasedLoadBalancer) master.getLoadBalancer()).isOnline());
115
116    rsGroupAdminEndpoint = (RSGroupAdminEndpoint) TEST_UTIL.getMiniHBaseCluster().getMaster()
117      .getMasterCoprocessorHost().findCoprocessor(RSGroupAdminEndpoint.class.getName());
118    // Wait for the ACL table to become available
119    TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME);
120    TEST_UTIL.waitUntilAllRegionsAssigned(RSGroupInfoManagerImpl.RSGROUP_TABLE_NAME);
121    TEST_UTIL.waitUntilNoRegionsInTransition();
122
123    // create a set of test users
124    SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
125    USER_ADMIN = User.createUserForTesting(conf, "admin2", new String[0]);
126    USER_RW = User.createUserForTesting(conf, "rwuser", new String[0]);
127    USER_RO = User.createUserForTesting(conf, "rouser", new String[0]);
128    USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
129    USER_CREATE = User.createUserForTesting(conf, "tbl_create", new String[0]);
130    USER_NONE = User.createUserForTesting(conf, "nouser", new String[0]);
131
132    USER_GROUP_ADMIN =
133      User.createUserForTesting(conf, "user_group_admin", new String[] { GROUP_ADMIN });
134    USER_GROUP_CREATE =
135      User.createUserForTesting(conf, "user_group_create", new String[] { GROUP_CREATE });
136    USER_GROUP_READ =
137      User.createUserForTesting(conf, "user_group_read", new String[] { GROUP_READ });
138    USER_GROUP_WRITE =
139      User.createUserForTesting(conf, "user_group_write", new String[] { GROUP_WRITE });
140
141    systemUserConnection = TEST_UTIL.getConnection();
142    setUpTableAndUserPermissions();
143  }
144
145  private static void setUpTableAndUserPermissions() throws Exception {
146    TableDescriptorBuilder tableBuilder = TableDescriptorBuilder.newBuilder(TEST_TABLE);
147    ColumnFamilyDescriptorBuilder cfd = ColumnFamilyDescriptorBuilder.newBuilder(TEST_FAMILY);
148    cfd.setMaxVersions(100);
149    tableBuilder.setColumnFamily(cfd.build());
150    tableBuilder.setValue(TableDescriptorBuilder.OWNER, USER_OWNER.getShortName());
151    createTable(TEST_UTIL, tableBuilder.build(), new byte[][] { Bytes.toBytes("s") });
152
153    // Set up initial grants
154    grantGlobal(TEST_UTIL, USER_ADMIN.getShortName(), Permission.Action.ADMIN,
155      Permission.Action.CREATE, Permission.Action.READ, Permission.Action.WRITE);
156
157    grantOnTable(TEST_UTIL, USER_RW.getShortName(), TEST_TABLE, TEST_FAMILY, null,
158      Permission.Action.READ, Permission.Action.WRITE);
159
160    // USER_CREATE is USER_RW plus CREATE permissions
161    grantOnTable(TEST_UTIL, USER_CREATE.getShortName(), TEST_TABLE, null, null,
162      Permission.Action.CREATE, Permission.Action.READ, Permission.Action.WRITE);
163
164    grantOnTable(TEST_UTIL, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null,
165      Permission.Action.READ);
166
167    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_ADMIN), Permission.Action.ADMIN);
168    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_CREATE), Permission.Action.CREATE);
169    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_READ), Permission.Action.READ);
170    grantGlobal(TEST_UTIL, toGroupEntry(GROUP_WRITE), Permission.Action.WRITE);
171
172    assertEquals(4, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size());
173    try {
174      assertEquals(4,
175        AccessControlClient.getUserPermissions(systemUserConnection, TEST_TABLE.toString()).size());
176    } catch (AssertionError e) {
177      fail(e.getMessage());
178    } catch (Throwable e) {
179      LOG.error("error during call of AccessControlClient.getUserPermissions. ", e);
180    }
181  }
182
183  private static void cleanUp() throws Exception {
184    // Clean the _acl_ table
185    try {
186      deleteTable(TEST_UTIL, TEST_TABLE);
187    } catch (TableNotFoundException ex) {
188      // Test deleted the table, no problem
189      LOG.info("Test deleted table " + TEST_TABLE);
190    }
191    // Verify all table/namespace permissions are erased
192    assertEquals(0, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size());
193    assertEquals(0,
194      PermissionStorage.getNamespacePermissions(conf, TEST_TABLE.getNamespaceAsString()).size());
195  }
196
197  @AfterClass
198  public static void tearDownAfterClass() throws Exception {
199    cleanUp();
200    TEST_UTIL.shutdownMiniCluster();
201  }
202
203  private static void configureRSGroupAdminEndpoint(Configuration conf) {
204    String currentCoprocessors = conf.get(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY);
205    String coprocessors = RSGroupAdminEndpoint.class.getName();
206    if (currentCoprocessors != null) {
207      coprocessors += "," + currentCoprocessors;
208    }
209    conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, coprocessors);
210    conf.set(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, RSGroupBasedLoadBalancer.class.getName());
211  }
212
213  @Test
214  public void testGetRSGroupInfo() throws Exception {
215    AccessTestAction action = () -> {
216      rsGroupAdminEndpoint.checkPermission("getRSGroupInfo");
217      return null;
218    };
219
220    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
221    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
222      USER_GROUP_WRITE, USER_GROUP_CREATE);
223  }
224
225  @Test
226  public void testGetRSGroupInfoOfTable() throws Exception {
227    AccessTestAction action = () -> {
228      rsGroupAdminEndpoint.checkPermission("getRSGroupInfoOfTable");
229      return null;
230    };
231
232    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
233    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
234      USER_GROUP_WRITE, USER_GROUP_CREATE);
235  }
236
237  @Test
238  public void testMoveServers() throws Exception {
239    AccessTestAction action = () -> {
240      rsGroupAdminEndpoint.checkPermission("moveServers");
241      return null;
242    };
243
244    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
245    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
246      USER_GROUP_WRITE, USER_GROUP_CREATE);
247  }
248
249  @Test
250  public void testMoveTables() throws Exception {
251    AccessTestAction action = () -> {
252      rsGroupAdminEndpoint.checkPermission("moveTables");
253      return null;
254    };
255
256    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
257    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
258      USER_GROUP_WRITE, USER_GROUP_CREATE);
259  }
260
261  @Test
262  public void testAddRSGroup() throws Exception {
263    AccessTestAction action = () -> {
264      rsGroupAdminEndpoint.checkPermission("addRSGroup");
265      return null;
266    };
267
268    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
269    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
270      USER_GROUP_WRITE, USER_GROUP_CREATE);
271  }
272
273  @Test
274  public void testRemoveRSGroup() throws Exception {
275    AccessTestAction action = () -> {
276      rsGroupAdminEndpoint.checkPermission("removeRSGroup");
277      return null;
278    };
279
280    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
281    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
282      USER_GROUP_WRITE, USER_GROUP_CREATE);
283  }
284
285  @Test
286  public void testBalanceRSGroup() throws Exception {
287    AccessTestAction action = () -> {
288      rsGroupAdminEndpoint.checkPermission("balanceRSGroup");
289      return null;
290    };
291
292    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
293    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
294      USER_GROUP_WRITE, USER_GROUP_CREATE);
295  }
296
297  @Test
298  public void testListRSGroup() throws Exception {
299    AccessTestAction action = () -> {
300      rsGroupAdminEndpoint.checkPermission("listRSGroup");
301      return null;
302    };
303
304    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
305    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
306      USER_GROUP_WRITE, USER_GROUP_CREATE);
307  }
308
309  @Test
310  public void testGetRSGroupInfoOfServer() throws Exception {
311    AccessTestAction action = () -> {
312      rsGroupAdminEndpoint.checkPermission("getRSGroupInfoOfServer");
313      return null;
314    };
315
316    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
317    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
318      USER_GROUP_WRITE, USER_GROUP_CREATE);
319  }
320
321  @Test
322  public void testMoveServersAndTables() throws Exception {
323    AccessTestAction action = () -> {
324      rsGroupAdminEndpoint.checkPermission("moveServersAndTables");
325      return null;
326    };
327
328    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
329    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
330      USER_GROUP_WRITE, USER_GROUP_CREATE);
331  }
332
333  @Test
334  public void testRenameRSGroup() throws Exception {
335    AccessTestAction action = () -> {
336      rsGroupAdminEndpoint.checkPermission("renameRSGroup");
337      return null;
338    };
339
340    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
341    verifyDenied(action, USER_CREATE, USER_OWNER, USER_RW, USER_RO, USER_NONE, USER_GROUP_READ,
342      USER_GROUP_WRITE, USER_GROUP_CREATE);
343  }
344}