ranger-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mad...@apache.org
Subject incubator-ranger git commit: RANGER-230: HBase plugin updates to: 1) fix generation of duplicate audit messages 2) fix issues in column-family/column filtering logic.
Date Thu, 05 Feb 2015 23:35:56 GMT
Repository: incubator-ranger
Updated Branches:
  refs/heads/stack 1f0dccadf -> 5c4b59af7


RANGER-230: HBase plugin updates to: 1) fix generation of duplicate audit messages 2) fix
issues in column-family/column filtering logic.


Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/5c4b59af
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/5c4b59af
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/5c4b59af

Branch: refs/heads/stack
Commit: 5c4b59af7e5f7ea9382d18566ff2835235f63375
Parents: 1f0dcca
Author: Alok Lal <alal@hortonworks.com>
Authored: Thu Feb 5 15:33:39 2015 -0800
Committer: Madhan Neethiraj <madhan@apache.org>
Committed: Thu Feb 5 15:33:39 2015 -0800

----------------------------------------------------------------------
 .../hbase/AuthorizationSession.java             |   5 +-
 .../hbase/HbaseAuditHandlerImpl.java            |   3 +-
 .../hbase/RangerAuthorizationCoprocessor.java   |  25 +++--
 .../hbase/RangerAuthorizationFilter.java        |  37 +++++--
 .../hbase/RangerAuthorizationFilterTest.java    | 108 +++++++++++++++++++
 5 files changed, 159 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5c4b59af/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java
----------------------------------------------------------------------
diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java
index e6067ce..977c745 100644
--- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java
+++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java
@@ -163,14 +163,15 @@ public class AuthorizationSession {
 		resource.setValue("column", _column);
 		
 		String user = _userUtils.getUserAsString(_user);
-		LOG.debug("AuthorizationSession buildRequest: user[" + user + "], groups[" + _groups +
"]");
-
 		RangerAccessRequestImpl request = new RangerAccessRequestImpl(resource, _access, user,
_groups);
 		request.setAction(_operation);
 		request.setRequestData(_otherInformation);
 		request.setClientIPAddress(_remoteAddress);
 		
 		_request = request;
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Built request: " + request.toString());
+		}
 		return this;
 	}
 	

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5c4b59af/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java
----------------------------------------------------------------------
diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java
index a5d3f16..fb4f8a0 100644
--- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java
+++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java
@@ -41,7 +41,8 @@ public class HbaseAuditHandlerImpl extends RangerDefaultAuditHandler implements
 			_allEvents.add(_mostRecentEvent);
 		}
 		_mostRecentEvent = event;
-		return event;
+		// We return null because we don't want default audit handler to audit anything!
+		return null;
 	}
 	
 	@Override

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5c4b59af/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java
----------------------------------------------------------------------
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 1a956d3..2e128ec 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
@@ -295,7 +295,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess
 		if (LOG.isDebugEnabled()) {
 			final String format = "evaluateAccess: entered: Operation[%s], access[%s], families[%s]";
 			Map<String, Set<String>> families = getColumnFamilies(familyMap);
-			String message = String.format(format, operation, access, families);
+			String message = String.format(format, operation, access, families.toString());
 			LOG.debug(message);
 		}
 
@@ -314,7 +314,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess
 			result = new ColumnFamilyAccessResult(true, true, null, null, null, null);
 			if (LOG.isDebugEnabled()) {
 				Map<String, Set<String>> families = getColumnFamilies(familyMap);
-				String message = String.format(messageTemplate, operation, access, families, result.toString());
+				String message = String.format(messageTemplate, operation, access, families.toString(),
result.toString());
 				LOG.debug(message);
 			}
 			return result;
