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