RANGER-1365: Modify Ranger Hbase Plugin ColumnIterator to use Cell instead of KeyValue (to avoid ClassCastException in certain cases)
Signed-off-by: rmani <rmani@hortonworks.com>
diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/ColumnIterator.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/ColumnIterator.java
index ccccb4e..7d78c08 100644
--- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/ColumnIterator.java
+++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/ColumnIterator.java
@@ -26,7 +26,8 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.util.Bytes;
public class ColumnIterator implements Iterator<String> {
@@ -34,7 +35,7 @@
private static final Log LOG = LogFactory.getLog(ColumnIterator.class.getName());
Iterator<byte[]> _setIterator;
- Iterator<KeyValue> _listIterator;
+ Iterator<Cell> _listIterator;
@SuppressWarnings("unchecked")
public ColumnIterator(Collection<?> columnCollection) {
@@ -42,7 +43,7 @@
if (columnCollection instanceof Set) {
_setIterator = ((Set<byte[]>)columnCollection).iterator();
} else if (columnCollection instanceof List) {
- _listIterator = ((List<KeyValue>)columnCollection).iterator();
+ _listIterator = ((List<Cell>)columnCollection).iterator();
} else { // unexpected
// TODO make message better
LOG.error("Unexpected type " + columnCollection.getClass().getName() + " passed as value in column family collection");
@@ -73,8 +74,8 @@
value = Bytes.toString(valueBytes);
}
} else if (_listIterator != null) {
- KeyValue kv = _listIterator.next();
- byte[] v = kv.getQualifier();
+ Cell cell = _listIterator.next();
+ byte[] v = CellUtil.cloneQualifier(cell);
if (v != null) {
value = Bytes.toString(v);
}
diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java
index 5dd727b..8ee3580 100644
--- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java
+++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java
@@ -243,9 +243,15 @@
} else {
Iterator<String> columnIterator = new ColumnIterator(columnCollection);
Set<String> columns = new HashSet<String>();
- while (columnIterator.hasNext()) {
- String column = columnIterator.next();
- columns.add(column);
+ try {
+ while (columnIterator.hasNext()) {
+ String column = columnIterator.next();
+ columns.add(column);
+ }
+ } catch (Throwable t) {
+ LOG.error("Exception encountered when converting family-map to set of columns. Ignoring and returning empty set of columns for family[" + family + "]", t);
+ LOG.error("Ignoring exception and returning empty set of columns for family[" + family +"]");
+ columns.clear();
}
result.put(family, columns);
}
@@ -293,8 +299,8 @@
}
ColumnFamilyAccessResult evaluateAccess(String operation, Action action, final RegionCoprocessorEnvironment env,
- final Map<byte[], ? extends Collection<?>> familyMap) throws AccessDeniedException {
-
+ final Map<byte[], ? extends Collection<?>> familyMap) throws AccessDeniedException {
+
String access = _authUtils.getAccess(action);
User user = getActiveUser();
String userName = _userUtils.getUserAsString(user);
diff --git a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/ColumnIteratorTest.java b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/ColumnIteratorTest.java
index 4b40038..917062b 100644
--- a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/ColumnIteratorTest.java
+++ b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/ColumnIteratorTest.java
@@ -27,7 +27,7 @@
import java.util.List;
import java.util.Set;
-import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.Cell;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
@@ -94,12 +94,12 @@
@SuppressWarnings("unchecked")
@Test
- public void test_ListOfKeyValue() {
+ public void test_ListOfCell() {
/*
* We are not interested in validating the behavior of the real iterator. Instead just the behavior specific to the column iterator.
*/
final String[] qualifiers = new String[] {"a", "b", "c"};
- Iterator<KeyValue> iterator = mock(Iterator.class);
+ Iterator<Cell> iterator = mock(Iterator.class);
// Have the iterator return true as many times as the size of keys array
when(iterator.hasNext()).thenAnswer(new Answer<Boolean>() {
int i = 0;
@@ -108,19 +108,21 @@
return i++ < qualifiers.length;
}
});
- // have the iterator return a KeyValue composed of the key and value arrays
- when(iterator.next()).thenAnswer(new Answer<KeyValue>() {
+ // have the iterator return a Cell composed of the key and value arrays
+ when(iterator.next()).thenAnswer(new Answer<Cell>() {
int i = 0;
@Override
- public KeyValue answer(InvocationOnMock invocation)
+ public Cell answer(InvocationOnMock invocation)
throws Throwable {
- KeyValue kv = mock(KeyValue.class);
- when(kv.getQualifier()).thenReturn(qualifiers[i++].getBytes());
- return kv;
+ Cell cell = mock(Cell.class);
+ when(cell.getQualifierOffset()).thenReturn(0);
+ when(cell.getQualifierLength()).thenReturn(1);
+ when(cell.getQualifierArray()).thenReturn(qualifiers[i++].getBytes());
+ return cell;
}
});
// stuff it into the collection
- List<KeyValue> list = mock(List.class);
+ List<Cell> list = mock(List.class);
when(list.iterator()).thenReturn(iterator);
// now let's check the behavior
ColumnIterator columnIterator = new ColumnIterator(list);