RANGER-230 Hbase plugin implementation using new pluggable service model

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

Branch: refs/heads/stack
Commit: 46633a9ed2ed3499e95ad87409ce5b0460929da7
Parents: 1d6a259
Author: Alok Lal <[email protected]>
Authored: Sat Jan 31 00:42:21 2015 -0800
Committer: Madhan Neethiraj <[email protected]>
Committed: Sat Jan 31 00:42:21 2015 -0800

----------------------------------------------------------------------
 .../hbase/AuthorizationSession.java             | 342 +++++++++++++++++++
 .../authorization/hbase/ColumnIterator.java     |  94 +++++
 .../authorization/hbase/HbaseAuditHandler.java  |  48 +++
 .../hbase/HbaseAuditHandlerImpl.java            |  69 ++++
 .../authorization/hbase/HbaseAuthUtils.java     |  33 ++
 .../authorization/hbase/HbaseAuthUtilsImpl.java |  66 ++++
 .../authorization/hbase/HbaseFactory.java       |  58 ++++
 .../authorization/hbase/HbaseUserUtils.java     |  52 +++
 .../authorization/hbase/HbaseUserUtilsImpl.java |  91 +++++
 .../hbase/RangerAuthorizationFilter.java        |  69 ++++
 .../hbase/AuthorizationSessionTest.java         | 218 ++++++++++++
 .../hbase/HbaseAuthUtilsImplTest.java           |  33 ++
 .../hbase/RangerCoprocessorTest.java            |  33 ++
 .../authorization/hbase/TestPolicyEngine.java   | 178 ++++++++++
 hbase-agent/src/test/resources/log4j.properties |  16 +
 .../policyengine/test_policyengine_hbase.json   | 159 +++++++++
 16 files changed, 1559 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/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
