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 2021/12/21 01:48:27 UTC

[ranger] 01/02: RANGER-3508: enhanced script condition expression for easier access to user/group/tag/resource attributes

This is an automated email from the ASF dual-hosted git repository.

madhan pushed a commit to branch ranger-2.3
in repository https://gitbox.apache.org/repos/asf/ranger.git

commit 911bdc88c86e316a04e8ae7719fc5a967425648e
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Mon Nov 8 17:12:58 2021 -0800

    RANGER-3508: enhanced script condition expression for easier access to user/group/tag/resource attributes
    
    (cherry picked from commit befc6d7e28b48c9e783af3e863af891c5fdd2b69)
---
 ...AnyOfExpectedTagsPresentConditionEvaluator.java |   6 +-
 ...oneOfExpectedTagsPresentConditionEvaluator.java |   9 +-
 .../RangerScriptConditionEvaluator.java            | 119 +-------
 .../RangerTagsAllPresentConditionEvaluator.java    |   6 +-
 .../RangerRequestScriptEvaluator.java}             | 307 +++++++++++++++++----
 .../ranger/plugin/service/RangerBasePlugin.java    |   4 +-
 .../ranger/plugin/util/RangerCommonConstants.java  |  28 +-
 .../ranger/plugin/util/ScriptEngineUtil.java       |  82 ++++++
 .../RangerCustomConditionMatcherTest.java          |  46 ++-
 .../RangerRequestScriptEvaluatorTest.java          | 169 ++++++++++++
 10 files changed, 590 insertions(+), 186 deletions(-)

diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerAnyOfExpectedTagsPresentConditionEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerAnyOfExpectedTagsPresentConditionEvaluator.java
index 3221f79..15826d1 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerAnyOfExpectedTagsPresentConditionEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerAnyOfExpectedTagsPresentConditionEvaluator.java
@@ -22,6 +22,7 @@ package org.apache.ranger.plugin.conditionevaluator;
 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.RangerRequestScriptEvaluator;
 
 import java.util.Collections;
 import java.util.HashSet;
@@ -63,9 +64,8 @@ public class RangerAnyOfExpectedTagsPresentConditionEvaluator extends RangerAbst
 
 		boolean matched = false;
 
-		RangerAccessRequest			 readOnlyRequest = request.getReadOnlyCopy();
-		RangerScriptExecutionContext context         = new RangerScriptExecutionContext(readOnlyRequest);
-		Set<String>                  resourceTags    = context.getAllTagTypes();
+		RangerRequestScriptEvaluator evaluator    = new RangerRequestScriptEvaluator(request);
+		Set<String>                  resourceTags = evaluator.getAllTagTypes();
 
 		if (resourceTags != null) {
 			// check if resource Tags does contain any of the policy Condition Tags
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerNoneOfExpectedTagsPresentConditionEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerNoneOfExpectedTagsPresentConditionEvaluator.java
index d04f4b3..9e6230d 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerNoneOfExpectedTagsPresentConditionEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerNoneOfExpectedTagsPresentConditionEvaluator.java
@@ -22,6 +22,7 @@ package org.apache.ranger.plugin.conditionevaluator;
 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.RangerRequestScriptEvaluator;
 
 import java.util.Collections;
 import java.util.HashSet;
@@ -61,11 +62,9 @@ public class RangerNoneOfExpectedTagsPresentConditionEvaluator extends RangerAbs
 			LOG.debug("==> RangerNoneOfExpectedTagsPresentConditionEvaluator.isMatched(" + request + ")");
 		}
 
