This is an automated email from the ASF dual-hosted git repository. abhay pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push: new 56d5bf917 RANGER-3999: Implement more efficient way to handle _any access authorization 56d5bf917 is described below commit 56d5bf9173dc2c6d04692a07e67eace5e5d98ed4 Author: Abhay Kulkarni <ab...@apache.org> AuthorDate: Tue Dec 6 14:25:10 2022 -0800 RANGER-3999: Implement more efficient way to handle _any access authorization --- .../policyengine/RangerAccessRequestWrapper.java | 105 +++++++++++++++++++++ .../policyengine/RangerPolicyEngineImpl.java | 37 ++------ .../RangerDefaultPolicyEvaluator.java | 95 +++++++++++++++++-- .../RangerOptimizedPolicyEvaluator.java | 6 ++ .../plugin/util/RangerAccessRequestUtil.java | 13 ++- 5 files changed, 218 insertions(+), 38 deletions(-) diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java new file mode 100644 index 000000000..6aec330d7 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java @@ -0,0 +1,105 @@ +/* + * 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.policyengine; + +import org.apache.commons.lang.StringUtils; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class RangerAccessRequestWrapper implements RangerAccessRequest { + + private final RangerAccessRequest request; + private final String accessType; + private final boolean isAccessTypeAny; + private final boolean isAccessTypeDelegatedAdmin; + + + public RangerAccessRequestWrapper(RangerAccessRequest request, String accessType) { + this.request = request; + this.accessType = accessType; + this.isAccessTypeAny = StringUtils.equals(accessType, RangerPolicyEngine.ANY_ACCESS); + this.isAccessTypeDelegatedAdmin = StringUtils.equals(accessType, RangerPolicyEngine.ADMIN_ACCESS); + } + + @Override + public RangerAccessResource getResource() { return request.getResource(); } + + @Override + public String getAccessType() { return accessType; } + + @Override + public boolean isAccessTypeAny() { return isAccessTypeAny; } + + @Override + public boolean isAccessTypeDelegatedAdmin() { return isAccessTypeDelegatedAdmin; } + + @Override + public String getUser() { return request.getUser(); } + + @Override + public Set<String> getUserGroups() { return request.getUserGroups(); } + + @Override + public Set<String> getUserRoles() {return request.getUserRoles(); } + + @Override + public Date getAccessTime() { return request.getAccessTime(); } + + @Override + public String getClientIPAddress() { return request.getClientIPAddress(); } + + @Override + public String getRemoteIPAddress() { return request.getRemoteIPAddress(); } + + @Override + public List<String> getForwardedAddresses() { return request.getForwardedAddresses(); } + + @Override + public String getClientType() { return request.getClientType(); } + + @Override + public String getAction() { return request.getAction(); } + + @Override + public String getRequestData() { return request.getRequestData(); } + + @Override + public String getSessionId() { return request.getSessionId(); } + + @Override + public String getClusterName() { return request.getClusterName(); } + + @Override + public String getClusterType() { return request.getClusterType(); } + + @Override + public Map<String, Object> getContext() { return request.getContext(); } + + @Override + public RangerAccessRequest getReadOnlyCopy() { return request.getReadOnlyCopy(); } + + @Override + public ResourceMatchingScope getResourceMatchingScope() { return request.getResourceMatchingScope(); } + +} + diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java index 23db18f3a..8d80ad6a3 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java @@ -692,42 +692,19 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine { final RangerAccessResult ret; if (request.isAccessTypeAny()) { - RangerAccessResult denyResult = null; - RangerAccessResult allowResult = null; - - ret = createAccessResult(request, policyType); - List<RangerServiceDef.RangerAccessTypeDef> allAccessDefs = getServiceDef().getAccessTypes(); + Set<String> allRequestedAccesses = new HashSet<>(); for (RangerServiceDef.RangerAccessTypeDef accessTypeDef : allAccessDefs) { - RangerAccessRequestImpl requestForOneAccessType = new RangerAccessRequestImpl(request); - RangerAccessRequestUtil.setIsAnyAccessInContext(requestForOneAccessType.getContext(), Boolean.TRUE); - - requestForOneAccessType.setAccessType(accessTypeDef.getName()); - - RangerAccessResult resultForOneAccessType = evaluatePoliciesForOneAccessTypeNoAudit(requestForOneAccessType, policyType, zoneName, policyRepository, tagPolicyRepository); - - ret.setAuditResultFrom(resultForOneAccessType); - - if (resultForOneAccessType.getIsAccessDetermined()) { - if (resultForOneAccessType.getIsAllowed()) { - allowResult = resultForOneAccessType; - break; - } else if (denyResult == null) { - denyResult = resultForOneAccessType; - } - } - } - - if (allowResult != null) { - ret.setAccessResultFrom(allowResult); - } else if (denyResult != null) { - ret.setAccessResultFrom(denyResult); + String requestedAccess = accessTypeDef.getName(); + allRequestedAccesses.add(requestedAccess); } - } else { - ret = evaluatePoliciesForOneAccessTypeNoAudit(request, policyType, zoneName, policyRepository, tagPolicyRepository); + RangerAccessRequestUtil.setIsAnyAccessInContext(request.getContext(), Boolean.TRUE); + request.getContext().put(RangerAccessRequestUtil.KEY_CONTEXT_ACCESSTYPES, allRequestedAccesses); } + ret = evaluatePoliciesForOneAccessTypeNoAudit(request, policyType, zoneName, policyRepository, tagPolicyRepository); + if (LOG.isDebugEnabled()) { LOG.debug("<== RangerPolicyEngineImpl.evaluatePoliciesNoAudit(" + request + ", policyType =" + policyType + ", zoneName=" + zoneName + "): " + ret); } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java index 520ddf865..55752e79c 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java @@ -43,6 +43,7 @@ import org.apache.ranger.plugin.model.RangerServiceDef; import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef; import org.apache.ranger.plugin.model.RangerValiditySchedule; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestWrapper; import org.apache.ranger.plugin.policyengine.RangerAccessResource; import org.apache.ranger.plugin.policyengine.RangerAccessResult; import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; @@ -241,7 +242,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator final boolean isMatched; - if (request.isAccessTypeAny() || Boolean.TRUE.equals(RangerAccessRequestUtil.getIsAnyAccessInContext(request.getContext()))) { + if (request.isAccessTypeAny() || RangerAccessRequestUtil.getIsAnyAccessInContext(request.getContext())) { isMatched = matchType != RangerPolicyResourceMatcher.MatchType.NONE; } else if (request.getResourceMatchingScope() == RangerAccessRequest.ResourceMatchingScope.SELF_OR_DESCENDANTS) { isMatched = matchType != RangerPolicyResourceMatcher.MatchType.NONE; @@ -794,7 +795,25 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator if (LOG.isDebugEnabled()) { LOG.debug("Using ACL Summary for access evaluation. PolicyId=[" + getPolicyId() + "]"); } - Integer accessResult = lookupPolicyACLSummary(request.getUser(), request.getUserGroups(), RangerAccessRequestUtil.getUserRoles(request), request.isAccessTypeAny() || Boolean.TRUE.equals(RangerAccessRequestUtil.getIsAnyAccessInContext(request.getContext())) ? RangerPolicyEngine.ANY_ACCESS : request.getAccessType()); + Integer accessResult = null; + + if (request.isAccessTypeAny() || RangerAccessRequestUtil.getIsAnyAccessInContext(request.getContext())) { + accessResult = lookupPolicyACLSummary(request.getUser(), request.getUserGroups(), request.getUserRoles(), RangerPolicyEngine.ANY_ACCESS); + } else { + Set<String> allRequestedAccesses = RangerAccessRequestUtil.getAllRequestedAccessTypes(request); + + if (CollectionUtils.isNotEmpty(allRequestedAccesses)) { + for (String accessType : allRequestedAccesses) { + accessResult = lookupPolicyACLSummary(request.getUser(), request.getUserGroups(), request.getUserRoles(), accessType); + if (accessResult == null) { + break; + } + } + } else { + accessResult = lookupPolicyACLSummary(request.getUser(), request.getUserGroups(), request.getUserRoles(), request.getAccessType()); + } + } + if (accessResult != null) { updateAccessResult(result, matchType, accessResult.equals(RangerPolicyEvaluator.ACCESS_ALLOWED), null); } else if (getPolicy().getIsDenyAllElse()) { @@ -804,13 +823,75 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator if (LOG.isDebugEnabled()) { LOG.debug("Using policyItemEvaluators for access evaluation. PolicyId=[" + getPolicyId() + "]"); } + Set<String> allRequestedAccesses = RangerAccessRequestUtil.getAllRequestedAccessTypes(request); - RangerPolicyItemEvaluator matchedPolicyItem = getMatchingPolicyItem(request, result); + if (CollectionUtils.isNotEmpty(allRequestedAccesses)) { - if (matchedPolicyItem != null) { - matchedPolicyItem.updateAccessResult(this, result, matchType); - } else if (getPolicy().getIsDenyAllElse() && (getPolicy().getPolicyType() == null || getPolicy().getPolicyType() == RangerPolicy.POLICY_TYPE_ACCESS)) { - updateAccessResult(result, matchType, false, "matched deny-all-else policy"); + RangerAccessResult denyResult = null; + RangerAccessResult allowResult = null; + boolean noResult = false; + + for (String accessType : allRequestedAccesses) { + + RangerAccessRequestWrapper oneRequest = new RangerAccessRequestWrapper(request, accessType); + RangerAccessResult oneResult = new RangerAccessResult(result.getPolicyType(), result.getServiceName(), result.getServiceDef(), oneRequest); + + oneResult.setAuditResultFrom(result); + + RangerPolicyItemEvaluator matchedPolicyItem = getMatchingPolicyItem(oneRequest, oneResult); + + if (matchedPolicyItem != null) { + matchedPolicyItem.updateAccessResult(this, oneResult, matchType); + } else if (getPolicy().getIsDenyAllElse() && (getPolicy().getPolicyType() == null || getPolicy().getPolicyType() == RangerPolicy.POLICY_TYPE_ACCESS)) { + updateAccessResult(oneResult, matchType, false, "matched deny-all-else policy"); + } + + if (request.isAccessTypeAny()) { + // Implement OR logic + if (oneResult.getIsAllowed()) { + allowResult = oneResult; + denyResult = null; + + break; + } else if (oneResult.getIsAccessDetermined()) { + if (!noResult) { + if (denyResult == null) { + denyResult = oneResult; + } + } + } else { + noResult = true; + denyResult = null; + } + } else { + // Implement AND logic + if (oneResult.getIsAccessDetermined() && !oneResult.getIsAllowed()) { + denyResult = oneResult; + allowResult = null; + + break; + } else if (oneResult.getIsAllowed()) { + allowResult = noResult ? null : oneResult; + } else { + noResult = true; + allowResult = null; + } + } + } + + if (allowResult != null) { + result.setAccessResultFrom(allowResult); + } else if (denyResult != null) { + result.setAccessResultFrom(denyResult); + } + + } else { + RangerPolicyItemEvaluator matchedPolicyItem = getMatchingPolicyItem(request, result); + if (matchedPolicyItem != null) { + matchedPolicyItem.updateAccessResult(this, result, matchType); + } else if (getPolicy().getIsDenyAllElse() && (getPolicy().getPolicyType() == null || getPolicy().getPolicyType() == RangerPolicy.POLICY_TYPE_ACCESS)) { + updateAccessResult(result, matchType, false, "matched deny-all-else policy"); + } } } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerOptimizedPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerOptimizedPolicyEvaluator.java index d3fc27d7d..e50eb5f54 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerOptimizedPolicyEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerOptimizedPolicyEvaluator.java @@ -257,6 +257,12 @@ public class RangerOptimizedPolicyEvaluator extends RangerDefaultPolicyEvaluator ret = true; } else { ret = accessPerms.contains(request.getAccessType()); + + if (!ret) { + Set<String> allRequestedAccesses = RangerAccessRequestUtil.getAllRequestedAccessTypes(request); + ret = CollectionUtils.containsAny(accessPerms, allRequestedAccesses); + } + if (!ret) { if (request.isAccessTypeDelegatedAdmin()) { ret = delegateAdmin; diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java index df03ed1c4..05d9a6007 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java @@ -199,7 +199,18 @@ public class RangerAccessRequestUtil { } public static Boolean getIsAnyAccessInContext(Map<String, Object> context) { - return (Boolean)context.get(KEY_CONTEXT_IS_ANY_ACCESS); + Boolean ret = (Boolean)context.get(KEY_CONTEXT_IS_ANY_ACCESS); + return ret == null ? Boolean.FALSE : ret; + } + + public static void setAllRequestedAccessTypes(Map<String, Object> context, Set<String> accessTypes) { + context.put(KEY_CONTEXT_ACCESSTYPES, accessTypes); + } + + public static Set<String> getAllRequestedAccessTypes(RangerAccessRequest request) { + Set<String> ret = (Set<String>) request.getContext().get(KEY_CONTEXT_ACCESSTYPES); + + return ret != null ? ret : Collections.singleton(request.getAccessType()); } public static void setRequestInContext(RangerAccessRequest request) {