diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlFilter.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlFilter.java index 559c593..72e5fd3 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlFilter.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlFilter.java @@ -96,25 +96,28 @@ if (isSystemTable) { return ReturnCode.INCLUDE; } - if (prevFam.getBytes() == null - || !(CellUtil.matchingFamily(cell, prevFam.getBytes(), prevFam.getOffset(), - prevFam.getLength()))) { - prevFam.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); - // Similar to VisibilityLabelFilter - familyMaxVersions = cfVsMaxVersions.get(prevFam); - // Family is changed. Just unset curQualifier. - prevQual.unset(); - } - if (prevQual.getBytes() == null - || !(CellUtil.matchingQualifier(cell, prevQual.getBytes(), prevQual.getOffset(), - prevQual.getLength()))) { - prevQual.set(cell.getQualifierArray(), cell.getQualifierOffset(), - cell.getQualifierLength()); - currentVersions = 0; - } - currentVersions++; - if (currentVersions > familyMaxVersions) { - return ReturnCode.SKIP; + boolean isDelete = CellUtil.isDelete(cell); + if (!isDelete) { + if (prevFam.getBytes() == null + || !(CellUtil.matchingFamily(cell, prevFam.getBytes(), prevFam.getOffset(), + prevFam.getLength()))) { + prevFam.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); + // Similar to VisibilityLabelFilter + familyMaxVersions = cfVsMaxVersions.get(prevFam); + // Family is changed. Just unset curQualifier. + prevQual.unset(); + } + if (prevQual.getBytes() == null + || !(CellUtil.matchingQualifier(cell, prevQual.getBytes(), prevQual.getOffset(), + prevQual.getLength()))) { + prevQual.set(cell.getQualifierArray(), cell.getQualifierOffset(), + cell.getQualifierLength()); + currentVersions = 0; + } + currentVersions++; + if (currentVersions > familyMaxVersions) { + return ReturnCode.SKIP; + } } // XXX: Compare in place, don't clone byte[] family = CellUtil.cloneFamily(cell); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityLabelFilter.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityLabelFilter.java index ef7e88a..1bf1a75 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityLabelFilter.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityLabelFilter.java @@ -57,6 +57,9 @@ @Override public ReturnCode filterKeyValue(Cell cell) throws IOException { + if (CellUtil.isDelete(cell)) { + return this.expEvaluator.evaluate(cell) ? ReturnCode.INCLUDE : ReturnCode.SKIP; + } if (curFamily.getBytes() == null || !(CellUtil.matchingFamily(cell, curFamily.getBytes(), curFamily.getOffset(), curFamily.getLength()))) { diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessControlFilter.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessControlFilter.java index cf01463..cb2c3e4 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessControlFilter.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessControlFilter.java @@ -21,18 +21,24 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; - +import static org.junit.Assert.assertNotNull; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.List; import java.util.UUID; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.Cell; +import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.KeepDeletedCells; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; @@ -203,4 +209,60 @@ } }); } + @Test + public void testRawScan() throws Exception { + TableName tableName = TableName.valueOf("testRawScan"); + final long now = System.currentTimeMillis(); + byte[] row1 = Bytes.toBytes("row1"); + HTableDescriptor desc = new HTableDescriptor(tableName); + desc.addFamily(new HColumnDescriptor(FAMILY) + .setMaxVersions(5) + .setKeepDeletedCells(KeepDeletedCells.TRUE) + ); + createTable(TEST_UTIL, TEST_UTIL.getAdmin(), desc, null); + SecureTestUtil.grantOnTable(TEST_UTIL, LIMITED.getShortName(), + tableName, FAMILY, PUBLIC_COL, Permission.Action.READ); + try (Table t = TEST_UTIL.getConnection().getTable(desc.getTableName())) { + Put p = new Put(row1); + // all allowed + p.addColumn(FAMILY, PUBLIC_COL, now, PUBLIC_COL); + p.addColumn(FAMILY, PUBLIC_COL, now + 1, PUBLIC_COL); + p.addColumn(FAMILY, PUBLIC_COL, now + 2, PUBLIC_COL); + p.addColumn(FAMILY, PUBLIC_COL, now + 3, PUBLIC_COL); + p.addColumn(FAMILY, PUBLIC_COL, now + 4, PUBLIC_COL); + t.put(p); + // denied + Delete d = new Delete(row1, now + 3); + t.delete(d); + d = new Delete(row1); + // allowed + d.addColumns(FAMILY, PUBLIC_COL, now + 2); + t.delete(d); + } + LIMITED.runAs(new PrivilegedExceptionAction() { + @Override + public Object run() throws Exception { + Scan s = new Scan(); + s.setMaxVersions(); + s.setRaw(true); + Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); + try (Connection connection = ConnectionFactory.createConnection(conf); + Table t = connection.getTable(TABLE); + ResultScanner scanner = t.getScanner(s)) { + Result r = scanner.next(); + Cell[] res = r.rawCells(); + assertNotNull(res); + assertEquals(6, res.length); + assertEquals(now + 4, res[0].getTimestamp()); + assertEquals(now + 3, res[1].getTimestamp()); + assertEquals(true, CellUtil.isDelete(res[2])); + assertEquals(now + 2, res[3].getTimestamp()); + assertEquals(now + 1, res[4].getTimestamp()); + assertEquals(now, res[5].getTimestamp()); + } + return null; + } + }); + deleteTable(TEST_UTIL, TEST_UTIL.getAdmin(), desc.getTableName()); + } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithDefaultVisLabelService.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithDefaultVisLabelService.java index 63c08a2..7405859 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithDefaultVisLabelService.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithDefaultVisLabelService.java @@ -56,6 +56,19 @@ import org.junit.experimental.categories.Category; import com.google.protobuf.ByteString; +import org.apache.hadoop.hbase.Cell; +import org.apache.hadoop.hbase.CellUtil; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.KeepDeletedCells; +import org.apache.hadoop.hbase.client.Delete; +import org.apache.hadoop.hbase.client.Put; +import static org.apache.hadoop.hbase.security.visibility.TestVisibilityLabels.TEST_UTIL; +import static org.apache.hadoop.hbase.security.visibility.TestVisibilityLabels.fam; +import static org.apache.hadoop.hbase.security.visibility.TestVisibilityLabels.qual; +import static org.apache.hadoop.hbase.security.visibility.TestVisibilityLabels.row1; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; @Category({SecurityTests.class, MediumTests.class}) public class TestVisibilityLabelsWithDefaultVisLabelService extends TestVisibilityLabels { @@ -240,4 +253,46 @@ assertTrue(next.length == 1); } } + @Test + public void testVisibilityLabelFilterWithRawScan() throws Exception { + TableName tableName = TableName.valueOf(TEST_NAME.getMethodName()); + long now = System.currentTimeMillis(); + HTableDescriptor desc = new HTableDescriptor(tableName); + desc.addFamily(new HColumnDescriptor(fam) + .setMaxVersions(5) + .setKeepDeletedCells(KeepDeletedCells.TRUE) + ); + TEST_UTIL.getAdmin().createTable(desc); + try (Table t = TEST_UTIL.getConnection().getTable(desc.getTableName())) { + Put p = new Put(row1); + p.addColumn(fam, qual, now, qual); + p.addColumn(fam, qual, now + 1, qual); + p.addColumn(fam, qual, now + 2, qual); + p.addColumn(fam, qual, now + 3, qual); + p.addColumn(fam, qual, now + 4, qual); + t.put(p); + Delete d = new Delete(row1, now + 3); + t.delete(d); + d = new Delete(row1); + d.addColumns(fam, qual, now + 2); + t.delete(d); + + Scan s = new Scan(); + s.setMaxVersions(); + s.setRaw(true); + ResultScanner scanner = t.getScanner(s); + Result r = scanner.next(); + Cell[] res = r.rawCells(); + assertEquals(7, res.length); + assertTrue(CellUtil.isDeleteFamily(res[0])); + assertEquals(now + 4, res[1].getTimestamp()); + assertEquals(now + 3, res[2].getTimestamp()); + assertTrue(CellUtil.isDelete(res[3])); + assertEquals(now + 2, res[4].getTimestamp()); + assertEquals(now + 1, res[5].getTimestamp()); + assertEquals(now, res[6].getTimestamp()); + } + TEST_UTIL.getAdmin().disableTable(desc.getTableName()); + TEST_UTIL.getAdmin().deleteTable(desc.getTableName()); + } }