RangerAuthorizationFilter extends FilterBase { @Override public ReturnCode filterKeyValue(Cell kv) throws IOException { if (LOG.isDebugEnabled()) { LOG.debug("==> filterKeyValue"); } String family = null; byte[] familyBytes = CellUtil.cloneFamily(kv); if (familyBytes != null && familyBytes.length > 0) { family = Bytes.toString(familyBytes); if (LOG.isDebugEnabled()) { LOG.debug("filterKeyValue: evaluating family[" + family + "]."); } } String column = null; byte[] qualifier = CellUtil.cloneQualifier(kv); if (qualifier != null && qualifier.length > 0) { column = Bytes.toString(qualifier); if (LOG.isDebugEnabled()) { LOG.debug("filterKeyValue: evaluating column[" + column + "]."); } } else { LOG.warn("filterKeyValue: empty/null column set! Unexpected!"); } ReturnCode result = ReturnCode.NEXT_COL; boolean authCheckNeeded = false; if (family == null) { LOG.warn("filterKeyValue: Unexpected - null/empty family! Access denied!"); } else if (_familiesAccessDenied.contains(family)) { LOG.debug("filterKeyValue: family found in access denied families cache. Access denied."); } else if (_columnsAccessAllowed.containsKey(family)) { LOG.debug("filterKeyValue: family found in column level access results cache."); if (_columnsAccessAllowed.get(family).contains(column)) { LOG.debug("filterKeyValue: family/column found in column level access results cache. Access allowed."); result = ReturnCode.INCLUDE; } else { LOG.debug("filterKeyValue: family/column not in column level access results cache. Access denied."); } } else if (_familiesAccessAllowed.contains(family)) { LOG.debug("filterKeyValue: family found in access allowed families cache. Must re-authorize for correct audit generation."); authCheckNeeded = true; } else if (_familiesAccessIndeterminate.contains(family)) { LOG.debug("filterKeyValue: family found in indeterminate families cache. Evaluating access..."); authCheckNeeded = true; } else { LOG.warn("filterKeyValue: Unexpected - alien family encountered that wasn't seen by pre-hook! Access Denied.!"); } if (authCheckNeeded) { LOG.debug("filterKeyValue: Checking authorization..."); _session.columnFamily(family) .column(column) .buildRequest() .authorize(); AuthzAuditEvent auditEvent = _auditHandler.getAndDiscardMostRecentEvent(); if (_session.isAuthorized()) { LOG.debug("filterKeyValue: Access granted."); result = ReturnCode.INCLUDE; if (auditEvent != null) { LOG.debug("filterKeyValue: access is audited."); _auditHandler.logAuthzAudits(Collections.singletonList(auditEvent)); } else { LOG.debug("filterKeyValue: no audit event returned. Access not audited."); } } else { LOG.debug("filterKeyValue: Access denied. Denial not audited."); } } if (LOG.isDebugEnabled()) { LOG.debug("filterKeyValue: " + result); } return result; } RangerAuthorizationFilter(AuthorizationSession session, Set<String> familiesAccessAllowed, Set<String> familiesAccessDenied, Set<String> familiesAccessIndeterminate,
									 Map<String, Set<String>> columnsAccessAllowed); @Override ReturnCode filterKeyValue(Cell kv); @Override String toString();  }
@Test public void testFilterKeyValueCell_happyPath() throws IOException { String[] allowedFamilies = new String[] { "family1", "family2" }; String[] deniedFamilies = new String[] { "family3", "family4" }; String[] indeterminateFamilies = new String[] { "family5", "family6" }; Set<String> familiesAccessAllowed = ImmutableSet.copyOf(allowedFamilies); Set<String> familiesAccessDenied = ImmutableSet.copyOf(deniedFamilies); Set<String> familiesAccessIndeterminate = ImmutableSet.copyOf(indeterminateFamilies); Map<String, Set<String>> columnsAccessAllowed = new HashMap<String, Set<String>>(); String[] family7KnowGoodColumns = new String[] {"family7-column1", "family7-column2"}; columnsAccessAllowed.put("family7", ImmutableSet.copyOf(family7KnowGoodColumns)); String[] family8KnowGoodColumns = new String[] {"family8-column1", "family8-column2"}; columnsAccessAllowed.put("family8", ImmutableSet.copyOf(family8KnowGoodColumns)); AuthorizationSession session = createSessionMock(); RangerAuthorizationFilter filter = new RangerAuthorizationFilter(session, familiesAccessAllowed, familiesAccessDenied, familiesAccessIndeterminate, columnsAccessAllowed); Cell aCell = mock(Cell.class); for (String family : deniedFamilies) { setFamilyArray(aCell, family.getBytes()); setQualifierArray(aCell, new byte[0]); assertEquals(ReturnCode.NEXT_COL, filter.filterKeyValue(aCell)); } setFamilyArray(aCell, "family7".getBytes()); setQualifierArray(aCell, new byte[0]); assertEquals(ReturnCode.NEXT_COL, filter.filterKeyValue(aCell)); for (String column : family7KnowGoodColumns ) { setQualifierArray(aCell, column.getBytes()); assertEquals(ReturnCode.INCLUDE, filter.filterKeyValue(aCell)); } setFamilyArray(aCell, "family8".getBytes()); for (String column : family8KnowGoodColumns ) { setQualifierArray(aCell, column.getBytes()); assertEquals(ReturnCode.INCLUDE, filter.filterKeyValue(aCell)); } for (String column : new String[] { "family8-column3", "family8-column4"}) { setQualifierArray(aCell, column.getBytes()); assertEquals(ReturnCode.NEXT_COL, filter.filterKeyValue(aCell)); } when(session.isAuthorized()).thenReturn(true); for (String family : allowedFamilies) { setFamilyArray(aCell, family.getBytes()); setQualifierArray(aCell, "some-column".getBytes()); assertEquals(ReturnCode.INCLUDE, filter.filterKeyValue(aCell)); } when(session.isAuthorized()).thenReturn(false); for (String family : indeterminateFamilies) { setFamilyArray(aCell, family.getBytes()); setQualifierArray(aCell, "some-column".getBytes()); assertEquals(ReturnCode.NEXT_COL, filter.filterKeyValue(aCell)); } }