Repository: incubator-ranger
Updated Branches:
  refs/heads/tag-policy 7ac1b6c87 -> 990213ca4


RANGER-619: Implemented mutual exclusion for Hive component

Signed-off-by: Madhan Neethiraj <[email protected]>


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

Branch: refs/heads/tag-policy
Commit: 990213ca4fbd484339c39f745db0ca3b5e2eaaa3
Parents: 7ac1b6c
Author: Abhay Kulkarni <[email protected]>
Authored: Mon Aug 10 15:15:06 2015 -0700
Committer: Madhan Neethiraj <[email protected]>
Committed: Wed Aug 19 23:13:01 2015 -0700

----------------------------------------------------------------------
 .../plugin/audit/RangerDefaultAuditHandler.java |  19 +-
 .../RangerAbstractConditionEvaluator.java       |   7 +
 .../RangerConditionEvaluator.java               |   3 +
 ...veResourcesNotAccessedTogetherCondition.java | 184 +++++++++++++++++++
 .../RangerDefaultPolicyItemEvaluator.java       |   1 +
 .../plugin/util/RangerRequestedResources.java   | 116 ++++++++++++
 .../service-defs/ranger-servicedef-hive.json    |   8 +
 .../plugin/policyengine/TestPolicyEngine.java   |  62 +++++--
 ...test_policyengine_hive_mutex_conditions.json | 178 ++++++++++++++++++
 .../authorizer/RangerHiveAccessRequest.java     |   1 +
 .../hive/authorizer/RangerHiveAuthorizer.java   |  93 ++++++++--
 11 files changed, 630 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/agents-common/src/main/java/org/apache/ranger/plugin/audit/RangerDefaultAuditHandler.java
