You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ap...@apache.org on 2014/04/15 19:48:31 UTC
svn commit: r1587648 - in /hbase/trunk/hbase-server/src:
main/java/org/apache/hadoop/hbase/security/access/
test/java/org/apache/hadoop/hbase/security/access/
Author: apurtell
Date: Tue Apr 15 17:48:30 2014
New Revision: 1587648
URL: http://svn.apache.org/r1587648
Log:
HBASE-10823 Resolve LATEST_TIMESTAMP to current server time before scanning for ACLs
Modified:
hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLWithMultipleVersions.java
hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java
Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java?rev=1587648&r1=1587647&r2=1587648&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java Tue Apr 15 17:48:30 2014
@@ -92,6 +92,7 @@ import org.apache.hadoop.hbase.security.
import org.apache.hadoop.hbase.security.access.Permission.Action;
import org.apache.hadoop.hbase.util.ByteRange;
import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.util.SimpleByteRange;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
@@ -476,7 +477,7 @@ public class AccessController extends Ba
}
private void requireCoveringPermission(String request, RegionCoprocessorEnvironment e,
- byte[] row, Map<byte[], ? extends Collection<?>> familyMap, long timestamp,
+ byte[] row, Map<byte[], ? extends Collection<?>> familyMap, long opTs,
boolean allVersions, Action...actions) throws IOException {
User user = getActiveUser();
@@ -511,9 +512,10 @@ public class AccessController extends Ba
// Table or CF permissions do not allow, enumerate the covered KVs. We
// can stop at the first which does not grant access.
int cellsChecked = 0;
+ opTs = opTs != HConstants.LATEST_TIMESTAMP ? opTs : 0;
+ long latestCellTs = 0;
if (canPersistCellACLs) {
Get get = new Get(row);
- if (timestamp != HConstants.LATEST_TIMESTAMP) get.setTimeStamp(timestamp);
if (allVersions) {
get.setMaxVersions();
} else {
@@ -546,6 +548,9 @@ public class AccessController extends Ba
} else {
get.addColumn(col, CellUtil.cloneQualifier(cell));
}
+ if (cell.getTimestamp() != HConstants.LATEST_TIMESTAMP) {
+ latestCellTs = Math.max(latestCellTs, cell.getTimestamp());
+ }
}
}
} else {
@@ -553,6 +558,17 @@ public class AccessController extends Ba
entry.getValue().getClass().getName());
}
}
+ // We want to avoid looking into the future. So, if the cells of the
+ // operation specify a timestamp, or the operation itself specifies a
+ // timestamp, then we use the maximum ts found. Otherwise, we bound
+ // the Get to the current server time. We add 1 to the timerange since
+ // the upper bound of a timerange is exclusive yet we need to examine
+ // any cells found there inclusively.
+ long latestTs = Math.max(opTs, latestCellTs);
+ if (latestTs == 0) {
+ latestTs = EnvironmentEdgeManager.currentTimeMillis();
+ }
+ get.setTimeRange(0, latestTs + 1);
if (LOG.isTraceEnabled()) {
LOG.trace("Scanning for cells with " + get);
}
Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java?rev=1587648&r1=1587647&r2=1587648&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java Tue Apr 15 17:48:30 2014
@@ -352,7 +352,7 @@ public class TableAuthManager {
try {
List<Permission> perms = AccessControlLists.getCellPermissionsForUser(user, cell);
if (LOG.isTraceEnabled()) {
- LOG.trace("Found perms for user " + user.getShortName() + " in cell " +
+ LOG.trace("Perms for user " + user.getShortName() + " in cell " +
cell + ": " + perms);
}
for (Permission p: perms) {
Modified: hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLWithMultipleVersions.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLWithMultipleVersions.java?rev=1587648&r1=1587647&r2=1587648&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLWithMultipleVersions.java (original)
+++ hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLWithMultipleVersions.java Tue Apr 15 17:48:30 2014
@@ -42,6 +42,7 @@ import org.apache.hadoop.hbase.master.Ma
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;
@@ -71,12 +72,16 @@ public class TestCellACLWithMultipleVers
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[] ZERO = Bytes.toBytes(0L);
+ private static final byte[] ONE = Bytes.toBytes(1L);
+ private static final byte[] TWO = Bytes.toBytes(2L);
private static Configuration conf;
private static User USER_OWNER;
private static User USER_OTHER;
+ private static User USER_OTHER2;
@BeforeClass
public static void setupBeforeClass() throws Exception {
@@ -112,6 +117,7 @@ public class TestCellACLWithMultipleVers
// create a set of test users
USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
USER_OTHER = User.createUserForTesting(conf, "other", new String[0]);
+ USER_OTHER2 = User.createUserForTesting(conf, "other2", new String[0]);
}
@AfterClass
@@ -349,6 +355,173 @@ public class TestCellACLWithMultipleVers
});
}
+
+ @Test
+ public void testDeleteWithFutureTimestamp() throws Exception {
+ // Store two values, one in the future
+
+ verifyAllowed(new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ // Store read only ACL at a future time
+ Put p = new Put(TEST_ROW).add(TEST_FAMILY, TEST_Q1,
+ EnvironmentEdgeManager.currentTimeMillis() + 1000000,
+ ZERO);
+ p.setACL(USER_OTHER.getShortName(), new Permission(Permission.Action.READ));
+ t.put(p);
+ // Store a read write ACL without a timestamp, server will use current time
+ p = new Put(TEST_ROW).add(TEST_FAMILY, TEST_Q2, ONE);
+ p.setACL(USER_OTHER.getShortName(), new Permission(Permission.Action.READ,
+ Permission.Action.WRITE));
+ t.put(p);
+ } finally {
+ t.close();
+ }
+ return null;
+ }
+ }, USER_OWNER);
+
+ // Confirm stores are visible
+
+ 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();
+ }
+ }
+ };
+
+ verifyAllowed(getQ1, USER_OWNER, USER_OTHER);
+ verifyAllowed(getQ2, USER_OWNER, USER_OTHER);
+
+
+ // Issue a DELETE for the family, should succeed because the future ACL is
+ // not considered
+
+ 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;
+ }
+ };
+
+ verifyAllowed(deleteFamily, USER_OTHER);
+
+ // The future put should still exist
+
+ verifyAllowed(getQ1, USER_OWNER, USER_OTHER);
+
+ // The other put should be covered by the tombstone
+
+ verifyDenied(getQ2, USER_OTHER);
+ }
+
+ @Test
+ public void testCellPermissionsWithDeleteWithUserTs() throws Exception {
+ USER_OWNER.runAs(new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ // This version (TS = 123) with rw ACL for USER_OTHER and USER_OTHER2
+ Put p = new Put(TEST_ROW);
+ p.add(TEST_FAMILY, TEST_Q1, 123L, ZERO);
+ p.add(TEST_FAMILY, TEST_Q2, 123L, ZERO);
+ Map<String, Permission> perms = new HashMap<String, Permission>();
+ perms.put(USER_OTHER.getShortName(), new Permission(Permission.Action.READ,
+ Permission.Action.WRITE));
+ perms.put(USER_OTHER2.getShortName(), new Permission(Permission.Action.READ,
+ Permission.Action.WRITE));
+ p.setACL(perms);
+ t.put(p);
+
+ // This version (TS = 125) with rw ACL for USER_OTHER
+ p = new Put(TEST_ROW);
+ p.add(TEST_FAMILY, TEST_Q1, 125L, ONE);
+ p.add(TEST_FAMILY, TEST_Q2, 125L, ONE);
+ perms = new HashMap<String, Permission>();
+ perms.put(USER_OTHER.getShortName(), new Permission(Permission.Action.READ,
+ Permission.Action.WRITE));
+ p.setACL(perms);
+ t.put(p);
+
+ // This version (TS = 127) with rw ACL for USER_OTHER
+ p = new Put(TEST_ROW);
+ p.add(TEST_FAMILY, TEST_Q1, 127L, TWO);
+ p.add(TEST_FAMILY, TEST_Q2, 127L, TWO);
+ perms = new HashMap<String, Permission>();
+ perms.put(USER_OTHER.getShortName(), new Permission(Permission.Action.READ,
+ Permission.Action.WRITE));
+ p.setACL(perms);
+ t.put(p);
+
+ return null;
+ } finally {
+ t.close();
+ }
+ }
+ });
+
+ // USER_OTHER2 should be allowed to delete the column f1:q1 versions older than TS 124L
+ USER_OTHER2.runAs(new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ Delete d = new Delete(TEST_ROW, 124L);
+ d.deleteColumns(TEST_FAMILY, TEST_Q1);
+ t.delete(d);
+ } finally {
+ t.close();
+ }
+ return null;
+ }
+ });
+
+ // USER_OTHER2 should be allowed to delete the column f1:q2 versions older than TS 124L
+ USER_OTHER2.runAs(new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ Delete d = new Delete(TEST_ROW);
+ d.deleteColumns(TEST_FAMILY, TEST_Q2, 124L);
+ t.delete(d);
+ } finally {
+ t.close();
+ }
+ return null;
+ }
+ });
+ }
+
@After
public void tearDown() throws Exception {
// Clean the _acl_ table
Modified: 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=1587648&r1=1587647&r2=1587648&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java (original)
+++ hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java Tue Apr 15 17:48:30 2014
@@ -44,7 +44,6 @@ import org.apache.hadoop.hbase.master.Ma
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;