-		boolean matched = true;
-
-		RangerAccessRequest readOnlyRequest = request.getReadOnlyCopy();
-		RangerScriptExecutionContext context = new RangerScriptExecutionContext(readOnlyRequest);
-		Set<String> resourceTags = context.getAllTagTypes();
+		boolean                      matched      = true;
+		RangerRequestScriptEvaluator evaluator    = new RangerRequestScriptEvaluator(request);
+		Set<String>                  resourceTags = evaluator.getAllTagTypes();
 
 		if (resourceTags != null) {
 			// check if resource Tags does not contain any tags in the policy condition
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java
index e57f599..b94225b 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java
@@ -24,17 +24,11 @@ import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.ranger.plugin.classloader.RangerPluginClassLoader;
-import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
 import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
-import org.apache.ranger.plugin.util.RangerPerfTracer;
+import org.apache.ranger.plugin.policyengine.RangerRequestScriptEvaluator;
+import org.apache.ranger.plugin.util.ScriptEngineUtil;
 
-import javax.script.Bindings;
 import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -43,24 +37,18 @@ import static org.apache.ranger.plugin.util.RangerCommonConstants.*;
 public class RangerScriptConditionEvaluator extends RangerAbstractConditionEvaluator {
 	private static final Log LOG = LogFactory.getLog(RangerScriptConditionEvaluator.class);
 
-	private static final Log PERF_POLICY_CONDITION_SCRIPT_EVAL = RangerPerfTracer.getPerfLogger("policy.condition.script.eval");
-
-	private static final String SCRIPT_PREEXEC = SCRIPT_VAR_CONTEXT + "=JSON.parse(" + SCRIPT_VAR_CONTEXT_JSON + ");";
-
 	private ScriptEngine scriptEngine;
 	private boolean      enableJsonCtx = false;
 
 	@Override
 	public void init() {
-
 		if (LOG.isDebugEnabled()) {
 			LOG.debug("==> RangerScriptConditionEvaluator.init(" + condition + ")");
 		}
 
 		super.init();
 
-		String engineName = "JavaScript";
-
+		String              engineName  = "JavaScript";
 		Map<String, String> evalOptions = conditionDef. getEvaluatorOptions();
 
 		if (MapUtils.isNotEmpty(evalOptions)) {
@@ -77,51 +65,11 @@ public class RangerScriptConditionEvaluator extends RangerAbstractConditionEvalu
 			LOG.debug("RangerScriptConditionEvaluator.init() - engineName=" + engineName);
 		}
 
-		String conditionType = condition != null ? condition.getType() : null;
-
-		try {
-			ScriptEngineManager manager = new ScriptEngineManager();
-
-			if (LOG.isDebugEnabled()) {
-				List<ScriptEngineFactory> factories = manager.getEngineFactories();
-
-				if (CollectionUtils.isEmpty(factories)) {
-					LOG.debug("List of scriptEngineFactories is empty!!");
-				} else {
-					for (ScriptEngineFactory factory : factories) {
-						LOG.debug("engineName=" + factory.getEngineName() + ", language=" + factory.getLanguageName());
-					}
-				}
-			}
-
-			scriptEngine = manager.getEngineByName(engineName);
-		} catch (Exception exp) {
-			LOG.error("RangerScriptConditionEvaluator.init() failed with exception=" + exp);
-		}
+		scriptEngine = ScriptEngineUtil.createScriptEngine(engineName, serviceDef.getName());
 
 		if (scriptEngine == null) {
-			LOG.warn("failed to initialize condition '" + conditionType + "': script engine '" + engineName + "' was not created in a default manner");
-			LOG.info("Will try to get script-engine from plugin-class-loader");
-
-
-			RangerPluginClassLoader pluginClassLoader;
-
-			try {
-
-				pluginClassLoader = RangerPluginClassLoader.getInstance(serviceDef.getName(), null);
-
-				if (pluginClassLoader != null) {
-					scriptEngine = pluginClassLoader.getScriptEngine(engineName);
-				} else {
-					LOG.error("Cannot get script-engine from null pluginClassLoader");
-				}
-
-			} catch (Throwable exp) {
-				LOG.error("RangerScriptConditionEvaluator.init() failed with exception=", exp);
-			}
-		}
+			String conditionType = condition != null ? condition.getType() : null;
 
-		if (scriptEngine == null) {
 			LOG.error("failed to initialize condition '" + conditionType + "': script engine '" + engineName + "' was not created");
 		} else {
 			LOG.info("ScriptEngine for engineName=[" + engineName + "] is successfully created");
@@ -137,70 +85,30 @@ public class RangerScriptConditionEvaluator extends RangerAbstractConditionEvalu
 		if (LOG.isDebugEnabled()) {
 			LOG.debug("==> RangerScriptConditionEvaluator.isMatched()");
 		}
+
 		boolean result = true;
 
 		if (scriptEngine != null) {
-
 			String script = getScript();
 
 			if (StringUtils.isNotBlank(script)) {
-
-				RangerAccessRequest readOnlyRequest = request.getReadOnlyCopy();
-
-				RangerScriptExecutionContext context    = new RangerScriptExecutionContext(readOnlyRequest);
-				RangerTagForEval             currentTag = context.getCurrentTag();
-				Map<String, String>          tagAttribs = currentTag != null ? currentTag.getAttributes() : Collections.emptyMap();
-
-				Bindings bindings = scriptEngine.createBindings();
-
-				bindings.put("ctx", context);
-				bindings.put("tag", currentTag);
-				bindings.put("tagAttr", tagAttribs);
-
-				if (enableJsonCtx) {
-					bindings.put(SCRIPT_VAR_CONTEXT_JSON, context.toJson());
-
-					script = SCRIPT_PREEXEC + script;
-				}
-
 				if (LOG.isDebugEnabled()) {
 					LOG.debug("RangerScriptConditionEvaluator.isMatched(): script={" + script + "}");
 				}
 
-				RangerPerfTracer perf = null;
-
-				try {
-					long requestHash = request.hashCode();
+				RangerRequestScriptEvaluator evaluator = new RangerRequestScriptEvaluator(request);
 
-					if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_CONDITION_SCRIPT_EVAL)) {
-						perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_CONDITION_SCRIPT_EVAL, "RangerScriptConditionEvaluator.isMatched(requestHash=" + requestHash + ")");
-					}
+				evaluator.evaluateConditionScript(scriptEngine, script, enableJsonCtx);
 
-					Object ret = scriptEngine.eval(script, bindings);
-
-					if (ret == null) {
-						ret = context.getResult();
-					}
-					if (ret instanceof Boolean) {
-						result = (Boolean) ret;
-					}
-
-				} catch (NullPointerException nullp) {
-					LOG.error("RangerScriptConditionEvaluator.isMatched(): eval called with NULL argument(s)", nullp);
-
-				} catch (ScriptException exception) {
-					LOG.error("RangerScriptConditionEvaluator.isMatched(): failed to evaluate script," +
-							" exception=" + exception);
-				} finally {
-					RangerPerfTracer.log(perf);
-				}
+				result = evaluator.getResult();
 			} else {
 				String conditionType = condition != null ? condition.getType() : null;
+
 				LOG.error("failed to evaluate condition '" + conditionType + "': script is empty");
 			}
-
 		} else {
 			String conditionType = condition != null ? condition.getType() : null;
+
 			LOG.error("failed to evaluate condition '" + conditionType + "': script engine not found");
 		}
 
@@ -213,13 +121,12 @@ public class RangerScriptConditionEvaluator extends RangerAbstractConditionEvalu
 	}
 
 	protected String getScript() {
-		String ret = null;
-
+		String       ret    = null;
 		List<String> values = condition.getValues();
 
 		if (CollectionUtils.isNotEmpty(values)) {
-
 			String value = values.get(0);
+
 			if (StringUtils.isNotBlank(value)) {
 				ret = value.trim();
 			}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerTagsAllPresentConditionEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerTagsAllPresentConditionEvaluator.java
index 8616c66..c8edf32 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerTagsAllPresentConditionEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerTagsAllPresentConditionEvaluator.java
@@ -23,6 +23,7 @@ import org.apache.commons.collections.CollectionUtils;
 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.RangerRequestScriptEvaluator;
 
 import java.util.HashSet;
 import java.util.Set;
@@ -63,9 +64,8 @@ public class RangerTagsAllPresentConditionEvaluator extends RangerAbstractCondit
 		boolean matched = true;
 
 		if (CollectionUtils.isNotEmpty(policyConditionTags))  {
-			RangerAccessRequest			 readOnlyRequest = request.getReadOnlyCopy();
-			RangerScriptExecutionContext context         = new RangerScriptExecutionContext(readOnlyRequest);
-			Set<String>                  resourceTags    = context.getAllTagTypes();
+			RangerRequestScriptEvaluator evaluator    = new RangerRequestScriptEvaluator(request);
+			Set<String>                  resourceTags = evaluator.getAllTagTypes();
 
 			// check if resource Tags  atleast have to have all the tags in policy Condition
 			matched = resourceTags != null && resourceTags.containsAll(policyConditionTags);
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptExecutionContext.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
similarity index 58%
rename from agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptExecutionContext.java
rename to agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
index 3563fd8..64f01c9 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptExecutionContext.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.ranger.plugin.conditionevaluator;
+package org.apache.ranger.plugin.policyengine;
 
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
@@ -27,16 +27,19 @@ import org.apache.hadoop.conf.Configuration;
 import org.apache.ranger.authorization.utils.JsonUtils;
 import org.apache.ranger.authorization.utils.StringUtil;
 import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
-import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
-import org.apache.ranger.plugin.policyengine.RangerAccessResource;
 import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.apache.ranger.plugin.util.RangerPerfTracer;
 import org.apache.ranger.plugin.util.RangerUserStore;
 
+import javax.script.Bindings;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
@@ -45,26 +48,42 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import static org.apache.ranger.plugin.util.RangerCommonConstants.*;
 
 
-public final class RangerScriptExecutionContext {
-	private static final Log LOG = LogFactory.getLog(RangerScriptExecutionContext.class);
+public final class RangerRequestScriptEvaluator {
+	private static final Log LOG = LogFactory.getLog(RangerRequestScriptEvaluator.class);
 
 	private static final Log    PERF_POLICY_CONDITION_SCRIPT_TOJSON         = RangerPerfTracer.getPerfLogger("policy.condition.script.tojson");
+	private static final Log    PERF_POLICY_CONDITION_SCRIPT_EVAL           = RangerPerfTracer.getPerfLogger("policy.condition.script.eval");
 	private static final String TAG_ATTR_DATE_FORMAT_PROP                   = "ranger.plugin.tag.attr.additional.date.formats";
 	private static final String TAG_ATTR_DATE_FORMAT_SEPARATOR              = "||";
 	private static final String TAG_ATTR_DATE_FORMAT_SEPARATOR_REGEX        = "\\|\\|";
 	private static final String DEFAULT_RANGER_TAG_ATTRIBUTE_DATE_FORMAT    = "yyyy/MM/dd";
 	private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME = "ATLAS_DATE_FORMAT";
 	private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT     = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
-
-	private final RangerAccessRequest accessRequest;
-	private Boolean result = false;
+	private static final String SCRIPT_PREEXEC                              = SCRIPT_VAR__CTX + "=JSON.parse(" + SCRIPT_VAR__CTX_JSON + "); J=JSON.stringify;" +
+                                                                                 SCRIPT_VAR_REQ + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_REQUEST + ";" +
+                                                                                 SCRIPT_VAR_RES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_RESOURCE + ";" +
+                                                                                 SCRIPT_VAR_USER + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ATTRIBUTES + ";" +
+                                                                                 SCRIPT_VAR_UGROUPS + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUPS + ";" +
+                                                                                 SCRIPT_VAR_UGROUP + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUP_ATTRIBUTES + ";" +
+                                                                                 SCRIPT_VAR_UGA + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_UGA + ";" +
+                                                                                 SCRIPT_VAR_UROLES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ROLES + ";" +
+                                                                                 SCRIPT_VAR_TAG + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG + ";" +
+                                                                                 SCRIPT_VAR_TAGS + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAGS + ";" +
+                                                                                 SCRIPT_VAR_TAGNAMES + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG_NAMES + ";";
+
+	private static final Pattern JSON_VAR_NAMES_PATTERN = Pattern.compile(getJsonVarNamesPattern());
 
 	private static String[] dateFormatStrings = null;
 
+	private final RangerAccessRequest accessRequest;
+	private       Boolean             result = false;
+
 	static {
 		init(null);
 	}
@@ -93,25 +112,99 @@ public final class RangerScriptExecutionContext {
 				}
 			};
 
-	RangerScriptExecutionContext(final RangerAccessRequest accessRequest) {
-		this.accessRequest = accessRequest;
+
+	public static boolean needsJsonCtxEnabled(String script) {
+		Matcher matcher = JSON_VAR_NAMES_PATTERN.matcher(script);
+
+		boolean ret = matcher.matches();
+
+		return ret;
+	}
+
+
+	public RangerRequestScriptEvaluator(final RangerAccessRequest accessRequest) {
+		this.accessRequest = accessRequest.getReadOnlyCopy();
+	}
+
+	public Object evaluateScript(ScriptEngine scriptEngine, String script) {
+		return evaluateScript(scriptEngine, script, needsJsonCtxEnabled(script));
+	}
+
+	public Object evaluateConditionScript(ScriptEngine scriptEngine, String script, boolean enableJsonCtx) {
+		Object ret = evaluateScript(scriptEngine, script, enableJsonCtx);
+
+		if (ret == null) {
+			ret = getResult();
+		}
+
+		if (ret instanceof Boolean) {
+			result = (Boolean) ret;
+		}
+
+		return ret;
 	}
 
-	public String toJson() {
+	private Object evaluateScript(ScriptEngine scriptEngine, String script, boolean enableJsonCtx) {
+		Object              ret        = null;
+		Bindings            bindings   = scriptEngine.createBindings();
+		RangerTagForEval    currentTag = this.getCurrentTag();
+		Map<String, String> tagAttribs = currentTag != null ? currentTag.getAttributes() : Collections.emptyMap();
+
+		bindings.put(SCRIPT_VAR_ctx, this);
+		bindings.put(SCRIPT_VAR_tag, currentTag);
+		bindings.put(SCRIPT_VAR_tagAttr, tagAttribs);
+
+		if (enableJsonCtx) {
+			bindings.put(SCRIPT_VAR__CTX_JSON, this.toJson());
+
+			script = SCRIPT_PREEXEC + script;
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("RangerRequestScriptEvaluator.evaluateScript(): script={" + script + "}");
+		}
+
+		RangerPerfTracer perf = null;
+
+		try {
+			long requestHash = accessRequest.hashCode();
+
+			if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_CONDITION_SCRIPT_EVAL)) {
+				perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_CONDITION_SCRIPT_EVAL, "RangerRequestScriptEvaluator.evaluateScript(requestHash=" + requestHash + ")");
+			}
+
+			ret = scriptEngine.eval(script, bindings);
+		} catch (NullPointerException nullp) {
+			LOG.error("RangerRequestScriptEvaluator.evaluateScript(): eval called with NULL argument(s)", nullp);
+
+		} catch (ScriptException exception) {
+			LOG.error("RangerRequestScriptEvaluator.evaluateScript(): failed to evaluate script," +
+					" exception=" + exception);
+		} finally {
+			RangerPerfTracer.log(perf);
+		}
+
+		return ret;
+	}
+
+	private String toJson() {
 		RangerPerfTracer perf = null;
 
 		long requestHash = accessRequest.hashCode();
 
 		if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_CONDITION_SCRIPT_TOJSON)) {
-			perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_CONDITION_SCRIPT_TOJSON, "RangerScriptExecutionContext.toJson(requestHash=" + requestHash + ")");
+			perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_CONDITION_SCRIPT_TOJSON, "RangerRequestScriptEvaluator.toJson(requestHash=" + requestHash + ")");
 		}
 
