You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2020/08/13 17:08:07 UTC
[ranger] branch master updated: RANGER-2948: Ranger plugin
enhancement to support a hook to register plugin chains
This is an automated email from the ASF dual-hosted git repository.
madhan 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 74d1638 RANGER-2948: Ranger plugin enhancement to support a hook to register plugin chains
74d1638 is described below
commit 74d163806fc1e26f955cc38854a77c94e9959102
Author: Abhay Kulkarni <ab...@apache.org>
AuthorDate: Sun Aug 9 15:16:11 2020 -0700
RANGER-2948: Ranger plugin enhancement to support a hook to register plugin chains
Signed-off-by: Madhan Neethiraj <ma...@apache.org>
---
.../ranger/admin/client/RangerAdminRESTClient.java | 6 +
.../hadoop/config/RangerChainedPluginConfig.java | 51 +++++++++
.../hadoop/config/RangerConfiguration.java | 30 ++++-
.../ranger/authorization/utils/JsonUtils.java | 12 +-
.../ranger/authorization/utils/StringUtil.java | 16 +++
.../plugin/contextenricher/RangerTagEnricher.java | 2 +-
.../contextenricher/RangerUserStoreEnricher.java | 1 +
.../ranger/plugin/model/RangerServiceResource.java | 25 ++++-
.../ranger/plugin/service/RangerBasePlugin.java | 125 +++++++++++++++++++--
.../ranger/plugin/service/RangerChainedPlugin.java | 62 ++++++++++
.../RangerCustomConditionMatcherTest.java | 2 +
.../test_policyengine_tag_hive_filebased.json | 8 ++
12 files changed, 315 insertions(+), 25 deletions(-)
diff --git a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
index 479a50c..9d527bf 100644
--- a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
+++ b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
@@ -30,6 +30,7 @@ import org.apache.hadoop.security.AccessControlException;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.ranger.admin.client.datatype.RESTResponse;
import org.apache.ranger.audit.provider.MiscUtil;
+import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig;
import org.apache.ranger.authorization.utils.StringUtil;
import org.apache.ranger.plugin.model.RangerRole;
import org.apache.ranger.plugin.util.*;
@@ -88,6 +89,11 @@ public class RangerAdminRESTClient extends AbstractRangerAdminClient {
clusterName = config.get(propertyPrefix + ".access.cluster.name", "");
if(StringUtil.isEmpty(clusterName)){
clusterName =config.get(propertyPrefix + ".ambari.cluster.name", "");
+ if (StringUtil.isEmpty(clusterName)) {
+ if (config instanceof RangerPluginConfig) {
+ clusterName = ((RangerPluginConfig)config).getClusterName();
+ }
+ }
}
int restClientConnTimeOutMs = config.getInt(propertyPrefix + ".policy.rest.client.connection.timeoutMs", 120 * 1000);
int restClientReadTimeOutMs = config.getInt(propertyPrefix + ".policy.rest.client.read.timeoutMs", 30 * 1000);
diff --git a/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerChainedPluginConfig.java b/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerChainedPluginConfig.java
new file mode 100644
index 0000000..9e25ae1
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerChainedPluginConfig.java
@@ -0,0 +1,51 @@
+/*
+ * 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.authorization.hadoop.config;
+
+public class RangerChainedPluginConfig extends RangerPluginConfig {
+ public RangerChainedPluginConfig(String serviceType, String serviceName, String appId, RangerPluginConfig sourcePluginConfig) {
+ super(serviceType, serviceName, appId, sourcePluginConfig.getClusterName(), sourcePluginConfig.getClusterType(), null);
+
+ // add necessary config "overrides", so that RangerAdminClient implementations (like RangerAdminRESTClient)
+ // will use configurations from ranger-<source-service-type>-security.xml (sourcePluginConfig) to connect to Ranger Admin
+
+ set(getPropertyPrefix() + ".service.name", serviceName);
+ copyProperty(sourcePluginConfig, ".policy.source.impl");
+ copyProperty(sourcePluginConfig, ".policy.cache.dir");
+ copyProperty(sourcePluginConfig, ".policy.rest.url");
+ copyProperty(sourcePluginConfig, ".policy.rest.ssl.config.file");
+ copyProperty(sourcePluginConfig, ".policy.pollIntervalMs", 30 * 1000);
+ copyProperty(sourcePluginConfig, ".policy.rest.client.connection.timeoutMs", 120 * 1000);
+ copyProperty(sourcePluginConfig, ".policy.rest.read.timeoutMs", 30 * 1000);
+ copyProperty(sourcePluginConfig, ".policy.rest.supports.policy.deltas");
+ copyProperty(sourcePluginConfig, ".tag.rest.supports.tag.deltas");
+ }
+
+ protected void copyProperty(RangerPluginConfig sourcePluginConfig, String propertySuffix) {
+ String value = sourcePluginConfig.get("ranger.plugin." + sourcePluginConfig.getServiceType() + propertySuffix);
+ if (value != null) {
+ set(getPropertyPrefix() + propertySuffix, sourcePluginConfig.get("ranger.plugin." + sourcePluginConfig.getServiceType() + propertySuffix));
+ }
+ }
+
+ protected void copyProperty(RangerPluginConfig sourcePluginConfig, String propertySuffix, int defaultValue) {
+ setInt(getPropertyPrefix() + propertySuffix, sourcePluginConfig.getInt("ranger.plugin" + sourcePluginConfig.getServiceType() + propertySuffix, defaultValue));
+ }
+}
diff --git a/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerConfiguration.java b/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerConfiguration.java
index 43ddf0b..d837a69 100644
--- a/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerConfiguration.java
+++ b/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerConfiguration.java
@@ -20,9 +20,12 @@
package org.apache.ranger.authorization.hadoop.config;
+import java.io.File;
+import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
+import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.log4j.Logger;
@@ -70,12 +73,29 @@ public class RangerConfiguration extends Configuration {
return getProps();
}
-
private URL getFileLocation(String fileName) {
- URL lurl = RangerConfiguration.class.getClassLoader().getResource(fileName);
-
- if (lurl == null ) {
- lurl = RangerConfiguration.class.getClassLoader().getResource("/" + fileName);
+ URL lurl = null;
+ if (!StringUtils.isEmpty(fileName)) {
+ lurl = RangerConfiguration.class.getClassLoader().getResource(fileName);
+
+ if (lurl == null ) {
+ lurl = RangerConfiguration.class.getClassLoader().getResource("/" + fileName);
+ }
+
+ if (lurl == null ) {
+ File f = new File(fileName);
+ if (f.exists()) {
+ try {
+ lurl=f.toURI().toURL();
+ } catch (MalformedURLException e) {
+ LOG.error("Unable to load the resource name [" + fileName + "]. Ignoring the resource:" + f.getPath());
+ }
+ } else {
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("Conf file path " + fileName + " does not exists");
+ }
+ }
+ }
}
return lurl;
}
diff --git a/agents-common/src/main/java/org/apache/ranger/authorization/utils/JsonUtils.java b/agents-common/src/main/java/org/apache/ranger/authorization/utils/JsonUtils.java
index 74555ee..994d394 100644
--- a/agents-common/src/main/java/org/apache/ranger/authorization/utils/JsonUtils.java
+++ b/agents-common/src/main/java/org/apache/ranger/authorization/utils/JsonUtils.java
@@ -29,20 +29,16 @@ import org.apache.ranger.plugin.model.RangerValidityRecurrence;
import org.apache.ranger.plugin.model.RangerValiditySchedule;
import java.lang.reflect.Type;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JsonUtils {
private static final Log LOG = LogFactory.getLog(JsonUtils.class);
- private static final HashMap<String, String> MAP_STRING_STRING = new HashMap<>();
-
private static final Gson gson;
static {
- gson = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z")
- .create();
+ gson = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").create();
}
public static String mapToJson(Map<?, ?> map) {
@@ -102,7 +98,8 @@ public class JsonUtils {
if(StringUtils.isNotEmpty(jsonStr)) {
try {
- ret = gson.fromJson(jsonStr, MAP_STRING_STRING.getClass());
+ Type mapType = new TypeToken<Map<String, String>>() {}.getType();
+ ret = gson.fromJson(jsonStr, mapType);
} catch(Exception excp) {
LOG.warn("jsonToObject() failed to convert json to object: " + jsonStr, excp);
}
@@ -113,8 +110,7 @@ public class JsonUtils {
public static List<RangerValiditySchedule> jsonToRangerValiditySchedule(String jsonStr) {
try {
- Type listType = new TypeToken<List<RangerValiditySchedule>>() {
- }.getType();
+ Type listType = new TypeToken<List<RangerValiditySchedule>>() {}.getType();
return gson.fromJson(jsonStr, listType);
} catch (Exception e) {
LOG.error("Cannot get List<RangerValiditySchedule> from " + jsonStr, e);
diff --git a/agents-common/src/main/java/org/apache/ranger/authorization/utils/StringUtil.java b/agents-common/src/main/java/org/apache/ranger/authorization/utils/StringUtil.java
index 4e959bc..e6c9602 100644
--- a/agents-common/src/main/java/org/apache/ranger/authorization/utils/StringUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/authorization/utils/StringUtil.java
@@ -22,6 +22,7 @@
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
@@ -307,6 +308,21 @@ public class StringUtil {
return values;
}
+ public static List<String> toList(String str) {
+ List<String> values;
+ if (StringUtils.isNotBlank(str)) {
+ values = new ArrayList<>();
+ for (String item : str.split(",")) {
+ if (StringUtils.isNotBlank(item)) {
+ values.add(StringUtils.trim(item));
+ }
+ }
+ } else {
+ values = Collections.emptyList();
+ }
+ return values;
+ }
+
public static List<String> getURLs(String configURLs) {
List<String> configuredURLs = new ArrayList<>();
if(configURLs!=null) {
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
index 4c60efe..94ac749 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
@@ -213,7 +213,7 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
* combinations in a service-def will be much smaller than the number of service-resources.
*/
- static class ResourceHierarchies {
+ static public class ResourceHierarchies {
private final Map<Collection<String>, Boolean> accessHierarchies = new HashMap<>();
private final Map<Collection<String>, Boolean> dataMaskHierarchies = new HashMap<>();
private final Map<Collection<String>, Boolean> rowFilterHierarchies = new HashMap<>();
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerUserStoreEnricher.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerUserStoreEnricher.java
index cc892d8..1061633 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerUserStoreEnricher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerUserStoreEnricher.java
@@ -99,6 +99,7 @@ public class RangerUserStoreEnricher extends RangerAbstractContextEnricher {
userStoreRetriever.init(enricherDef.getEnricherOptions());
userStoreRefresher = new RangerUserStoreRefresher(userStoreRetriever, this, null, -1L, userStoreDownloadQueue, cacheFile);
+ LOG.info("Created Thread(RangerUserStoreRefresher(" + getName() + ")");
try {
userStoreRefresher.populateUserStoreInfo();
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceResource.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceResource.java
index 67230c6..bdd3e54 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceResource.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceResource.java
@@ -39,24 +39,31 @@ public class RangerServiceResource extends RangerBaseModelObject {
private String serviceName;
private Map<String, RangerPolicy.RangerPolicyResource> resourceElements;
+ private String ownerUser;
private String resourceSignature;
- public RangerServiceResource(String guid, String serviceName, Map<String, RangerPolicy.RangerPolicyResource> resourceElements, String resourceSignature) {
+ public RangerServiceResource(String guid, String serviceName, Map<String, RangerPolicy.RangerPolicyResource> resourceElements, String resourceSignature, String ownerUser) {
super();
setGuid(guid);
setServiceName(serviceName);
setResourceElements(resourceElements);
setResourceSignature(resourceSignature);
+ setOwnerUser(ownerUser);
}
+ public RangerServiceResource(String guid, String serviceName, Map<String, RangerPolicy.RangerPolicyResource> resourceElements, String resourceSignature) {
+ this(guid, serviceName, resourceElements, resourceSignature, null);
+
+ }
+
public RangerServiceResource(String guid, String serviceName, Map<String, RangerPolicy.RangerPolicyResource> resourceElements) {
- this(guid, serviceName, resourceElements, null);
+ this(guid, serviceName, resourceElements, null, null);
}
public RangerServiceResource(String serviceName, Map<String, RangerPolicy.RangerPolicyResource> resourceElements) {
- this(null, serviceName, resourceElements, null);
+ this(null, serviceName, resourceElements, null, null);
}
public RangerServiceResource() {
- this(null, null, null, null);
+ this(null, null, null, null, null);
}
public String getServiceName() { return serviceName; }
@@ -67,6 +74,10 @@ public class RangerServiceResource extends RangerBaseModelObject {
return resourceSignature;
}
+ public String getOwnerUser() {
+ return ownerUser;
+ }
+
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
@@ -79,6 +90,10 @@ public class RangerServiceResource extends RangerBaseModelObject {
this.resourceSignature = resourceSignature;
}
+ public void setOwnerUser(String ownerUser) {
+ this.ownerUser = ownerUser;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -107,6 +122,8 @@ public class RangerServiceResource extends RangerBaseModelObject {
}
sb.append("} ");
+ sb.append("ownerUser={").append(ownerUser).append("} ");
+
sb.append("resourceSignature={").append(resourceSignature).append("} ");
sb.append(" }");
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
index 794d3cb..2d9bc73 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
@@ -66,6 +66,7 @@ public class RangerBasePlugin {
private RangerAuthContext currentAuthContext;
private RangerAccessResultProcessor resultProcessor;
private RangerRoles roles;
+ private final List<RangerChainedPlugin> chainedPlugins;
public RangerBasePlugin(String serviceType, String appId) {
@@ -90,6 +91,8 @@ public class RangerBasePlugin {
setAuditExcludedUsersGroupsRoles(auditExcludeUsers, auditExcludeGroups, auditExcludeRoles);
RangerScriptExecutionContext.init(pluginConfig);
+
+ this.chainedPlugins = initChainedPlugins();
}
public static AuditHandler getAuditProvider(String serviceName) {
@@ -180,6 +183,10 @@ public class RangerBasePlugin {
LOG.info("Created PolicyRefresher Thread(" + refresher.getName() + ")");
refresher.setDaemon(true);
refresher.startRefresher();
+
+ for (RangerChainedPlugin chainedPlugin : chainedPlugins) {
+ chainedPlugin.init();
+ }
}
public void setPolicies(ServicePolicies policies) {
@@ -339,23 +346,64 @@ public class RangerBasePlugin {
}
public RangerAccessResult isAccessAllowed(RangerAccessRequest request, RangerAccessResultProcessor resultProcessor) {
+ RangerAccessResult ret = null;
RangerPolicyEngine policyEngine = this.policyEngine;
- if(policyEngine != null) {
- return policyEngine.evaluatePolicies(request, RangerPolicy.POLICY_TYPE_ACCESS, resultProcessor);
+ if (policyEngine != null) {
+ ret = policyEngine.evaluatePolicies(request, RangerPolicy.POLICY_TYPE_ACCESS, null);
}
- return null;
+ if (ret != null) {
+ for (RangerChainedPlugin chainedPlugin : chainedPlugins) {
+ RangerAccessResult chainedResult = chainedPlugin.isAccessAllowed(request);
+
+ if (chainedResult != null) {
+ updateResultFromChainedResult(ret, chainedResult);
+ }
+ }
+
+ }
+
+ if (resultProcessor != null) {
+ resultProcessor.processResult(ret);
+ }
+
+ return ret;
}
public Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests, RangerAccessResultProcessor resultProcessor) {
- RangerPolicyEngine policyEngine = this.policyEngine;
+ Collection<RangerAccessResult> ret = null;
+ RangerPolicyEngine policyEngine = this.policyEngine;
- if(policyEngine != null) {
- return policyEngine.evaluatePolicies(requests, RangerPolicy.POLICY_TYPE_ACCESS, resultProcessor);
+ if (policyEngine != null) {
+ ret = policyEngine.evaluatePolicies(requests, RangerPolicy.POLICY_TYPE_ACCESS, null);
}
- return null;
+ if (CollectionUtils.isNotEmpty(ret)) {
+ for (RangerChainedPlugin chainedPlugin : chainedPlugins) {
+ Collection<RangerAccessResult> chainedResults = chainedPlugin.isAccessAllowed(requests);
+
+ if (CollectionUtils.isNotEmpty(chainedResults)) {
+ Iterator<RangerAccessResult> iterRet = ret.iterator();
+ Iterator<RangerAccessResult> iterChainedResults = chainedResults.iterator();
+
+ while (iterRet.hasNext() && iterChainedResults.hasNext()) {
+ RangerAccessResult result = iterRet.next();
+ RangerAccessResult chainedResult = iterChainedResults.next();
+
+ if (result != null && chainedResult != null) {
+ updateResultFromChainedResult(result, chainedResult);
+ }
+ }
+ }
+ }
+ }
+
+ if (resultProcessor != null) {
+ resultProcessor.processResults(ret);
+ }
+
+ return ret;
}
public RangerAccessResult evalDataMaskPolicies(RangerAccessRequest request, RangerAccessResultProcessor resultProcessor) {
@@ -750,6 +798,69 @@ public class RangerBasePlugin {
return admin;
}
+ private List<RangerChainedPlugin> initChainedPlugins() {
+ List<RangerChainedPlugin> ret = new ArrayList<>();
+ String chainedServicePropPrefix = pluginConfig.getPropertyPrefix() + ".chained.services";
+
+ for (String chainedService : StringUtil.toList(pluginConfig.get(chainedServicePropPrefix))) {
+ if (StringUtils.isBlank(chainedService)) {
+ continue;
+ }
+
+ String className = pluginConfig.get(chainedServicePropPrefix + "." + chainedService + ".impl");
+
+ if (StringUtils.isBlank(className)) {
+ LOG.error("Ignoring chained service " + chainedService + ": no impl class specified");
+
+ continue;
+ }
+
+ try {
+ @SuppressWarnings("unchecked")
+ Class<RangerChainedPlugin> pluginClass = (Class<RangerChainedPlugin>) Class.forName(className);
+ RangerChainedPlugin chainedPlugin = pluginClass.getConstructor(RangerBasePlugin.class, String.class).newInstance(this, chainedService);
+
+ ret.add(chainedPlugin);
+ } catch (Throwable t) {
+ LOG.error("initChainedPlugins(): error instantiating plugin impl " + className, t);
+ }
+ }
+
+ return ret;
+ }
+
+ private void updateResultFromChainedResult(RangerAccessResult result, RangerAccessResult chainedResult) {
+ boolean overrideResult = false;
+
+ if (chainedResult.getIsAccessDetermined()) { // only if chained-result is definitive
+ // override if result is not definitive or chained-result is by a higher priority policy
+ overrideResult = !result.getIsAccessDetermined() || chainedResult.getPolicyPriority() > result.getPolicyPriority();
+
+ if (!overrideResult) {
+ // override if chained-result is from the same policy priority, and if denies access
+ if (chainedResult.getPolicyPriority() == result.getPolicyPriority() && !chainedResult.getIsAllowed()) {
+ // let's not override if result is already denied
+ if (result.getIsAllowed()) {
+ overrideResult = true;
+ }
+ }
+ }
+ }
+
+ if (overrideResult) {
+ result.setIsAllowed(chainedResult.getIsAllowed());
+ result.setIsAccessDetermined(chainedResult.getIsAccessDetermined());
+ result.setPolicyId(chainedResult.getPolicyId());
+ result.setPolicyVersion(chainedResult.getPolicyVersion());
+ result.setPolicyPriority(chainedResult.getPolicyPriority());
+ }
+
+ if (!result.getIsAuditedDetermined() && chainedResult.getIsAuditedDetermined()) {
+ result.setIsAudited(chainedResult.getIsAudited());
+ result.setAuditPolicyId(chainedResult.getAuditPolicyId());
+ }
+ }
+
private static AuditProviderFactory getAuditProviderFactory(String serviceName) {
AuditProviderFactory ret = AuditProviderFactory.getInstance();
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerChainedPlugin.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerChainedPlugin.java
new file mode 100644
index 0000000..0fca2d9
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerChainedPlugin.java
@@ -0,0 +1,62 @@
+/*
+ * 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.service;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessResult;
+
+import java.util.Collection;
+
+public abstract class RangerChainedPlugin {
+ private static final Log LOG = LogFactory.getLog(RangerChainedPlugin.class);
+
+ protected final RangerBasePlugin rootPlugin;
+ protected final String serviceType;
+ protected final String serviceName;
+ protected final RangerBasePlugin plugin;
+
+ protected RangerChainedPlugin(RangerBasePlugin rootPlugin, String serviceType, String serviceName) {
+ LOG.info("RangerChainedPlugin(" + serviceType + ", " + serviceName + ")");
+
+ this.rootPlugin = rootPlugin;
+ this.serviceType = serviceType;
+ this.serviceName = serviceName;
+ this.plugin = buildChainedPlugin(serviceType, serviceName, rootPlugin.getAppId());
+ }
+
+ public void init() {
+ LOG.info("==> RangerChainedPlugin.init(" + serviceType + ", " + serviceName + ")");
+
+ this.plugin.init();
+
+ LOG.info("<== RangerChainedPlugin.init(" + serviceType + ", " + serviceName + ")");
+ }
+
+ protected RangerBasePlugin buildChainedPlugin(String serviceType, String serviceName, String appId) {
+ return new RangerBasePlugin(serviceType, serviceName, appId);
+ }
+
+ public abstract RangerAccessResult isAccessAllowed(RangerAccessRequest request);
+
+ public abstract Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests);
+
+}
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerCustomConditionMatcherTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerCustomConditionMatcherTest.java
index 2c708d7..0a4dd4a 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerCustomConditionMatcherTest.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerCustomConditionMatcherTest.java
@@ -169,6 +169,8 @@ public class RangerCustomConditionMatcherTest {
RangerAccessRequest createRequest(List<String> resourceTags) {
RangerAccessResource resource = mock(RangerAccessResource.class);
+ when(resource.getAsString()).thenReturn("Dummy resource");
+
RangerAccessRequest request = new RangerAccessRequestImpl(resource,"dummy","test", null, null);
Set<RangerTagForEval> rangerTagForEvals = new HashSet<>();
RangerPolicyResourceMatcher.MatchType matchType = RangerPolicyResourceMatcher.MatchType.NONE;
diff --git a/agents-common/src/test/resources/policyengine/test_policyengine_tag_hive_filebased.json b/agents-common/src/test/resources/policyengine/test_policyengine_tag_hive_filebased.json
index 21d936a..7beb5ab 100644
--- a/agents-common/src/test/resources/policyengine/test_policyengine_tag_hive_filebased.json
+++ b/agents-common/src/test/resources/policyengine/test_policyengine_tag_hive_filebased.json
@@ -225,6 +225,14 @@
},
"tests":[
+ {"name":"DENY 'select from employee.personal;' for user1 using EXPIRES_ON tag",
+ "request":{
+ "resource":{"elements":{"database":"employee", "table":"personal"}}, "resourceMatchingScope": "SELF_OR_DESCENDANTS",
+ "accessType":"select","user":"user1","userGroups":[],"requestData":"select from employee.personal;' for user1"
+
+ },
+ "result":{"isAudited":true,"isAllowed":false,"policyId":5}
+ },
{"name":"ALLOW 'select ssn from employee.personal;' for user1 using EXPIRES_ON tag",
"request":{
"resource":{"elements":{"database":"employee", "table":"personal", "column":"ssn"}},