@@ -331,8 +331,11 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess
 				.access(access)
 				.table(table);
 		Map<String, Set<String>> families = getColumnFamilies(familyMap);
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("evaluateAccess: families to process: " + families.toString());
+		}
 		if (families == null || families.isEmpty()) {
-			// table level access is desired
+			LOG.debug("evaluateAccess: Null or empty families collection, ok.  Table level access
is desired");
 			session.buildRequest()
 				.authorize();
 			boolean authorized = session.isAuthorized();
@@ -347,10 +350,12 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess
 						authorized ? Collections.singletonList(event) : null,
 						authorized ? null : event, null, reason); 
 			if (LOG.isDebugEnabled()) {
-				String message = String.format(messageTemplate, operation, access, families, result.toString());
+				String message = String.format(messageTemplate, operation, access, families.toString(),
result.toString());
 				LOG.debug(message);
 			}
 			return result;
+		} else {
+			LOG.debug("evaluateAccess: Families collection not null.  Skipping table-level check,
will do finer level check");
 		}
 		
 		boolean everythingIsAccessible = true;
@@ -365,10 +370,12 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess
 		for (Map.Entry<String, Set<String>> anEntry : families.entrySet()) {
 			String family = anEntry.getKey();
 			session.columnFamily(family);
-			
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("evaluateAccess: Processing family: " + family);
+			}
 			Set<String> columns = anEntry.getValue();
 			if (columns == null || columns.isEmpty()) {
-				// family level access is desired.
+				LOG.debug("evaluateAccess: columns collection null or empty, ok.  Family level access
is desired.");
 				session.column(null) // zap stale column from prior iteration of this loop, if any
 					.buildRequest()
 					.authorize();
@@ -387,8 +394,12 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess
 					denialReason = String.format("Insufficient permissions for user ‘%s',action: %s, tableName:%s,
family:%s, no columns found.", user.getName(), operation, table, family);
 				}
 			} else {
+				LOG.debug("evaluateAccess: columns collection not empty.  Skipping Family level check,
will do finer level access check.");
 				Set<String> accessibleColumns = new HashSet<String>(); // will be used in
to populate our results cache for the filter
  				for (String column : columns) {
+ 					if (LOG.isDebugEnabled()) {
+ 						LOG.debug("evaluateAccess: Processing column: " + column);
+ 					}
  					session.column(column)
  						.buildRequest()
  						.authorize();
@@ -414,7 +425,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess
 		
 		result = new ColumnFamilyAccessResult(everythingIsAccessible, somethingIsAccessible, authorizedEvents,
deniedEvent, accessResultsCache, denialReason);
 		if (LOG.isDebugEnabled()) {
-			String message = String.format(messageTemplate, operation, access, families, result.toString());
+			String message = String.format(messageTemplate, operation, access, families.toString(),
result.toString());
 			LOG.debug(message);
 		}
 		return result;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5c4b59af/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationFilter.java
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationFilter.java
index 5a66eb2..ae61a1e 100644
--- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationFilter.java
+++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationFilter.java
@@ -23,12 +23,16 @@ import java.io.IOException;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.filter.FilterBase;
 import org.apache.hadoop.hbase.util.Bytes;
 
 public class RangerAuthorizationFilter extends FilterBase {
 
+	private static final Log LOG = LogFactory.getLog(RangerAuthorizationFilter.class.getName());
 	final Map<String, Set<String>> _cache;
 
 	public RangerAuthorizationFilter(Map<String, Set<String>> cache) {
@@ -38,31 +42,46 @@ public class RangerAuthorizationFilter extends FilterBase {
 	@SuppressWarnings("deprecation")
 	@Override
 	public ReturnCode filterKeyValue(Cell kv) throws IOException {
-		// if our cache is null or empty then there is no hope for any access
+		
 		if (_cache == null || _cache.isEmpty()) {
+			LOG.debug("filterKeyValue: if cache is null or empty then there is no hope for any access.
Denied!");
 			return ReturnCode.NEXT_COL;
 		}
-		// null/empty families are denied
+		
 		byte[] familyBytes = kv.getFamily();
 		if (familyBytes == null || familyBytes.length == 0) {
+			LOG.debug("filterKeyValue: null/empty families in request! Denied!");
 			return ReturnCode.NEXT_COL;
 		}
 		String family = Bytes.toString(familyBytes);
-		// null/empty columns are also denied
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("filterKeyValue: Evaluating family[" + family + "]");
+		}
+		
+		if (!_cache.containsKey(family)) {
+			LOG.debug("filterKeyValue: Cache map did not contain the family, i.e. nothing in family
has access! Denied!");
+			return ReturnCode.NEXT_COL;
+		}
+		Set<String> columns = _cache.get(family);
+		
+		if (CollectionUtils.isEmpty(columns)) {
+			LOG.debug("filterKeyValue: empty/null column set in cache for family implies family level
access. No need to bother with column level.  Allowed!");
+			return ReturnCode.INCLUDE;
+		}		
 		byte[] columnBytes = kv.getQualifier();
 		if (columnBytes == null || columnBytes.length == 0) {
+			LOG.debug("filterKeyValue: empty/null column set in request implies family level access,
which isn't available.  Denied!");
 			return ReturnCode.NEXT_COL;
 		}
 		String column = Bytes.toString(columnBytes);
-		// allow if cache contains the family/column in it
-		Set<String> columns = _cache.get(family);
-		if (columns == null || columns.isEmpty()) {
-			// column family with a null/empty set of columns means all columns within that family
are allowed
-			return ReturnCode.INCLUDE;
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("filterKeyValue: Evaluating column[" + column + "]");
 		}
-		else if (columns.contains(column)) {
+		if (columns.contains(column)) {
+			LOG.debug("filterKeyValue: cache contains Column in column-family's collection.  Access
allowed!");
 			return ReturnCode.INCLUDE;
 		} else {
+			LOG.debug("filterKeyValue: cache missing Column in column-family's collection.  Access
denied!");
 			return ReturnCode.NEXT_COL;
 		}
 	}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5c4b59af/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAuthorizationFilterTest.java
----------------------------------------------------------------------
diff --git a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAuthorizationFilterTest.java
b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAuthorizationFilterTest.java
new file mode 100644
index 0000000..5575ea7
--- /dev/null
+++ b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAuthorizationFilterTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.authorization.hbase;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.filter.Filter.ReturnCode;
+import org.junit.Test;
+
+import com.google.common.collect.Sets;
+
+@SuppressWarnings("deprecation")
+public class RangerAuthorizationFilterTest {
+
+	@Test
+	public void testFilterKeyValueCell_happyPath() throws IOException {
+
+		// null/empty column collection in cache for a family implies family level access  
+		Map<String, Set<String>> cache = new HashMap<String, Set<String>>();
+		cache.put("family1", Collections.<String> emptySet());
+		RangerAuthorizationFilter filter = new RangerAuthorizationFilter(cache);
+
+		Cell aCell = mock(Cell.class);
+		when(aCell.getFamily()).thenReturn("family1".getBytes());
+		when(aCell.getQualifier()).thenReturn("column1".getBytes());
+		assertEquals(ReturnCode.INCLUDE, filter.filterKeyValue(aCell));
+
+		when(aCell.getQualifier()).thenReturn("column2".getBytes());
+		assertEquals(ReturnCode.INCLUDE, filter.filterKeyValue(aCell));
+		
+		// null empty column collection in REQUEST implies family level access
+		when(aCell.getQualifier()).thenReturn(null);
+		assertEquals(ReturnCode.INCLUDE, filter.filterKeyValue(aCell));
+		
+		// specific columns in cache should be allowed only if there is a match of family and column
+		cache.clear();
+		cache.put("family1", Sets.newHashSet("column11", "column12"));
+		cache.put("family2", Sets.newHashSet("column21", "column22"));
+		filter = new RangerAuthorizationFilter(cache);
+
+		when(aCell.getFamily()).thenReturn("family1".getBytes());
+		when(aCell.getQualifier()).thenReturn("column11".getBytes());
+		assertEquals(ReturnCode.INCLUDE, filter.filterKeyValue(aCell));
+		when(aCell.getQualifier()).thenReturn("column12".getBytes());
+		assertEquals(ReturnCode.INCLUDE, filter.filterKeyValue(aCell));
+		when(aCell.getQualifier()).thenReturn("column13".getBytes());
+		assertEquals(ReturnCode.NEXT_COL, filter.filterKeyValue(aCell));
+
+		when(aCell.getFamily()).thenReturn("family2".getBytes());
+		when(aCell.getQualifier()).thenReturn("column22".getBytes());
+		assertEquals(ReturnCode.INCLUDE, filter.filterKeyValue(aCell));
+
+		when(aCell.getFamily()).thenReturn("family3".getBytes());
+		when(aCell.getQualifier()).thenReturn("column11".getBytes());
+		assertEquals(ReturnCode.NEXT_COL, filter.filterKeyValue(aCell));
+		
+		// asking for family level access when one doesn't exist (colum collection for a family
is not null/empty then it should get denied
+		when(aCell.getFamily()).thenReturn("family1".getBytes());
+		when(aCell.getQualifier()).thenReturn(null);
+		assertEquals(ReturnCode.NEXT_COL, filter.filterKeyValue(aCell));
+	}
+
+	@Test
+	public void testFilterKeyValueCell_firewalling() throws IOException {
+		// null cache will deny everything.
+		RangerAuthorizationFilter filter = new RangerAuthorizationFilter(null);
+		Cell aCell = mock(Cell.class);
+		when(aCell.getFamily()).thenReturn("family1".getBytes());
+		when(aCell.getQualifier()).thenReturn("column1".getBytes());
+		assertEquals(ReturnCode.NEXT_COL, filter.filterKeyValue(aCell));
+
+		// non-null but empty cache should do the same
+		Map<String, Set<String>> cache = new HashMap<String, Set<String>>();
+		filter = new RangerAuthorizationFilter(cache);
+		assertEquals(ReturnCode.NEXT_COL, filter.filterKeyValue(aCell));
+
+		// Null family in request would get denied, too
+		when(aCell.getFamily()).thenReturn(null);
+		when(aCell.getQualifier()).thenReturn("column1".getBytes());
+		assertEquals(ReturnCode.NEXT_COL, filter.filterKeyValue(aCell));
+	}
+}


Mime
View raw message