blob: 5bd3a0934a4c3be3a0d0627197ea02fa00f8bc8b [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.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.store.RoleStore;
import org.apache.ranger.plugin.policyengine.RangerPluginContext;
import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions;
import org.apache.ranger.plugin.store.SecurityZoneStore;
import org.apache.ranger.plugin.store.ServiceStore;
import org.apache.ranger.plugin.util.RangerPolicyDeltaUtil;
import org.apache.ranger.plugin.util.RangerRoles;
import org.apache.ranger.plugin.util.ServicePolicies;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RangerPolicyAdminCache {
static class RangerPolicyAdminWrapper {
final RangerPolicyAdmin policyAdmin;
final Lock lock = new ReentrantLock();
RangerPolicyAdminWrapper(RangerPolicyAdmin policyAdmin) {
this.policyAdmin = policyAdmin;
}
RangerPolicyAdmin getPolicyAdmin() {
return policyAdmin;
}
Lock getLock() {
return lock;
}
}
private static final Logger LOG = LoggerFactory.getLogger(RangerPolicyAdminCache.class);
private final Map<String, RangerPolicyAdminWrapper> policyAdminCache = Collections.synchronizedMap(new HashMap<>());
final RangerPolicyAdmin getServicePoliciesAdmin(String serviceName, ServiceStore svcStore, RoleStore roleStore, SecurityZoneStore zoneStore, RangerPolicyEngineOptions options) {
if (serviceName == null || svcStore == null || roleStore == null || zoneStore == null) {
LOG.warn("Cannot get policy-admin for null serviceName or serviceStore or roleStore or zoneStore");
return null;
}
try {
if (!svcStore.serviceExists(serviceName)) {
LOG.warn("Service:[" + serviceName + "] does not exist in service-store. Returning null policy-engine!");
policyAdminCache.remove(serviceName);
return null;
}
} catch (Exception exception) {
LOG.error("Failed to check if service:[" + serviceName + "] exists in service-store", exception);
return null;
}
long policyVersion;
long roleVersion;
RangerRoles roles;
boolean isRolesUpdated = true;
RangerPolicyAdminWrapper ret = policyAdminCache.get(serviceName);
try {
if (ret == null) {
policyVersion = -1L;
roleVersion = -1L;
roles = roleStore.getRoles(serviceName, roleVersion);
if (roles == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("There are no roles in ranger-admin for service:" + serviceName + "]");
}
}
} else {
policyVersion = ret.getPolicyAdmin().getPolicyVersion();
roleVersion = ret.getPolicyAdmin().getRoleVersion();
roles = roleStore.getRoles(serviceName, roleVersion);
if (roles == null) { // No changes to roles
roles = roleStore.getRoles(serviceName, -1L);
isRolesUpdated = false;
}
}
ServicePolicies policies = svcStore.getServicePoliciesIfUpdated(serviceName, policyVersion, ServiceDBStore.isSupportsPolicyDeltas());
if (policies != null) {
ret = addOrUpdatePolicyAdmin(ret, policies, roles, options);
if (ret == null) {
LOG.error("getPolicyAdmin(" + serviceName + "): failed to build engine from policies from service-store");
} else {
if (isRolesUpdated) {
ret.getPolicyAdmin().setRoles(roles);
}
}
}
} catch (Exception exception) {
LOG.error("getPolicyAdmin(" + serviceName + "): failed to get latest policies from service-store", exception);
}
if (ret == null) {
LOG.error("Policy-engine is not built! Returning null policy-engine!");
} else {
ret.getPolicyAdmin().setServiceStore(svcStore);
}
return ret == null ? null : ret.getPolicyAdmin();
}
private RangerPolicyAdminWrapper addOrUpdatePolicyAdmin(RangerPolicyAdminWrapper policyAdminWrapper, ServicePolicies policies, RangerRoles roles, RangerPolicyEngineOptions options) {
final RangerPolicyAdminWrapper ret;
RangerPolicyAdmin policyAdmin = null;
boolean isPolicyEngineShared = false;
RangerPolicyAdminImpl oldPolicyAdmin = policyAdminWrapper == null ? null : (RangerPolicyAdminImpl) policyAdminWrapper.getPolicyAdmin();
Boolean hasPolicyDeltas = RangerPolicyDeltaUtil.hasPolicyDeltas(policies);
if (hasPolicyDeltas != null) {
if (hasPolicyDeltas.equals(Boolean.TRUE)) {
if (oldPolicyAdmin != null) {
boolean isLocked = false;
try {
policyAdminWrapper.getLock().lockInterruptibly();
isLocked = true;
} catch (Exception e) {
// Ignore
}
if (isLocked) {
try {
policyAdmin = RangerPolicyAdminImpl.getPolicyAdmin(oldPolicyAdmin, policies);
if (policyAdmin != null) {
policyAdmin.setRoles(roles);
isPolicyEngineShared = true;
}
} finally {
policyAdminWrapper.getLock().unlock();
}
}
} else {
LOG.error("Old policy engine is null! Cannot apply deltas without old policy engine!");
}
} else {
if (policies.getPolicies() == null) {
policies.setPolicies(new ArrayList<>());
}
policyAdmin = addPolicyAdmin(policies, roles, options);
}
} else {
LOG.warn("Provided policies do not require policy change !! [" + policies + "]. Keeping old policy-engine!");
policyAdmin = oldPolicyAdmin;
}
if (policyAdmin != null) {
if (LOG.isDebugEnabled()) {
if (oldPolicyAdmin == null) {
LOG.debug("Adding policy-engine to cache with serviceName:[" + policies.getServiceName() + "] as key");
} else {
LOG.debug("Replacing policy-engine in cache with serviceName:[" + policies.getServiceName() + "] as key");
}
}
ret = new RangerPolicyAdminWrapper(policyAdmin);
policyAdminCache.put(policies.getServiceName(), ret);
if (oldPolicyAdmin != null && oldPolicyAdmin != policyAdmin) {
oldPolicyAdmin.releaseResources(!isPolicyEngineShared);
}
} else {
LOG.warn("Could not build new policy-engine.");
ret = null;
}
return ret;
}
private RangerPolicyAdmin addPolicyAdmin(ServicePolicies policies, RangerRoles roles, RangerPolicyEngineOptions options) {
RangerServiceDef serviceDef = policies.getServiceDef();
String serviceType = (serviceDef != null) ? serviceDef.getName() : "";
RangerPluginContext rangerPluginContext = new RangerPluginContext(new RangerPluginConfig(serviceType, null, "ranger-admin", null, null, options));
return new RangerPolicyAdminImpl(policies, rangerPluginContext, roles);
}
}