new file mode 100644
index 0000000..e6067ce
--- /dev/null
+++ 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java
@@ -0,0 +1,342 @@
+/*
+ * 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 java.util.List;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.security.AccessDeniedException;
+import org.apache.hadoop.hbase.security.User;
+import org.apache.ranger.audit.model.AuthzAuditEvent;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResult;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
+import org.apache.ranger.plugin.policyengine.RangerResourceImpl;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
+
+public class AuthorizationSession {
+
+       private static final Log LOG = 
LogFactory.getLog(AuthorizationSession.class.getName());
+       // collaborator objects
+       final HbaseFactory _factory = HbaseFactory.getInstance();
+       final HbaseUserUtils _userUtils = _factory.getUserUtils();
+       final HbaseAuthUtils _authUtils = _factory.getAuthUtils();
+       // immutable state
+       final RangerPolicyEngine _authorizer;
+       // Mutable state: Use supplied state information
+       String _operation;
+       String _otherInformation;
+       String _access;
+       String _table;
+       String _column;
+       String _columnFamily;
+       String _remoteAddress;
+       User _user;
+       Set<String> _groups; // this exits to avoid having to get group for a 
user repeatedly.  It is kept in sync with _user;
+       // Passing a null handler to policy engine would suppress audit logging.
+       HbaseAuditHandler _auditHandler = null;
+       
+       // internal state per-authorization
+       RangerAccessRequest _request;
+       RangerAccessResult _result;
+       
+       public AuthorizationSession(RangerPolicyEngine authorizer) {
+               _authorizer = authorizer;
+       }
+
+       AuthorizationSession operation(String anOperation) {
+               _operation = anOperation;
+               return this;
+       }
+
+       AuthorizationSession otherInformation(String information) {
+               _otherInformation = information;
+               return this;
+       }
+       
+       AuthorizationSession remoteAddress(String ipAddress) {
+               _remoteAddress = ipAddress;
+               return this;
+       }
+       
+       AuthorizationSession access(String anAccess) {
+               _access = anAccess; 
+               return this;
+       }
+
+       AuthorizationSession user(User aUser) {
+               _user = aUser;
+               if (_user == null) {
+                       LOG.debug("AuthorizationSession.user: user is null!");
+                       _groups = null;
+               } else {
+                       _groups = _userUtils.getUserGroups(_user);
+               }
+               return this;
+       }
+       AuthorizationSession table(String aTable) {
+               _table = aTable;
+               return this;
+       }
+
+       AuthorizationSession columnFamily(String aColumnFamily) {
+               _columnFamily = aColumnFamily;
+               return this;
+       }
+
+       AuthorizationSession column(String aColumn) {
+               _column = aColumn;
+               return this;
+       }
+
+       void verifyBuildable() {
+               
+               String template = "Internal error: Incomplete/inconsisten 
state: [%s]. Can't build auth request!";
+               if (_factory == null) {
+                       String message = String.format(template, "factory is 
null");
+                       LOG.error(message);
+                       throw new IllegalStateException(message);
+               }
+               if (_access == null || _access.isEmpty()) {
+                       String message = String.format(template, "access is 
null");
+                       LOG.error(message);
+                       throw new IllegalStateException(message);
+               }
+               if (_user == null) {
+                       String message = String.format(template, "user is 
null");
+                       LOG.error(message);
+                       throw new IllegalStateException(message);
+               }
+               if (isProvided(_columnFamily) && !isProvided(_table)) {
+                       String message = String.format(template, "Table must be 
provided if column-family is provided");
+                       LOG.error(message);
+                       throw new IllegalStateException(message);
+               }
+               if (isProvided(_column) && !isProvided(_columnFamily)) {
+                       String message = String.format(template, "Column family 
must be provided if column is provided");
+                       LOG.error(message);
+                       throw new IllegalStateException(message);
+               }
+       }
+
+       void zapAuthorizationState() {
+               _request = null;
+               _result = null;
+       }
+
+       boolean isProvided(String aString) {
+               return aString != null && !aString.isEmpty();
+       }
+       
+       AuthorizationSession buildRequest() {
+
+               verifyBuildable();
+               // session can be reused so reset its state
+               zapAuthorizationState();
+               // TODO get this via a factory instead
+               RangerResourceImpl resource = new RangerResourceImpl();
+               // policy engine should deal sensibly with null/empty values, 
if any
+               resource.setValue("table", _table);
+               resource.setValue("column-family", _columnFamily);
+               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;
+               return this;
+       }
+       
+       AuthorizationSession authorize() {
+               if (LOG.isDebugEnabled()) {
+                       String message = "authorize: " + getRequestMessage();
+                       LOG.debug(message);
+               }
+               if (_request == null) {
+                       String message = String.format("Invalid state 
transition: buildRequest() must be called before authorize().  This request 
would ultimately get denied.!");
+                       throw new IllegalStateException(message);
+               } else {
+                       // ok to pass potentially null handler to policy 
engine.  Null handler effectively suppresses the audit.
+                       _result = _authorizer.isAccessAllowed(_request, 
_auditHandler);
+               }
+               if (LOG.isDebugEnabled()) {
+                       boolean allowed = isAuthorized();
+                       String reason = getDenialReason();
+                       String message = "AuthorizationSession.authorize: " + 
getLogMessage(allowed, reason);
+                       LOG.debug(message);
+               }
+               return this;
+       }
+       
+       void publishResults() throws AccessDeniedException {
+
+               boolean authorized = isAuthorized();
+               if (_auditHandler != null) {
+                       List<AuthzAuditEvent> events = null;
+                       /*
+                        * What we log to audit depends on authorization 
status.  For success we log all accumulated events.  In case of failure 
+                        * we log just the last set of audit messages as we 
only need to record the cause of overall denial.
+                        */
+                       if (authorized) {
+                               List<AuthzAuditEvent> theseEvents = 
_auditHandler.getCapturedEvents();
+                               if (theseEvents != null && 
!theseEvents.isEmpty()) {
+                                       events = theseEvents;
+                               }
+                       } else {
+                               AuthzAuditEvent event = 
_auditHandler.discardMostRecentEvent();
+                               if (event != null) {
+                                       events = Lists.newArrayList(event);
+                               }
+                       }
+                       if (LOG.isDebugEnabled()) {
+                               int size = events == null ? 0 : events.size();
+                               String auditMessage = events == null ? "" : 
events.toString();
+                               String message = String.format("Writing %d 
messages to audit: [%s]", size, auditMessage);
+                               LOG.debug(message);
+                       }
+                       _auditHandler.logAuthzAudits(events);
+               }
+               if (!authorized) {
+                       // and throw and exception... callers expect this 
behavior
+                       String reason = getDenialReason();
+                       String message = getLogMessage(false, reason);
+                       if (LOG.isDebugEnabled()) {
+                               LOG.debug("AuthorizationSession.publishResults: 
throwing exception: " + message);
+                       }
+                       throw new AccessDeniedException("Insufficient 
permissions for user '" + _user.getName() + "' (action=" + _access + ")");
+               }
+       }
+       
+       boolean isAudited() {
+
+               boolean audited = false;
+               if (_result == null) {
+                       String message = String.format("Internal error: _result 
was null!  Assuming no audit. Request[%s]", _request.toString());
+                       LOG.error(message);
+               } else {
+                       audited = _result.getIsAudited();
+               }
+               return audited;
+       }
+
+       boolean isAuthorized() {
+               boolean allowed = false;
+               if (_result == null) {
+                       String message = String.format("Internal error: _result 
was null! Returning false.");
+                       LOG.error(message);
+               } else {
+                       allowed = _result.getIsAllowed();
+               }
+               return allowed;
+       }
+       
+       String getDenialReason() {
+               String reason = "";
+               if (_result == null) {
+                       String message = String.format("Internal error: _result 
was null!  Returning empty reason.");
+                       LOG.error(message);
+               } else {
+                       boolean allowed = _result.getIsAllowed();
+                       if (!allowed) {
+                               reason = _result.getReason();
+                       }
+               }
+               return reason;
+       }
+       
+       String requestToString() {
+               return Objects.toStringHelper(_request.getClass())
+                       .add("operation", _operation)
+                       .add("otherInformation", _otherInformation)
+                       .add("access", _access)
+                       .add("user", _user == null ? null : _user.getName())
+                       .add("groups", _groups)
+                       .add("auditHandler", _auditHandler == null ? null : 
_auditHandler.getClass().getSimpleName())
+                       .add("table", _table)
+                       .add("column", _column)
+                       .add("column-family", _columnFamily)
+                       .toString();
+       }
+
+       String getPrintableValue(String value) {
+               if (isProvided(value)) {
+                       return value;
+               } else {
+                       return "";
+               }
+       }
+       
+       String getRequestMessage() {
+               String format = "Access[%s] by user[%s] belonging to groups[%s] 
to table[%s] for column-family[%s], column[%s] triggered by operation[%s], 
otherInformation[%s]";
+               String user = _userUtils.getUserAsString();
+               String message = String.format(format, 
getPrintableValue(_access), getPrintableValue(user), _groups, 
getPrintableValue(_table),
+                               getPrintableValue(_columnFamily), 
getPrintableValue(_column), getPrintableValue(_operation), 
getPrintableValue(_otherInformation));
+               return message;
+       }
+       
+       String getLogMessage(boolean allowed, String reason) {
+               String format = " %s: status[%s], reason[%s]";
+               String message = String.format(format, getRequestMessage(), 
allowed ? "allowed" : "denied", reason);
+               return message;
+       }
+
+       /**
+        * Hand creates a result object and set it on the request for cases 
where we need not go to policy manager.
+        * @return
+        */
+       AuthorizationSession knownPatternAllowedNotAudited(String reason) {
+               _result = buildResult(true, false, reason);
+               return this;
+       }
+
+       AuthorizationSession knownPatternDisallowedNotAudited(String reason) {
+               _result = buildResult(false, false, reason);
+               
+               return this;
+       }
+       
+       /**
+        * This method could potentially null out an earlier audit handler -- 
which effectively would suppress audits. 
+        * @param anAuditHandler
+        * @return
+        */
+       AuthorizationSession auditHandler(HbaseAuditHandler anAuditHandler) {
+               _auditHandler = anAuditHandler;
+               return this;
+       }
+
+       RangerAccessResult buildResult(boolean allowed, boolean audited, String 
reason) {
+               RangerAccessResult result = 
_authorizer.createAccessResult(_request);
+               result.setIsAllowed(allowed);
+               result.setReason(reason);
+               result.setIsAudited(audited);
+               return result;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/ColumnIterator.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..2c6f805
--- /dev/null
+++ 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/ColumnIterator.java
@@ -0,0 +1,94 @@
+/*
+ * 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 java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.util.Bytes;
+
+public class ColumnIterator implements Iterator<String> {
+       // TODO write tests for this class
+       
+       private static final Log LOG = 
LogFactory.getLog(ColumnIterator.class.getName());
+       Iterator<byte[]> _setIterator;
+       Iterator<KeyValue> _listIterator;
+       
+       @SuppressWarnings("unchecked")
+       public ColumnIterator(Collection<?> columnCollection) {
+               if (columnCollection != null) {
+                       if (columnCollection instanceof Set) {
+                               _setIterator = 
((Set<byte[]>)columnCollection).iterator();
+                       } else if (columnCollection instanceof List) {
+                               _listIterator = 
((List<KeyValue>)columnCollection).iterator();
+                       } else { // unexpected
+                               // TODO make message better
+                               LOG.error("Unexpected type " + 
columnCollection.getClass().getName() + " passed as value in column family 
collection");
+                       }
+               }
+       }
+
+       @Override
+       public boolean hasNext() {
+               if (_setIterator != null) {
+                       return _setIterator.hasNext();
+               }
+               if (_listIterator != null) {
+                       _listIterator.hasNext();
+               }
+               return false;
+       }
+
+       /**
+        * Never returns a null value.  Will return empty string in case of 
null value.
+        */
+       @Override
+       public String next() {
+               String value = "";
+               if (_setIterator != null) {
+                       byte[] valueBytes = _setIterator.next();
+                       if (valueBytes != null) {
+                               value = Bytes.toString(valueBytes);
+                       }
+               } else if (_listIterator != null) {
+                       KeyValue kv = _listIterator.next();
+                       byte[] v = kv.getQualifier();
+                       if (v != null) {
+                               value = Bytes.toString(v);
+                       }
+               } else {
+                       // TODO make the error message better
+                       throw new NoSuchElementException("Empty values passed 
in!");
+               }
+               return value;
+       }
+
+       @Override
+       public void remove() {
+               // TODO make the error message better
+               throw new UnsupportedOperationException("Remove not supported 
from iterator!");
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandler.java
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandler.java
 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandler.java
new file mode 100644
index 0000000..28d41aa
--- /dev/null
+++ 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandler.java
@@ -0,0 +1,48 @@
+/*
+ * 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 java.util.Collection;
+import java.util.List;
+
+import org.apache.ranger.audit.model.AuthzAuditEvent;
+import org.apache.ranger.plugin.audit.RangerAuditHandler;
+
+public interface HbaseAuditHandler extends RangerAuditHandler {
+
+       List<AuthzAuditEvent> getCapturedEvents();
+       
+       void logAuthzAudits(Collection<AuthzAuditEvent> auditEvents);
+       
+       /**
+        * Discards and returns the last audit events captured by the audit 
handler.  Last audit event should be the ones generated during the most recent 
authorization request.
+        * However, it won't be all of the audit events called during an 
authorize call since implementation class may not override the method which 
takes a list of responses -- in 
+        * which case there would be several audit messages generated by one 
call but this only allows you to get last of those messages created during 
single auth request.
+        * After this call the last set of audit events won't be returned by 
<code>getCapturedEvents</code>. 
+        * @return
+        */
+       AuthzAuditEvent discardMostRecentEvent();
+       
+       /**
+        * This is a complement to <code>discardMostRecentEvent</code> to set 
the most recent events.  Often useful to un-pop audit messages that were take 
out.
+        * @param capturedEvents
+        */
+       void setMostRecentEvent(AuthzAuditEvent capturedEvents);
+       
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/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
new file mode 100644
index 0000000..a5d3f16
--- /dev/null
+++ 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java
@@ -0,0 +1,69 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import org.apache.ranger.audit.model.AuthzAuditEvent;
+import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler;
+import org.apache.ranger.plugin.policyengine.RangerAccessResult;
+
+public class HbaseAuditHandlerImpl extends RangerDefaultAuditHandler 
implements HbaseAuditHandler {
+
+       static final List<AuthzAuditEvent> _EmptyList = new 
ArrayList<AuthzAuditEvent>();
+       final List<AuthzAuditEvent> _allEvents = new 
ArrayList<AuthzAuditEvent>();
+       // we replace its contents anytime new audit events are generated.
+       AuthzAuditEvent _mostRecentEvent = null;
+       
+       @Override
+       public AuthzAuditEvent getAuthzEvents(RangerAccessResult result) {
+               
+               AuthzAuditEvent event = super.getAuthzEvents(result);
+               // first accumulate last set of events and then capture these 
as the most recent ones
+               if (_mostRecentEvent != null) {
+                       _allEvents.add(_mostRecentEvent);
+               }
+               _mostRecentEvent = event;
+               return event;
+       }
+       
+       @Override
+       public List<AuthzAuditEvent> getCapturedEvents() {
+               // construct a new collection since we don't want to lose track 
of which were the most recent events;
+               List<AuthzAuditEvent> result = new 
ArrayList<AuthzAuditEvent>(_allEvents);
+               if (_mostRecentEvent != null) {
+                       result.add(_mostRecentEvent);
+               }
+               
+               return result;
+       }
+
+       @Override
+       public AuthzAuditEvent  discardMostRecentEvent() {
+               AuthzAuditEvent result = _mostRecentEvent;
+               _mostRecentEvent = null;
+               return result;
+       }
+
+       @Override
+       public void setMostRecentEvent(AuthzAuditEvent event) {
+               _mostRecentEvent = event;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtils.java
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtils.java
 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtils.java
new file mode 100644
index 0000000..45d4cb4
--- /dev/null
+++ 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtils.java
@@ -0,0 +1,33 @@
+/*
+ * 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 org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
+import org.apache.hadoop.hbase.security.access.Permission.Action;
+
+public interface HbaseAuthUtils {
+
+       String getAccess(Action action);
+
+       boolean isReadAccess(String access);
+       
+       boolean isWriteAccess(String access);
+
+       String getTable(RegionCoprocessorEnvironment regionServerEnv);
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java
 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java
new file mode 100644
index 0000000..955a85c
--- /dev/null
+++ 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.NamespaceDescriptor;
+import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
+import org.apache.hadoop.hbase.security.access.Permission.Action;
+import org.apache.hadoop.hbase.util.Bytes;
+
+public class HbaseAuthUtilsImpl implements HbaseAuthUtils {
+
+       private static final Log LOG = 
LogFactory.getLog(HbaseAuthUtilsImpl.class.getName());
+
+       public String getNameSpace(NamespaceDescriptor ns) {
+               if (ns == null) {
+                       // TODO log an error and Throw an error so the 
operation is denied?
+               }
+               return ns.getName();
+       }
+
+       @Override
+       public String getAccess(Action action) {
+               return action.toString().toLowerCase();
+       }
+
+       @Override
+       public boolean isReadAccess(String access) {
+               return getAccess(Action.READ).equals(access);
+       }
+
+       @Override
+       public boolean isWriteAccess(String access) {
+               return getAccess(Action.WRITE).equals(access);
+       }
+
+       @Override
+       public String getTable(RegionCoprocessorEnvironment regionServerEnv) {
+               HRegionInfo hri = regionServerEnv.getRegion().getRegionInfo();
+               byte[] tableName = hri.getTable().getName() ;
+               String tableNameStr = Bytes.toString(tableName);
+               if (LOG.isDebugEnabled()) {
+                       String message = String.format("getTable: Returning 
tablename[%s]", tableNameStr);
+                       LOG.debug(message);
+               }
+               return tableNameStr;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseFactory.java
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseFactory.java
 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseFactory.java
new file mode 100644
index 0000000..97e70ec
--- /dev/null
+++ 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseFactory.java
@@ -0,0 +1,58 @@
+/*
+ * 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 org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngineImpl;
+
+
+// TODO remove this in favor of Guice DI
+public class HbaseFactory {
+       
+       static final HbaseUserUtils _UserUtils = new HbaseUserUtilsImpl();
+       static final HbaseAuthUtils _AuthUtils = new HbaseAuthUtilsImpl();
+       static final RangerPolicyEngine _PolicyEngine = new 
RangerPolicyEngineImpl();
+       static final HbaseFactory _Factory = new HbaseFactory();
+       /**
+        * This is a singleton 
+        */
+       private HbaseFactory() {
+               // TODO remove this clutch to enforce singleton by moving to a 
DI framework
+       }
+       
+       static HbaseFactory getInstance() {
+               return _Factory;
+       }
+       
+       HbaseAuthUtils getAuthUtils() {
+               return _AuthUtils;
+       }
+       
+       HbaseUserUtils getUserUtils() {
+               return _UserUtils;
+       }
+       
+       RangerPolicyEngine getPolicyEngine() {
+               return _PolicyEngine;
+       }
+       
+       HbaseAuditHandler getAuditHandler() {
+               return new HbaseAuditHandlerImpl();
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtils.java
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtils.java
 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtils.java
new file mode 100644
index 0000000..aa85994
--- /dev/null
+++ 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtils.java
@@ -0,0 +1,52 @@
+/*
+ * 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 java.util.Set;
+
+import org.apache.hadoop.hbase.security.User;
+
+public interface HbaseUserUtils {
+       /**
+        * Returns user's short name or empty string if null is passed in.
+        * @param user
+        * @return
+        */
+       String getUserAsString(User user);
+
+       /**
+        * Returns the groups to which user belongs to as known to User object. 
 For null values it returns an empty set.
+        * @param user
+        * @return
+        */
+       Set<String> getUserGroups(User user);
+
+       /**
+        * May return null in case of an error 
+        * @return
+        */
+       User getUser();
+       
+       /**
+        * Returns the user short name.  Returns an empty string if Hbase User 
of context can't be found.
+        * @param request
+        * @return
+        */
+       String getUserAsString();
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtilsImpl.java
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtilsImpl.java
 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtilsImpl.java
new file mode 100644
index 0000000..6b32e54
--- /dev/null
+++ 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtilsImpl.java
@@ -0,0 +1,91 @@
+/*
+ * 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 java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.ipc.RequestContext;
+import org.apache.hadoop.hbase.security.User;
+
+public class HbaseUserUtilsImpl implements HbaseUserUtils {
+
+       private static final Log LOG = 
LogFactory.getLog(HbaseUserUtilsImpl.class.getName());
+
+       static Set<String> _SuperUsers = Collections.synchronizedSet(new 
HashSet<String>());
+       static AtomicBoolean initialized = new AtomicBoolean(false);
+       
+       @Override
+       public String getUserAsString(User user) {
+               if (user == null) {
+                       throw new IllegalArgumentException("User is null!");
+               }
+               else {
+                       return user.getShortName();
+               }
+       }
+
+       @Override
+       public Set<String> getUserGroups(User user) {
+               if (user == null) {
+                       throw new IllegalArgumentException("User is null!");
+               }
+               else {
+                       String[] groupsArray = user.getGroupNames();
+                       return new HashSet<String>(Arrays.asList(groupsArray));
+               }
+       }
+
+       @Override
+       public User getUser() {
+               // current implementation does not use the request object!
+               User user;
+               if (RequestContext.isInRequestContext()) {
+                       // this is the more common case
+                       user = RequestContext.getRequestUser();
+               }
+               else {
+                       try {
+                               user = User.getCurrent();
+                       } catch (IOException e) {
+                               LOG.error("Unable to get current user: 
User.getCurrent() threw IOException");
+                               user = null;
+                       }
+               }
+               return user;
+       }
+
+
+       @Override
+       public String getUserAsString() {
+               User user = getUser();
+               if (user == null) {
+                       return "";
+               }
+               else {
+                       return getUserAsString(user);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/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
new file mode 100644
index 0000000..5a66eb2
--- /dev/null
+++ 
b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationFilter.java
@@ -0,0 +1,69 @@
+/*
+ * 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 java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+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 {
+
+       final Map<String, Set<String>> _cache;
+
+       public RangerAuthorizationFilter(Map<String, Set<String>> cache) {
+               _cache = cache;
+       }
+       
+       @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()) {
+                       return ReturnCode.NEXT_COL;
+               }
+               // null/empty families are denied
+               byte[] familyBytes = kv.getFamily();
+               if (familyBytes == null || familyBytes.length == 0) {
+                       return ReturnCode.NEXT_COL;
+               }
+               String family = Bytes.toString(familyBytes);
+               // null/empty columns are also denied
+               byte[] columnBytes = kv.getQualifier();
+               if (columnBytes == null || columnBytes.length == 0) {
+                       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;
+               }
+               else if (columns.contains(column)) {
+                       return ReturnCode.INCLUDE;
+               } else {
+                       return ReturnCode.NEXT_COL;
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/AuthorizationSessionTest.java
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/AuthorizationSessionTest.java
 
b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/AuthorizationSessionTest.java
new file mode 100644
index 0000000..1cd0d92
--- /dev/null
+++ 
b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/AuthorizationSessionTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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.*;
+import static org.mockito.Mockito.*;
+
+import org.apache.hadoop.hbase.security.User;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngineImpl;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AuthorizationSessionTest {
+
+       @Test
+       public void testAuthorizationSession() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testOperation() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testOtherInformation() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testAccess() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testUser() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testTable() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testColumnFamily() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testColumn() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testIsBuildable() {
+               RangerPolicyEngine engine = new RangerPolicyEngineImpl();
+               AuthorizationSession session = new AuthorizationSession(engine);
+               try {
+                       session.verifyBuildable();
+                       Assert.fail("Should have thrown exception");
+               } catch (IllegalStateException e) { }
+               // user and access are the only required ones.
+               User user = mock(User.class);
+               when(user.getGroupNames()).thenReturn(new String[] { "groups", 
"group2" });
+               session.access(" ");
+               session.user(user);
+               try {
+                       session.verifyBuildable();
+               } catch (IllegalStateException e) {
+                       fail("Shouldn't have thrown an exception!");
+               }
+               // setting column-family without table is a problem
+               session.columnFamily("family");
+               try {
+                       session.verifyBuildable();
+                       fail("Should have thrown an exception");
+               } catch (IllegalStateException e) { }
+               
+               session.table("table");
+               try {
+                       session.verifyBuildable();
+               } catch (IllegalStateException e) {
+                       fail("Shouldn't have thrown an exception!");
+               }
+               // setting column without column-family is a problem
+               session.columnFamily(null);
+               session.column("col");
+               try {
+                       session.verifyBuildable();
+                       fail("Should have thrown an exception");
+               } catch (IllegalStateException e) { }
+               session.columnFamily("family");
+               try {
+                       session.verifyBuildable();
+               } catch (IllegalStateException e) { 
+                       fail("Should have thrown an exception");
+               }
+       }
+
+       @Test
+       public void testZapAuthorizationState() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testIsProvided() {
+               AuthorizationSession session = new AuthorizationSession(null);
+               assertFalse(session.isProvided(null));
+               assertFalse(session.isProvided(""));
+               assertTrue(session.isProvided(" "));
+               assertTrue(session.isProvided("xtq"));
+       }
+
+       @Test
+       public void testBuildRequest() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testAuthorize() {
+               RangerPolicyEngine engine = new RangerPolicyEngineImpl();
+               
+               User user = mock(User.class);
+               when(user.getShortName()).thenReturn("user1");
+               when(user.getGroupNames()).thenReturn(new String[] { "users" } 
);
+               AuthorizationSession session = new AuthorizationSession(engine);
+               session.access("read")
+                       .user(user)
+                       .table(":meta:")
+                       .buildRequest()
+                       .authorize();
+       }
+
+       @Test
+       public void testPublishResults() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testIsAuthorized() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetDenialReason() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetResourceType() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testRequestToString() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testAudit() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testGetPrintableValue() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testBuildAccessDeniedMessage() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testBuildAccessDeniedMessageString() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testKnownPatternAllowedNotAudited() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testKnownPatternDisallowedNotAudited() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testAuditHandler() {
+//             fail("Not yet implemented");
+       }
+
+       @Test
+       public void testBuildResult() {
+//             fail("Not yet implemented");
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImplTest.java
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImplTest.java
 
b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImplTest.java
new file mode 100644
index 0000000..e40f31a
--- /dev/null
+++ 
b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImplTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.assertTrue;
+
+import org.junit.Test;
+
+public class HbaseAuthUtilsImplTest {
+
+       @Test
+       public void testIsReadAccess() {
+               HbaseAuthUtilsImpl authUtils = new HbaseAuthUtilsImpl();
+               assertTrue(authUtils.isReadAccess("read"));
+               assertTrue(authUtils.isWriteAccess("write"));
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerCoprocessorTest.java
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerCoprocessorTest.java
 
b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerCoprocessorTest.java
new file mode 100644
index 0000000..15d4f93
--- /dev/null
+++ 
b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerCoprocessorTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.assertNotNull;
+
+import org.junit.Test;
+
+public class RangerCoprocessorTest {
+
+       @Test
+       public void test_canBeNewed() {
+               RangerAuthorizationCoprocessor _coprocessor = new 
RangerAuthorizationCoprocessor();
+               assertNotNull(_coprocessor);
+       }
+       
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/TestPolicyEngine.java
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/TestPolicyEngine.java
 
b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/TestPolicyEngine.java
new file mode 100644
index 0000000..ed6bcf0
--- /dev/null
+++ 
b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/TestPolicyEngine.java
@@ -0,0 +1,178 @@
+/*
+ * 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.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Type;
+import java.util.List;
+
+import org.apache.hadoop.hbase.security.AccessDeniedException;
+import org.apache.hadoop.hbase.security.User;
+import 
org.apache.ranger.authorization.hbase.TestPolicyEngine.PolicyEngineTestCase.TestData;
+import org.apache.ranger.plugin.model.RangerPolicy;
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResult;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngineImpl;
+import org.apache.ranger.plugin.policyengine.RangerResource;
+import org.apache.ranger.plugin.policyengine.RangerResourceImpl;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+
+
+public class TestPolicyEngine {
+       static RangerPolicyEngineImpl policyEngine = null;
+       static Gson                   gsonBuilder  = null;
+
+
+       @BeforeClass
+       public static void setUpBeforeClass() throws Exception {
+               policyEngine = new RangerPolicyEngineImpl();
+               gsonBuilder = new 
GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z")
+                                                                          
.setPrettyPrinting()
+                                                                          
.registerTypeAdapter(RangerAccessRequest.class, new 
RangerAccessRequestDeserializer())
+                                                                          
.registerTypeAdapter(RangerResource.class,  new RangerResourceDeserializer())
+                                                                          
.create();
+       }
+
+       @AfterClass
+       public static void tearDownAfterClass() throws Exception {
+       }
+
+       @Test
+       public void testPolicyEngine_hbase() {
+               String[] hbaseTestResourceFiles = { 
"/policyengine/test_policyengine_hbase.json" };
+
+               runTestsFromResourceFiles(hbaseTestResourceFiles);
+               
+               // lets use that policy engine now
+               AuthorizationSession session = new 
AuthorizationSession(policyEngine);
+               User user = mock(User.class);
+               when(user.getShortName()).thenReturn("user1");
+               when(user.getGroupNames()).thenReturn(new String[] { "users" });
+               session.access("read")
+                       .user(user)
+                       .table("finance")
+                       .buildRequest()
+                       .authorize();
+               assertTrue(session.isAuthorized());
+               try {
+                       session.publishResults();
+               } catch (AccessDeniedException e) {
+                       e.printStackTrace();
+                       fail(e.getMessage());
+               }
+               
+               when(user.getShortName()).thenReturn("user1");
+               when(user.getGroupNames()).thenReturn(new String[] { "users" });
+               session.access("write")
+                       .buildRequest()
+                       .authorize();
+               assertFalse(session.isAuthorized());
+               try {
+                       session.publishResults();
+                       fail("Should have throw exception on denied request!");
+               } catch (AccessDeniedException e) {
+               }
+               
+       }
+
+       private void runTestsFromResourceFiles(String[] resourceNames) {
+               for(String resourceName : resourceNames) {
+                       InputStream       inStream = 
this.getClass().getResourceAsStream(resourceName);
+                       InputStreamReader reader   = new 
InputStreamReader(inStream);
+
+                       runTests(reader, resourceName);
+               }
+       }
+
+       private void runTests(InputStreamReader reader, String testName) {
+               try {
+                       PolicyEngineTestCase testCase = 
gsonBuilder.fromJson(reader, PolicyEngineTestCase.class);
+
+                       assertTrue("invalid input: " + testName, testCase != 
null && testCase.serviceDef != null && testCase.policies != null && 
testCase.tests != null);
+
+                       policyEngine.setPolicies(testCase.serviceName, 
testCase.serviceDef, testCase.policies);
+                       boolean justBuildingPolicyEngine = true;
+                       if (justBuildingPolicyEngine) {
+                               return;
+                       } else {
+                               for(TestData test : testCase.tests) {
+                                       RangerAccessResult expected = 
test.result;
+                                       RangerAccessResult result   = 
policyEngine.isAccessAllowed(test.request, null);
+       
+                                       assertNotNull(test.name, result);
+                                       assertEquals(test.name, 
expected.getIsAllowed(), result.getIsAllowed());
+                               }
+                       }
+               } catch(Throwable excp) {
+                       excp.printStackTrace();
+               }
+               
+       }
+
+       static class PolicyEngineTestCase {
+               public String             serviceName;
+               public RangerServiceDef   serviceDef;
+               public List<RangerPolicy> policies;
+               public List<TestData>     tests;
+               
+               class TestData {
+                       public String              name;
+                       public RangerAccessRequest request;
+                       public RangerAccessResult  result;
+               }
+       }
+       
+       static class RangerAccessRequestDeserializer implements 
JsonDeserializer<RangerAccessRequest> {
+               @Override
+               public RangerAccessRequest deserialize(JsonElement jsonObj, 
Type type,
+                               JsonDeserializationContext context) throws 
JsonParseException {
+                       return gsonBuilder.fromJson(jsonObj, 
RangerAccessRequestImpl.class);
+               }
+       }
+       
+       static class RangerResourceDeserializer implements 
JsonDeserializer<RangerResource> {
+               @Override
+               public RangerResource deserialize(JsonElement jsonObj, Type 
type,
+                               JsonDeserializationContext context) throws 
JsonParseException {
+                       return gsonBuilder.fromJson(jsonObj, 
RangerResourceImpl.class);
+               }
+       }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/hbase-agent/src/test/resources/log4j.properties 
b/hbase-agent/src/test/resources/log4j.properties
new file mode 100644
index 0000000..71a8957
--- /dev/null
+++ b/hbase-agent/src/test/resources/log4j.properties
@@ -0,0 +1,16 @@
+# Define some default values that can be overridden by system properties
+ranger.root.logger=DEBUG,console
+# Define the root logger to the system property "hbase.root.logger".
+log4j.rootLogger=${ranger.root.logger}
+
+# Logging Threshold
+log4j.threshold=ALL
+
+#
+# console
+# Add "console" to rootlogger above if you want to use this
+#
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.target=System.err
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2}: 
%m%n
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/46633a9e/hbase-agent/src/test/resources/policyengine/test_policyengine_hbase.json
----------------------------------------------------------------------
diff --git 
a/hbase-agent/src/test/resources/policyengine/test_policyengine_hbase.json 
b/hbase-agent/src/test/resources/policyengine/test_policyengine_hbase.json
new file mode 100644
index 0000000..f563c28
--- /dev/null
+++ b/hbase-agent/src/test/resources/policyengine/test_policyengine_hbase.json
@@ -0,0 +1,159 @@
+{
+  "serviceName":"hbasedev",
+
+  "serviceDef":{
+    "name":"hbase",
+    "id":2,
+    "resources":[
+      
{"name":"table","level":1,"parent":"","mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":"wildCard=true;ignoreCase=true","label":"HBase
 Table","description":"HBase Table"},
+      
{"name":"column-family","level":2,"table":"database","mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":"wildCard=true;ignoreCase=true","label":"HBase
 Column-Family","description":"HBase Column-Family"},
+      
{"name":"column","level":3,"parent":"column-family","mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":"wildCard=true;ignoreCase=true","label":"HBase
 Column","description":"HBase Column"}
+    ],
+    "accessTypes":[
+      {"name":"read","label":"Read"},
+      {"name":"write","label":"Write"},
+      {"name":"create","label":"Create"},
+      
{"name":"admin","label":"Admin","impliedGrants":["read","write","create"]}
+    ]
+  },
+
+  "policies":[
+    {"id":1,"name":"table=finance; column-family=restricted*: 
audit-all-access","isEnabled":true,"isAuditEnabled":true,
+     
"resources":{"table":{"values":["finance"]},"column-family":{"values":["restricted*"]}},
+     "policyItems":[
+       {"accesses":[],"users":[],"groups":["public"],"delegateAdmin":false}
+     ]
+    }
+    ,
+    {"id":2,"name":"table=finance; 
column-family=restricted*","isEnabled":true,"isAuditEnabled":true,
+     
"resources":{"table":{"values":["finance"]},"column-family":{"values":["restricted*"]}},
+     "policyItems":[
+       
{"accesses":[{"type":"read","isAllowed":true},{"type":"write","isAllowed":true}],"users":[],"groups":["finance"],"delegateAdmin":false}
+       ,
+       
{"accesses":[{"type":"admin","isAllowed":true}],"users":[],"groups":["finance-admin"],"delegateAdmin":true}
+     ]
+    }
+    ,
+    {"id":3,"name":"table=*; 
column-family=<excluding>restricted*","isEnabled":true,"isAuditEnabled":false,
+     
"resources":{"table":{"values":["*"]},"column-family":{"values":["restricted*"],"isExcludes":true}},
+     "policyItems":[
+       
{"accesses":[{"type":"read","isAllowed":true}],"users":[],"groups":["public"],"delegateAdmin":false}
+     ]
+    }
+  ],
+
+  "tests":[
+    {"name":"ALLOW 'scan finance restricted-cf;' for finance",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["read"],"user":"user1","userGroups":["users","finance"],"requestData":"scan
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"read":{"isAllowed":true,"isAudited":true,"policyId":2}}}
+    }
+    ,
+    {"name":"ALLOW 'put finance restricted-cf;' for finance",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["write"],"user":"user1","userGroups":["users","finance"],"requestData":"put
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"write":{"isAllowed":true,"isAudited":true,"policyId":2}}}
+    }
+    ,
+    {"name":"DENY 'create finance restricted-cf;' for finance",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["create"],"user":"user1","userGroups":["users","finance"],"requestData":"create
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"create":{"isAllowed":false,"isAudited":true,"policyId":-1}}}
+    }
+    ,
+    {"name":"DENY 'grant finance restricted-cf;' for finance",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["admin"],"user":"user1","userGroups":["users","finance"],"requestData":"grant
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"admin":{"isAllowed":false,"isAudited":true,"policyId":-1}}}
+    }
+    ,
+    {"name":"DENY 'scan finance restricted-cf;' for user1",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["read"],"user":"user1","userGroups":["users"],"requestData":"scan
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"read":{"isAllowed":false,"isAudited":true,"policyId":-1}}}
+    }
+    ,
+    {"name":"DENY 'put finance restricted-cf;' for user1",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["write"],"user":"user1","userGroups":["users"],"requestData":"put
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"write":{"isAllowed":false,"isAudited":true,"policyId":-1}}}
+    }
+    ,
+    {"name":"DENY 'create finance restricted-cf;' for user1",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["create"],"user":"user1","userGroups":["users"],"requestData":"create
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"create":{"isAllowed":false,"isAudited":true,"policyId":-1}}}
+    }
+    ,
+    {"name":"DENY 'grant finance restricted-cf;' for user1",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["admin"],"user":"user1","userGroups":["users"],"requestData":"grant
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"admin":{"isAllowed":false,"isAudited":true,"policyId":-1}}}
+    }
+    ,
+    {"name":"ALLOW 'scan finance restricted-cf;' for finance-admin",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["read"],"user":"user1","userGroups":["users","finance-admin"],"requestData":"scan
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"read":{"isAllowed":true,"isAudited":true,"policyId":2}}}
+    }
+    ,
+    {"name":"ALLOW 'put finance restricted-cf;' for finance-admin",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["write"],"user":"user1","userGroups":["users","finance-admin"],"requestData":"put
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"write":{"isAllowed":true,"isAudited":true,"policyId":2}}}
+    }
+    ,
+    {"name":"ALLOW 'create finance restricted-cf;' for finance-admin",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["create"],"user":"user1","userGroups":["users","finance-admin"],"requestData":"create
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"create":{"isAllowed":true,"isAudited":true,"policyId":2}}}
+    }
+    ,
+    {"name":"ALLOW 'grant finance restricted-cf;' for finance-admin",
+     "request":{
+      
"resource":{"elements":{"table":"finance","column-family":"restricted-cf"}},
+      
"accessTypes":["admin"],"user":"user1","userGroups":["users","finance-admin"],"requestData":"grant
 finance restricted-cf"
+     },
+     
"result":{"accessTypeResults":{"admin":{"isAllowed":true,"isAudited":true,"policyId":2}}}
+    }
+    ,
+    {"name":"ALLOW 'scan finance regular-cf;' for user1",
+     "request":{
+      "resource":{"elements":{"table":"finance","column-family":"regular-cf"}},
+      
"accessTypes":["read"],"user":"user1","userGroups":["users"],"requestData":"scan
 finance regular-cf"
+     },
+     
"result":{"accessTypeResults":{"read":{"isAllowed":true,"isAudited":false,"policyId":3}}}
+    }
+    ,
+    {"name":"DENY 'put finance regular-cf;' for user1",
+     "request":{
+      "resource":{"elements":{"table":"finance","column-family":"regular-cf"}},
+      
"accessTypes":["write"],"user":"user1","userGroups":["users"],"requestData":"put
 finance regular-cf"
+     },
+     
"result":{"accessTypeResults":{"write":{"isAllowed":false,"isAudited":false,"policyId":-1}}}
+    }
+  ]
+}
+

Reply via email to