HBASE-10854 [VisibilityController] Apply MAX_VERSIONS from schema or request when scanning. (Anoop)

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1584327 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
anoopsamjohn 2014-04-03 09:28:16 +00:00
parent 5ae0acfdd4
commit 3e1d49e146
3 changed files with 153 additions and 4 deletions

View File

@ -108,8 +108,10 @@ import org.apache.hadoop.hbase.security.visibility.expression.ExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.LeafExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.NonLeafExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.Operator;
import org.apache.hadoop.hbase.util.ByteRange;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.util.SimpleByteRange;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import com.google.common.collect.Lists;
@ -979,6 +981,10 @@ public class VisibilityController extends BaseRegionObserver implements MasterOb
}
private Filter createVisibilityLabelFilter(HRegion region, Authorizations authorizations) {
Map<ByteRange, Integer> cfVsMaxVersions = new HashMap<ByteRange, Integer>();
for (HColumnDescriptor hcd : region.getTableDesc().getFamilies()) {
cfVsMaxVersions.put(new SimpleByteRange(hcd.getName()), hcd.getMaxVersions());
}
if (authorizations == null) {
// No Authorizations present for this scan/Get!
// In case of "labels" table and user tables, create an empty auth set. In other system tables
@ -988,7 +994,7 @@ public class VisibilityController extends BaseRegionObserver implements MasterOb
if (table.isSystemTable() && !table.equals(LABELS_TABLE_NAME)) {
return null;
}
return new VisibilityLabelFilter(new BitSet(0));
return new VisibilityLabelFilter(new BitSet(0), cfVsMaxVersions);
}
Filter visibilityLabelFilter = null;
if (this.scanLabelGenerator != null) {
@ -1008,7 +1014,7 @@ public class VisibilityController extends BaseRegionObserver implements MasterOb
}
}
}
visibilityLabelFilter = new VisibilityLabelFilter(bs);
visibilityLabelFilter = new VisibilityLabelFilter(bs, cfVsMaxVersions);
}
return visibilityLabelFilter;
}

View File

