Author: apurtell
Date: Sat Apr 12 17:22:31 2014
New Revision: 1586880
URL: http://svn.apache.org/r1586880
Log:
HBASE-10963 Refactor cell ACL tests; add file missing from previous commit
Added:
hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java
Added:
hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java
URL:
http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java?rev=1586880&view=auto
==============================================================================
---
hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java
(added)
+++
hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java
Sat Apr 12 17:22:31 2014
@@ -0,0 +1,394 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.security.access;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.Coprocessor;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.MediumTests;
+import org.apache.hadoop.hbase.TableNotFoundException;
+import org.apache.hadoop.hbase.client.Delete;
+import org.apache.hadoop.hbase.client.Get;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.client.Increment;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.client.ResultScanner;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
+import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
+import org.apache.hadoop.hbase.security.User;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
+import org.apache.hadoop.hbase.util.TestTableName;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.google.common.collect.Lists;
+
+@Category(MediumTests.class)
+public class TestCellACLs extends SecureTestUtil {
+ private static final Log LOG = LogFactory.getLog(TestCellACLs.class);
+
+ static {
+ Logger.getLogger(AccessController.class).setLevel(Level.TRACE);
+ Logger.getLogger(AccessControlFilter.class).setLevel(Level.TRACE);
+ Logger.getLogger(TableAuthManager.class).setLevel(Level.TRACE);
+ }
+
+ @Rule
+ public TestTableName TEST_TABLE = new TestTableName();
+ private static final HBaseTestingUtility TEST_UTIL = new
HBaseTestingUtility();
+ private static final byte[] TEST_FAMILY = Bytes.toBytes("f1");
+ private static final byte[] TEST_ROW = Bytes.toBytes("cellpermtest");
+ private static final byte[] TEST_Q1 = Bytes.toBytes("q1");
+ private static final byte[] TEST_Q2 = Bytes.toBytes("q2");
+ private static final byte[] TEST_Q3 = Bytes.toBytes("q3");
+ private static final byte[] TEST_Q4 = Bytes.toBytes("q4");
+ private static final byte[] ZERO = Bytes.toBytes(0L);
+
+ private static Configuration conf;
+
+ private static User USER_OWNER;
+ private static User USER_OTHER;
+
+ @BeforeClass
+ public static void setupBeforeClass() throws Exception {
+ // setup configuration
+ conf = TEST_UTIL.getConfiguration();
+ conf.set("hbase.master.hfilecleaner.plugins",
+ "org.apache.hadoop.hbase.master.cleaner.HFileLinkCleaner,"
+ + "org.apache.hadoop.hbase.master.snapshot.SnapshotHFileCleaner");
+ conf.set("hbase.master.logcleaner.plugins",
+ "org.apache.hadoop.hbase.master.snapshot.SnapshotLogCleaner");
+ // Enable security
+ enableSecurity(conf);
+ // Verify enableSecurity sets up what we require
+ verifyConfiguration(conf);
+
+ // Enable EXEC permission checking
+ conf.setBoolean(AccessController.EXEC_PERMISSION_CHECKS_KEY, true);
+
+ TEST_UTIL.startMiniCluster();
+ MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster()
+ .getMasterCoprocessorHost();
+ cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
+ AccessController ac = (AccessController)
+ cpHost.findCoprocessor(AccessController.class.getName());
+ cpHost.createEnvironment(AccessController.class, ac,
Coprocessor.PRIORITY_HIGHEST, 1, conf);
+ RegionServerCoprocessorHost rsHost =
TEST_UTIL.getMiniHBaseCluster().getRegionServer(0)
+ .getRegionServerCoprocessorHost();
+ rsHost.createEnvironment(AccessController.class, ac,
Coprocessor.PRIORITY_HIGHEST, 1, conf);
+
+ // Wait for the ACL table to become available
+ TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME.getName());
+
+ // create a set of test users
+ USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
+ USER_OTHER = User.createUserForTesting(conf, "other", new String[0]);
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ TEST_UTIL.shutdownMiniCluster();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ // Create the test table (owner added to the _acl_ table)
+ HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
+ HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName());
+ HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
+ hcd.setMaxVersions(4);
+ htd.setOwner(USER_OWNER);
+ htd.addFamily(hcd);
+ admin.createTable(htd, new byte[][] { Bytes.toBytes("s") });
+ TEST_UTIL.waitTableEnabled(TEST_TABLE.getTableName().getName());
+ }
+
+ @Test
+ public void testCellPermissions() throws Exception {
+ // store two sets of values, one store with a cell level ACL, and one
without
+ verifyAllowed(new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ Put p;
+ // with ro ACL
+ p = new Put(TEST_ROW).add(TEST_FAMILY, TEST_Q1, ZERO);
+ p.setACL(USER_OTHER.getShortName(), new
Permission(Permission.Action.READ));
+ t.put(p);
+ // with rw ACL
+ p = new Put(TEST_ROW).add(TEST_FAMILY, TEST_Q2, ZERO);
+ p.setACL(USER_OTHER.getShortName(), new
Permission(Permission.Action.READ,
+ Permission.Action.WRITE));
+ t.put(p);
+ // no ACL
+ p = new Put(TEST_ROW)
+ .add(TEST_FAMILY, TEST_Q3, ZERO)
+ .add(TEST_FAMILY, TEST_Q4, ZERO);
+ t.put(p);
+ } finally {
+ t.close();
+ }
+ return null;
+ }
+ }, USER_OWNER);
+
+ /* ---- Gets ---- */
+
+ AccessTestAction getQ1 = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Get get = new Get(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q1);
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ return t.get(get).listCells();
+ } finally {
+ t.close();
+ }
+ }
+ };
+
+ AccessTestAction getQ2 = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Get get = new Get(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q2);
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ return t.get(get).listCells();
+ } finally {
+ t.close();
+ }
+ }
+ };
+
+ AccessTestAction getQ3 = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Get get = new Get(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q3);
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ return t.get(get).listCells();
+ } finally {
+ t.close();
+ }
+ }
+ };
+
+ AccessTestAction getQ4 = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Get get = new Get(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q4);
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ return t.get(get).listCells();
+ } finally {
+ t.close();
+ }
+ }
+ };
+
+ // Confirm special read access set at cell level
+
+ verifyAllowed(getQ1, USER_OTHER);
+ verifyAllowed(getQ2, USER_OTHER);
+
+ // Confirm this access does not extend to other cells
+
+ verifyDenied(getQ3, USER_OTHER);
+ verifyDenied(getQ4, USER_OTHER);
+
+ /* ---- Scans ---- */
+
+ // check that a scan over the test data returns the expected number of KVs
+
+ final List<Cell> scanResults = Lists.newArrayList();
+
+ AccessTestAction scanAction = new AccessTestAction() {
+ @Override
+ public List<Cell> run() throws Exception {
+ Scan scan = new Scan();
+ scan.setStartRow(TEST_ROW);
+ scan.setStopRow(Bytes.add(TEST_ROW, new byte[]{ 0 } ));
+ scan.addFamily(TEST_FAMILY);
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ ResultScanner scanner = t.getScanner(scan);
+ Result result = null;
+ do {
+ result = scanner.next();
+ if (result != null) {
+ scanResults.addAll(result.listCells());
+ }
+ } while (result != null);
+ } finally {
+ t.close();
+ }
+ return scanResults;
+ }
+ };
+
+ // owner will see all values
+ scanResults.clear();
+ verifyAllowed(scanAction, USER_OWNER);
+ assertEquals(4, scanResults.size());
+
+ // other user will see 2 values
+ scanResults.clear();
+ verifyAllowed(scanAction, USER_OTHER);
+ assertEquals(2, scanResults.size());
+
+ /* ---- Increments ---- */
+
+ AccessTestAction incrementQ1 = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Increment i = new Increment(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q1,
1L);
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ t.increment(i);
+ } finally {
+ t.close();
+ }
+ return null;
+ }
+ };
+
+ AccessTestAction incrementQ2 = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Increment i = new Increment(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q2,
1L);
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ t.increment(i);
+ } finally {
+ t.close();
+ }
+ return null;
+ }
+ };
+
+ AccessTestAction incrementQ2newDenyACL = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Increment i = new Increment(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q2,
1L);
+ // Tag this increment with an ACL that denies write permissions to
USER_OTHER
+ i.setACL(USER_OTHER.getShortName(), new
Permission(Permission.Action.READ));
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ t.increment(i);
+ } finally {
+ t.close();
+ }
+ return null;
+ }
+ };
+
+ AccessTestAction incrementQ3 = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Increment i = new Increment(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q3,
1L);
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ t.increment(i);
+ } finally {
+ t.close();
+ }
+ return null;
+ }
+ };
+
+ verifyDenied(incrementQ1, USER_OTHER);
+ verifyDenied(incrementQ3, USER_OTHER);
+
+ // We should be able to increment Q2 twice, the previous ACL will be
+ // carried forward
+ verifyAllowed(incrementQ2, USER_OTHER);
+ verifyAllowed(incrementQ2newDenyACL, USER_OTHER);
+ // But not again after we denied ourselves write permission with an ACL
+ // update
+ verifyDenied(incrementQ2, USER_OTHER);
+
+ /* ---- Deletes ---- */
+
+ AccessTestAction deleteFamily = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Delete delete = new Delete(TEST_ROW).deleteFamily(TEST_FAMILY);
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ t.delete(delete);
+ } finally {
+ t.close();
+ }
+ return null;
+ }
+ };
+
+ AccessTestAction deleteQ1 = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Delete delete = new Delete(TEST_ROW).deleteColumn(TEST_FAMILY,
TEST_Q1);
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ t.delete(delete);
+ } finally {
+ t.close();
+ }
+ return null;
+ }
+ };
+
+ verifyDenied(deleteFamily, USER_OTHER);
+ verifyDenied(deleteQ1, USER_OTHER);
+ verifyAllowed(deleteQ1, USER_OWNER);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Clean the _acl_ table
+ try {
+ TEST_UTIL.deleteTable(TEST_TABLE.getTableName());
+ } catch (TableNotFoundException ex) {
+ // Test deleted the table, no problem
+ LOG.info("Test deleted table " + TEST_TABLE.getTableName());
+ }
+ assertEquals(0, AccessControlLists.getTablePermissions(conf,
TEST_TABLE.getTableName()).size());
+ }
+}