blob: 1e2d74d54c6f1acda5fbae69f09f8c3eacd22444 [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.plugin.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.ranger.admin.client.RangerAdminClient;
import org.apache.ranger.plugin.service.RangerBasePlugin;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Date;
import java.util.HashSet;
public class RangerRolesProvider {
private static final Log LOG = LogFactory.getLog(RangerRolesProvider.class);
private static final Log PERF_POLICYENGINE_INIT_LOG = RangerPerfTracer.getPerfLogger("policyengine.init");
private final String serviceType;
private final String serviceName;
private final RangerAdminClient rangerAdmin;
private final String cacheFileName;
private final String cacheFileNamePrefix;
private final String cacheDir;
private final Gson gson;
private final boolean disableCacheIfServiceNotFound;
private long lastActivationTimeInMillis;
private long lastKnownRoleVersion = -1L;
private boolean rangerUserGroupRolesSetInPlugin;
private boolean serviceDefSetInPlugin;
public RangerRolesProvider(String serviceType, String appId, String serviceName, RangerAdminClient rangerAdmin, String cacheDir, Configuration config) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerRolesProvider(serviceName=" + serviceName + ").RangerRolesProvider()");
}
this.serviceType = serviceType;
this.serviceName = serviceName;
this.rangerAdmin = rangerAdmin;
if (StringUtils.isEmpty(appId)) {
appId = serviceType;
}
cacheFileNamePrefix = "roles";
String cacheFilename = String.format("%s_%s_%s.json", appId, serviceName, cacheFileNamePrefix);
cacheFilename = cacheFilename.replace(File.separatorChar, '_');
cacheFilename = cacheFilename.replace(File.pathSeparatorChar, '_');
this.cacheFileName = cacheFilename;
this.cacheDir = cacheDir;
Gson gson = null;
try {
gson = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").create();
} catch (Throwable excp) {
LOG.fatal("RangerRolesProvider(): failed to create GsonBuilder object", excp);
}
this.gson = gson;
String propertyPrefix = "ranger.plugin." + serviceType;
disableCacheIfServiceNotFound = config.getBoolean(propertyPrefix + ".disable.cache.if.servicenotfound", true);
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerRolesProvider(serviceName=" + serviceName + ").RangerRolesProvider()");
}
}
public long getLastActivationTimeInMillis() {
return lastActivationTimeInMillis;
}
public void setLastActivationTimeInMillis(long lastActivationTimeInMillis) {
this.lastActivationTimeInMillis = lastActivationTimeInMillis;
}
public void loadUserGroupRoles(RangerBasePlugin plugIn) {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerRolesProvider(serviceName= " + serviceName + " serviceType= " + serviceType +").loadUserGroupRoles()");
}
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_INIT_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_INIT_LOG, "RangerRolesProvider.loadUserGroupRoles(serviceName=" + serviceName + ")");
long freeMemory = Runtime.getRuntime().freeMemory();
long totalMemory = Runtime.getRuntime().totalMemory();
PERF_POLICYENGINE_INIT_LOG.debug("In-Use memory: " + (totalMemory-freeMemory) + ", Free memory:" + freeMemory);
}
try {
//load userGroupRoles from ranger admin
RangerRoles rangerRoles = loadUserGroupRolesFromAdmin();
if (rangerRoles == null) {
//if userGroupRoles fetch from ranger Admin Fails, load from cache
if (!rangerUserGroupRolesSetInPlugin) {
rangerRoles = loadUserGroupRolesFromCache();
}
}
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 (rangerRoles != null) {
plugIn.setRangerRoles(rangerRoles);
rangerUserGroupRolesSetInPlugin = true;
setLastActivationTimeInMillis(System.currentTimeMillis());
lastKnownRoleVersion = rangerRoles.getRoleVersion();
} else {
if (!rangerUserGroupRolesSetInPlugin && !serviceDefSetInPlugin) {
plugIn.setRangerRoles(null);
serviceDefSetInPlugin = true;
}
}
} catch (RangerServiceNotFoundException snfe) {
if (disableCacheIfServiceNotFound) {
disableCache();
plugIn.setRangerRoles(null);
setLastActivationTimeInMillis(System.currentTimeMillis());
lastKnownRoleVersion = -1L;
serviceDefSetInPlugin = true;
}
} catch (Exception excp) {
LOG.error("Encountered unexpected exception, ignoring..", excp);
}
RangerPerfTracer.log(perf);
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerRolesProvider(serviceName=" + serviceName + ").loadUserGroupRoles()");
}
}
private RangerRoles loadUserGroupRolesFromAdmin() throws RangerServiceNotFoundException {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerRolesProvider(serviceName=" + serviceName + ").loadUserGroupRolesFromAdmin()");
}
RangerRoles rangerRoles = null;
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_INIT_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_INIT_LOG, "RangerRolesProvider.loadUserGroupRolesFromAdmin(serviceName=" + serviceName + ")");
}
try {
rangerRoles = rangerAdmin.getRolesIfUpdated(lastKnownRoleVersion, lastActivationTimeInMillis);
boolean isUpdated = rangerRoles != null;
if(isUpdated) {
long newVersion = rangerRoles.getRoleVersion() == null ? -1 : rangerRoles.getRoleVersion().longValue();
saveToCache(rangerRoles);
LOG.info("RangerRolesProvider(serviceName=" + serviceName + "): found updated version. lastKnownRoleVersion=" + lastKnownRoleVersion + "; newVersion=" + newVersion );
} else {
if(LOG.isDebugEnabled()) {
LOG.debug("RangerRolesProvider(serviceName=" + serviceName + ").run(): no update found. lastKnownRoleVersion=" + lastKnownRoleVersion );
}
}
} catch (RangerServiceNotFoundException snfe) {
LOG.error("RangerRolesProvider(serviceName=" + serviceName + "): failed to find service. Will clean up local cache of rangerRoles (" + lastKnownRoleVersion + ")", snfe);
throw snfe;
} catch (Exception excp) {
LOG.error("RangerRolesProvider(serviceName=" + serviceName + "): failed to refresh rangerRoles. Will continue to use last known version of rangerRoles (" + "lastKnowRoleVersion= " + lastKnownRoleVersion, excp);
rangerRoles = null;
}
RangerPerfTracer.log(perf);
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerRolesProvider(serviceName=" + serviceName + " serviceType= " + serviceType + " ).loadUserGroupRolesFromAdmin()");
}
return rangerRoles;
}
private RangerRoles loadUserGroupRolesFromCache() {
RangerRoles rangerRoles = null;
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerRolesProvider(serviceName=" + serviceName + ").loadUserGroupRolesFromCache()");
}
File cacheFile = cacheDir == null ? null : new File(cacheDir + File.separator + cacheFileName);
if (cacheFile != null && cacheFile.isFile() && cacheFile.canRead()) {
Reader reader = null;
RangerPerfTracer perf = null;
if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_INIT_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_INIT_LOG, "RangerRolesProvider.loadUserGroupRolesFromCache(serviceName=" + serviceName + ")");
}
try {
reader = new FileReader(cacheFile);
rangerRoles = gson.fromJson(reader, RangerRoles.class);
if (rangerRoles != null) {
if (!StringUtils.equals(serviceName, rangerRoles.getServiceName())) {
LOG.warn("ignoring unexpected serviceName '" + rangerRoles.getServiceName() + "' in cache file '" + cacheFile.getAbsolutePath() + "'");
rangerRoles.setServiceName(serviceName);
}
lastKnownRoleVersion = rangerRoles.getRoleVersion() == null ? -1 : rangerRoles.getRoleVersion().longValue();
}
} catch (Exception excp) {
LOG.error("failed to load userGroupRoles from cache file " + cacheFile.getAbsolutePath(), excp);
} finally {
RangerPerfTracer.log(perf);
if (reader != null) {
try {
reader.close();
} catch (Exception excp) {
LOG.error("error while closing opened cache file " + cacheFile.getAbsolutePath(), excp);
}
}
}
} else {
rangerRoles = new RangerRoles();
rangerRoles.setServiceName(serviceName);
rangerRoles.setRoleVersion(-1L);
rangerRoles.setRoleUpdateTime(new Date());
rangerRoles.setRangerRoles(new HashSet<>());
saveToCache(rangerRoles);
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerRolesProvider(serviceName=" + serviceName + ").RangerRolesProvider()");
}
return rangerRoles;
}
public void saveToCache(RangerRoles rangerRoles) {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerRolesProvider(serviceName=" + serviceName + ").saveToCache()");
}
if(rangerRoles != null) {
File cacheFile = null;
if (cacheDir != null) {
// Create the cacheDir if it doesn't already exist
File cacheDirTmp = new File(cacheDir);
if (cacheDirTmp.exists()) {
cacheFile = new File(cacheDir + File.separator + cacheFileName);
} else {
try {
cacheDirTmp.mkdirs();
cacheFile = new File(cacheDir + File.separator + cacheFileName);
} catch (SecurityException ex) {
LOG.error("Cannot create cache directory", ex);
}
}
}
if(cacheFile != null) {
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_INIT_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_INIT_LOG, "RangerRolesProvider.saveToCache(serviceName=" + serviceName + ")");
}
Writer writer = null;
try {
writer = new FileWriter(cacheFile);
gson.toJson(rangerRoles, writer);
} catch (Exception excp) {
LOG.error("failed to save rangerRoles to cache file '" + cacheFile.getAbsolutePath() + "'", excp);
} finally {
if(writer != null) {
try {
writer.close();
} catch(Exception excp) {
LOG.error("error while closing opened cache file '" + cacheFile.getAbsolutePath() + "'", excp);
}
}
}
RangerPerfTracer.log(perf);
}
} else {
LOG.info("rangerRoles is null. Nothing to save in cache");
}
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerRolesProvider.saveToCache(serviceName=" + serviceName + ")");
}
}
private void disableCache() {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerRolesProvider.disableCache(serviceName=" + serviceName + ")");
}
File cacheFile = cacheDir == null ? null : new File(cacheDir + File.separator + cacheFileName);
if(cacheFile != null && cacheFile.isFile() && cacheFile.canRead()) {
LOG.warn("Cleaning up local RangerRoles cache");
String renamedCacheFile = cacheFile.getAbsolutePath() + "_" + System.currentTimeMillis();
if (!cacheFile.renameTo(new File(renamedCacheFile))) {
LOG.error("Failed to move " + cacheFile.getAbsolutePath() + " to " + renamedCacheFile);
} else {
LOG.warn("Moved " + cacheFile.getAbsolutePath() + " to " + renamedCacheFile);
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("No local RangerRoles cache found. No need to disable it!");
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerRolesProvider.disableCache(serviceName=" + serviceName + ")");
}
}
}