blob: b0734e4f30a9ccd6af286506bbd9729356d8464e [file] [log] [blame]
/*
* 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.biz;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ranger.authorization.utils.JsonUtils;
import org.apache.ranger.authorization.utils.StringUtil;
import org.apache.ranger.db.RangerDaoManager;
import org.apache.ranger.entity.XXPolicy;
import org.apache.ranger.entity.XXPortalUser;
import org.apache.ranger.entity.XXService;
import org.apache.ranger.plugin.model.RangerPolicy;
import org.apache.ranger.plugin.model.RangerPolicy.RangerDataMaskPolicyItem;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemCondition;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
import org.apache.ranger.plugin.util.RangerPerfTracer;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
public class RangerPolicyRetriever {
static final Log LOG = LogFactory.getLog(RangerPolicyRetriever.class);
static final Log PERF_LOG = RangerPerfTracer.getPerfLogger("db.RangerPolicyRetriever");
private final RangerDaoManager daoMgr;
private final LookupCache lookupCache = new LookupCache();
private final PlatformTransactionManager txManager;
private final TransactionTemplate txTemplate;
public RangerPolicyRetriever(RangerDaoManager daoMgr, PlatformTransactionManager txManager) {
this.daoMgr = daoMgr;
this.txManager = txManager;
if (this.txManager != null) {
this.txTemplate = new TransactionTemplate(this.txManager);
this.txTemplate.setReadOnly(true);
} else {
this.txTemplate = null;
}
}
public RangerPolicyRetriever(RangerDaoManager daoMgr) {
this.daoMgr = daoMgr;
this.txManager = null;
this.txTemplate = null;
}
public List<RangerPolicy> getServicePolicies(Long serviceId) {
List<RangerPolicy> ret = null;
if(serviceId != null) {
XXService xService = getXXService(serviceId);
if(xService != null) {
ret = getServicePolicies(xService);
} else {
if(LOG.isDebugEnabled()) {
LOG.debug("RangerPolicyRetriever.getServicePolicies(serviceId=" + serviceId + "): service not found");
}
}
}
return ret;
}
public List<RangerPolicy> getServicePolicies(String serviceName) {
List<RangerPolicy> ret = null;
if(serviceName != null) {
XXService xService = getXXService(serviceName);
if(xService != null) {
ret = getServicePolicies(xService);
} else {
if(LOG.isDebugEnabled()) {
LOG.debug("RangerPolicyRetriever.getServicePolicies(serviceName=" + serviceName + "): service not found");
}
}
}
return ret;
}
private class PolicyLoaderThread extends Thread {
final TransactionTemplate txTemplate;
final XXService xService;
List<RangerPolicy> policies;
PolicyLoaderThread(TransactionTemplate txTemplate, final XXService xService) {
this.txTemplate = txTemplate;
this.xService = xService;
}
public List<RangerPolicy> getPolicies() { return policies; }
@Override
public void run() {
try {
txTemplate.setReadOnly(true);
policies = txTemplate.execute(new TransactionCallback<List<RangerPolicy>>() {
@Override
public List<RangerPolicy> doInTransaction(TransactionStatus status) {
try {
RetrieverContext ctx = new RetrieverContext(xService);
return ctx.getAllPolicies();
} catch (Exception ex) {
LOG.error("RangerPolicyRetriever.getServicePolicies(): Failed to get policies for service:[" + xService.getName() + "] in a new transaction", ex);
status.setRollbackOnly();
return null;
}
}
});
} catch (Throwable ex) {
LOG.error("RangerPolicyRetriever.getServicePolicies(): Failed to get policies for service:[" + xService.getName() + "] in a new transaction", ex);
}
}
}
public List<RangerPolicy> getServicePolicies(final XXService xService) {
String serviceName = xService == null ? null : xService.getName();
Long serviceId = xService == null ? null : xService.getId();
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyRetriever.getServicePolicies(serviceName=" + serviceName + ", serviceId=" + serviceId + ")");
}
List<RangerPolicy> ret = null;
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_LOG, "RangerPolicyRetriever.getServicePolicies(serviceName=" + serviceName + ",serviceId=" + serviceId + ")");
}
if(xService != null) {
if (txTemplate == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Transaction Manager is null; Retrieving policies in the existing transaction");
}
RetrieverContext ctx = new RetrieverContext(xService);
ret = ctx.getAllPolicies();
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Retrieving policies in a new, read-only transaction");
}
PolicyLoaderThread t = new PolicyLoaderThread(txTemplate, xService);
t.setDaemon(true);
t.start();
try {
t.join();
ret = t.getPolicies();
} catch (InterruptedException ie) {
LOG.error("Failed to retrieve policies in a new, read-only thread.", ie);
}
}
} else {
if(LOG.isDebugEnabled()) {
LOG.debug("RangerPolicyRetriever.getServicePolicies(xService=" + xService + "): invalid parameter");
}
}
RangerPerfTracer.log(perf);
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyRetriever.getServicePolicies(serviceName=" + serviceName + ", serviceId=" + serviceId + "): policyCount=" + (ret == null ? 0 : ret.size()));
}
return ret;
}
public RangerPolicy getPolicy(Long policyId) {
RangerPolicy ret = null;
if(policyId != null) {
XXPolicy xPolicy = getXXPolicy(policyId);
if(xPolicy != null) {
ret = getPolicy(xPolicy);
} else {
if(LOG.isDebugEnabled()) {
LOG.debug("RangerPolicyRetriever.getPolicy(policyId=" + policyId + "): policy not found");
}
}
}
return ret;
}
public RangerPolicy getPolicy(XXPolicy xPolicy) {
RangerPolicy ret = null;
if(xPolicy != null) {
XXService xService = getXXService(xPolicy.getService());
if(xService != null) {
ret = getPolicy(xPolicy, xService);
} else {
if(LOG.isDebugEnabled()) {
LOG.debug("RangerPolicyRetriever.getPolicy(policyId=" + xPolicy.getId() + "): service not found (serviceId=" + xPolicy.getService() + ")");
}
}
}
return ret;
}
public RangerPolicy getPolicy(XXPolicy xPolicy, XXService xService) {
Long policyId = xPolicy == null ? null : xPolicy.getId();
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerPolicyRetriever.getPolicy(" + policyId + ")");
}
RangerPolicy ret = null;
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_LOG, "RangerPolicyRetriever.getPolicy(policyId=" + policyId + ")");
}
if(xPolicy != null && xService != null) {
RetrieverContext ctx = new RetrieverContext(xPolicy, xService);
ret = ctx.getNextPolicy();
} else {
if(LOG.isDebugEnabled()) {
LOG.debug("RangerPolicyRetriever.getPolicy(xPolicy=" + xPolicy + ", xService=" + xService + "): invalid parameter(s)");
}
}
RangerPerfTracer.log(perf);
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerPolicyRetriever.getPolicy(" + policyId + "): " + ret);
}
return ret;
}
private XXService getXXService(Long serviceId) {
XXService ret = null;
if(serviceId != null) {
ret = daoMgr.getXXService().getById(serviceId);
}
return ret;
}
private XXService getXXService(String serviceName) {
XXService ret = null;
if(serviceName != null) {
ret = daoMgr.getXXService().findByName(serviceName);
}
return ret;
}
private XXPolicy getXXPolicy(Long policyId) {
XXPolicy ret = null;
if(policyId != null) {
ret = daoMgr.getXXPolicy().getById(policyId);
}
return ret;
}
class LookupCache {
final Map<Long, String> userScreenNames = new HashMap<Long, String>();
final Map<Long, Map<String, String>> groupMappingsPerPolicy = new HashMap<>();
final Map<Long, Map<String, String>> userMappingsPerPolicy = new HashMap<>();
final Map<Long, Map<String, String>> accessMappingsPerPolicy = new HashMap<>();
final Map<Long, Map<String, String>> resourceMappingsPerPolicy = new HashMap<>();
final Map<Long, Map<String, String>> dataMaskMappingsPerPolicy = new HashMap<>();
final Map<Long, Map<String, String>> conditionMappingsPerPolicy = new HashMap<>();
String getUserScreenName(Long userId) {
String ret = null;
if(userId != null) {
ret = userScreenNames.get(userId);
if(ret == null) {
XXPortalUser user = daoMgr.getXXPortalUser().getById(userId);
if(user != null) {
ret = user.getPublicScreenName();
if (StringUtil.isEmpty(ret)) {
ret = user.getFirstName();
if(StringUtil.isEmpty(ret)) {
ret = user.getLoginId();
} else {
if(!StringUtil.isEmpty(user.getLastName())) {
ret += (" " + user.getLastName());
}
}
}
if(ret != null) {
userScreenNames.put(userId, ret);
}
}
}
}
return ret;
}
void setNameMapping(Map<Long, Map<String, String>> nameMappingContainer, List<PolicyTextNameMap> nameMappings) {
nameMappingContainer.clear();
for (PolicyTextNameMap nameMapping : nameMappings) {
Map<String, String> policyNameMap = nameMappingContainer.get(nameMapping.policyId);
if (policyNameMap == null) {
policyNameMap = new HashMap<>();
nameMappingContainer.put(nameMapping.policyId, policyNameMap);
}
policyNameMap.put(nameMapping.oldName, nameMapping.currentName);
}
}
String getMappedName(Map<Long, Map<String, String>> nameMappingContainer, Long policyId, String nameToMap) {
Map<String, String> policyNameMap = nameMappingContainer.get(policyId);
return policyNameMap != null ? policyNameMap.get(nameToMap) : null;
}
void setGroupNameMapping(List<PolicyTextNameMap> groupNameMapping) {
setNameMapping(groupMappingsPerPolicy, groupNameMapping);
}
void setUserNameMapping(List<PolicyTextNameMap> userNameMapping) {
setNameMapping(userMappingsPerPolicy, userNameMapping);
}
void setAccessNameMapping(List<PolicyTextNameMap> accessNameMapping) {
setNameMapping(accessMappingsPerPolicy, accessNameMapping);
}
public void setResourceNameMapping(List<PolicyTextNameMap> resourceNameMapping) {
setNameMapping(resourceMappingsPerPolicy, resourceNameMapping);
}
public void setDataMaskNameMapping(List<PolicyTextNameMap> dataMaskMapping) {
setNameMapping(dataMaskMappingsPerPolicy, dataMaskMapping);
}
public void setConditionNameMapping(List<PolicyTextNameMap> conditionNameMapping) {
setNameMapping(conditionMappingsPerPolicy, conditionNameMapping);
}
}
public static class PolicyTextNameMap {
final Long policyId;
final String oldName;
final String currentName;
public PolicyTextNameMap(Long policyId, String oldName, String currentName) {
this.policyId = policyId;
this.oldName = oldName;
this.currentName = currentName;
}
}
static List<XXPolicy> asList(XXPolicy policy) {
List<XXPolicy> ret = new ArrayList<>();
if (policy != null) {
ret.add(policy);
}
return ret;
}
class RetrieverContext {
final XXService service;
final ListIterator<XXPolicy> iterPolicy;
RetrieverContext(XXService xService) {
if (xService != null) {
Long serviceId = xService.getId();
lookupCache.setGroupNameMapping(daoMgr.getXXPolicyRefGroup().findUpdatedGroupNamesByService(serviceId));
lookupCache.setUserNameMapping(daoMgr.getXXPolicyRefUser().findUpdatedUserNamesByService(serviceId));
lookupCache.setAccessNameMapping(daoMgr.getXXPolicyRefAccessType().findUpdatedAccessNamesByService(serviceId));
lookupCache.setResourceNameMapping(daoMgr.getXXPolicyRefResource().findUpdatedResourceNamesByService(serviceId));
lookupCache.setDataMaskNameMapping(daoMgr.getXXPolicyRefDataMaskType().findUpdatedDataMaskNamesByService(serviceId));
lookupCache.setConditionNameMapping(daoMgr.getXXPolicyRefCondition().findUpdatedConditionNamesByService(serviceId));
this.service = xService;
this.iterPolicy = daoMgr.getXXPolicy().findByServiceId(serviceId).listIterator();
} else {
this.service = null;
this.iterPolicy = null;
}
}
RetrieverContext(XXPolicy xPolicy, XXService xService) {
Long policyId = xPolicy.getId();
lookupCache.setGroupNameMapping(daoMgr.getXXPolicyRefGroup().findUpdatedGroupNamesByPolicy(policyId));
lookupCache.setUserNameMapping(daoMgr.getXXPolicyRefUser().findUpdatedUserNamesByPolicy(policyId));
lookupCache.setAccessNameMapping(daoMgr.getXXPolicyRefAccessType().findUpdatedAccessNamesByPolicy(policyId));
lookupCache.setResourceNameMapping(daoMgr.getXXPolicyRefResource().findUpdatedResourceNamesByPolicy(policyId));
lookupCache.setDataMaskNameMapping(daoMgr.getXXPolicyRefDataMaskType().findUpdatedDataMaskNamesByPolicy(policyId));
lookupCache.setConditionNameMapping(daoMgr.getXXPolicyRefCondition().findUpdatedConditionNamesByPolicy(policyId));
this.service = xService;
this.iterPolicy = asList(xPolicy).listIterator();
}
RangerPolicy getNextPolicy() {
RangerPolicy ret = null;
if (service != null && iterPolicy != null && iterPolicy.hasNext()) {
XXPolicy xPolicy = iterPolicy.next();
if (xPolicy != null) {
String policyText = xPolicy.getPolicyText();
ret = JsonUtils.jsonToObject(policyText, RangerPolicy.class);
if (ret != null) {
ret.setId(xPolicy.getId());
ret.setGuid(xPolicy.getGuid());
ret.setCreatedBy(lookupCache.getUserScreenName(xPolicy.getAddedByUserId()));
ret.setUpdatedBy(lookupCache.getUserScreenName(xPolicy.getUpdatedByUserId()));
ret.setCreateTime(xPolicy.getCreateTime());
ret.setUpdateTime(xPolicy.getUpdateTime());
ret.setVersion(xPolicy.getVersion());
ret.setPolicyType(xPolicy.getPolicyType() == null ? RangerPolicy.POLICY_TYPE_ACCESS : xPolicy.getPolicyType());
ret.setService(service.getName());
updatePolicyReferenceFields(ret);
}
}
}
return ret;
}
void updatePolicyReferenceFields(final RangerPolicy policy) {
final Long policyId = policy.getId();
Map<String, String> policyResourceNameMap = lookupCache.resourceMappingsPerPolicy.get(policyId);
if (MapUtils.isNotEmpty(policyResourceNameMap) && CollectionUtils.containsAny(policyResourceNameMap.keySet(), policy.getResources().keySet())) {
Map<String, RangerPolicyResource> updatedResources = new HashMap<>();
for (Map.Entry<String, RangerPolicyResource> entry : policy.getResources().entrySet()) {
String resourceName = entry.getKey();
RangerPolicyResource policyResource = entry.getValue();
String updatedName = policyResourceNameMap.get(resourceName);
if (updatedName == null) {
updatedName = resourceName;
}
updatedResources.put(updatedName, policyResource);
}
policy.setResources(updatedResources);
}
for (List<? extends RangerPolicyItem> policyItems : PolicyRefUpdater.getAllPolicyItems(policy)) {
if (CollectionUtils.isEmpty(policyItems)) {
continue;
}
for (RangerPolicyItem policyItem : policyItems) {
if (lookupCache.groupMappingsPerPolicy.containsKey(policyId)) {
List<String> updatedGroups = getUpdatedNames(lookupCache.groupMappingsPerPolicy, policyId, policyItem.getGroups());
if (updatedGroups != null) {
policyItem.setGroups(updatedGroups);
}
}
if (lookupCache.userMappingsPerPolicy.containsKey(policyId)) {
List<String> updatedUsers = getUpdatedNames(lookupCache.userMappingsPerPolicy, policyId, policyItem.getUsers());
if (updatedUsers != null) {
policyItem.setUsers(updatedUsers);
}
}
if (lookupCache.accessMappingsPerPolicy.containsKey(policyId)) {
for (RangerPolicyItemAccess itemAccess : policyItem.getAccesses()) {
String updatedName = lookupCache.getMappedName(lookupCache.accessMappingsPerPolicy, policyId, itemAccess.getType());
if (updatedName != null) {
itemAccess.setType(updatedName);
}
}
}
if (lookupCache.conditionMappingsPerPolicy.containsKey(policyId)) {
for (RangerPolicyItemCondition condition : policyItem.getConditions()) {
String updatedName = lookupCache.getMappedName(lookupCache.conditionMappingsPerPolicy, policyId, condition.getType());
if (updatedName != null) {
condition.setType(updatedName);
}
}
}
if (policyItem instanceof RangerDataMaskPolicyItem && lookupCache.dataMaskMappingsPerPolicy.containsKey(policyId)) {
RangerDataMaskPolicyItem dataMaskItem = (RangerDataMaskPolicyItem) policyItem;
String updatedName = lookupCache.getMappedName(lookupCache.dataMaskMappingsPerPolicy, policyId, dataMaskItem.getDataMaskInfo().getDataMaskType());
if (updatedName != null) {
dataMaskItem.getDataMaskInfo().setDataMaskType(updatedName);
}
}
}
}
}
List<String> getUpdatedNames(final Map<Long, Map<String, String>> nameMappingContainer, final Long policyId, final List<String> namesToMap) {
List<String> ret = null;
Map<String, String> policyNameMap = nameMappingContainer.get(policyId);
if (MapUtils.isNotEmpty(policyNameMap) && CollectionUtils.containsAny(policyNameMap.keySet(), namesToMap)) {
ret = new ArrayList<>();
for (String nameToMap : namesToMap) {
String mappedName = policyNameMap.get(nameToMap);
if (mappedName != null) {
ret.add(mappedName);
} else {
ret.add(nameToMap);
}
}
}
return ret;
}
List<RangerPolicy> getAllPolicies() {
List<RangerPolicy> ret = new ArrayList<>();
if (iterPolicy != null) {
while (iterPolicy.hasNext()) {
RangerPolicy policy = getNextPolicy();
if (policy != null) {
ret.add(policy);
}
}
}
return ret;
}
}
}