-		Map<String, Object> ret       = new HashMap<>();
-		Map<String, Object> request   = new HashMap<>();
-		RangerUserStore     userStore = RangerAccessRequestUtil.getRequestUserStoreFromContext(accessRequest.getContext());
+		Map<String, Object> ret        = new HashMap<>();
+		Map<String, Object> request    = new HashMap<>();
+		RangerUserStore     userStore  = RangerAccessRequestUtil.getRequestUserStoreFromContext(accessRequest.getContext());
+		Collection<String>  userGroups = getSorted(getUserGroups());
+		Collection<String>  userRoles  = getSorted(getUserRoles());
+		Date                accessTime = accessRequest.getAccessTime();
 
-		if (accessRequest.getAccessTime() != null) {
-			request.put(SCRIPT_FIELD_ACCESS_TIME, accessRequest.getAccessTime().getTime());
+		if (accessTime != null) {
+			request.put(SCRIPT_FIELD_ACCESS_TIME, accessTime.getTime());
 		}
 
 		request.put(SCRIPT_FIELD_ACCESS_TYPE, accessRequest.getAccessType());
@@ -125,63 +218,69 @@ public final class RangerScriptExecutionContext {
 		request.put(SCRIPT_FIELD_REQUEST_DATA, accessRequest.getRequestData());
 
 		if (accessRequest.getResource() != null) {
-			request.put(SCRIPT_FIELD_RESOURCE, accessRequest.getResource().getAsMap());
-			request.put(SCRIPT_FIELD_RESOURCE_OWNER_USER, accessRequest.getResource().getOwnerUser());
+			Map<String, Object> resource = new HashMap<>(accessRequest.getResource().getAsMap());
+
+			resource.put(SCRIPT_FIELD__OWNER_USER, accessRequest.getResource().getOwnerUser());
+
+			request.put(SCRIPT_FIELD_RESOURCE, resource);
 		}
 
 		request.put(SCRIPT_FIELD_RESOURCE_MATCHING_SCOPE, accessRequest.getResourceMatchingScope());
 
-		request.put(SCRIPT_FIELD_USER, accessRequest.getUser());
-		request.put(SCRIPT_FIELD_USER_GROUPS, accessRequest.getUserGroups());
-		request.put(SCRIPT_FIELD_USER_ROLES, accessRequest.getUserRoles());
+		request.put(SCRIPT_FIELD_USER, getUser());
+		request.put(SCRIPT_FIELD_USER_GROUPS, userGroups);
+		request.put(SCRIPT_FIELD_USER_ROLES, userRoles);
 
-		if (userStore != null) {
-			Map<String, Map<String, String>> userAttrMapping  = userStore.getUserAttrMapping();
-			Map<String, Map<String, String>> groupAttrMapping = userStore.getGroupAttrMapping();
+		Map<String, Map<String, String>> userAttrMapping  = userStore != null ? userStore.getUserAttrMapping() : Collections.emptyMap();
+		Map<String, Map<String, String>> groupAttrMapping = userStore != null ? userStore.getGroupAttrMapping() : Collections.emptyMap();
+		Map<String, String>              userAttrs        = userAttrMapping.get(accessRequest.getUser());
+		Map<String, Map<String, String>> groupAttrs       = new HashMap<>();
 
-			if (userAttrMapping != null) {
-				request.put(SCRIPT_FIELD_USER_ATTRIBUTES, userAttrMapping.get(accessRequest.getUser()));
-			}
+		userAttrs = userAttrs != null ? new HashMap<>(userAttrs) : new HashMap<>();
 
-			if (groupAttrMapping != null && accessRequest.getUserGroups() != null) {
-				Map<String, Map<String, String>> groupAttrs = new HashMap<>();
+		userAttrs.put(SCRIPT_FIELD__NAME, getUser());
 
-				for (String groupName : accessRequest.getUserGroups()) {
-					groupAttrs.put(groupName, groupAttrMapping.get(groupName));
-				}
+		request.put(SCRIPT_FIELD_USER_ATTRIBUTES, userAttrs);
+
+		if (userGroups != null) {
+			for (String groupName : userGroups) {
+				Map<String, String> attrs = groupAttrMapping.get(groupName);
+
+				attrs = attrs != null ? new HashMap<>(attrs) : new HashMap<>();
+
+				attrs.put(SCRIPT_FIELD__NAME, groupName);
 
-				request.put(SCRIPT_FIELD_USER_GROUP_ATTRIBUTES, groupAttrs);
+				groupAttrs.put(groupName, attrs);
 			}
 		}
 
+		request.put(SCRIPT_FIELD_USER_GROUP_ATTRIBUTES, groupAttrs);
+		request.put(SCRIPT_FIELD_UGA, new UserGroupsAttributes(userGroups, groupAttrs).getAttributes());
+
 		ret.put(SCRIPT_FIELD_REQUEST, request);
 
 		Set<RangerTagForEval> requestTags = RangerAccessRequestUtil.getRequestTagsFromContext(getRequestContext());
 
 		if (CollectionUtils.isNotEmpty(requestTags)) {
-			Set<Map<String, Object>> tags = new HashSet<>();
+			Set<Map<String, Object>> tags     = new HashSet<>();
+			Set<String>              tagNames = new HashSet<>();
 
 			for (RangerTagForEval tag : requestTags) {
 				tags.add(toMap(tag));
+				tagNames.add(tag.getType());
 			}
 
 			ret.put(SCRIPT_FIELD_TAGS, tags);
+			ret.put(SCRIPT_FIELD_TAG_NAMES, tagNames);
 
 			RangerTagForEval currentTag = RangerAccessRequestUtil.getCurrentTagFromContext(getRequestContext());
 
 			if (currentTag != null) {
 				ret.put(SCRIPT_FIELD_TAG, toMap(currentTag));
 			}
-		}
-
-		RangerAccessResource resource = RangerAccessRequestUtil.getCurrentResourceFromContext(getRequestContext());
-
-		if (resource != null) {
-			ret.put(SCRIPT_FIELD_RESOURCE, resource.getAsMap());
-
-			if (resource.getOwnerUser() != null) {
-				ret.put(SCRIPT_FIELD_RESOURCE_OWNER_USER, resource.getOwnerUser());
-			}
+		} else {
+			ret.put(SCRIPT_FIELD_TAGS, Collections.emptySet());
+			ret.put(SCRIPT_FIELD_TAG_NAMES, Collections.emptySet());
 		}
 
 		String strRet = JsonUtils.objectToJson(ret);
@@ -211,7 +310,7 @@ public final class RangerScriptExecutionContext {
 			}
 		});
 
-		RangerScriptExecutionContext.dateFormatStrings = formatStrings;
+		RangerRequestScriptEvaluator.dateFormatStrings = formatStrings;
 	}
 
 	public String getResource() {
@@ -251,6 +350,8 @@ public final class RangerScriptExecutionContext {
 
 	public Set<String> getUserGroups() { return accessRequest.getUserGroups(); }
 
+	public Set<String> getUserRoles() { return accessRequest.getUserRoles(); }
+
 	public Date getAccessTime() { return accessRequest.getAccessTime() != null ? accessRequest.getAccessTime() : new Date(); }
 
 	public String getClientIPAddress() { return accessRequest.getClientIPAddress(); }
@@ -268,7 +369,7 @@ public final class RangerScriptExecutionContext {
 
 		if(ret == null ) {
 			if (LOG.isDebugEnabled()) {
-				logDebug("RangerScriptExecutionContext.getCurrentTag() - No current TAG object. Script execution must be for resource-based policy.");
+				logDebug("RangerRequestScriptEvaluator.getCurrentTag() - No current TAG object. Script execution must be for resource-based policy.");
 			}
 		}
 		return ret;
@@ -433,7 +534,7 @@ public final class RangerScriptExecutionContext {
 				ret = getAsDate(value, simpleDateFormat);
 				if (ret != null) {
 					if (LOG.isDebugEnabled()) {
-						logDebug("RangerScriptExecutionContext.getAsDate() -The best match found for Format-String:[" + simpleDateFormat.toPattern() + "], date:[" + ret +"]");
+						logDebug("RangerRequestScriptEvaluator.getAsDate() -The best match found for Format-String:[" + simpleDateFormat.toPattern() + "], date:[" + ret +"]");
 					}
 					break;
 				}
@@ -441,7 +542,7 @@ public final class RangerScriptExecutionContext {
 		}
 
 		if (ret == null) {
-			logError("RangerScriptExecutionContext.getAsDate() - Could not convert [" + value + "] to Date using any of the Format-Strings: " + Arrays.toString(dateFormatStrings));
+			logError("RangerRequestScriptEvaluator.getAsDate() - Could not convert [" + value + "] to Date using any of the Format-Strings: " + Arrays.toString(dateFormatStrings));
 		} else {
 			ret = StringUtil.getUTCDateForLocalDate(ret);
 		}
@@ -509,7 +610,7 @@ public final class RangerScriptExecutionContext {
 			if (LOG.isDebugEnabled()) {
 				String resource = accessRequest.getResource().getAsString();
 
-				logDebug("RangerScriptExecutionContext.getAllTags() - No TAGS. No TAGS for the RangerAccessResource=" + resource);
+				logDebug("RangerRequestScriptEvaluator.getAllTags() - No TAGS. No TAGS for the RangerAccessResource=" + resource);
 			}
 		}
 
@@ -519,13 +620,53 @@ public final class RangerScriptExecutionContext {
 	private static Map<String, Object> toMap(RangerTagForEval tag) {
 		Map<String, Object> ret = new HashMap<>();
 
-		ret.put("type", tag.getType());
-		ret.put("attributes", tag.getAttributes());
-		ret.put("matchType", tag.getMatchType());
+		if (tag.getAttributes() != null) {
+			ret.putAll(tag.getAttributes());
+		}
+
+		ret.put(SCRIPT_FIELD__TYPE, tag.getType());
+		ret.put(SCRIPT_FIELD__MATCH_TYPE, tag.getMatchType());
 
 		return ret;
 	}
 
+	private Collection<String> getSorted(Collection<String> coll) {
+		if (coll != null && coll.size() > 1) {
+			List<String> lst = new ArrayList<>(coll);
+
+			Collections.sort(lst);
+
+			coll = lst;
+		}
+
+		return coll;
+	}
+
+	private static String getJsonVarNamesPattern() {
+		List<String> varNames = new ArrayList<>();
+
+		/* include only variables setup by JSON.parse()
+		 *
+		varNames.add(SCRIPT_VAR_ctx);
+		varNames.add(SCRIPT_VAR_tag);
+		varNames.add(SCRIPT_VAR_tagAttr);
+		 *
+		 */
+		varNames.add(SCRIPT_VAR__CTX);
+		varNames.add(SCRIPT_VAR_REQ);
+		varNames.add(SCRIPT_VAR_RES);
+		varNames.add(SCRIPT_VAR_TAG);
+		varNames.add(SCRIPT_VAR_TAGNAMES);
+		varNames.add(SCRIPT_VAR_TAGS);
+		varNames.add(SCRIPT_VAR_UGA);
+		varNames.add(SCRIPT_VAR_UGROUP);
+		varNames.add(SCRIPT_VAR_UGROUPS);
+		varNames.add(SCRIPT_VAR_UROLES);
+		varNames.add(SCRIPT_VAR_USER);
+
+		return ".*(" + StringUtils.join(varNames, '|') + ").*";
+	}
+
 	public void logDebug(Object msg) {
 		LOG.debug(msg);
 	}
@@ -545,4 +686,64 @@ public final class RangerScriptExecutionContext {
 	public void logFatal(Object msg) {
 		LOG.fatal(msg);
 	}
+
+	public static class UserGroupsAttributes {
+		private final Collection<String>               groupNames;
+		private final Map<String, Map<String, String>> groupAttributes;
+
+		public UserGroupsAttributes(Collection<String> groupNames, Map<String, Map<String, String>> groupAttributes) {
+			this.groupNames      = groupNames;
+			this.groupAttributes = groupAttributes;
+		}
+
+		/*
+		  {
+		    sVal: {
+		      attr1: val1,
+		      attr2: val2
+		    },
+		    mVal: {
+		      attr1: [ val1, val1_2 ],
+		      attr2: [ val2, val2_2 ]
+		    }
+		  }
+		 */
+		public Map<String, Map<String, Object>> getAttributes() {
+			Map<String, Map<String, Object>> ret       = new HashMap<>();
+			Map<String, String>              valueMap  = new HashMap<>();
+			Map<String, List<String>>        valuesMap = new HashMap<>();
+
+			ret.put("sVal", (Map) valueMap);
+			ret.put("mVal", (Map) valuesMap);
+
+			if (groupNames != null && groupAttributes != null) {
+				for (String groupName : groupNames) {
+					Map<String, String> attributes = groupAttributes.get(groupName);
+
+					if (attributes != null) {
+						for (Map.Entry<String, String> entry : attributes.entrySet()) {
+							String attrName  = entry.getKey();
+							String attrValue = entry.getValue();
+
+							if (!valueMap.containsKey(attrName)) {
+								valueMap.put(attrName, attrValue);
+							}
+
+							List<String> values = valuesMap.get(attrName);
+
+							if (values == null) {
+								values = new ArrayList<>();
+
+								valuesMap.put(attrName, values);
+							}
+
+							values.add(attrValue);
+						}
+					}
+				}
+			}
+
+			return ret;
+		}
+	}
 }
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 57a4b4b..6430b98 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
@@ -33,7 +33,7 @@ import org.apache.ranger.audit.provider.StandAloneAuditProviderFactory;
 import org.apache.ranger.authorization.hadoop.config.RangerAuditConfig;
 import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig;
 import org.apache.ranger.authorization.utils.StringUtil;
-import org.apache.ranger.plugin.conditionevaluator.RangerScriptExecutionContext;
+import org.apache.ranger.plugin.policyengine.RangerRequestScriptEvaluator;
 import org.apache.ranger.plugin.contextenricher.RangerContextEnricher;
 import org.apache.ranger.plugin.contextenricher.RangerTagEnricher;
 import org.apache.ranger.plugin.model.RangerPolicy;
@@ -94,7 +94,7 @@ public class RangerBasePlugin {
 		setIsFallbackSupported(pluginConfig.getBoolean(pluginConfig.getPropertyPrefix() + ".is.fallback.supported", false));
 		setServiceAdmins(serviceAdmins);
 
-		RangerScriptExecutionContext.init(pluginConfig);
+		RangerRequestScriptEvaluator.init(pluginConfig);
 
 		this.chainedPlugins = initChainedPlugins();
 	}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java
index 75132d8..63bed50 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java
@@ -51,8 +51,23 @@ public class RangerCommonConstants {
 	public static final boolean POLICY_REST_CLIENT_SESSION_COOKIE_ENABLED            = true;
 
 	public static final String SCRIPT_OPTION_ENABLE_JSON_CTX        = "enableJsonCtx";
-	public static final String SCRIPT_VAR_CONTEXT                   = "_ctx";
-	public static final String SCRIPT_VAR_CONTEXT_JSON              = "_ctx_json";
+
+	public static final String SCRIPT_VAR_ctx                       = "ctx";
+	public static final String SCRIPT_VAR_tag                       = "tag";
+	public static final String SCRIPT_VAR_tagAttr                   = "tagAttr";
+	public static final String SCRIPT_VAR__CTX                      = "_ctx";
+	public static final String SCRIPT_VAR__CTX_JSON                 = "_ctx_json";
+	public static final String SCRIPT_VAR_REQ                       = "REQ";
+	public static final String SCRIPT_VAR_RES                       = "RES";
+	public static final String SCRIPT_VAR_TAG                       = "TAG";
+	public static final String SCRIPT_VAR_TAGNAMES                  = "TAGNAMES";
+	public static final String SCRIPT_VAR_TAGS                      = "TAGS";
+	public static final String SCRIPT_VAR_UGA                       = "UGA";
+	public static final String SCRIPT_VAR_UGROUP                    = "UGROUP";
+	public static final String SCRIPT_VAR_UGROUPS                   = "UGROUPS";
+	public static final String SCRIPT_VAR_UROLES                    = "UROLES";
+	public static final String SCRIPT_VAR_USER                      = "USER";
+
 	public static final String SCRIPT_FIELD_ACCESS_TIME             = "accessTime";
 	public static final String SCRIPT_FIELD_ACCESS_TYPE             = "accessType";
 	public static final String SCRIPT_FIELD_ACTION                  = "action";
@@ -61,17 +76,22 @@ public class RangerCommonConstants {
 	public static final String SCRIPT_FIELD_CLUSTER_NAME            = "clusterName";
 	public static final String SCRIPT_FIELD_CLUSTER_TYPE            = "clusterType";
 	public static final String SCRIPT_FIELD_FORWARDED_ADDRESSES     = "forwardedAddresses";
+	public static final String SCRIPT_FIELD__MATCH_TYPE             = "_matchType";
+	public static final String SCRIPT_FIELD__NAME                   = "_name";
+	public static final String SCRIPT_FIELD__OWNER_USER             = "_ownerUser";
 	public static final String SCRIPT_FIELD_REMOTE_IP_ADDRESS       = "remoteIPAddress";
+	public static final String SCRIPT_FIELD_REQUEST                 = "request";
 	public static final String SCRIPT_FIELD_REQUEST_DATA            = "requestData";
 	public static final String SCRIPT_FIELD_RESOURCE                = "resource";
-	public static final String SCRIPT_FIELD_RESOURCE_OWNER_USER     = "resourceOwnerUser";
 	public static final String SCRIPT_FIELD_RESOURCE_MATCHING_SCOPE = "resourceMatchingScope";
 	public static final String SCRIPT_FIELD_TAG                     = "tag";
 	public static final String SCRIPT_FIELD_TAGS                    = "tags";
+	public static final String SCRIPT_FIELD_TAG_NAMES               = "tagNames";
+	public static final String SCRIPT_FIELD__TYPE                   = "_type";
 	public static final String SCRIPT_FIELD_USER                    = "user";
 	public static final String SCRIPT_FIELD_USER_ATTRIBUTES         = "userAttributes";
 	public static final String SCRIPT_FIELD_USER_GROUPS             = "userGroups";
 	public static final String SCRIPT_FIELD_USER_GROUP_ATTRIBUTES   = "userGroupAttributes";
+	public static final String SCRIPT_FIELD_UGA                     = "uga";
 	public static final String SCRIPT_FIELD_USER_ROLES              = "userRoles";
-	public static final String SCRIPT_FIELD_REQUEST                 = "request";
 }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/ScriptEngineUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/ScriptEngineUtil.java
new file mode 100644
index 0000000..b0782ec
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/ScriptEngineUtil.java
@@ -0,0 +1,82 @@
+/*
+ * 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 org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.classloader.RangerPluginClassLoader;
+import org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptEngineManager;
+import java.util.List;
+
+public class ScriptEngineUtil {
+    private static final Log LOG = LogFactory.getLog(RangerScriptConditionEvaluator.class);
+
+
+    public static ScriptEngine createScriptEngine(String engineName, String serviceType) {
+        ScriptEngine ret = null;
+
+        try {
+            ScriptEngineManager manager = new ScriptEngineManager();
+
+            if (LOG.isDebugEnabled()) {
+                List<ScriptEngineFactory> factories = manager.getEngineFactories();
+
+                if (CollectionUtils.isEmpty(factories)) {
+                    LOG.debug("List of scriptEngineFactories is empty!!");
+                } else {
+                    for (ScriptEngineFactory factory : factories) {
+                        LOG.debug("engineName=" + factory.getEngineName() + ", language=" + factory.getLanguageName());
+                    }
+                }
+            }
+
+            ret = manager.getEngineByName(engineName);
+        } catch (Exception exp) {
+            LOG.error("RangerScriptConditionEvaluator.init() failed with exception=" + exp);
+        }
+
+        if (ret == null) {
+            LOG.warn("failed to initialize script engine '" + engineName + "' in a default manner." +
+                     " Will try to get script-engine from plugin-class-loader");
+
+            RangerPluginClassLoader pluginClassLoader;
+
+            try {
+                pluginClassLoader = RangerPluginClassLoader.getInstance(serviceType, null);
+
+                if (pluginClassLoader != null) {
+                    ret = pluginClassLoader.getScriptEngine(engineName);
+                } else {
+                    LOG.error("Cannot get script-engine from null pluginClassLoader");
+                }
+            } catch (Throwable exp) {
+                LOG.error("RangerScriptConditionEvaluator.init() failed with exception=", exp);
+            }
+        }
+
+        return ret;
+    }
+}
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 36504c7..d5f1564 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
@@ -21,6 +21,7 @@ package org.apache.ranger.plugin.conditionevaluator;
 
 
 import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
+import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerPolicyConditionDef;
 import org.apache.ranger.plugin.model.RangerTag;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemCondition;
@@ -61,13 +62,24 @@ public class RangerCustomConditionMatcherTest {
 		RangerScriptConditionEvaluator accessTypeCondition     = createScriptConditionEvaluator("_ctx.request.accessType.equals('select')");
 		RangerScriptConditionEvaluator actionCondition         = createScriptConditionEvaluator("_ctx.request.action.equals('query')");
 		RangerScriptConditionEvaluator userCondition           = createScriptConditionEvaluator("_ctx.request.user.equals('test-user')");
-		RangerScriptConditionEvaluator userGroupsLenCondition  = createScriptConditionEvaluator("_ctx.request.userGroups.length == 1");
-		RangerScriptConditionEvaluator userRolesLenCondition   = createScriptConditionEvaluator("_ctx.request.userRoles.length == 1");
+		RangerScriptConditionEvaluator userGroupsLenCondition  = createScriptConditionEvaluator("_ctx.request.userGroups.length == 2");
+		RangerScriptConditionEvaluator userGroupsHas1Condition = createScriptConditionEvaluator("_ctx.request.userGroups.indexOf('test-group1') != -1");
+		RangerScriptConditionEvaluator userGroupsHas2Condition = createScriptConditionEvaluator("_ctx.request.userGroups.indexOf('test-group2') != -1");
+		RangerScriptConditionEvaluator userRolesLenCondition   = createScriptConditionEvaluator("_ctx.request.userRoles.length == 2");
+		RangerScriptConditionEvaluator userRolesHas1Condition  = createScriptConditionEvaluator("_ctx.request.userRoles.indexOf('test-role1') != -1");
+		RangerScriptConditionEvaluator userRolesHas2Condition  = createScriptConditionEvaluator("_ctx.request.userRoles.indexOf('test-role2') != -1");
+		RangerScriptConditionEvaluator userAttrLenCondition    = createScriptConditionEvaluator("Object.keys(_ctx.request.userAttributes).length == 3");
+		RangerScriptConditionEvaluator userAttr1Condition      = createScriptConditionEvaluator("_ctx.request.userAttributes['attr1'].equals('test-user-value1')");
+		RangerScriptConditionEvaluator userAttr2Condition      = createScriptConditionEvaluator("_ctx.request.userAttributes['attr2'].equals('test-user-value2')");
+		RangerScriptConditionEvaluator userGroup1Attr1Condition = createScriptConditionEvaluator("_ctx.request.userGroupAttributes['test-group1']['attr1'].equals('test-group1-value1')");
+		RangerScriptConditionEvaluator userGroup1Attr2Condition = createScriptConditionEvaluator("_ctx.request.userGroupAttributes['test-group1']['attr2'].equals('test-group1-value2')");
+		RangerScriptConditionEvaluator userGroup2Attr1Condition = createScriptConditionEvaluator("_ctx.request.userGroupAttributes['test-group2']['attr1'].equals('test-group2-value1')");
+		RangerScriptConditionEvaluator userGroup2Attr2Condition = createScriptConditionEvaluator("_ctx.request.userGroupAttributes['test-group2']['attr2'].equals('test-group2-value2')");
 		RangerScriptConditionEvaluator tagsLengthCondition     = createScriptConditionEvaluator("_ctx.tags.length == 2");
-		RangerScriptConditionEvaluator tagTypeCondition        = createScriptConditionEvaluator("_ctx.tag.type.equals('PCI')");
-		RangerScriptConditionEvaluator tagAttributesCondition  = createScriptConditionEvaluator("_ctx.tag.attributes.attr1.equals('PCI_value')");
-		RangerScriptConditionEvaluator tagsTypeCondition       = createScriptConditionEvaluator("switch(_ctx.tags[0].type) { case 'PCI': _ctx.tags[1].type.equals('PII'); break; case 'PII': _ctx.tags[1].type.equals('PCI'); break; default: false; }");
-		RangerScriptConditionEvaluator tagsAttributesCondition = createScriptConditionEvaluator("switch(_ctx.tags[0].type) { case 'PCI': _ctx.tags[0].attributes.attr1.equals('PCI_value') && _ctx.tags[1].attributes.attr1.equals('PII_value'); break; case 'PII': _ctx.tags[0].attributes.attr1.equals('PII_value') && _ctx.tags[1].attributes.attr1.equals('PCI_value'); break; default: false; }");
+		RangerScriptConditionEvaluator tagTypeCondition        = createScriptConditionEvaluator("_ctx.tag._type.equals('PCI')");
+		RangerScriptConditionEvaluator tagAttributesCondition  = createScriptConditionEvaluator("_ctx.tag.attr1.equals('PCI_value')");
+		RangerScriptConditionEvaluator tagsTypeCondition       = createScriptConditionEvaluator("switch(_ctx.tags[0]._type) { case 'PCI': _ctx.tags[1]._type.equals('PII'); break; case 'PII': _ctx.tags[1]._type.equals('PCI'); break; default: false; }");
+		RangerScriptConditionEvaluator tagsAttributesCondition = createScriptConditionEvaluator("switch(_ctx.tags[0]._type) { case 'PCI': _ctx.tags[0].attr1.equals('PCI_value') && _ctx.tags[1].attr1.equals('PII_value'); break; case 'PII': _ctx.tags[0].attr1.equals('PII_value') && _ctx.tags[1].attr1.equals('PCI_value'); break; default: false; }");
 
 		Assert.assertTrue("request.resource.database should be db1", resourceDbCondition.isMatched(request));
 		Assert.assertTrue("request.resource.database should not be db2", resourceDbCondition2.isMatched(request));
@@ -76,10 +88,21 @@ public class RangerCustomConditionMatcherTest {
 		Assert.assertTrue("request.accessType should be select", accessTypeCondition.isMatched(request));
 		Assert.assertTrue("request.action should be query", actionCondition.isMatched(request));
 		Assert.assertTrue("request.user should be testUser", userCondition.isMatched(request));
-		Assert.assertTrue("request.userGroups should have 1 entry", userGroupsLenCondition.isMatched(request));
-		Assert.assertTrue("request.userRoles should have 1 entry", userRolesLenCondition.isMatched(request));
-		Assert.assertTrue("tag.type should be PCI", tagTypeCondition.isMatched(request));
-		Assert.assertTrue("tag.attributes.attr1 should be PCI_value", tagAttributesCondition.isMatched(request));
+		Assert.assertTrue("request.userGroups should have 2 entries", userGroupsLenCondition.isMatched(request));
+		Assert.assertTrue("request.userGroups should have test-group1", userGroupsHas1Condition.isMatched(request));
+		Assert.assertTrue("request.userGroups should have test-group2", userGroupsHas2Condition.isMatched(request));
+		Assert.assertTrue("request.userRoles should have 2 entries", userRolesLenCondition.isMatched(request));
+		Assert.assertTrue("request.userRoles should have test-role1", userRolesHas1Condition.isMatched(request));
+		Assert.assertTrue("request.userRoles should have test-role2", userRolesHas2Condition.isMatched(request));
+		Assert.assertTrue("request.userAttributes should have 3 entries", userAttrLenCondition.isMatched(request));
+		Assert.assertTrue("request.userAttributes[attr1] should be test-user-value1", userAttr1Condition.isMatched(request));
+		Assert.assertTrue("request.userAttributes[attr2] should be test-user-value2", userAttr2Condition.isMatched(request));
+		Assert.assertTrue("request.userGroup1Attributes[attr1] should be test-group1-value1", userGroup1Attr1Condition.isMatched(request));
+		Assert.assertTrue("request.userGroup1Attributes[attr2] should be test-group1-value2", userGroup1Attr2Condition.isMatched(request));
+		Assert.assertTrue("request.userGroup2Attributes[attr1] should be test-group2-value1", userGroup2Attr1Condition.isMatched(request));
+		Assert.assertTrue("request.userGroup2Attributes[attr2] should be test-group2-value2", userGroup2Attr2Condition.isMatched(request));
+		Assert.assertTrue("tag._type should be PCI", tagTypeCondition.isMatched(request));
+		Assert.assertTrue("tag.attr1 should be PCI_value", tagAttributesCondition.isMatched(request));
 		Assert.assertTrue("should have 2 tags", tagsLengthCondition.isMatched(request));
 		Assert.assertTrue("tags PCI and PII should be found", tagsTypeCondition.isMatched(request));
 		Assert.assertTrue("tag attributes for PCI and PII should be found", tagsAttributesCondition.isMatched(request));
@@ -204,12 +227,15 @@ public class RangerCustomConditionMatcherTest {
 	RangerScriptConditionEvaluator createScriptConditionEvaluator(String script) {
 		RangerScriptConditionEvaluator ret = new RangerScriptConditionEvaluator();
 
+		RangerServiceDef          serviceDef   = mock(RangerServiceDef.class);
 		RangerPolicyConditionDef  conditionDef = mock(RangerPolicyConditionDef.class);
 		RangerPolicyItemCondition condition    = mock(RangerPolicyItemCondition.class);
 
+		when(serviceDef.getName()).thenReturn("test");
 		when(conditionDef.getEvaluatorOptions()).thenReturn(Collections.singletonMap(SCRIPT_OPTION_ENABLE_JSON_CTX, "true"));
 		when(condition.getValues()).thenReturn(Arrays.asList(script));
 
+		ret.setServiceDef(serviceDef);
 		ret.setConditionDef(conditionDef);
 		ret.setPolicyItemCondition(condition);
 
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerRequestScriptEvaluatorTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerRequestScriptEvaluatorTest.java
new file mode 100644
index 0000000..798da05
--- /dev/null
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerRequestScriptEvaluatorTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.conditionevaluator;
+
+import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
+import org.apache.ranger.plugin.model.RangerTag;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResource;
+import org.apache.ranger.plugin.policyengine.RangerRequestScriptEvaluator;
+import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
+import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
+import org.apache.ranger.plugin.util.RangerUserStore;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class RangerRequestScriptEvaluatorTest {
+    final String              engineName   = "JavaScript";
+    final ScriptEngineManager manager      = new ScriptEngineManager();
+    final ScriptEngine        scriptEngine = manager.getEngineByName(engineName);
+
+    @Test
+    public void testRequestAttributes() {
+        RangerAccessRequest          request   = createRequest(Arrays.asList("PII", "PCI"));
+        RangerRequestScriptEvaluator evaluator = new RangerRequestScriptEvaluator(request);
+
+        Assert.assertTrue("test: USER._name is 'test-user'", (Boolean) evaluator.evaluateScript(scriptEngine, "USER._name == 'test-user'"));
+        Assert.assertTrue("test: USER['state'] is 'CA'", (Boolean) evaluator.evaluateScript(scriptEngine, "USER['state'] == 'CA'"));
+        Assert.assertTrue("test: USER.state is 'CA'", (Boolean) evaluator.evaluateScript(scriptEngine, "USER.state == 'CA'"));
+
+        Assert.assertTrue("test: UGROUPS has test-group1", (Boolean)evaluator.evaluateScript(scriptEngine, "UGROUPS.indexOf('test-group1') != -1"));
+        Assert.assertTrue("test: UGROUPS has test-group2", (Boolean)evaluator.evaluateScript(scriptEngine, "UGROUPS.indexOf('test-group2') != -1"));
+        Assert.assertTrue("test: UGROUPS doesn't have test-group3", (Boolean)evaluator.evaluateScript(scriptEngine, "UGROUPS.indexOf('test-group3') == -1"));
+        Assert.assertTrue("test: UGROUP['test-group1'].dept is 'ENGG'", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group1'].dept == 'ENGG'"));
+        Assert.assertTrue("test: UGROUP['test-group1'].site is 10", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group1'].site == 10"));
+        Assert.assertTrue("test: UGROUP['test-group2'].dept is 'PROD'", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group2'].dept == 'PROD'"));
+        Assert.assertTrue("test: UGROUP['test-group2'].site is 20", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group2'].site == 20"));
+        Assert.assertTrue("test: UGROUP['test-group3'] is null", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group3'] == null"));
+        Assert.assertTrue("test: UGROUP['test-group1'].notExists is null", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group1'].notExists == null"));
+
+        Assert.assertTrue("test: UROLES has test-role1", (Boolean)evaluator.evaluateScript(scriptEngine, "UROLES.indexOf('test-role1') != -1"));
+        Assert.assertTrue("test: UROLES has test-role2", (Boolean)evaluator.evaluateScript(scriptEngine, "UROLES.indexOf('test-role2') != -1"));
+        Assert.assertTrue("test: UROLES doesn't have test-role3", (Boolean)evaluator.evaluateScript(scriptEngine, "UROLES.indexOf('test-role3') == -1"));
+
+        Assert.assertTrue("test: UGA.sVal['dept'] is 'ENGG'", (Boolean)evaluator.evaluateScript(scriptEngine, "UGA.sVal['dept'] == 'ENGG'"));
+        Assert.assertTrue("test: UGA.sVal['site'] is 10", (Boolean) evaluator.evaluateScript(scriptEngine, "UGA.sVal['site'] == 10"));
+        Assert.assertTrue("test: UGA.sVal['notExists'] is null", (Boolean) evaluator.evaluateScript(scriptEngine, "UGA.sVal['notExists'] == null"));
+        Assert.assertTrue("test: UGA.mVal['dept'] is [\"ENGG\", \"PROD\"]", (Boolean) evaluator.evaluateScript(scriptEngine, "J(UGA.mVal['dept']) == '[\"ENGG\",\"PROD\"]'"));
+        Assert.assertTrue("test: UGA.mVal['site'] is [10, 20]", (Boolean) evaluator.evaluateScript(scriptEngine, "J(UGA.mVal['site']) == '[\"10\",\"20\"]'"));
+        Assert.assertTrue("test: UGA.mVal['notExists'] is null", (Boolean) evaluator.evaluateScript(scriptEngine, "UGA.mVal['notExists'] == null"));
+        Assert.assertTrue("test: UGA.mVal['dept'] has 'ENGG'", (Boolean) evaluator.evaluateScript(scriptEngine, "UGA.mVal['dept'].indexOf('ENGG') != -1"));
+        Assert.assertTrue("test: UGA.mVal['dept'] has 'PROD'", (Boolean) evaluator.evaluateScript(scriptEngine, "UGA.mVal['dept'].indexOf('PROD') != -1"));
+        Assert.assertTrue("test: UGA.mVal['dept'] doesn't have 'EXEC'", (Boolean) evaluator.evaluateScript(scriptEngine, "UGA.mVal['dept'].indexOf('EXEC') == -1"));
+
+        Assert.assertTrue("test: REQ.accessTyp is 'select'", (Boolean) evaluator.evaluateScript(scriptEngine, "REQ.accessType == 'select'"));
+        Assert.assertTrue("test: REQ.action is 'query'", (Boolean) evaluator.evaluateScript(scriptEngine, "REQ.action == 'query'"));
+
+        Assert.assertTrue("test: RES._ownerUser is 'testUser'", (Boolean) evaluator.evaluateScript(scriptEngine, "RES._ownerUser == 'testUser'"));
+        Assert.assertTrue("test: RES.database is 'db1'", (Boolean) evaluator.evaluateScript(scriptEngine, "RES.database == 'db1'"));
+        Assert.assertTrue("test: RES.table is 'tbl1'", (Boolean) evaluator.evaluateScript(scriptEngine, "RES.table == 'tbl1'"));
+        Assert.assertTrue("test: RES.column is 'col1'", (Boolean) evaluator.evaluateScript(scriptEngine, "RES.column == 'col1'"));
+
+        Assert.assertTrue("test: TAG._type is 'PII'", (Boolean) evaluator.evaluateScript(scriptEngine, "TAG._type == 'PII'"));
+        Assert.assertTrue("test: TAG.attr1 is 'PII_value'", (Boolean) evaluator.evaluateScript(scriptEngine, "TAG.attr1 == 'PII_value'"));
+        Assert.assertTrue("test: TAGS.length is 2", (Boolean) evaluator.evaluateScript(scriptEngine, "TAGS.length == 2"));
+        Assert.assertTrue("test: TAGS has PII and PCI", (Boolean) evaluator.evaluateScript(scriptEngine, "TAGS[0]._type == 'PCI' ? TAGS[1]._type == 'PII' : TAGS[0]._type == 'PII' && TAGS[1]._type == 'PCI'"));
+        Assert.assertTrue("test: TAGS has PII.attr1=PII_value and PCI.attr1=PCI_value", (Boolean) evaluator.evaluateScript(scriptEngine, "TAGS[0]._type == 'PCI' ? (TAGS[0].attr1 == 'PCI_value' && TAGS[1].attr1 == 'PII_value') : (TAGS[0].attr1 == 'PII_value' && TAGS[1].attr1 == 'PCI_value')"));
+
+        Assert.assertTrue("test: TAGNAMES.length is 2", (Boolean) evaluator.evaluateScript(scriptEngine, "TAGNAMES.length == 2"));
+        Assert.assertTrue("test: TAGNAMES has 'PII'", (Boolean)evaluator.evaluateScript(scriptEngine, "TAGNAMES.indexOf('PII') != -1"));
+        Assert.assertTrue("test: TAGNAMES has 'PCI'", (Boolean)evaluator.evaluateScript(scriptEngine, "TAGNAMES.indexOf('PCI') != -1"));
+    }
+
+
+    RangerAccessRequest createRequest(List<String> resourceTags) {
+        RangerAccessResource resource = mock(RangerAccessResource.class);
+
+        Map<String, Object> resourceMap = new HashMap<>();
+
+        resourceMap.put("database", "db1");
+        resourceMap.put("table", "tbl1");
+        resourceMap.put("column", "col1");
+
+        when(resource.getAsString()).thenReturn("db1/tbl1/col1");
+        when(resource.getOwnerUser()).thenReturn("testUser");
+        when(resource.getAsMap()).thenReturn(resourceMap);
+        when(resource.getReadOnlyCopy()).thenReturn(resource);
+
+        RangerAccessRequestImpl request = new RangerAccessRequestImpl();
+
+        request.setResource(resource);
+        request.setResourceMatchingScope(RangerAccessRequest.ResourceMatchingScope.SELF);
+        request.setAccessType("select");
+        request.setAction("query");
+        request.setUser("test-user");
+        request.setUserGroups(new HashSet<>(Arrays.asList("test-group1", "test-group2")));
+        request.setUserRoles(new HashSet<>(Arrays.asList("test-role1", "test-role2")));
+
+        RangerAccessRequestUtil.setCurrentResourceInContext(request.getContext(), resource);
+
+        if (resourceTags != null) {
+            Set<RangerTagForEval> rangerTagForEvals = new HashSet<>();
+            RangerTagForEval      currentTag        = null;
+
+            for (String resourceTag : resourceTags) {
+                RangerTag tag        = new RangerTag(UUID.randomUUID().toString(), resourceTag, Collections.singletonMap("attr1", resourceTag + "_value"), null, null, null);
+                RangerTagForEval tagForEval = new RangerTagForEval(tag, RangerPolicyResourceMatcher.MatchType.SELF);
+
+                rangerTagForEvals.add(tagForEval);
+
+                if (currentTag == null) {
+                    currentTag = tagForEval;
+                }
+            }
+
+            RangerAccessRequestUtil.setRequestTagsInContext(request.getContext(), rangerTagForEvals);
+            RangerAccessRequestUtil.setCurrentTagInContext(request.getContext(), currentTag);
+        }  else {
+            RangerAccessRequestUtil.setRequestTagsInContext(request.getContext(), null);
+        }
+
+        RangerUserStore userStore = mock(RangerUserStore.class);
+
+        RangerAccessRequestUtil.setRequestUserStoreInContext(request.getContext(), userStore);
+
+        Map<String, Map<String, String>> userAttrMapping  = Collections.singletonMap("test-user", Collections.singletonMap("state", "CA"));
+        Map<String, Map<String, String>> groupAttrMapping = new HashMap<>();
+
+        groupAttrMapping.put("test-group1", new HashMap<String, String>() {{ put("dept", "ENGG"); put("site", "10"); }});
+        groupAttrMapping.put("test-group2", new HashMap<String, String>() {{ put("dept", "PROD"); put("site", "20"); }});
+
+        when(userStore.getUserAttrMapping()).thenReturn(userAttrMapping);
+        when(userStore.getGroupAttrMapping()).thenReturn(groupAttrMapping);
+
+        return request;
+    }
+
+}
\ No newline at end of file