----------------------------------------------------------------------
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/audit/RangerDefaultAuditHandler.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/audit/RangerDefaultAuditHandler.java
index 85ba5c0..9d7c16d 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/audit/RangerDefaultAuditHandler.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/audit/RangerDefaultAuditHandler.java
@@ -98,7 +98,7 @@ public class RangerDefaultAuditHandler implements 
RangerAccessResultProcessor {
                        ret.setEventTime(request.getAccessTime());
                        ret.setUser(request.getUser());
                        ret.setAction(request.getAccessType());
-                       ret.setAccessResult((short)(result.getIsAllowed() ? 1 : 
0));
+                       ret.setAccessResult((short) (result.getIsAllowed() ? 1 
: 0));
                        ret.setPolicyId(result.getPolicyId());
                        ret.setAccessType(request.getAction());
                        ret.setClientIP(request.getClientIPAddress());
@@ -108,7 +108,6 @@ public class RangerDefaultAuditHandler implements 
RangerAccessResultProcessor {
                        ret.setTags(getTags(request));
 
                        populateDefaults(ret);
-
                }
 
                if(LOG.isDebugEnabled()) {
@@ -180,6 +179,7 @@ public class RangerDefaultAuditHandler implements 
RangerAccessResultProcessor {
                if (auditEvent.getEventId() == null || 
auditEvent.getEventId().isEmpty()) {
                        auditEvent.setEventId(MiscUtil.generateUniqueId());
                }
+
                auditEvent.setSeqNum(sequenceNumber++);
        }
 
@@ -208,13 +208,16 @@ public class RangerDefaultAuditHandler implements 
RangerAccessResultProcessor {
                Set<String> tags = new HashSet<String>();
 
                if (contextObj != null) {
-                       @SuppressWarnings("unchecked")
-                       List<RangerTaggedResource.RangerResourceTag> 
resourceTags = (List<RangerTaggedResource.RangerResourceTag>) contextObj;
-
-                       if (CollectionUtils.isNotEmpty(resourceTags)) {
-                               for (RangerTaggedResource.RangerResourceTag 
resourceTag : resourceTags) {
-                                       tags.add(resourceTag.getName());
+                       try {
+                               @SuppressWarnings("unchecked")
+                               List<RangerTaggedResource.RangerResourceTag> 
resourceTags = (List<RangerTaggedResource.RangerResourceTag>) contextObj;
+                               if (CollectionUtils.isNotEmpty(resourceTags)) {
+                                       for 
(RangerTaggedResource.RangerResourceTag resourceTag : resourceTags) {
+                                               tags.add(resourceTag.getName());
+                                       }
                                }
+                       } catch (Throwable t) {
+                               LOG.error("RangerDefaultAuditHandler.getTags(), 
exception when getting tags from context, exception=" + t);
                        }
                }
                return tags;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerAbstractConditionEvaluator.java
----------------------------------------------------------------------
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerAbstractConditionEvaluator.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerAbstractConditionEvaluator.java
index be05144..0bcb744 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerAbstractConditionEvaluator.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerAbstractConditionEvaluator.java
@@ -20,14 +20,21 @@
 package org.apache.ranger.plugin.conditionevaluator;
 
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemCondition;
+import org.apache.ranger.plugin.model.RangerServiceDef;
 import 
org.apache.ranger.plugin.model.RangerServiceDef.RangerPolicyConditionDef;
 
 
 public abstract class RangerAbstractConditionEvaluator implements 
RangerConditionEvaluator {
+       protected RangerServiceDef serviceDef = null;
        protected RangerPolicyConditionDef  conditionDef = null;
        protected RangerPolicyItemCondition condition    = null;
 
        @Override
+       public void setServiceDef(RangerServiceDef serviceDef) {
+               this.serviceDef = serviceDef;
+       }
+
+       @Override
        public void setConditionDef(RangerPolicyConditionDef conditionDef) {
                this.conditionDef = conditionDef;
        }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerConditionEvaluator.java
----------------------------------------------------------------------
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerConditionEvaluator.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerConditionEvaluator.java
index 3ad8781..602b80e 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerConditionEvaluator.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerConditionEvaluator.java
@@ -20,6 +20,7 @@
 package org.apache.ranger.plugin.conditionevaluator;
 
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemCondition;
+import org.apache.ranger.plugin.model.RangerServiceDef;
 import 
org.apache.ranger.plugin.model.RangerServiceDef.RangerPolicyConditionDef;
 import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
 
@@ -28,6 +29,8 @@ public interface RangerConditionEvaluator {
 
        void setPolicyItemCondition(RangerPolicyItemCondition condition);
 
+       void setServiceDef(RangerServiceDef serviceDef);
+
 
        void init();
 

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerHiveResourcesNotAccessedTogetherCondition.java
----------------------------------------------------------------------
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerHiveResourcesNotAccessedTogetherCondition.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerHiveResourcesNotAccessedTogetherCondition.java
new file mode 100644
index 0000000..0f44bba
--- /dev/null
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerHiveResourcesNotAccessedTogetherCondition.java
@@ -0,0 +1,184 @@
+/*
+ * 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.plugin.conditionevaluator;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+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.RangerAccessResource;
+import 
org.apache.ranger.plugin.policyresourcematcher.RangerDefaultPolicyResourceMatcher;
+import 
org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
+import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
+import org.apache.ranger.plugin.util.RangerRequestedResources;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RangerHiveResourcesNotAccessedTogetherCondition extends 
RangerAbstractConditionEvaluator {
+       private static final Log LOG = 
LogFactory.getLog(RangerHiveResourcesNotAccessedTogetherCondition.class);
+
+       private List<RangerPolicyResourceMatcher> matchers = new ArrayList<>();
+       private boolean isInitialized = false;
+
+       @Override
+       public void init() {
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("==> 
RangerHiveResourcesNotAccessedTogetherCondition.init(" + condition + ")");
+               }
+
+               super.init();
+
+               if (serviceDef != null) {
+                       doInitialize();
+               } else {
+                       
LOG.error("RangerHiveResourcesNotAccessedTogetherCondition.init() - ServiceDef 
not set ... ERROR ..");
+               }
+
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("<== 
RangerHiveResourcesNotAccessedTogetherCondition.init(" + condition + ")");
+               }
+       }
+
+       @Override
+       public boolean isMatched(final RangerAccessRequest request) {
+               boolean ret = true;
+
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("==> 
RangerHiveResourcesNotAccessedTogetherCondition.isMatched(" + request + ")");
+               }
+
+               if (isInitialized) {
+                       @SuppressWarnings("unchecked")
+                       RangerRequestedResources requestedResources = 
(RangerRequestedResources) 
request.getContext().get(RangerRequestedResources.KEY_CONTEXT_REQUESTED_RESOURCES);
+                       ret = requestedResources == null ? true : 
requestedResources.isMutuallyExcluded(matchers);
+               } else {
+                       
LOG.error("RangerHiveResourcesNotAccessedTogetherCondition.isMatched() - 
Enforcer is not initialized correctly, Mutual Exclusion will NOT be enforced");
+               }
+
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("<== 
RangerHiveResourcesNotAccessedTogetherCondition.isMatched(" + request + ")" + 
", result=" + ret);
+               }
+
+               return ret;
+       }
+
+       private void doInitialize() {
+               List<String> mutuallyExclusiveResources = condition.getValues();
+
+               if (CollectionUtils.isNotEmpty(mutuallyExclusiveResources)) {
+                       initializeMatchers(mutuallyExclusiveResources);
+
+                       if (CollectionUtils.isEmpty(matchers)) {
+                               if (LOG.isDebugEnabled()) {
+                                       
LOG.debug("RangerHiveResourcesNotAccessedTogetherCondition.doInitialize() - 
Cannot create matchers from values in MutualExclustionEnforcer");
+                               }
+                       } else {
+                               if (LOG.isDebugEnabled()) {
+                                       
LOG.debug("RangerHiveResourcesNotAccessedTogetherCondition.doInitialize() - 
Created " + matchers.size() + " matchers from values in 
MutualExclustionEnforcer");
+                               }
+                       }
+               } else {
+                       if (LOG.isDebugEnabled()) {
+                               
LOG.debug("RangerHiveResourcesNotAccessedTogetherCondition.doInitialize() - No 
values in MutualExclustionEnforcer");
+                       }
+               }
+
+               isInitialized = true;
+       }
+
+       private void initializeMatchers(List<String> 
mutuallyExclusiveResources) {
+
+               for (String s : mutuallyExclusiveResources) {
+
+                       String policyResourceSpec = s.trim();
+
+                       RangerPolicyResourceMatcher matcher = 
buildMatcher(policyResourceSpec);
+
+                       if (matcher != null) {
+                               matchers.add(matcher);
+                       }
+               }
+       }
+
+       private RangerPolicyResourceMatcher buildMatcher(String 
policyResourceSpec) {
+
+               RangerPolicyResourceMatcher matcher = null;
+
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("==> 
RangerHiveResourcesNotAccessedTogetherCondition.buildMatcher(" + 
policyResourceSpec + ")");
+               }
+
+               // Works only for Hive serviceDef for now
+               if (serviceDef != null && 
serviceDef.getName().equals(EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_HIVE_NAME))
 {
+
+                       //Parse policyResourceSpec
+                       char separator = '.';
+                       String any = "*";
+
+                       Map<String, RangerPolicy.RangerPolicyResource> 
policyResources = new HashMap<>();
+
+                       String[] elements = 
StringUtils.split(policyResourceSpec, separator);
+
+                       RangerPolicy.RangerPolicyResource policyResource;
+
+                       if (elements.length > 0 && elements.length < 4) {
+                               if (elements.length == 3) {
+                                       policyResource = new 
RangerPolicy.RangerPolicyResource(elements[2]);
+                               } else {
+                                       policyResource = new 
RangerPolicy.RangerPolicyResource(any);
+                               }
+                               policyResources.put("column", policyResource);
+
+                               if (elements.length >= 2) {
+                                       policyResource = new 
RangerPolicy.RangerPolicyResource(elements[1]);
+                               } else {
+                                       policyResource = new 
RangerPolicy.RangerPolicyResource(any);
+                               }
+                               policyResources.put("table", policyResource);
+
+                               policyResource = new 
RangerPolicy.RangerPolicyResource(elements[0]);
+                               policyResources.put("database", policyResource);
+
+                               matcher = new 
RangerDefaultPolicyResourceMatcher();
+                               matcher.setPolicyResources(policyResources);
+                               matcher.setServiceDef(serviceDef);
+                               matcher.init();
+
+                       } else {
+                               
LOG.error("RangerHiveResourcesNotAccessedTogetherCondition.buildMatcher() - 
Incorrect elements in the hierarchy specified ("
+                                               + elements.length + ")");
+                       }
+               } else {
+                       
LOG.error("RangerHiveResourcesNotAccessedTogetherCondition.buildMatcher() - 
ServiceDef not set or ServiceDef is not for Hive");
+               }
+
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("<== 
RangerHiveResourcesNotAccessedTogetherCondition.buildMatcher(" + 
policyResourceSpec + ")" + ", matcher=" + matcher);
+               }
+
+               return matcher;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyItemEvaluator.java
----------------------------------------------------------------------
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyItemEvaluator.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyItemEvaluator.java
index 16335fa..a617e70 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyItemEvaluator.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyItemEvaluator.java
@@ -66,6 +66,7 @@ public class RangerDefaultPolicyItemEvaluator extends 
RangerAbstractPolicyItemEv
                                RangerConditionEvaluator conditionEvaluator = 
newConditionEvaluator(conditionDef.getEvaluator());
 
                                if (conditionEvaluator != null) {
+                                       
conditionEvaluator.setServiceDef(serviceDef);
                                        
conditionEvaluator.setConditionDef(conditionDef);
                                        
conditionEvaluator.setPolicyItemCondition(condition);
                                        conditionEvaluator.init();

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestedResources.java
----------------------------------------------------------------------
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestedResources.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestedResources.java
new file mode 100644
index 0000000..19456c5
--- /dev/null
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestedResources.java
@@ -0,0 +1,116 @@
+/*
+ * 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.plugin.util;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.ranger.plugin.policyengine.RangerAccessResource;
+import 
org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.ArrayList;
+import java.util.List;
+
+@JsonAutoDetect(getterVisibility= JsonAutoDetect.Visibility.NONE, 
setterVisibility= JsonAutoDetect.Visibility.NONE, fieldVisibility= 
JsonAutoDetect.Visibility.ANY)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL )
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+
+public class RangerRequestedResources {
+       private List<RangerAccessResource> requestedResources = new 
ArrayList<RangerAccessResource>();
+       public static final String KEY_CONTEXT_REQUESTED_RESOURCES = 
"REQUESTED_RESOURCES";
+
+       public RangerRequestedResources() {
+       }
+
+       public void addRequestedResource(RangerAccessResource 
requestedResource) {
+               if (requestedResource != null) {
+
+                       if (CollectionUtils.isEmpty(requestedResources)) {
+                               requestedResources = new ArrayList<>();
+                       }
+
+                       boolean exists = false;
+
+                       for (RangerAccessResource resource : 
requestedResources) {
+
+                               if (requestedResource.equals(resource)) {
+                                       exists = true;
+                                       break;
+                               }
+                       }
+
+                       if (!exists) {
+                               requestedResources.add(requestedResource);
+                       }
+               }
+       }
+
+       public boolean isMutuallyExcluded(final 
List<RangerPolicyResourceMatcher> matchers) {
+               boolean ret = true;
+
+               int matchedCount = 0;
+
+               if (!CollectionUtils.isEmpty(matchers) && 
!CollectionUtils.isEmpty(requestedResources) && requestedResources.size() > 1) {
+
+                       for (RangerAccessResource resource : 
requestedResources) {
+
+                               for (RangerPolicyResourceMatcher matcher : 
matchers) {
+
+                                       if (matcher.isMatch(resource) && 
matchedCount++ > 0) {
+                                               ret = false;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               return ret;
+       }
+
+       @Override
+       public String toString( ) {
+               StringBuilder sb = new StringBuilder();
+
+               toString(sb);
+
+               return sb.toString();
+       }
+
+       StringBuilder toString(StringBuilder sb) {
+               sb.append("AllRequestedHiveResources={");
+               for (RangerAccessResource resource : requestedResources) {
+                       if (resource != null) {
+                               sb.append(resource.getAsString());
+                               sb.append("; ");
+                       }
+               }
+               sb.append("} ");
+
+               return sb;
+       }
+}
+
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/agents-common/src/main/resources/service-defs/ranger-servicedef-hive.json
----------------------------------------------------------------------
diff --git 
a/agents-common/src/main/resources/service-defs/ranger-servicedef-hive.json 
b/agents-common/src/main/resources/service-defs/ranger-servicedef-hive.json
index 2c48298..53b1926 100644
--- a/agents-common/src/main/resources/service-defs/ranger-servicedef-hive.json
+++ b/agents-common/src/main/resources/service-defs/ranger-servicedef-hive.json
@@ -214,5 +214,13 @@
 
        "policyConditions": 
        [
+         {
+               "itemId":1,
+               "name":"not-accessed-together",
+               "evaluator": 
"org.apache.ranger.plugin.conditionevaluator.RangerHiveResourcesNotAccessedTogetherCondition",
+               "evaluatorOptions" : {},
+               "label":"Not Accessed Together?",
+               "description": "List of Hive resources"
+         }
        ]
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
----------------------------------------------------------------------
diff --git 
a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
 
b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
index a7ce78d..269a27f 100644
--- 
a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
+++ 
b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
@@ -34,6 +34,7 @@ import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerTaggedResource;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import 
org.apache.ranger.plugin.policyengine.TestPolicyEngine.PolicyEngineTestCase.TestData;
+import org.apache.ranger.plugin.util.RangerRequestedResources;
 import org.apache.ranger.plugin.util.ServicePolicies;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -177,6 +178,13 @@ public class TestPolicyEngine {
                runTestsFromResourceFiles(conditionsTestResourceFiles);
        }
 
+       @Test
+       public void testPolicyEngine_hive_mutex_conditions() {
+               String[] conditionsTestResourceFiles = { 
"/policyengine/test_policyengine_hive_mutex_conditions.json" };
+
+               runTestsFromResourceFiles(conditionsTestResourceFiles);
+       }
+
        private void runTestsFromResourceFiles(String[] resourceNames) {
                for(String resourceName : resourceNames) {
                        InputStream       inStream = 
this.getClass().getResourceAsStream(resourceName);
@@ -218,7 +226,8 @@ public class TestPolicyEngine {
 
                for(TestData test : testCase.tests) {
 
-                       if 
(test.request.getContext().containsKey(RangerPolicyEngine.KEY_CONTEXT_TAGS)) {
+                       if 
(test.request.getContext().containsKey(RangerPolicyEngine.KEY_CONTEXT_TAGS) ||
+                                       
test.request.getContext().containsKey(RangerRequestedResources.KEY_CONTEXT_REQUESTED_RESOURCES))
 {
                                // Create a new AccessRequest
                                RangerAccessRequestImpl newRequest =
                                                new 
RangerAccessRequestImpl(test.request.getResource(), 
test.request.getAccessType(),
@@ -232,22 +241,43 @@ public class TestPolicyEngine {
                                
newRequest.setSessionId(test.request.getSessionId());
 
                                Map<String, Object> context = 
test.request.getContext();
-                               String tagsJsonString = (String) 
context.get(RangerPolicyEngine.KEY_CONTEXT_TAGS);
-                               
context.remove(RangerPolicyEngine.KEY_CONTEXT_TAGS);
-
-                               if(!StringUtils.isEmpty(tagsJsonString)) {
-                                       try {
-                                               Type listType = new 
TypeToken<List<RangerTaggedResource.RangerResourceTag>>() {
-                                               }.getType();
-                                               
List<RangerTaggedResource.RangerResourceTag> tagList = 
gsonBuilder.fromJson(tagsJsonString, listType);
-
-                                               
context.put(RangerPolicyEngine.KEY_CONTEXT_TAGS, tagList);
-                                       } catch (Exception e) {
-                                               
System.err.println("TestPolicyEngine.runTests(): error parsing TAGS JSON string 
in file " + testName + ", tagsJsonString=" +
-                                                               tagsJsonString 
+ ", exception=" + e);
+                               if 
(test.request.getContext().containsKey(RangerPolicyEngine.KEY_CONTEXT_TAGS)) {
+                                       String tagsJsonString = (String) 
context.get(RangerPolicyEngine.KEY_CONTEXT_TAGS);
+                                       
context.remove(RangerPolicyEngine.KEY_CONTEXT_TAGS);
+
+                                       if 
(!StringUtils.isEmpty(tagsJsonString)) {
+                                               try {
+                                                       Type listType = new 
TypeToken<List<RangerTaggedResource.RangerResourceTag>>() {
+                                                       }.getType();
+                                                       
List<RangerTaggedResource.RangerResourceTag> tagList = 
gsonBuilder.fromJson(tagsJsonString, listType);
+
+                                                       
context.put(RangerPolicyEngine.KEY_CONTEXT_TAGS, tagList);
+                                               } catch (Exception e) {
+                                                       
System.err.println("TestPolicyEngine.runTests(): error parsing TAGS JSON string 
in file " + testName + ", tagsJsonString=" +
+                                                                       
tagsJsonString + ", exception=" + e);
+                                               }
+                                       }
+                               } else if 
(test.request.getContext().containsKey(RangerRequestedResources.KEY_CONTEXT_REQUESTED_RESOURCES))
 {
+                                       String resourcesJsonString = (String) 
context.get(RangerRequestedResources.KEY_CONTEXT_REQUESTED_RESOURCES);
+                                       
context.remove(RangerRequestedResources.KEY_CONTEXT_REQUESTED_RESOURCES);
+                                       if 
(!StringUtils.isEmpty(resourcesJsonString)) {
+                                               try {
+                                                       /*
+                                                       Reader stringReader = 
new StringReader(resourcesJsonString);
+                                                       
RangerRequestedResources resources = gsonBuilder.fromJson(stringReader, 
RangerRequestedResources.class);
+                                                       */
+
+                                                       Type myType = new 
TypeToken<RangerRequestedResources>() {
+                                                       }.getType();
+                                                       
RangerRequestedResources resources = gsonBuilder.fromJson(resourcesJsonString, 
myType);
+
+                                                       
context.put(RangerRequestedResources.KEY_CONTEXT_REQUESTED_RESOURCES, 
resources);
+                                               } catch (Exception e) {
+                                                       
System.err.println("TestPolicyEngine.runTests(): error parsing 
REQUESTED_RESOURCES string in file " + testName + ", resourcesJsonString=" +
+                                                                       
resourcesJsonString + ", exception=" + e);
+                                               }
                                        }
                                }
-
                                newRequest.setContext(context);
 
                                // accessResource.ServiceDef is set here, so 
that we can skip call to policyEngine.preProcess() which
@@ -261,6 +291,8 @@ public class TestPolicyEngine {
 
                                request = newRequest;
 
+                       } else
+                       if 
(test.request.getContext().containsKey(RangerRequestedResources.KEY_CONTEXT_REQUESTED_RESOURCES))
 {
                        }
                        else {
                                request = test.request;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/agents-common/src/test/resources/policyengine/test_policyengine_hive_mutex_conditions.json
----------------------------------------------------------------------
diff --git 
a/agents-common/src/test/resources/policyengine/test_policyengine_hive_mutex_conditions.json
 
b/agents-common/src/test/resources/policyengine/test_policyengine_hive_mutex_conditions.json
new file mode 100644
index 0000000..b9bcad4
--- /dev/null
+++ 
b/agents-common/src/test/resources/policyengine/test_policyengine_hive_mutex_conditions.json
@@ -0,0 +1,178 @@
+{
+  "serviceName":"hivedev",
+
+  "serviceDef":{
+    "name":"hive",
+    "id":3,
+    "resources":[
+      
{"name":"database","level":1,"mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":{"wildCard":true,
 "ignoreCase":true},"label":"Hive Database","description":"Hive Database"},
+      
{"name":"table","level":2,"parent":"database","mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":{"wildCard":true,
 "ignoreCase":true},"label":"Hive Table","description":"Hive Table"},
+      
{"name":"udf","level":2,"parent":"database","mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":{"wildCard":true,
 "ignoreCase":true},"label":"Hive UDF","description":"Hive UDF"},
+      
{"name":"column","level":3,"parent":"table","mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":{"wildCard":true,
 "ignoreCase":true},"label":"Hive Column","description":"Hive Column"}
+    ],
+    "accessTypes":[
+      {"name":"select","label":"Select"},
+      {"name":"update","label":"Update"},
+      {"name":"create","label":"Create"},
+      {"name":"drop","label":"Drop"},
+      {"name":"alter","label":"Alter"},
+      {"name":"index","label":"Index"},
+      {"name":"lock","label":"Lock"},
+      {"name":"all","label":"All"}
+    ],
+    "policyConditions":[
+      {
+        "itemId":1,
+        "name":"not-accessed-together",
+        "evaluator": 
"org.apache.ranger.plugin.conditionevaluator.RangerHiveResourcesNotAccessedTogetherCondition",
+        "evaluatorOptions" : {"ui.isMultiline":"false" },
+        "label":"Not Accessed Together?",
+        "description": "List of Hive resources"
+      }
+    ]
+  },
+
+  "policies":[
+    {"id":1,"name":"db=default; allow_exclusive select with mutual exclusion 
of col* for user1","isEnabled":true,"isAuditEnabled":true,"policyType":2,
+      
"resources":{"database":{"values":["d*"]},"table":{"values":["*"]},"column":{"values":["*"]}},
+      "policyItems":[
+        
{"accesses":[{"type":"select"}],"users":["user1"],"groups":[],"delegateAdmin":false,
 
"conditions":[{"type":"not-accessed-together","values":["default.testTable.col*"]}]},
+        
{"accesses":[{"type":"select"}],"users":["user2"],"groups":[],"delegateAdmin":false,
 
"conditions":[{"type":"not-accessed-together","values":["default.testTable.col1",
 "default.testTable.name"]}]},
+        
{"accesses":[{"type":"select"}],"users":["admin"],"groups":["admin"],"delegateAdmin":false}
+      ]
+    }
+  ],
+
+  "tests":[
+    {
+      "name": "DENY 'select col1, col2 from default.testtable;' to user1",
+      "request": {
+        "resource": {
+          "elements": {
+            "database": "default",
+            "table": "testTable",
+            "column": "col1"
+          }
+        },
+        "accessType": "select",
+        "user": "user1",
+        "userGroups": [
+
+        ],
+        "requestData": "select col1,col2 from default.testtable",
+        "context": {
+          "REQUESTED_RESOURCES": "{\"requestedResources\":[ 
{\"elements\":{\"database\":\"default\",\"table\":\"testTable\",\"column\":\"col1\"}
 }, 
{\"elements\":{\"database\":\"default\",\"table\":\"testTable\",\"column\":\"col2\"}
 } ]}"
+        }
+      },
+      "result": {
+        "isAudited": true,
+        "isAllowed": false,
+        "policyId": 1
+      }
+    }
+    , {
+      "name": "DENY 'select col1, name from default.testtable;' to user2",
+      "request": {
+        "resource": {
+          "elements": {
+            "database": "default",
+            "table": "testTable",
+            "column": "col1"
+          }
+        },
+        "accessType": "select",
+        "user": "user2",
+        "userGroups": [
+        ],
+        "requestData": "select col1,name from default.testtable",
+        "context": {
+          "REQUESTED_RESOURCES": "{\"requestedResources\":[ 
{\"elements\":{\"database\":\"default\",\"table\":\"testTable\",\"column\":\"col1\"}
 }, 
{\"elements\":{\"database\":\"default\",\"table\":\"testTable\",\"column\":\"name\"}
 } ]}"
+        }
+      },
+      "result": {
+        "isAudited": true,
+        "isAllowed": false,
+        "policyId": 1
+      }
+    }
+    ,
+    {
+      "name": "ALLOW 'select col1, col2 from default.testtable;' to admin",
+      "request": {
+        "resource": {
+          "elements": {
+            "database": "default",
+            "table": "testTable",
+            "column": "col1"
+          }
+        },
+        "accessType": "select",
+        "user": "admin",
+        "userGroups": [
+        ],
+        "requestData": "select col1,col2 from default.testtable",
+        "context": {
+          "REQUESTED_RESOURCES": "{\"requestedResources\":[ 
{\"elements\":{\"database\":\"default\",\"table\":\"testTable\",\"column\":\"col1\"}
 }, 
{\"elements\":{\"database\":\"default\",\"table\":\"testTable\",\"column\":\"col2\"}
 } ]}"
+        }
+      },
+      "result": {
+        "isAudited": true,
+        "isAllowed": true,
+        "policyId": 1
+      }
+    }
+    ,{
+      "name": "ALLOW 'select col2, name from default.testtable;' to user1",
+      "request": {
+        "resource": {
+          "elements": {
+            "database": "default",
+            "table": "testTable",
+            "column": "col1"
+          }
+        },
+        "accessType": "select",
+        "user": "user1",
+        "userGroups": [
+          "public"
+        ],
+        "requestData": "select col2,name from default.testtable",
+        "context": {
+          "REQUESTED_RESOURCES": "{\"requestedResources\":[ 
{\"elements\":{\"database\":\"default\",\"table\":\"testTable\",\"column\":\"col2\"}
 }, 
{\"elements\":{\"database\":\"default\",\"table\":\"testTable\",\"column\":\"name\"}
 } ]}"
+        }
+      },
+      "result": {
+        "isAudited": true,
+        "isAllowed": true,
+        "policyId": 1
+      }
+    }
+    ,{
+      "name": "ALLOW 'select col2, col2 from default.testtable;' to user1",
+      "request": {
+        "resource": {
+          "elements": {
+            "database": "default",
+            "table": "testTable",
+            "column": "col1"
+          }
+        },
+        "accessType": "select",
+        "user": "user1",
+        "userGroups": [
+          "public"
+        ],
+        "requestData": "select col2 from default.testtable",
+        "context": {
+          "REQUESTED_RESOURCES": "{\"requestedResources\":[ 
{\"elements\":{\"database\":\"default\",\"table\":\"testTable\",\"column\":\"col2\"}
 } ]}"
+        }
+      },
+      "result": {
+        "isAudited": true,
+        "isAllowed": true,
+        "policyId": 1
+      }
+    }
+  ]
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAccessRequest.java
----------------------------------------------------------------------
diff --git 
a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAccessRequest.java
 
