/*
* 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.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
import org.apache.ranger.plugin.contextenricher.RangerContextEnricher;
import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
import org.apache.ranger.plugin.model.RangerPolicy;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator;
import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
import org.apache.ranger.plugin.util.RangerPerfTracer;
import org.apache.ranger.plugin.util.ServicePolicies;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class RangerPolicyEngineImpl implements RangerPolicyEngine {
private static final Log LOG = LogFactory.getLog(RangerPolicyEngineImpl.class);
private static final Log PERF_POLICYENGINE_INIT_LOG = RangerPerfTracer.getPerfLogger("policyengine.init");
private static final Log PERF_POLICYENGINE_REQUEST_LOG = RangerPerfTracer.getPerfLogger("policyengine.request");
private static final Log PERF_POLICYENGINE_AUDIT_LOG = RangerPerfTracer.getPerfLogger("policyengine.audit");
private static final Log PERF_CONTEXTENRICHER_REQUEST_LOG = RangerPerfTracer.getPerfLogger("contextenricher.request");
private static final Log PERF_POLICYENGINE_REBALANCE_LOG = RangerPerfTracer.getPerfLogger("policyengine.rebalance");
private static final Log PERF_POLICYENGINE_USAGE_LOG = RangerPerfTracer.getPerfLogger("policyengine.usage");
private static final int MAX_POLICIES_FOR_CACHE_TYPE_EVALUATOR = 100;
private final RangerPolicyRepository policyRepository;
private final RangerPolicyRepository tagPolicyRepository;
private List<RangerContextEnricher> allContextEnrichers;
private final Map<Long, RangerPolicyEvaluator> policyEvaluatorsMap;
private boolean useForwardedIPAddress;
private String[] trustedProxyAddresses;
public RangerPolicyEngineImpl(String appId, ServicePolicies servicePolicies, RangerPolicyEngineOptions options) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl(" + appId + ", " + servicePolicies + ", " + options + ")");
}
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_INIT_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_INIT_LOG, "RangerPolicyEngine.init(appId=" + appId + ",hashCode=" + Integer.toHexString(System.identityHashCode(this)) + ")");
long freeMemory = Runtime.getRuntime().freeMemory();
long totalMemory = Runtime.getRuntime().totalMemory();
PERF_POLICYENGINE_INIT_LOG.debug("In-Use memory: " + (totalMemory - freeMemory) + ", Free memory:" + freeMemory);
}
if (options == null) {
options = new RangerPolicyEngineOptions();
}
if(StringUtils.isBlank(options.evaluatorType) || StringUtils.equalsIgnoreCase(options.evaluatorType, RangerPolicyEvaluator.EVALUATOR_TYPE_AUTO)) {
String serviceType = servicePolicies.getServiceDef().getName();
String propertyName = "ranger.plugin." + serviceType + ".policyengine.evaluator.auto.maximum.policycount.for.cache.type";
int thresholdForUsingOptimizedEvaluator = RangerConfiguration.getInstance().getInt(propertyName, MAX_POLICIES_FOR_CACHE_TYPE_EVALUATOR);
int servicePoliciesCount = servicePolicies.getPolicies().size() + (servicePolicies.getTagPolicies() != null ? servicePolicies.getTagPolicies().getPolicies().size() : 0);
if (servicePoliciesCount > thresholdForUsingOptimizedEvaluator) {
options.evaluatorType = RangerPolicyEvaluator.EVALUATOR_TYPE_OPTIMIZED;
} else {
options.evaluatorType = RangerPolicyEvaluator.EVALUATOR_TYPE_CACHED;
}
} else if (StringUtils.equalsIgnoreCase(options.evaluatorType, RangerPolicyEvaluator.EVALUATOR_TYPE_CACHED)) {
options.evaluatorType = RangerPolicyEvaluator.EVALUATOR_TYPE_CACHED;
} else {
// All other cases
options.evaluatorType = RangerPolicyEvaluator.EVALUATOR_TYPE_OPTIMIZED;
}
policyRepository = new RangerPolicyRepository(appId, servicePolicies, options);
ServicePolicies.TagPolicies tagPolicies = servicePolicies.getTagPolicies();
if (!options.disableTagPolicyEvaluation
&& tagPolicies != null
&& !StringUtils.isEmpty(tagPolicies.getServiceName())
&& tagPolicies.getServiceDef() != null
&& !CollectionUtils.isEmpty(tagPolicies.getPolicies())) {
if (LOG.isDebugEnabled()) {
LOG.debug("RangerPolicyEngineImpl : Building tag-policy-repository for tag-service " + tagPolicies.getServiceName());
}
tagPolicyRepository = new RangerPolicyRepository(appId, tagPolicies, options, servicePolicies.getServiceDef(), servicePolicies.getServiceName());
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("RangerPolicyEngineImpl : No tag-policy-repository for service " + servicePolicies.getServiceName());
}
tagPolicyRepository = null;
}
List<RangerContextEnricher> tmpList;
List<RangerContextEnricher> tagContextEnrichers = tagPolicyRepository == null ? null :tagPolicyRepository.getContextEnrichers();
List<RangerContextEnricher> resourceContextEnrichers = policyRepository.getContextEnrichers();
if (CollectionUtils.isEmpty(tagContextEnrichers)) {
tmpList = resourceContextEnrichers;
} else if (CollectionUtils.isEmpty(resourceContextEnrichers)) {
tmpList = tagContextEnrichers;
} else {
tmpList = new ArrayList<>(tagContextEnrichers);
tmpList.addAll(resourceContextEnrichers);
}
this.allContextEnrichers = tmpList;
policyEvaluatorsMap = createPolicyEvaluatorsMap();
RangerPerfTracer.log(perf);
if (PERF_POLICYENGINE_INIT_LOG.isDebugEnabled()) {
long freeMemory = Runtime.getRuntime().freeMemory();
long totalMemory = Runtime.getRuntime().totalMemory();
PERF_POLICYENGINE_INIT_LOG.debug("In-Use memory: " + (totalMemory - freeMemory) + ", Free memory:" + freeMemory);
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl()");
}
}
@Override
public String getServiceName() {
return policyRepository.getServiceName();
}
@Override
public RangerServiceDef getServiceDef() {
return policyRepository.getServiceDef();
}
@Override
public long getPolicyVersion() {
return policyRepository.getPolicyVersion();
}
public RangerPolicyEvaluator getPolicyEvaluator(Long id) {
return policyEvaluatorsMap.get(id);
}
public RangerPolicy getPolicy(Long id) {
RangerPolicyEvaluator evaluator = getPolicyEvaluator(id);
return evaluator != null ? evaluator.getPolicy() : null;
}
@Override
public RangerAccessResult createAccessResult(RangerAccessRequest request) {
RangerAccessResult ret = new RangerAccessResult(this.getServiceName(), policyRepository.getServiceDef(), request);
switch (policyRepository.getAuditModeEnum()) {
case AUDIT_ALL:
ret.setIsAudited(true);
break;
case AUDIT_NONE:
ret.setIsAudited(false);
break;
default:
if (CollectionUtils.isEmpty(policyRepository.getPolicies()) && tagPolicyRepository == null) {
ret.setIsAudited(true);
}
break;
}
return ret;
}
@Override
public void preProcess(RangerAccessRequest request) {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.preProcess(" + request + ")");
}
setResourceServiceDef(request);
if (request instanceof RangerAccessRequestImpl) {
((RangerAccessRequestImpl) request).extractAndSetClientIPAddress(useForwardedIPAddress, trustedProxyAddresses);
}
RangerAccessRequestUtil.setCurrentUserInContext(request.getContext(), request.getUser());
List<RangerContextEnricher> enrichers = allContextEnrichers;
if(!CollectionUtils.isEmpty(enrichers)) {
for(RangerContextEnricher enricher : enrichers) {
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_CONTEXTENRICHER_REQUEST_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_CONTEXTENRICHER_REQUEST_LOG, "RangerContextEnricher.enrich(requestHashCode=" + Integer.toHexString(System.identityHashCode(request)) + ", enricherName=" + enricher.getName() + ")");
}
enricher.enrich(request);
RangerPerfTracer.log(perf);
}
}
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.preProcess(" + request + ")");
}
}
@Override
public void preProcess(Collection<RangerAccessRequest> requests) {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.preProcess(" + requests + ")");
}
if(CollectionUtils.isNotEmpty(requests)) {
for(RangerAccessRequest request : requests) {
preProcess(request);
}
}
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.preProcess(" + requests + ")");
}
}
@Override
public RangerAccessResult isAccessAllowed(RangerAccessRequest request, RangerAccessResultProcessor resultProcessor) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowed(" + request + ")");
}
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_REQUEST_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_REQUEST_LOG, "RangerPolicyEngine.isAccessAllowed(requestHashCode=" + Integer.toHexString(System.identityHashCode(request)) + ")");
}
RangerAccessResult ret = isAccessAllowedNoAudit(request);
updatePolicyUsageCounts(request, ret);
if (resultProcessor != null) {
RangerPerfTracer perfAuditTracer = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_AUDIT_LOG)) {
perfAuditTracer = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_AUDIT_LOG, "RangerPolicyEngine.processAudit(requestHashCode=" + Integer.toHexString(System.identityHashCode(request)) + ")");
}
resultProcessor.processResult(ret);
RangerPerfTracer.log(perfAuditTracer);
}
RangerPerfTracer.log(perf);
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowed(" + request + "): " + ret);
}
return ret;
}
@Override
public Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests, RangerAccessResultProcessor resultProcessor) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowed(" + requests + ")");
}
Collection<RangerAccessResult> ret = new ArrayList<>();
if (requests != null) {
for (RangerAccessRequest request : requests) {
RangerAccessResult result = isAccessAllowedNoAudit(request);
ret.add(result);
}
}
if (resultProcessor != null) {
resultProcessor.processResults(ret);
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowed(" + requests + "): " + ret);
}
return ret;
}
@Override
public RangerDataMaskResult evalDataMaskPolicies(RangerAccessRequest request, RangerAccessResultProcessor resultProcessor) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.evalDataMaskPolicies(" + request + ")");
}
RangerDataMaskResult ret = new RangerDataMaskResult(getServiceName(), getServiceDef(), request);
if(request != null) {
List<RangerPolicyEvaluator> evaluators = policyRepository.getDataMaskPolicyEvaluators(request.getResource());
for (RangerPolicyEvaluator evaluator : evaluators) {
evaluator.evaluate(request, ret);
if (ret.getIsAccessDetermined() && ret.getIsAuditedDetermined()) {
if(!StringUtils.equalsIgnoreCase(ret.getMaskType(), RangerPolicy.MASK_TYPE_NONE)) {
break;
} else {
ret.setMaskType(null);
ret.setIsAccessDetermined(false);
}
}
}
}
// no need to audit if mask is not enabled
if(! ret.isMaskEnabled()) {
ret.setIsAudited(false);
}
updatePolicyUsageCounts(request, ret);
if (resultProcessor != null) {
resultProcessor.processResult(ret);
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.evalDataMaskPolicies(" + request + "): " + ret);
}
return ret;
}
@Override
public RangerRowFilterResult evalRowFilterPolicies(RangerAccessRequest request, RangerAccessResultProcessor resultProcessor) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.evalRowFilterPolicies(" + request + ")");
}
RangerRowFilterResult ret = new RangerRowFilterResult(getServiceName(), getServiceDef(), request);
if(request != null) {
List<RangerPolicyEvaluator> evaluators = policyRepository.getRowFilterPolicyEvaluators(request.getResource());
for (RangerPolicyEvaluator evaluator : evaluators) {
evaluator.evaluate(request, ret);
if (ret.getIsAccessDetermined() && ret.getIsAuditedDetermined()) {
if(StringUtils.isNotEmpty(ret.getFilterExpr())) {
break;
} else {
ret.setIsAccessDetermined(false);
}
}
}
}
// no need to audit if filter is not enabled
if(! ret.isRowFilterEnabled()) {
ret.setIsAudited(false);
}
updatePolicyUsageCounts(request, ret);
if (resultProcessor != null) {
resultProcessor.processResult(ret);
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.evalRowFilterPolicies(" + request + "): " + ret);
}
return ret;
}
@Override
public boolean isAccessAllowed(RangerAccessResource resource, String user, Set<String> userGroups, String accessType) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowed(" + resource + ", " + user + ", " + userGroups + ", " + accessType + ")");
}
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_REQUEST_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_REQUEST_LOG, "RangerPolicyEngine.isAccessAllowed(user=" + user + ",accessType=" + accessType + "resource=" + resource.getAsString() + ")");
}
boolean ret = false;
for (RangerPolicyEvaluator evaluator : policyRepository.getPolicyEvaluators(resource)) {
ret = evaluator.isAccessAllowed(resource, user, userGroups, accessType);
if (ret) {
break;
}
}
RangerPerfTracer.log(perf);
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowed(" + resource + ", " + user + ", " + userGroups + ", " + accessType + "): " + ret);
}
return ret;
}
@Override
public boolean isAccessAllowed(Map<String, RangerPolicyResource> resources, String user, Set<String> userGroups, String accessType) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowed(" + resources + ", " + user + ", " + userGroups + ", " + accessType + ")");
}
boolean ret = false;
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_REQUEST_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_REQUEST_LOG, "RangerPolicyEngine.isAccessAllowed(user=" + user + "," + userGroups + ",accessType=" + accessType + ")");
}
for (RangerPolicyEvaluator evaluator : policyRepository.getPolicyEvaluators()) {
ret = evaluator.isAccessAllowed(resources, user, userGroups, accessType);
if (ret) {
break;
}
}
RangerPerfTracer.log(perf);
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowed(" + resources + ", " + user + ", " + userGroups + ", " + accessType + "): " + ret);
}
return ret;
}
@Override
public List<RangerPolicy> getExactMatchPolicies(RangerAccessResource resource, Map<String, Object> evalContext) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.getExactMatchPolicies(" + resource + ", " + evalContext + ")");
}
List<RangerPolicy> ret = null;
for (RangerPolicyEvaluator evaluator : policyRepository.getPolicyEvaluators()) {
if (evaluator.isCompleteMatch(resource, evalContext)) {
if(ret == null) {
ret = new ArrayList<>();
}
ret.add(evaluator.getPolicy());
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.getExactMatchPolicies(" + resource + ", " + evalContext + "): " + ret);
}
return ret;
}
@Override
public List<RangerPolicy> getExactMatchPolicies(Map<String, RangerPolicyResource> resources, Map<String, Object> evalContext) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.getExactMatchPolicies(" + resources + ", " + evalContext + ")");
}
List<RangerPolicy> ret = null;
for (RangerPolicyEvaluator evaluator : policyRepository.getPolicyEvaluators()) {
if (evaluator.isCompleteMatch(resources, evalContext)) {
if(ret == null) {
ret = new ArrayList<>();
}
ret.add(evaluator.getPolicy());
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.getExactMatchPolicies(" + resources + ", " + evalContext + "): " + ret);
}
return ret;
}
@Override
public List<RangerPolicy> getAllowedPolicies(String user, Set<String> userGroups, String accessType) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.getAllowedPolicies(" + user + ", " + userGroups + ", " + accessType + ")");
}
List<RangerPolicy> ret = new ArrayList<>();
// TODO: run through evaluator in tagPolicyRepository as well
for (RangerPolicyEvaluator evaluator : policyRepository.getPolicyEvaluators()) {
RangerPolicy policy = evaluator.getPolicy();
boolean isAccessAllowed = isAccessAllowed(policy.getResources(), user, userGroups, accessType);
if (isAccessAllowed) {
ret.add(policy);
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.getAllowedPolicies(" + user + ", " + userGroups + ", " + accessType + "): policyCount=" + ret.size());
}
return ret;
}
@Override
public RangerResourceAccessInfo getResourceAccessInfo(RangerAccessRequest request) {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.getResourceAccessInfo(" + request + ")");
}
RangerResourceAccessInfo ret = new RangerResourceAccessInfo(request);
List<RangerPolicyEvaluator> tagPolicyEvaluators = tagPolicyRepository == null ? null : tagPolicyRepository.getPolicyEvaluators();
if (CollectionUtils.isNotEmpty(tagPolicyEvaluators)) {
Set<RangerTagForEval> tags = RangerAccessRequestUtil.getRequestTagsFromContext(request.getContext());
if(CollectionUtils.isNotEmpty(tags)) {
for (RangerTagForEval tag : tags) {
RangerAccessRequest tagEvalRequest = new RangerTagAccessRequest(tag, tagPolicyRepository.getServiceDef(), request);
List<RangerPolicyEvaluator> evaluators = tagPolicyRepository.getPolicyEvaluators(tagEvalRequest.getResource());
for (RangerPolicyEvaluator evaluator : evaluators) {
evaluator.getResourceAccessInfo(tagEvalRequest, ret);
}
}
}
}
List<RangerPolicyEvaluator> resPolicyEvaluators = policyRepository.getPolicyEvaluators(request.getResource());
if(CollectionUtils.isNotEmpty(resPolicyEvaluators)) {
for (RangerPolicyEvaluator evaluator : resPolicyEvaluators) {
evaluator.getResourceAccessInfo(request, ret);
}
}
ret.getAllowedUsers().removeAll(ret.getDeniedUsers());
ret.getAllowedGroups().removeAll(ret.getDeniedGroups());
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.getResourceAccessInfo(" + request + "): " + ret);
}
return ret;
}
protected RangerAccessResult isAccessAllowedNoAudit(RangerAccessRequest request) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowedNoAudit(" + request + ")");
}
RangerAccessResult ret = createAccessResult(request);
if (ret != null && request != null) {
if (hasTagPolicies()) {
isAccessAllowedForTagPolicies(request, ret);
if (LOG.isDebugEnabled()) {
if (ret.getIsAccessDetermined() && ret.getIsAuditedDetermined()) {
LOG.debug("RangerPolicyEngineImpl.isAccessAllowedNoAudit() - access and audit determined by tag policy. No resource policies will be evaluated, request=" + request + ", result=" + ret);
}
}
}
boolean isAllowedByTags = ret.getIsAccessDetermined() && ret.getIsAllowed();
boolean isDeniedByTags = ret.getIsAccessDetermined() && !ret.getIsAllowed();
boolean evaluateResourcePolicies = hasResourcePolicies() && (!isDeniedByTags || !ret.getIsAuditedDetermined());
if (evaluateResourcePolicies) {
boolean findAuditByResource = !ret.getIsAuditedDetermined();
boolean foundInCache = findAuditByResource && policyRepository.setAuditEnabledFromCache(request, ret);
if(isAllowedByTags) {
ret.setIsAccessDetermined(false); // discard allowed result by tag-policies, to evaluate resource policies for possible deny
}
List<RangerPolicyEvaluator> evaluators = policyRepository.getPolicyEvaluators(request.getResource());
for (RangerPolicyEvaluator evaluator : evaluators) {
ret.incrementEvaluatedPoliciesCount();
evaluator.evaluate(request, ret);
if(ret.getIsAllowed() && !evaluator.hasDeny()) { // all policies having deny have been evaluated
ret.setIsAccessDetermined(true);
}
if(ret.getIsAuditedDetermined() && ret.getIsAccessDetermined()) {
break; // Break out of policy-evaluation loop
}
}
if(ret.getIsAllowed()) {
ret.setIsAccessDetermined(true);
}
if (findAuditByResource && !foundInCache) {
policyRepository.storeAuditEnabledInCache(request, ret);
}
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowedNoAudit(" + request + "): " + ret);
}
return ret;
}
protected void isAccessAllowedForTagPolicies(final RangerAccessRequest request, RangerAccessResult result) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowedForTagPolicies(" + request + ", " + result + ")");
}
List<RangerPolicyEvaluator> tagEvaluators = tagPolicyRepository == null ? null : tagPolicyRepository.getPolicyEvaluators();
if (CollectionUtils.isNotEmpty(tagEvaluators)) {
Set<RangerTagForEval> tags = RangerAccessRequestUtil.getRequestTagsFromContext(request.getContext());
if (CollectionUtils.isNotEmpty(tags)) {
for (RangerTagForEval tag : tags) {
if (LOG.isDebugEnabled()) {
LOG.debug("RangerPolicyEngineImpl.isAccessAllowedForTagPolicies: Evaluating policies for tag (" + tag.getType() + ")");
}
RangerAccessRequest tagEvalRequest = new RangerTagAccessRequest(tag, tagPolicyRepository.getServiceDef(), request);
RangerAccessResult tagEvalResult = createAccessResult(tagEvalRequest);
// carry fwd results from earlier tags, to optimize the current evaluation
// - if access was already allowed by a tag, only deny needs to be looked into
// - if audit was already determined, evaluation can bail out as soon as access is determined
if (result.getIsAllowed()) {
tagEvalResult.setIsAllowed(result.getIsAllowed());
}
tagEvalResult.setAuditResultFrom(result);
List<RangerPolicyEvaluator> evaluators = tagPolicyRepository.getPolicyEvaluators(tagEvalRequest.getResource());
for (RangerPolicyEvaluator evaluator : evaluators) {
tagEvalResult.incrementEvaluatedPoliciesCount();
evaluator.evaluate(tagEvalRequest, tagEvalResult);
if (tagEvalResult.getIsAllowed() && !evaluator.hasDeny()) { // all policies having deny have been evaluated
tagEvalResult.setIsAccessDetermined(true);
}
if (tagEvalResult.getIsAuditedDetermined() && tagEvalResult.getIsAccessDetermined()) {
if (LOG.isDebugEnabled()) {
LOG.debug("RangerPolicyEngineImpl.isAccessAllowedForTagPolicies: concluding eval of tag (" + tag.getType() + ") with authorization=" + tagEvalResult.getIsAllowed());
}
break; // Break out of policy-evaluation loop for this tag
}
}
if (tagEvalResult.getIsAllowed()) {
tagEvalResult.setIsAccessDetermined(true);
}
if (tagEvalResult.getIsAudited()) {
result.setIsAudited(true);
result.setAuditPolicyId(tagEvalResult.getAuditPolicyId());
}
if (!result.getIsAccessDetermined() && tagEvalResult.getIsAccessDetermined()) {
if (!tagEvalResult.getIsAllowed()) { // access is denied for this tag
result.setAccessResultFrom(tagEvalResult);
} else { // access is allowed for this tag
// if a policy evaluated earlier allowed the access, don't update with current tag result
if (!result.getIsAllowed()) {
result.setAccessResultFrom(tagEvalResult);
result.setIsAccessDetermined(false); // so that evaluation will continue for deny
}
}
}
if (result.getIsAuditedDetermined() && result.getIsAccessDetermined()) {
break; // Break out of policy-evaluation loop
}
}
if (result.getIsAllowed()) {
result.setIsAccessDetermined(true);
}
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowedForTagPolicies(" + request + ", " + result + ")");
}
}
@Override
public void reorderPolicyEvaluators() {
if (LOG.isDebugEnabled()) {
LOG.debug("==> reorderEvaluators()");
}
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_REBALANCE_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_REBALANCE_LOG, "RangerPolicyEngine.reorderEvaluators()");
}
if (MapUtils.isNotEmpty(policyEvaluatorsMap)) {
for (Map.Entry<Long, RangerPolicyEvaluator> entry : policyEvaluatorsMap.entrySet()) {
entry.getValue().setUsageCountImmutable();
}
}
if (tagPolicyRepository != null) {
tagPolicyRepository.reorderPolicyEvaluators();
}
if (policyRepository != null) {
policyRepository.reorderPolicyEvaluators();
}
if (MapUtils.isNotEmpty(policyEvaluatorsMap)) {
for (Map.Entry<Long, RangerPolicyEvaluator> entry : policyEvaluatorsMap.entrySet()) {
entry.getValue().resetUsageCount();
}
}
RangerPerfTracer.log(perf);
if (LOG.isDebugEnabled()) {
LOG.debug("<== reorderEvaluators()");
}
}
@Override
public boolean preCleanup() {
boolean ret = true;
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.preCleanup()");
}
if (CollectionUtils.isNotEmpty(allContextEnrichers)) {
for (RangerContextEnricher contextEnricher : allContextEnrichers) {
boolean notReadyForCleanup = contextEnricher.preCleanup();
if (!notReadyForCleanup) {
if (LOG.isDebugEnabled()) {
LOG.debug("contextEnricher.preCleanup() failed for contextEnricher=" + contextEnricher.getName());
}
ret = false;
}
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.preCleanup() : result=" + ret);
}
return ret;
}
@Override
public void cleanup() {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyEngineImpl.cleanup()");
}
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_INIT_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_INIT_LOG, "RangerPolicyEngine.cleanUp(hashCode=" + Integer.toHexString(System.identityHashCode(this)) + ")");
}
preCleanup();
if (CollectionUtils.isNotEmpty(allContextEnrichers)) {
for (RangerContextEnricher contextEnricher : allContextEnrichers) {
contextEnricher.cleanup();
}
}
this.allContextEnrichers = null;
RangerPerfTracer.log(perf);
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyEngineImpl.cleanup()");
}
}
@Override
protected void finalize() throws Throwable {
try {
cleanup();
}
finally {
super.finalize();
}
}
@Override
public void setUseForwardedIPAddress(boolean useForwardedIPAddress) {
this.useForwardedIPAddress = useForwardedIPAddress;
}
@Override
public void setTrustedProxyAddresses(String[] trustedProxyAddresses) {
this.trustedProxyAddresses = trustedProxyAddresses;
}
@Override
public String toString( ) {
StringBuilder sb = new StringBuilder();
toString(sb);
return sb.toString();
}
public StringBuilder toString(StringBuilder sb) {
sb.append("RangerPolicyEngineImpl={");
sb.append("serviceName={").append(this.getServiceName()).append("} ");
sb.append(policyRepository);
sb.append("}");
return sb;
}
private void setResourceServiceDef(RangerAccessRequest request) {
RangerAccessResource resource = request.getResource();
if (resource.getServiceDef() == null) {
if (resource instanceof RangerMutableResource) {
RangerMutableResource mutable = (RangerMutableResource) resource;
mutable.setServiceDef(getServiceDef());
} else {
LOG.debug("RangerPolicyEngineImpl.setResourceServiceDef(): Cannot set ServiceDef in RangerMutableResource.");
}
}
}
private boolean hasTagPolicies() {
return tagPolicyRepository != null && CollectionUtils.isNotEmpty(tagPolicyRepository.getPolicies());
}
private boolean hasResourcePolicies() {
return policyRepository != null && CollectionUtils.isNotEmpty(policyRepository.getPolicies());
}
private Map<Long, RangerPolicyEvaluator> createPolicyEvaluatorsMap() {
Map<Long, RangerPolicyEvaluator> tmpPolicyEvaluatorMap = new HashMap<>();
if (tagPolicyRepository != null) {
for (RangerPolicyEvaluator evaluator : tagPolicyRepository.getPolicyEvaluators()) {
tmpPolicyEvaluatorMap.put(evaluator.getPolicy().getId(), evaluator);
}
for (RangerPolicyEvaluator evaluator : tagPolicyRepository.getDataMaskPolicyEvaluators()) {
tmpPolicyEvaluatorMap.put(evaluator.getPolicy().getId(), evaluator);
}
for (RangerPolicyEvaluator evaluator : tagPolicyRepository.getRowFilterPolicyEvaluators()) {
tmpPolicyEvaluatorMap.put(evaluator.getPolicy().getId(), evaluator);
}
}
for (RangerPolicyEvaluator evaluator : policyRepository.getPolicyEvaluators()) {
tmpPolicyEvaluatorMap.put(evaluator.getPolicy().getId(), evaluator);
}
for (RangerPolicyEvaluator evaluator : policyRepository.getDataMaskPolicyEvaluators()) {
tmpPolicyEvaluatorMap.put(evaluator.getPolicy().getId(), evaluator);
}
for (RangerPolicyEvaluator evaluator : policyRepository.getRowFilterPolicyEvaluators()) {
tmpPolicyEvaluatorMap.put(evaluator.getPolicy().getId(), evaluator);
}
return Collections.unmodifiableMap(tmpPolicyEvaluatorMap);
}
private void updatePolicyUsageCounts(RangerAccessRequest accessRequest, RangerAccessResult accessResult) {
boolean auditCountUpdated = false;
if (accessResult.getIsAccessDetermined()) {
RangerPolicyEvaluator accessPolicy = getPolicyEvaluator(accessResult.getPolicyId());
if (accessPolicy != null) {
if (accessPolicy.getPolicy().getIsAuditEnabled()) {
updateUsageCount(accessPolicy, 2);
accessResult.setAuditPolicyId(accessResult.getPolicyId());
auditCountUpdated = true;
} else {
updateUsageCount(accessPolicy, 1);
}
}
}
if (!auditCountUpdated && accessResult.getIsAuditedDetermined()) {
long auditPolicyId = accessResult.getAuditPolicyId();
RangerPolicyEvaluator auditPolicy = auditPolicyId == -1 ? null : getPolicyEvaluator(auditPolicyId);
updateUsageCount(auditPolicy, 1);
}
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_USAGE_LOG)) {
RangerAccessRequestImpl rangerAccessRequest = (RangerAccessRequestImpl) accessRequest;
RangerPerfTracer perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_USAGE_LOG,
"RangerPolicyEngine.usage(accessingUser=" + rangerAccessRequest.getUser()
+ ",accessedResource=" + rangerAccessRequest.getResource().getAsString()
+ ",accessType=" + rangerAccessRequest.getAccessType()
+ ",evaluatedPoliciesCount=" + accessResult.getEvaluatedPoliciesCount() + ")");
RangerPerfTracer.logAlways(perf);
}
}
private void updateUsageCount(RangerPolicyEvaluator evaluator, int number) {
if (evaluator != null) {
evaluator.incrementUsageCount(number);
}
}
}