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 2022/01/04 23:26:10 UTC
[ranger] branch ranger-2.3 updated: RANGER-3567: support request expressions in policy resources
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
The following commit(s) were added to refs/heads/ranger-2.3 by this push:
new 6488213 RANGER-3567: support request expressions in policy resources
6488213 is described below
commit 64882134083c87790eb94b4f5504eeb10c70f82c
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Sun Dec 26 23:53:13 2021 -0800
RANGER-3567: support request expressions in policy resources
(cherry picked from commit 56bac60551f77f582bdb9693705a8c8682b17b56)
---
.../policyengine/RangerAccessRequestImpl.java | 19 +++-
.../policyengine/RangerRequestScriptEvaluator.java | 8 +-
.../plugin/policyengine/RangerResourceTrie.java | 6 ++
.../RangerAbstractResourceMatcher.java | 79 +++++++-------
.../resourcematcher/RangerPathResourceMatcher.java | 36 +++----
.../resourcematcher/RangerURLResourceMatcher.java | 28 ++---
.../plugin/resourcematcher/ResourceMatcher.java | 38 +++++--
.../plugin/util/RangerAccessRequestUtil.java | 29 ++++++
.../plugin/util/RangerRequestExprResolver.java | 1 +
.../ranger/plugin/util/StringTokenReplacer.java | 7 +-
.../plugin/policyengine/TestPolicyEngine.java | 20 ++++
...policyengine_resource_with_req_expressions.json | 113 +++++++++++++++++++++
12 files changed, 298 insertions(+), 86 deletions(-)
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java
index 8bfc161..a22b8b6 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java
@@ -30,6 +30,7 @@ import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
+import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
public class RangerAccessRequestImpl implements RangerAccessRequest {
private static final Logger LOG = Logger.getLogger(RangerAccessRequestImpl.class);
@@ -256,7 +257,17 @@ public class RangerAccessRequestImpl implements RangerAccessRequest {
public void setResourceMatchingScope(ResourceMatchingScope scope) { this.resourceMatchingScope = scope; }
public void setContext(Map<String, Object> context) {
- this.context = (context == null) ? new HashMap<String, Object>() : context;
+ if (context == null) {
+ this.context = new HashMap<>();
+ } else {
+ this.context = context;
+ }
+
+ RangerAccessRequest current = RangerAccessRequestUtil.getRequestFromContext(this.context);
+
+ if (current == null) {
+ RangerAccessRequestUtil.setRequestInContext(this);
+ }
}
public void extractAndSetClientIPAddress(boolean useForwardedIPAddress, String[]trustedProxyAddresses) {
@@ -344,7 +355,11 @@ public class RangerAccessRequestImpl implements RangerAccessRequest {
sb.append("context={");
if(context != null) {
for(Map.Entry<String, Object> e : context.entrySet()) {
- sb.append(e.getKey()).append("={").append(e.getValue()).append("} ");
+ Object val = e.getValue();
+
+ if (!(val instanceof RangerAccessRequest)) { // to avoid recursive calls
+ sb.append(e.getKey()).append("={").append(val).append("} ");
+ }
}
}
sb.append("} ");
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
index d99a7d5..6f12b1b 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
@@ -324,10 +324,6 @@ public final class RangerRequestScriptEvaluator {
return ret;
}
- public Map<String, Object> getRequestContext() {
- return accessRequest.getContext();
- }
-
public String getRequestContextAttribute(String attributeName) {
String ret = null;
@@ -604,6 +600,10 @@ public final class RangerRequestScriptEvaluator {
return ret;
}
+ private Map<String, Object> getRequestContext() {
+ return accessRequest.getContext();
+ }
+
private Set<RangerTagForEval> getAllTags() {
Set<RangerTagForEval> ret = RangerAccessRequestUtil.getRequestTagsFromContext(accessRequest.getContext());
if(ret == null) {
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java
index 7c37e05..13dacf8 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java
@@ -31,6 +31,7 @@ import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceEvalua
import org.apache.ranger.plugin.resourcematcher.RangerAbstractResourceMatcher;
import org.apache.ranger.plugin.resourcematcher.RangerResourceMatcher;
import org.apache.ranger.plugin.util.RangerPerfTracer;
+import org.apache.ranger.plugin.util.RangerRequestExprResolver;
import org.apache.ranger.plugin.util.ServiceDefUtil;
import java.util.ArrayList;
@@ -121,6 +122,7 @@ public class RangerResourceTrie<T extends RangerPolicyResourceEvaluator> {
Map<String, String> matcherOptions = resourceDef.getMatcherOptions();
boolean optReplaceTokens = RangerAbstractResourceMatcher.getOptionReplaceTokens(matcherOptions);
+ boolean optReplaceReqExpressions = RangerAbstractResourceMatcher.getOptionReplaceReqExpressions(matcherOptions);
String tokenReplaceSpecialChars = "";
if(optReplaceTokens) {
@@ -133,6 +135,10 @@ public class RangerResourceTrie<T extends RangerPolicyResourceEvaluator> {
tokenReplaceSpecialChars += delimiterEscape;
}
+ if (optReplaceReqExpressions) {
+ tokenReplaceSpecialChars += RangerRequestExprResolver.EXPRESSION_START.charAt(0);
+ }
+
this.resourceDef = resourceDef;
this.optIgnoreCase = RangerAbstractResourceMatcher.getOptionIgnoreCase(matcherOptions);
this.optWildcard = RangerAbstractResourceMatcher.getOptionWildCard(matcherOptions);
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java
index 7841838..beb9bc7 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java
@@ -40,15 +40,16 @@ public abstract class RangerAbstractResourceMatcher implements RangerResourceMat
public final static String WILDCARD_ASTERISK = "*";
- public final static String OPTION_IGNORE_CASE = "ignoreCase";
- public final static String OPTION_QUOTED_CASE_SENSITIVE = "quotedCaseSensitive";
- public final static String OPTION_QUOTE_CHARS = "quoteChars";
- public final static String OPTION_WILD_CARD = "wildCard";
- public final static String OPTION_REPLACE_TOKENS = "replaceTokens";
- public final static String OPTION_TOKEN_DELIMITER_START = "tokenDelimiterStart";
- public final static String OPTION_TOKEN_DELIMITER_END = "tokenDelimiterEnd";
- public final static String OPTION_TOKEN_DELIMITER_ESCAPE = "tokenDelimiterEscape";
- public final static String OPTION_TOKEN_DELIMITER_PREFIX = "tokenDelimiterPrefix";
+ public final static String OPTION_IGNORE_CASE = "ignoreCase";
+ public final static String OPTION_QUOTED_CASE_SENSITIVE = "quotedCaseSensitive";
+ public final static String OPTION_QUOTE_CHARS = "quoteChars";
+ public final static String OPTION_WILD_CARD = "wildCard";
+ public final static String OPTION_REPLACE_TOKENS = "replaceTokens";
+ public final static String OPTION_TOKEN_DELIMITER_START = "tokenDelimiterStart";
+ public final static String OPTION_TOKEN_DELIMITER_END = "tokenDelimiterEnd";
+ public final static String OPTION_TOKEN_DELIMITER_ESCAPE = "tokenDelimiterEscape";
+ public final static String OPTION_TOKEN_DELIMITER_PREFIX = "tokenDelimiterPrefix";
+ public final static String OPTION_REPLACE_REQ_EXPRESSIONS = "replaceReqExpressions";
protected RangerResourceDef resourceDef;
protected RangerPolicyResource policyResource;
@@ -181,6 +182,12 @@ public abstract class RangerAbstractResourceMatcher implements RangerResourceMat
return ServiceDefUtil.getOption(options, OPTION_TOKEN_DELIMITER_PREFIX, "");
}
+ public static boolean getOptionReplaceReqExpressions(Map<String, String> options) {
+ return ServiceDefUtil.getBooleanOption(options, OPTION_REPLACE_REQ_EXPRESSIONS, true);
+ }
+
+ protected Map<String, String> getOptions() { return resourceDef != null ? resourceDef.getMatcherOptions() : null; }
+
protected ResourceMatcherWrapper buildResourceMatchers() {
List<ResourceMatcher> resourceMatchers = new ArrayList<>();
boolean needsDynamicEval = false;
@@ -362,17 +369,17 @@ public abstract class RangerAbstractResourceMatcher implements RangerResourceMat
}
if (needWildcardMatch) { // test?, test*a*, test*a*b, *test*a
- ret = optIgnoreCase ? (optQuotedCaseSensitive ? new QuotedCaseSensitiveWildcardMatcher(policyValue, optQuoteChars) : new CaseInsensitiveWildcardMatcher(policyValue)) : new CaseSensitiveWildcardMatcher(policyValue);
+ ret = optIgnoreCase ? (optQuotedCaseSensitive ? new QuotedCaseSensitiveWildcardMatcher(policyValue, getOptions(), optQuoteChars) : new CaseInsensitiveWildcardMatcher(policyValue, getOptions())) : new CaseSensitiveWildcardMatcher(policyValue, getOptions());
} else if (wildcardStartIdx == -1) { // test, testa, testab
- ret = optIgnoreCase ? (optQuotedCaseSensitive ? new QuotedCaseSensitiveStringMatcher(policyValue, optQuoteChars) : new CaseInsensitiveStringMatcher(policyValue)) : new CaseSensitiveStringMatcher(policyValue);
+ ret = optIgnoreCase ? (optQuotedCaseSensitive ? new QuotedCaseSensitiveStringMatcher(policyValue, getOptions(), optQuoteChars) : new CaseInsensitiveStringMatcher(policyValue, getOptions())) : new CaseSensitiveStringMatcher(policyValue, getOptions());
} else if (wildcardStartIdx == 0) { // *test, **test, *testa, *testab
String matchStr = policyValue.substring(wildcardEndIdx + 1);
- ret = optIgnoreCase ? (optQuotedCaseSensitive ? new QuotedCaseSensitiveEndsWithMatcher(matchStr, optQuoteChars) : new CaseInsensitiveEndsWithMatcher(matchStr)) : new CaseSensitiveEndsWithMatcher(matchStr);
+ ret = optIgnoreCase ? (optQuotedCaseSensitive ? new QuotedCaseSensitiveEndsWithMatcher(matchStr, getOptions(), optQuoteChars) : new CaseInsensitiveEndsWithMatcher(matchStr, getOptions())) : new CaseSensitiveEndsWithMatcher(matchStr, getOptions());
} else if (wildcardEndIdx != (len - 1)) { // test*a, test*ab
- ret = optIgnoreCase ? (optQuotedCaseSensitive ? new QuotedCaseSensitiveWildcardMatcher(policyValue, optQuoteChars) : new CaseInsensitiveWildcardMatcher(policyValue)) : new CaseSensitiveWildcardMatcher(policyValue);
+ ret = optIgnoreCase ? (optQuotedCaseSensitive ? new QuotedCaseSensitiveWildcardMatcher(policyValue, getOptions(), optQuoteChars) : new CaseInsensitiveWildcardMatcher(policyValue, getOptions())) : new CaseSensitiveWildcardMatcher(policyValue, getOptions());
} else { // test*, test**, testa*, testab*
String matchStr = policyValue.substring(0, wildcardStartIdx);
- ret = optIgnoreCase ? (optQuotedCaseSensitive ? new QuotedCaseSensitiveStartsWithMatcher(matchStr, optQuoteChars) : new CaseInsensitiveStartsWithMatcher(matchStr)) : new CaseSensitiveStartsWithMatcher(matchStr);
+ ret = optIgnoreCase ? (optQuotedCaseSensitive ? new QuotedCaseSensitiveStartsWithMatcher(matchStr, getOptions(), optQuoteChars) : new CaseInsensitiveStartsWithMatcher(matchStr, getOptions())) : new CaseSensitiveStartsWithMatcher(matchStr, getOptions());
}
if(optReplaceTokens) {
@@ -384,8 +391,8 @@ public abstract class RangerAbstractResourceMatcher implements RangerResourceMat
}
final class CaseSensitiveStringMatcher extends ResourceMatcher {
- CaseSensitiveStringMatcher(String value) {
- super(value);
+ CaseSensitiveStringMatcher(String value, Map<String, String> options) {
+ super(value, options);
}
@Override
@@ -396,7 +403,7 @@ final class CaseSensitiveStringMatcher extends ResourceMatcher {
}
final class CaseInsensitiveStringMatcher extends ResourceMatcher {
- CaseInsensitiveStringMatcher(String value) { super(value); }
+ CaseInsensitiveStringMatcher(String value, Map<String, String> options) { super(value, options); }
@Override
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
@@ -408,8 +415,8 @@ final class CaseInsensitiveStringMatcher extends ResourceMatcher {
final class QuotedCaseSensitiveStringMatcher extends ResourceMatcher {
private final String quoteChars;
- QuotedCaseSensitiveStringMatcher(String value, String quoteChars) {
- super(value);
+ QuotedCaseSensitiveStringMatcher(String value, Map<String, String> options, String quoteChars) {
+ super(value, options);
this.quoteChars = quoteChars;
}
@@ -427,8 +434,8 @@ final class QuotedCaseSensitiveStringMatcher extends ResourceMatcher {
}
final class CaseSensitiveStartsWithMatcher extends ResourceMatcher {
- CaseSensitiveStartsWithMatcher(String value) {
- super(value);
+ CaseSensitiveStartsWithMatcher(String value, Map<String, String> options) {
+ super(value, options);
}
@Override
@@ -439,7 +446,7 @@ final class CaseSensitiveStartsWithMatcher extends ResourceMatcher {
}
final class CaseInsensitiveStartsWithMatcher extends ResourceMatcher {
- CaseInsensitiveStartsWithMatcher(String value) { super(value); }
+ CaseInsensitiveStartsWithMatcher(String value, Map<String, String> options) { super(value, options); }
@Override
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
@@ -451,8 +458,8 @@ final class CaseInsensitiveStartsWithMatcher extends ResourceMatcher {
final class QuotedCaseSensitiveStartsWithMatcher extends ResourceMatcher {
private final String quoteChars;
- QuotedCaseSensitiveStartsWithMatcher(String value, String quoteChars) {
- super(value);
+ QuotedCaseSensitiveStartsWithMatcher(String value, Map<String, String> options, String quoteChars) {
+ super(value, options);
this.quoteChars = quoteChars;
}
@@ -470,8 +477,8 @@ final class QuotedCaseSensitiveStartsWithMatcher extends ResourceMatcher {
}
final class CaseSensitiveEndsWithMatcher extends ResourceMatcher {
- CaseSensitiveEndsWithMatcher(String value) {
- super(value);
+ CaseSensitiveEndsWithMatcher(String value, Map<String, String> options) {
+ super(value, options);
}
@Override
@@ -482,8 +489,8 @@ final class CaseSensitiveEndsWithMatcher extends ResourceMatcher {
}
final class CaseInsensitiveEndsWithMatcher extends ResourceMatcher {
- CaseInsensitiveEndsWithMatcher(String value) {
- super(value);
+ CaseInsensitiveEndsWithMatcher(String value, Map<String, String> options) {
+ super(value, options);
}
@Override
@@ -496,8 +503,8 @@ final class CaseInsensitiveEndsWithMatcher extends ResourceMatcher {
final class QuotedCaseSensitiveEndsWithMatcher extends ResourceMatcher {
private final String quoteChars;
- QuotedCaseSensitiveEndsWithMatcher(String value, String quoteChars) {
- super(value);
+ QuotedCaseSensitiveEndsWithMatcher(String value, Map<String, String> options, String quoteChars) {
+ super(value, options);
this.quoteChars = quoteChars;
}
@@ -515,8 +522,8 @@ final class QuotedCaseSensitiveEndsWithMatcher extends ResourceMatcher {
}
final class CaseSensitiveWildcardMatcher extends ResourceMatcher {
- CaseSensitiveWildcardMatcher(String value) {
- super(value);
+ CaseSensitiveWildcardMatcher(String value, Map<String, String> options) {
+ super(value, options);
}
@Override
@@ -528,8 +535,8 @@ final class CaseSensitiveWildcardMatcher extends ResourceMatcher {
final class CaseInsensitiveWildcardMatcher extends ResourceMatcher {
- CaseInsensitiveWildcardMatcher(String value) {
- super(value);
+ CaseInsensitiveWildcardMatcher(String value, Map<String, String> options) {
+ super(value, options);
}
@Override
@@ -542,8 +549,8 @@ final class CaseInsensitiveWildcardMatcher extends ResourceMatcher {
final class QuotedCaseSensitiveWildcardMatcher extends ResourceMatcher {
private final String quoteChars;
- QuotedCaseSensitiveWildcardMatcher(String value, String quoteChars) {
- super(value);
+ QuotedCaseSensitiveWildcardMatcher(String value, Map<String, String> options, String quoteChars) {
+ super(value, options);
this.quoteChars = quoteChars;
}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java
index 43297d6..46e10f2 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java
@@ -111,7 +111,7 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
// To ensure that when policyValue is single '*', ResourceMatcher created here returns true for isMatchAny()
if (optWildCard && WILDCARD_ASTERISK.equals(policyValue)) {
- return new CaseInsensitiveStringMatcher("");
+ return new CaseInsensitiveStringMatcher("", getOptions());
}
boolean isWildcardPresent = false;
@@ -130,9 +130,9 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
final ResourceMatcher ret;
if (isWildcardPresent) {
- ret = new RecursiveWildcardResourceMatcher(policyValue, pathSeparatorChar, optIgnoreCase, RangerPathResourceMatcher::isRecursiveWildCardMatch, optIgnoreCase ? 8 : 7);
+ ret = new RecursiveWildcardResourceMatcher(policyValue, getOptions(), pathSeparatorChar, optIgnoreCase, RangerPathResourceMatcher::isRecursiveWildCardMatch, optIgnoreCase ? 8 : 7);
} else {
- ret = new RecursivePathResourceMatcher(policyValue, pathSeparatorChar, optIgnoreCase ? StringUtils::equalsIgnoreCase : StringUtils::equals, optIgnoreCase ? StringUtils::startsWithIgnoreCase : StringUtils::startsWith, optIgnoreCase ? 8 : 7);
+ ret = new RecursivePathResourceMatcher(policyValue, getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::equalsIgnoreCase : StringUtils::equals, optIgnoreCase ? StringUtils::startsWithIgnoreCase : StringUtils::startsWith, optIgnoreCase ? 8 : 7);
}
if (optReplaceTokens) {
@@ -233,17 +233,17 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
}
if (needWildcardMatch) { // test?, test*a*, test*a*b, *test*a
- ret = new WildcardResourceMatcher(policyValue, pathSeparatorChar, optIgnoreCase, FilenameUtils::wildcardMatch, 6);
+ ret = new WildcardResourceMatcher(policyValue, getOptions(), pathSeparatorChar, optIgnoreCase, FilenameUtils::wildcardMatch, 6);
} else if (wildcardStartIdx == -1) { // test, testa, testab
- ret = new StringResourceMatcher(policyValue, pathSeparatorChar, optIgnoreCase ? StringUtils::equalsIgnoreCase : StringUtils::equals, optIgnoreCase ? 2 : 1);
+ ret = new StringResourceMatcher(policyValue, getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::equalsIgnoreCase : StringUtils::equals, optIgnoreCase ? 2 : 1);
} else if (wildcardStartIdx == 0) { // *test, **test, *testa, *testab
String matchStr = policyValue.substring(wildcardEndIdx + 1);
- ret = new StringResourceMatcher(matchStr, pathSeparatorChar, optIgnoreCase ? StringUtils::endsWithIgnoreCase : StringUtils::endsWith, optIgnoreCase ? 4 : 3);
+ ret = new StringResourceMatcher(matchStr, getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::endsWithIgnoreCase : StringUtils::endsWith, optIgnoreCase ? 4 : 3);
} else if (wildcardEndIdx != (len - 1)) { // test*a, test*ab
- ret = new WildcardResourceMatcher(policyValue, pathSeparatorChar, optIgnoreCase, FilenameUtils::wildcardMatch, 6);
+ ret = new WildcardResourceMatcher(policyValue, getOptions(), pathSeparatorChar, optIgnoreCase, FilenameUtils::wildcardMatch, 6);
} else { // test*, test**, testa*, testab*
String matchStr = policyValue.substring(0, wildcardStartIdx);
- ret = new StringResourceMatcher(matchStr, pathSeparatorChar, optIgnoreCase ? StringUtils::startsWithIgnoreCase : StringUtils::startsWith, optIgnoreCase ? 4 : 3);
+ ret = new StringResourceMatcher(matchStr, getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::startsWithIgnoreCase : StringUtils::startsWith, optIgnoreCase ? 4 : 3);
}
if (optReplaceTokens) {
@@ -265,8 +265,8 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
final char pathSeparatorChar;
final int priority;
- PathResourceMatcher(String value, char pathSeparatorChar, int priority) {
- super(value);
+ PathResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, int priority) {
+ super(value, options);
this.pathSeparatorChar = pathSeparatorChar;
this.priority = priority;
}
@@ -277,8 +277,8 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
static class StringResourceMatcher extends PathResourceMatcher {
final BiFunction<String, String, Boolean> function;
- StringResourceMatcher(String value, char pathSeparatorChar, BiFunction<String, String, Boolean> function, int priority) {
- super(value, pathSeparatorChar, priority);
+ StringResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, BiFunction<String, String, Boolean> function, int priority) {
+ super(value, options, pathSeparatorChar, priority);
this.function = function;
}
@Override
@@ -313,8 +313,8 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
final TriFunction<String, String, IOCase, Boolean> function;
final IOCase ioCase;
- WildcardResourceMatcher(String value, char pathSeparatorChar, boolean optIgnoreCase, TriFunction<String, String, IOCase, Boolean> function, int priority) {
- super(value, pathSeparatorChar, priority);
+ WildcardResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, boolean optIgnoreCase, TriFunction<String, String, IOCase, Boolean> function, int priority) {
+ super(value, options, pathSeparatorChar, priority);
this.function = function;
this.ioCase = optIgnoreCase ? IOCase.INSENSITIVE : IOCase.SENSITIVE;
}
@@ -349,8 +349,8 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
final QuadFunction<String, String, Character, IOCase, Boolean> function;
final IOCase ioCase;
- RecursiveWildcardResourceMatcher(String value, char pathSeparatorChar, boolean optIgnoreCase, QuadFunction<String, String, Character, IOCase, Boolean> function, int priority) {
- super(value, pathSeparatorChar, priority);
+ RecursiveWildcardResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, boolean optIgnoreCase, QuadFunction<String, String, Character, IOCase, Boolean> function, int priority) {
+ super(value, options, pathSeparatorChar, priority);
this.function = function;
this.ioCase = optIgnoreCase ? IOCase.INSENSITIVE : IOCase.SENSITIVE;
}
@@ -388,8 +388,8 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
final BiFunction<String, String, Boolean> primaryFunction;
final BiFunction<String, String, Boolean> fallbackFunction;
- RecursivePathResourceMatcher(String value, char pathSeparatorChar, BiFunction<String, String, Boolean> primaryFunction, BiFunction<String, String, Boolean> fallbackFunction, int priority) {
- super(value, pathSeparatorChar, priority);
+ RecursivePathResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, BiFunction<String, String, Boolean> primaryFunction, BiFunction<String, String, Boolean> fallbackFunction, int priority) {
+ super(value, options, pathSeparatorChar, priority);
this.primaryFunction = primaryFunction;
this.fallbackFunction = fallbackFunction;
}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcher.java
index 880e485..b28e169 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcher.java
@@ -110,7 +110,7 @@ public class RangerURLResourceMatcher extends RangerDefaultResourceMatcher {
// To ensure that when policyValue is single '*', ResourceMatcher created here returns true for isMatchAny()
if (optWildCard && WILDCARD_ASTERISK.equals(policyValue)) {
- return new CaseInsensitiveStringMatcher("");
+ return new CaseInsensitiveStringMatcher("", getOptions());
}
boolean isWildcardPresent = false;
@@ -129,10 +129,10 @@ public class RangerURLResourceMatcher extends RangerDefaultResourceMatcher {
final ResourceMatcher ret;
if (isWildcardPresent) {
- ret = optIgnoreCase ? new CaseInsensitiveURLRecursiveWildcardMatcher(policyValue, pathSeparatorChar)
- : new CaseSensitiveURLRecursiveWildcardMatcher(policyValue, pathSeparatorChar);
+ ret = optIgnoreCase ? new CaseInsensitiveURLRecursiveWildcardMatcher(policyValue, getOptions(), pathSeparatorChar)
+ : new CaseSensitiveURLRecursiveWildcardMatcher(policyValue, getOptions(), pathSeparatorChar);
} else {
- ret = optIgnoreCase ? new CaseInsensitiveURLRecursiveMatcher(policyValue, pathSeparatorChar) : new CaseSensitiveURLRecursiveMatcher(policyValue, pathSeparatorChar);
+ ret = optIgnoreCase ? new CaseInsensitiveURLRecursiveMatcher(policyValue, getOptions(), pathSeparatorChar) : new CaseSensitiveURLRecursiveMatcher(policyValue, getOptions(), pathSeparatorChar);
}
if (optReplaceTokens) {
@@ -223,8 +223,8 @@ public class RangerURLResourceMatcher extends RangerDefaultResourceMatcher {
final class CaseSensitiveURLRecursiveWildcardMatcher extends ResourceMatcher {
private final char levelSeparatorChar;
- CaseSensitiveURLRecursiveWildcardMatcher(String value, char levelSeparatorChar) {
- super(value);
+ CaseSensitiveURLRecursiveWildcardMatcher(String value, Map<String, String> options, char levelSeparatorChar) {
+ super(value, options);
this.levelSeparatorChar = levelSeparatorChar;
}
@@ -237,8 +237,8 @@ final class CaseSensitiveURLRecursiveWildcardMatcher extends ResourceMatcher {
final class CaseInsensitiveURLRecursiveWildcardMatcher extends ResourceMatcher {
private final char levelSeparatorChar;
- CaseInsensitiveURLRecursiveWildcardMatcher(String value, char levelSeparatorChar) {
- super(value);
+ CaseInsensitiveURLRecursiveWildcardMatcher(String value, Map<String, String> options, char levelSeparatorChar) {
+ super(value, options);
this.levelSeparatorChar = levelSeparatorChar;
}
@@ -255,8 +255,8 @@ abstract class RecursiveMatcher extends ResourceMatcher {
String valueWithoutSeparator;
String valueWithSeparator;
- RecursiveMatcher(String value, char levelSeparatorChar) {
- super(value);
+ RecursiveMatcher(String value, Map<String, String> options, char levelSeparatorChar) {
+ super(value, options);
this.levelSeparatorChar = levelSeparatorChar;
}
@@ -270,8 +270,8 @@ abstract class RecursiveMatcher extends ResourceMatcher {
}
final class CaseSensitiveURLRecursiveMatcher extends RecursiveMatcher {
- CaseSensitiveURLRecursiveMatcher(String value, char levelSeparatorChar) {
- super(value, levelSeparatorChar);
+ CaseSensitiveURLRecursiveMatcher(String value, Map<String, String> options, char levelSeparatorChar) {
+ super(value, options, levelSeparatorChar);
}
@Override
@@ -302,8 +302,8 @@ final class CaseSensitiveURLRecursiveMatcher extends RecursiveMatcher {
}
final class CaseInsensitiveURLRecursiveMatcher extends RecursiveMatcher {
- CaseInsensitiveURLRecursiveMatcher(String value, char levelSeparatorChar) {
- super(value, levelSeparatorChar);
+ CaseInsensitiveURLRecursiveMatcher(String value, Map<String, String> options, char levelSeparatorChar) {
+ super(value, options, levelSeparatorChar);
}
@Override
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java
index 6d8e293..abda58f 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java
@@ -22,6 +22,9 @@ package org.apache.ranger.plugin.resourcematcher;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
+import org.apache.ranger.plugin.util.RangerRequestExprResolver;
import org.apache.ranger.plugin.util.StringTokenReplacer;
import java.io.Serializable;
@@ -32,12 +35,21 @@ import java.util.Map;
abstract class ResourceMatcher {
private static final Log LOG = LogFactory.getLog(ResourceMatcher.class);
- protected final String value;
- protected StringTokenReplacer tokenReplacer;
+ protected final String value;
+ protected final RangerRequestExprResolver exprResolver;
+ protected StringTokenReplacer tokenReplacer;
static final int DYNAMIC_EVALUATION_PENALTY = 8;
- ResourceMatcher(String value) { this.value = value; }
+ ResourceMatcher(String value, Map<String, String> options) {
+ this.value = value;
+
+ if (RangerAbstractResourceMatcher.getOptionReplaceReqExpressions(options) && RangerRequestExprResolver.hasExpressions(value)) {
+ exprResolver = new RangerRequestExprResolver(value, null); // TODO: serviceType
+ } else {
+ exprResolver = null;
+ }
+ }
abstract boolean isMatch(String resourceValue, Map<String, Object> evalContext);
abstract int getPriority();
@@ -45,7 +57,7 @@ abstract class ResourceMatcher {
boolean isMatchAny() { return value != null && value.length() == 0; }
boolean getNeedsDynamicEval() {
- return tokenReplacer != null;
+ return exprResolver != null || tokenReplacer != null;
}
public boolean isMatchAny(Collection<String> resourceValues, Map<String, Object> evalContext) {
@@ -71,7 +83,7 @@ abstract class ResourceMatcher {
", endDelimiter=" + endDelimiterChar + ", escapeChar=" + escapeChar + ", prefix=" + tokenPrefix);
}
- if(value != null && (value.indexOf(escapeChar) != -1 || (value.indexOf(startDelimiterChar) != -1 && value.indexOf(endDelimiterChar) != -1))) {
+ if(exprResolver != null || StringTokenReplacer.hasToken(value, startDelimiterChar, endDelimiterChar, escapeChar)) {
tokenReplacer = new StringTokenReplacer(startDelimiterChar, endDelimiterChar, escapeChar, tokenPrefix);
}
@@ -82,12 +94,18 @@ abstract class ResourceMatcher {
}
String getExpandedValue(Map<String, Object> evalContext) {
- final String ret;
+ String ret = value;
- if(tokenReplacer != null) {
- ret = tokenReplacer.replaceTokens(value, evalContext);
- } else {
- ret = value;
+ if (exprResolver != null) {
+ RangerAccessRequest accessRequest = RangerAccessRequestUtil.getRequestFromContext(evalContext);
+
+ if (accessRequest != null) {
+ ret = exprResolver.resolveExpressions(accessRequest);
+ }
+ }
+
+ if (tokenReplacer != null) {
+ ret = tokenReplacer.replaceTokens(ret, evalContext);
}
return ret;
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
index 4740055..12bd473 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
@@ -29,6 +29,7 @@ import org.apache.commons.collections.MapUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
import org.apache.ranger.plugin.policyengine.RangerAccessResource;
public class RangerAccessRequestUtil {
@@ -45,6 +46,7 @@ public class RangerAccessRequestUtil {
public static final String KEY_ROLES = "ROLES";
public static final String KEY_CONTEXT_ACCESSTYPES = "ACCESSTYPES";
public static final String KEY_CONTEXT_IS_ANY_ACCESS = "ISANYACCESS";
+ public static final String KEY_CONTEXT_REQUEST = "_REQUEST";
public static void setRequestTagsInContext(Map<String, Object> context, Set<RangerTagForEval> tags) {
if(CollectionUtils.isEmpty(tags)) {
@@ -184,4 +186,31 @@ public class RangerAccessRequestUtil {
public static Boolean getIsAnyAccessInContext(Map<String, Object> context) {
return (Boolean)context.get(KEY_CONTEXT_IS_ANY_ACCESS);
}
+
+ public static void setRequestInContext(RangerAccessRequest request) {
+ Map<String, Object> context = request.getContext();
+
+ if (context != null) {
+ context.put(KEY_CONTEXT_REQUEST, request);
+ }
+ }
+
+ public static RangerAccessRequest getRequestFromContext(Map<String, Object> context) {
+ RangerAccessRequest ret = null;
+
+ if (context != null) {
+ Object val = context.get(KEY_CONTEXT_REQUEST);
+
+ if (val != null) {
+ if (val instanceof RangerAccessRequest) {
+ ret = (RangerAccessRequest) val;
+ } else {
+ LOG.error("getRequestFromContext(): expected RangerAccessRequest, but found " + val.getClass().getCanonicalName());
+ }
+ }
+ }
+
+ return ret;
+ }
+
}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java
index d70430b..ceffdda 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java
@@ -36,6 +36,7 @@ public class RangerRequestExprResolver {
private static final String REGEX_GROUP_EXPR = "expr";
private static final String SCRIPT_ENGINE_NAME = "JavaScript";
private static final Pattern PATTERN = Pattern.compile("\\$\\{\\{(?<" + REGEX_GROUP_EXPR + ">.*?)\\}\\}");
+ public static final String EXPRESSION_START = "${{";
private final String str;
private final String serviceType;
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/StringTokenReplacer.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/StringTokenReplacer.java
index 2d09d44..bf482ff 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/StringTokenReplacer.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/StringTokenReplacer.java
@@ -34,9 +34,12 @@ public class StringTokenReplacer {
this.tokenPrefix = tokenPrefix;
}
+ public static boolean hasToken(String value, char startDelimiterChar, char endDelimiterChar, char escapeChar) {
+ return value != null && (value.indexOf(escapeChar) != -1 || (value.indexOf(startDelimiterChar) != -1 && value.indexOf(endDelimiterChar) != -1));
+ }
+
public String replaceTokens(String value, Map<String, Object> tokens) {
- if(tokens == null || tokens.size() < 1 || value == null || value.length() < 1 ||
- (value.indexOf(startChar) == -1 && value.indexOf(endChar) == -1 && value.indexOf(escapeChar) == -1)) {
+ if(tokens == null || tokens.size() < 1 || !hasToken(value, startChar, endChar, escapeChar)) {
return value;
}
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
index 81c3744..9ba418a 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
@@ -28,6 +28,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ranger.audit.provider.AuditHandler;
import org.apache.ranger.audit.provider.AuditProviderFactory;
@@ -51,6 +52,7 @@ import org.apache.ranger.plugin.service.RangerBasePlugin;
import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
import org.apache.ranger.plugin.util.RangerRequestedResources;
import org.apache.ranger.plugin.util.RangerRoles;
+import org.apache.ranger.plugin.util.RangerUserStore;
import org.apache.ranger.plugin.util.ServicePolicies;
import org.apache.ranger.plugin.util.ServiceTags;
import org.junit.AfterClass;
@@ -449,6 +451,13 @@ public class TestPolicyEngine {
runTestsFromResourceFiles(awsTestResourceFiles);
}
+ @Test
+ public void testPolicyEngine_resourceWithReqExpressions() {
+ String[] resourceFiles = {"/policyengine/test_policyengine_resource_with_req_expressions.json"};
+
+ runTestsFromResourceFiles(resourceFiles);
+ }
+
private void runTestsFromResourceFiles(String[] resourceNames) {
for(String resourceName : resourceNames) {
InputStream inStream = this.getClass().getResourceAsStream(resourceName);
@@ -660,6 +669,15 @@ public class TestPolicyEngine {
RangerAccessResult expected = test.result;
RangerAccessResult result;
+ if (MapUtils.isNotEmpty(test.userAttributes) || MapUtils.isNotEmpty(test.groupAttributes)) {
+ RangerUserStore userStore = new RangerUserStore();
+
+ userStore.setUserAttrMapping(test.userAttributes);
+ userStore.setGroupAttrMapping(test.groupAttributes);
+
+ RangerAccessRequestUtil.setRequestUserStoreInContext(request.getContext(), userStore);
+ }
+
result = policyEngine.evaluatePolicies(request, RangerPolicy.POLICY_TYPE_ACCESS, auditHandler);
policyEngine.evaluateAuditPolicies(result);
@@ -771,6 +789,8 @@ public class TestPolicyEngine {
public RangerAccessResult dataMaskResult;
public RangerAccessResult rowFilterResult;
public RangerResourceAccessInfo resourceAccessInfo;
+ public Map<String, Map<String, String>> userAttributes;
+ public Map<String, Map<String, String>> groupAttributes;
}
class TagPolicyInfo {
diff --git a/agents-common/src/test/resources/policyengine/test_policyengine_resource_with_req_expressions.json b/agents-common/src/test/resources/policyengine/test_policyengine_resource_with_req_expressions.json
new file mode 100644
index 0000000..95e0c7c
--- /dev/null
+++ b/agents-common/src/test/resources/policyengine/test_policyengine_resource_with_req_expressions.json
@@ -0,0 +1,113 @@
+{
+ "serviceName":"hdfsdev",
+
+ "serviceDef":{
+ "name":"hdfs",
+ "id":1,
+ "resources":[
+ {"name":"path","type":"path","level":1,"mandatory":true,"lookupSupported":true,"recursiveSupported": true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher","matcherOptions":{"wildCard":true, "ignoreCase":true},"label":"Resource Path","description":"HDFS file or directory path"},
+ {"name":"path2","type":"path","level":1,"mandatory":true,"lookupSupported":true,"recursiveSupported": true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher","matcherOptions":{"wildCard":true, "ignoreCase":true, "replaceReqExpressions":false},"label":"Resource Path","description":"HDFS file or directory path"}
+ ],
+ "accessTypes":[
+ {"name":"read","label":"Read"},
+ {"name":"write","label":"Write"},
+ {"name":"execute","label":"Execute"}
+ ],
+ "contextEnrichers": [],
+ "policyConditions": []
+ },
+
+ "policies":[
+ {"id":10,"name":"allow-all-to-user /home/${{USER._name}}","isEnabled":true,"isAuditEnabled":true,
+ "resources":{"path":{"values":["/home/${{USER._name}}"],"isRecursive":false}},
+ "policyItems":[
+ {"accesses":[{"type":"read","isAllowed":true}, {"type":"write","isAllowed":true}, {"type":"execute","isAllowed":true}],"users":[],"groups":["public"],"delegateAdmin":false}
+ ]
+ },
+ {"id":20,"name":"allow-all-to-user1 /home/${{USER._name}}","isEnabled":true,"isAuditEnabled":true,
+ "resources":{"path2":{"values":["/home/${{USER._name}}"],"isRecursive":false}},
+ "policyItems":[
+ {"accesses":[{"type":"read","isAllowed":true}, {"type":"write","isAllowed":true}, {"type":"execute","isAllowed":true}],"users":[],"groups":["public"],"delegateAdmin":false}
+ ]
+ },
+ {"id":30,"name":"allow-all-to-user /home/${{USER._name}}/{USER}.data","isEnabled":true,"isAuditEnabled":true,
+ "resources":{"path":{"values":["/home/${{USER._name}}/{USER}.data"],"isRecursive":true}},
+ "policyItems":[
+ {"accesses":[{"type":"read","isAllowed":true}, {"type":"write","isAllowed":true}, {"type":"execute","isAllowed":true}],"users":[],"groups":["public"],"delegateAdmin":false}
+ ]
+ },
+ {"id":40,"name":"allow-all-to-user /test/${{USER.testAttr1}}","isEnabled":true,"isAuditEnabled":true,
+ "resources":{"path":{"values":["/test/${{USER.testAttr1}}"],"isRecursive":true}},
+ "policyItems":[
+ {"accesses":[{"type":"read","isAllowed":true}, {"type":"write","isAllowed":true}, {"type":"execute","isAllowed":true}],"users":[],"groups":["public"],"delegateAdmin":false}
+ ]
+ }
+ ],
+
+ "tests":[
+ {"name":"ALLOW 'write path2=/home/${{USER._name}}' for u=scott; no evaluation of request-expression",
+ "request":{
+ "resource":{"elements":{"path2":"/home/${{USER._name}}"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+ "accessType":"write","user":"scott","userGroups":[],"requestData":"write path2=/home/${{USER._name}}"
+ },
+ "result":{"isAudited":true,"isAllowed":true,"policyId": 20}
+ },
+ {"name":"DENY 'write path2=/home/scott' for u=scott; no evaluation of request-expression",
+ "request":{
+ "resource":{"elements":{"path2":"/home/scott"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+ "accessType":"write","user":"scott","userGroups":[],"requestData":"write path2=/home/scott"
+ },
+ "result":{"isAudited":false,"isAllowed":false,"policyId": -1}
+ },
+ {"name":"ALLOW 'write /home/scott' for u=scott for scope SELF_OR_CHILD",
+ "request":{
+ "resource":{"elements":{"path":"/home/scott"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+ "accessType":"write","user":"scott","userGroups":[],"requestData":"write /home/scott"
+ },
+ "result":{"isAudited":true,"isAllowed":true,"policyId": 10}
+ },
+ {"name":"DENY 'ANY /home/scott' for u=joe for scope SELF_OR_CHILD",
+ "request":{
+ "resource":{"elements":{"path":"/home/scott"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+ "accessType":"","user":"joe","userGroups":[],"requestData":"ANY /home/scott"
+ },
+ "result":{"isAudited":false,"isAllowed":false,"policyId": -1}
+ },
+ {"name":"DENY 'ANY /home/scott' for u=scot for scope SELF_OR_CHILD",
+ "request":{
+ "resource":{"elements":{"path":"/home/scott"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+ "accessType":"","user":"scot","userGroups":[],"requestData":"ANY /home/scott"
+ },
+ "result":{"isAudited":false,"isAllowed":false,"policyId": -1}
+ },
+ {"name":"DENY 'ANY /home/sscott' for u=scott for scope SELF_OR_CHILD",
+ "request":{
+ "resource":{"elements":{"path":"/home/sscott"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+ "accessType":"","user":"scott","userGroups":[],"requestData":"ANY /home/sscott"
+ },
+ "result":{"isAudited":false,"isAllowed":false,"policyId": -1}
+ },
+ {"name":"ALLOW 'write /home/scott/scott.data/test.txt' for u=scott",
+ "request":{
+ "resource":{"elements":{"path":"/home/scott/scott.data/test.txt"}},
+ "accessType":"write","user":"scott","userGroups":[],"requestData":"write /home/scott/scott.data/test.txt"
+ },
+ "result":{"isAudited":true,"isAllowed":true,"policyId": 30}
+ },
+ {"name":"ALLOW 'write /home/scott/scott.data/test.txt' for u=scott",
+ "request":{
+ "resource":{"elements":{"path":"/home/scott/scott.data/test.txt"}},
+ "accessType":"write","user":"scott","userGroups":[],"requestData":"write /home/scott/scott.data/test.txt"
+ },
+ "result":{"isAudited":true,"isAllowed":true,"policyId": 30}
+ },
+ {"name":"ALLOW 'write /test/x_scott_y/test.txt' for u=scott",
+ "request":{
+ "resource":{"elements":{"path":"/test/x_scott_y/test.txt"}},
+ "accessType":"write","user":"scott","userGroups":[],"requestData":"write /test/x_scott_y/test.txt"
+ },
+ "userAttributes": { "scott": { "testAttr1": "x_{USER}_y" } },
+ "result":{"isAudited":true,"isAllowed":true,"policyId": 40}
+ }
+ ]
+}
\ No newline at end of file