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,
