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 <[email protected]>
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 <[email protected]>
---
 .../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"}},

Reply via email to