@ -20,6 +20,7 @@ package org.apache.hadoop.hbase.security.visibility;
import java.io.IOException;
import java.util.BitSet;
import java.util.Iterator;
import java.util.Map;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hbase.Cell;
@ -27,7 +28,10 @@ import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.Tag;
import org.apache.hadoop.hbase.filter.FilterBase;
import org.apache.hadoop.hbase.io.util.StreamUtils;
import org.apache.hadoop.hbase.util.ByteRange;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.util.SimpleByteRange;
/**
* This Filter checks the visibility expression with each KV against visibility labels associated
@ -36,14 +40,46 @@ import org.apache.hadoop.hbase.util.Pair;
@InterfaceAudience.Private
class VisibilityLabelFilter extends FilterBase {
private BitSet authLabels;
private final BitSet authLabels;
private final Map<ByteRange, Integer> cfVsMaxVersions;
private final ByteRange curFamily;
private final ByteRange curQualifier;
private int curFamilyMaxVersions;
private int curQualMetVersions;
public VisibilityLabelFilter(BitSet authLabels) {
public VisibilityLabelFilter(BitSet authLabels, Map<ByteRange, Integer> cfVsMaxVersions) {
this.authLabels = authLabels;
this.cfVsMaxVersions = cfVsMaxVersions;
this.curFamily = new SimpleByteRange();
this.curQualifier = new SimpleByteRange();
}
@Override
public ReturnCode filterKeyValue(Cell cell) throws IOException {
if (curFamily.getBytes() == null
|| (Bytes.compareTo(curFamily.getBytes(), curFamily.getOffset(), curFamily.getLength(),
cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()) != 0)) {
curFamily.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
// For this family, all the columns can have max of curFamilyMaxVersions versions. No need to
// consider the older versions for visibility label check.
// Ideally this should have been done at a lower layer by HBase (?)
curFamilyMaxVersions = cfVsMaxVersions.get(curFamily);
// Family is changed. Just unset curQualifier.
curQualifier.unset();
}
if (curQualifier.getBytes() == null
|| (Bytes.compareTo(curQualifier.getBytes(), curQualifier.getOffset(),
curQualifier.getLength(), cell.getQualifierArray(), cell.getQualifierOffset(),
cell.getQualifierLength()) != 0)) {
curQualifier.set(cell.getQualifierArray(), cell.getQualifierOffset(),
cell.getQualifierLength());
curQualMetVersions = 0;
}
curQualMetVersions++;
if (curQualMetVersions > curFamilyMaxVersions) {
return ReturnCode.SKIP;
}
Iterator<Tag> tagsItr = CellUtil.tagsIterator(cell.getTagsArray(), cell.getTagsOffset(),
cell.getTagsLength());
boolean visibilityTagPresent = false;
@ -82,4 +118,12 @@ class VisibilityLabelFilter extends FilterBase {
}
return visibilityTagPresent ? ReturnCode.SKIP : ReturnCode.INCLUDE;
}
@Override
public void reset() throws IOException {
this.curFamily.unset();
this.curQualifier.unset();
this.curFamilyMaxVersions = 0;
this.curQualMetVersions = 0;
}
}

View File

@ -764,6 +764,105 @@ public class TestVisibilityLabels {
}
}
@Test
public void testMultipleVersions() throws Exception {
final byte[] r1 = Bytes.toBytes("row1");
final byte[] r2 = Bytes.toBytes("row2");
final byte[] v1 = Bytes.toBytes("100");
final byte[] v2 = Bytes.toBytes("101");
final byte[] fam2 = Bytes.toBytes("info2");
final byte[] qual2 = Bytes.toBytes("qual2");
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
HTableDescriptor desc = new HTableDescriptor(tableName);
HColumnDescriptor col = new HColumnDescriptor(fam);// Default max versions is 1.
desc.addFamily(col);
col = new HColumnDescriptor(fam2);
col.setMaxVersions(5);
desc.addFamily(col);
TEST_UTIL.getHBaseAdmin().createTable(desc);
HTable table = null;
try {
table = new HTable(TEST_UTIL.getConfiguration(), tableName);
Put put = new Put(r1);
put.add(fam, qual, 3l, v1);
put.add(fam, qual2, 3l, v1);
put.add(fam2, qual, 3l, v1);
put.add(fam2, qual2, 3l, v1);
put.setCellVisibility(new CellVisibility(SECRET));
table.put(put);
put = new Put(r1);
put.add(fam, qual, 4l, v2);
put.add(fam, qual2, 4l, v2);
put.add(fam2, qual, 4l, v2);
put.add(fam2, qual2, 4l, v2);
put.setCellVisibility(new CellVisibility(PRIVATE));
table.put(put);
put = new Put(r2);
put.add(fam, qual, 3l, v1);
put.add(fam, qual2, 3l, v1);
put.add(fam2, qual, 3l, v1);
put.add(fam2, qual2, 3l, v1);
put.setCellVisibility(new CellVisibility(SECRET));
table.put(put);
put = new Put(r2);
put.add(fam, qual, 4l, v2);
put.add(fam, qual2, 4l, v2);
put.add(fam2, qual, 4l, v2);
put.add(fam2, qual2, 4l, v2);
put.setCellVisibility(new CellVisibility(SECRET));
table.put(put);
// TEST_UTIL.getHBaseAdmin().flush(tableName.getNameAsString());
Scan s = new Scan();
s.setMaxVersions(1);
s.setAuthorizations(new Authorizations(SECRET));
ResultScanner scanner = table.getScanner(s);
Result result = scanner.next();
assertTrue(Bytes.equals(r1, result.getRow()));
// for cf 'fam' max versions in HCD is 1. So the old version cells, which are having matching
// CellVisibility with Authorizations, should not get considered in the label evaluation at
// all.
assertNull(result.getColumnLatestCell(fam, qual));
assertNull(result.getColumnLatestCell(fam, qual2));
// for cf 'fam2' max versions in HCD is > 1. So we can consider the old version cells, which
// are having matching CellVisibility with Authorizations, in the label evaluation. It can
// just skip those recent versions for which visibility is not there as per the new version's
// CellVisibility. The old versions which are having visibility can be send back
Cell cell = result.getColumnLatestCell(fam2, qual);
assertNotNull(cell);
assertTrue(Bytes.equals(v1, 0, v1.length, cell.getValueArray(), cell.getValueOffset(),
cell.getValueLength()));
cell = result.getColumnLatestCell(fam2, qual2);
assertNotNull(cell);
assertTrue(Bytes.equals(v1, 0, v1.length, cell.getValueArray(), cell.getValueOffset(),
cell.getValueLength()));
result = scanner.next();
assertTrue(Bytes.equals(r2, result.getRow()));
cell = result.getColumnLatestCell(fam, qual);
assertNotNull(cell);
assertTrue(Bytes.equals(v2, 0, v2.length, cell.getValueArray(), cell.getValueOffset(),
cell.getValueLength()));
cell = result.getColumnLatestCell(fam, qual2);
assertNotNull(cell);
assertTrue(Bytes.equals(v2, 0, v2.length, cell.getValueArray(), cell.getValueOffset(),
cell.getValueLength()));
cell = result.getColumnLatestCell(fam2, qual);
assertNotNull(cell);
assertTrue(Bytes.equals(v2, 0, v2.length, cell.getValueArray(), cell.getValueOffset(),
cell.getValueLength()));
cell = result.getColumnLatestCell(fam2, qual2);
assertNotNull(cell);
assertTrue(Bytes.equals(v2, 0, v2.length, cell.getValueArray(), cell.getValueOffset(),
cell.getValueLength()));
} finally {
if (table != null) {
table.close();
}
}
}
private static HTable createTableAndWriteDataWithLabels(TableName tableName, String... labelExps)
throws Exception {
HTable table = null;