b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAccessRequest.java
index 2ae4149..9f99ea1 100644
--- 
a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAccessRequest.java
+++ 
b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAccessRequest.java
@@ -101,6 +101,7 @@ public class RangerHiveAccessRequest extends 
RangerAccessRequestImpl {
                ret.setRequestData(getRequestData());
                ret.setClientType(getClientType());
                ret.setSessionId(getSessionId());
+               ret.setContext(getContext());
                ret.accessType = accessType;
 
                return ret;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/990213ca/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java
----------------------------------------------------------------------
diff --git 
a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java
 
b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java
index 9075b57..3c8b7e1 100644
--- 
a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java
+++ 
b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java
@@ -57,8 +57,8 @@ import 
org.apache.ranger.plugin.policyengine.RangerAccessRequest;
 import org.apache.ranger.plugin.policyengine.RangerAccessResult;
 import org.apache.ranger.plugin.service.RangerBasePlugin;
 import org.apache.ranger.plugin.util.GrantRevokeRequest;
-
 import com.google.common.collect.Sets;
+import org.apache.ranger.plugin.util.RangerRequestedResources;
 
 public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase {
        private static final Log LOG = 
LogFactory.getLog(RangerHiveAuthorizer.class) ; 
@@ -189,7 +189,7 @@ public class RangerHiveAuthorizer extends 
RangerHiveAuthorizerBase {
        /**
         * Check if user has privileges to do this action on these objects
         * @param hiveOpType
-        * @param inputsHObjs
+        * @param inputHObjs
         * @param outputHObjs
         * @param context
         * @throws HiveAuthzPluginException
@@ -226,18 +226,7 @@ public class RangerHiveAuthorizer extends 
RangerHiveAuthorizerBase {
 
                        List<RangerHiveAccessRequest> requests = new 
ArrayList<RangerHiveAccessRequest>();
 
-                       if(CollectionUtils.isEmpty(inputHObjs)) {
-                               // this should happen only for SHOWDATABASES
-                               if (hiveOpType == 
HiveOperationType.SHOWDATABASES) {
-                                       RangerHiveResource resource = new 
RangerHiveResource(HiveObjectType.DATABASE, null);
-                                       RangerHiveAccessRequest request = new 
RangerHiveAccessRequest(resource, user, groups, hiveOpType.name(), 
HiveAccessType.USE, context, sessionContext);
-                                       requests.add(request);
-                               } else {
-                                       if (LOG.isDebugEnabled()) {
-                                               
LOG.debug("RangerHiveAuthorizer.checkPrivileges: Unexpected operation type[" + 
hiveOpType + "] received with empty input objects list!");
-                                       }
-                               }
-                       } else {
+                       if(!CollectionUtils.isEmpty(inputHObjs)) {
                                for(HivePrivilegeObject hiveObj : inputHObjs) {
                                        RangerHiveResource resource = 
getHiveResource(hiveOpType, hiveObj);
 
@@ -245,9 +234,9 @@ public class RangerHiveAuthorizer extends 
RangerHiveAuthorizerBase {
                                                String   path       = 
hiveObj.getObjectName();
                                                FsAction permission = 
FsAction.READ;
 
-                               if(!isURIAccessAllowed(user, groups, 
permission, path, getHiveConf())) {
-                                               throw new 
HiveAccessControlException(String.format("Permission denied: user [%s] does not 
have [%s] privilege on [%s]", user, permission.name(), path));
-                               }
+                                               if(!isURIAccessAllowed(user, 
groups, permission, path, getHiveConf())) {
+                                                       throw new 
HiveAccessControlException(String.format("Permission denied: user [%s] does not 
have [%s] privilege on [%s]", user, permission.name(), path));
+                                               }
 
                                                continue;
                                        }
@@ -264,9 +253,20 @@ public class RangerHiveAuthorizer extends 
RangerHiveAuthorizerBase {
                                                requests.add(request);
                                        }
                                }
+                       } else {
+                               // this should happen only for SHOWDATABASES
+                               if (hiveOpType == 
HiveOperationType.SHOWDATABASES) {
+                                       RangerHiveResource resource = new 
RangerHiveResource(HiveObjectType.DATABASE, null);
+                                       RangerHiveAccessRequest request = new 
RangerHiveAccessRequest(resource, user, groups, hiveOpType.name(), 
HiveAccessType.USE, context, sessionContext);
+                                       requests.add(request);
+                               } else {
+                                       if (LOG.isDebugEnabled()) {
+                                               
LOG.debug("RangerHiveAuthorizer.checkPrivileges: Unexpected operation type[" + 
hiveOpType + "] received with empty input objects list!");
+                                       }
+                               }
                        }
 
-                       if(outputHObjs != null) {
+                       if(!CollectionUtils.isEmpty(outputHObjs)) {
                                for(HivePrivilegeObject hiveObj : outputHObjs) {
                                        RangerHiveResource resource = 
getHiveResource(hiveOpType, hiveObj);
 
@@ -295,6 +295,8 @@ public class RangerHiveAuthorizer extends 
RangerHiveAuthorizerBase {
                                }
                        }
 
+                       buildRequestContextWithAllAccessedResources(requests);
+
                        for(RangerHiveAccessRequest request : requests) {
                                RangerHiveResource resource = 
(RangerHiveResource)request.getResource();
                                RangerAccessResult result   = null;
@@ -460,6 +462,11 @@ public class RangerHiveAuthorizer extends 
RangerHiveAuthorizerBase {
                default:
                        LOG.warn("RangerHiveAuthorizer.getHiveResource: 
unexpected objectType:" + objectType);
                }
+
+               if (resource != null) {
+                       resource.setServiceDef(hivePlugin == null ? null : 
hivePlugin.getServiceDef());
+               }
+
                return resource;
        }
 
@@ -495,6 +502,10 @@ public class RangerHiveAuthorizer extends 
RangerHiveAuthorizerBase {
                        break;
                }
 
+               if (ret != null) {
+                       ret.setServiceDef(hivePlugin == null ? null : 
hivePlugin.getServiceDef());
+               }
+
                return ret;
        }
 
@@ -883,7 +894,51 @@ public class RangerHiveAuthorizer extends 
RangerHiveAuthorizerBase {
 
                return ret;
        }
-       
+
+       private RangerRequestedResources 
buildRequestContextWithAllAccessedResources(List<RangerHiveAccessRequest> 
requests) {
+
+               RangerRequestedResources requestedResources = new 
RangerRequestedResources();
+
+               for (RangerHiveAccessRequest request : requests) {
+                       // Build list of all things requested and put it in the 
context of each request
+                       
request.getContext().put(RangerRequestedResources.KEY_CONTEXT_REQUESTED_RESOURCES,
 requestedResources);
+
+                       RangerHiveResource resource = (RangerHiveResource) 
request.getResource();
+
+                       if (resource.getObjectType() == HiveObjectType.COLUMN 
&& StringUtils.contains(resource.getColumn(), COLUMN_SEP)) {
+
+                               String[] columns = 
StringUtils.split(resource.getColumn(), COLUMN_SEP);
+
+                               // in case of multiple columns, original 
request is not sent to the plugin; hence service-def will not be set
+                               
resource.setServiceDef(hivePlugin.getServiceDef());
+
+                               for (String column : columns) {
+                                       if (column != null) {
+                                               column = column.trim();
+                                       }
+                                       if (StringUtils.isBlank(column)) {
+                                               continue;
+                                       }
+
+                                       RangerHiveResource colResource = new 
RangerHiveResource(HiveObjectType.COLUMN, resource.getDatabase(), 
resource.getTable(), column);
+                                       
colResource.setServiceDef(hivePlugin.getServiceDef());
+
+                                       
requestedResources.addRequestedResource(colResource);
+
+                               }
+                       } else {
+                               
resource.setServiceDef(hivePlugin.getServiceDef());
+                               
requestedResources.addRequestedResource(resource);
+                       }
+               }
+
+               if (LOG.isDebugEnabled()) {
+                       
LOG.debug("RangerHiveAuthorizer.buildRequestContextWithAllAccessedResources() - 
" + requestedResources);
+               }
+
+               return requestedResources;
+       }
+
        private String toString(HiveOperationType         hiveOpType,
                                                        
List<HivePrivilegeObject> inputHObjs,
                                                        
List<HivePrivilegeObject> outputHObjs,


Reply via email to