This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push:
new c9d138ff7 RANGER-4328: updated resource matcher handling of
SELF_OR_PREFIX scope
c9d138ff7 is described below
commit c9d138ff7d9b5aeaa58a56d318ea5aaae357ba16
Author: Madhan Neethiraj <[email protected]>
AuthorDate: Mon Jul 24 09:09:54 2023 -0700
RANGER-4328: updated resource matcher handling of SELF_OR_PREFIX scope
---
.../RangerAbstractResourceMatcher.java | 125 ++++++++---
.../RangerDefaultResourceMatcher.java | 76 ++++---
.../resourcematcher/RangerPathResourceMatcher.java | 239 +++++++++++++++++++--
.../resourcematcher/RangerResourceMatcher.java | 3 +
.../resourcematcher/RangerURLResourceMatcher.java | 35 ++-
.../plugin/resourcematcher/ResourceMatcher.java | 165 ++++++++++++--
.../RangerAbstractResourceMatcherTest.java | 9 +
.../RangerDefaultResourceMatcherTest.java | 132 ++++++++++--
.../RangerPathResourceMatcherTest.java | 73 +++++++
.../RangerURLResourceMatcherTest.java | 73 +++++++
10 files changed, 820 insertions(+), 110 deletions(-)
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 cb8d46adf..5eee8d11a 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
@@ -30,15 +30,18 @@ import org.apache.commons.io.IOCase;
import org.apache.commons.lang.StringUtils;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
+import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchType;
import org.apache.ranger.plugin.util.ServiceDefUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchType.*;
public abstract class RangerAbstractResourceMatcher implements
RangerResourceMatcher {
private static final Logger LOG =
LoggerFactory.getLogger(RangerAbstractResourceMatcher.class);
- public final static String WILDCARD_ASTERISK = "*";
+ public final static String WILDCARD_ASTERISK = "*";
+ public final static String WILDCARD_QUESTION_MARK = "?";
public final static String OPTION_IGNORE_CASE =
"ignoreCase";
public final static String OPTION_QUOTED_CASE_SENSITIVE =
"quotedCaseSensitive";
@@ -324,6 +327,12 @@ public abstract class RangerAbstractResourceMatcher
implements RangerResourceMat
return !resultWithoutExcludes;
// all other cases flip it
}
+ public ResourceElementMatchType applyExcludes(boolean
allValuesRequested, ResourceElementMatchType resultWithoutExcludes) {
+ if (!policyIsExcludes) return resultWithoutExcludes;
// not an excludes policy!
+ if (allValuesRequested && !isMatchAny) return
resultWithoutExcludes; // one case where excludes has no effect
+ return resultWithoutExcludes == NONE ? SELF : NONE;
// all other cases flip it
+ }
+
ResourceMatcher getMatcher(String policyValue) {
final int len = policyValue != null ? policyValue.length() : 0;
@@ -391,18 +400,8 @@ public abstract class RangerAbstractResourceMatcher
implements RangerResourceMat
}
abstract class AbstractStringResourceMatcher extends ResourceMatcher {
- private final boolean isCaseSensitive;
-
- protected AbstractStringResourceMatcher(String value, Map<String,
String> options, boolean isCaseSensitive) {
+ protected AbstractStringResourceMatcher(String value, Map<String,
String> options) {
super(value, options);
-
- this.isCaseSensitive = isCaseSensitive;
- }
-
- @Override
- public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
- return isCaseSensitive ?
StringUtils.startsWith(getExpandedValue(evalContext), resourceValue)
- :
StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext), resourceValue);
}
@Override
@@ -413,23 +412,35 @@ abstract class AbstractStringResourceMatcher extends
ResourceMatcher {
final class CaseSensitiveStringMatcher extends AbstractStringResourceMatcher {
CaseSensitiveStringMatcher(String value, Map<String, String> options) {
- super(value, options, true);
+ super(value, options);
}
@Override
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
return StringUtils.equals(resourceValue,
getExpandedValue(evalContext));
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return StringUtils.startsWith(getExpandedValue(evalContext),
resourceValue);
+ }
+
int getPriority() { return 1 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0);}
}
final class CaseInsensitiveStringMatcher extends AbstractStringResourceMatcher
{
- CaseInsensitiveStringMatcher(String value, Map<String, String> options)
{ super(value, options, false); }
+ CaseInsensitiveStringMatcher(String value, Map<String, String> options)
{ super(value, options); }
@Override
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
return StringUtils.equalsIgnoreCase(resourceValue,
getExpandedValue(evalContext));
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return
StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext), resourceValue);
+ }
+
int getPriority() {return 2 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0); }
}
@@ -437,7 +448,7 @@ final class QuotedCaseSensitiveStringMatcher extends
AbstractStringResourceMatch
private final String quoteChars;
QuotedCaseSensitiveStringMatcher(String value, Map<String, String>
options, String quoteChars) {
- super(value, options, true);
+ super(value, options);
this.quoteChars = quoteChars;
}
@@ -451,28 +462,49 @@ final class QuotedCaseSensitiveStringMatcher extends
AbstractStringResourceMatch
}
}
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ if (startsWithAnyChar(resourceValue, quoteChars)) {
+ return
StringUtils.startsWith(getExpandedValue(evalContext), resourceValue);
+ } else {
+ return
StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext), resourceValue);
+ }
+ }
+
int getPriority() {return 2 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0); }
}
final class CaseSensitiveStartsWithMatcher extends
AbstractStringResourceMatcher {
CaseSensitiveStartsWithMatcher(String value, Map<String, String>
options) {
- super(value, options, true);
+ super(value, options);
}
@Override
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
return StringUtils.startsWith(resourceValue,
getExpandedValue(evalContext));
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return StringUtils.startsWith(getExpandedValue(evalContext),
resourceValue);
+ }
+
int getPriority() { return 3 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0);}
}
final class CaseInsensitiveStartsWithMatcher extends
AbstractStringResourceMatcher {
- CaseInsensitiveStartsWithMatcher(String value, Map<String, String>
options) { super(value, options, false); }
+ CaseInsensitiveStartsWithMatcher(String value, Map<String, String>
options) { super(value, options); }
@Override
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
return StringUtils.startsWithIgnoreCase(resourceValue,
getExpandedValue(evalContext));
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return
StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext), resourceValue);
+ }
+
int getPriority() { return 4 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0); }
}
@@ -480,7 +512,7 @@ final class QuotedCaseSensitiveStartsWithMatcher extends
AbstractStringResourceM
private final String quoteChars;
QuotedCaseSensitiveStartsWithMatcher(String value, Map<String, String>
options, String quoteChars) {
- super(value, options, true);
+ super(value, options);
this.quoteChars = quoteChars;
}
@@ -494,30 +526,51 @@ final class QuotedCaseSensitiveStartsWithMatcher extends
AbstractStringResourceM
}
}
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ if (startsWithAnyChar(resourceValue, quoteChars)) {
+ return
StringUtils.startsWith(getExpandedValue(evalContext), resourceValue);
+ } else {
+ return
StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext), resourceValue);
+ }
+ }
+
int getPriority() { return 4 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0); }
}
final class CaseSensitiveEndsWithMatcher extends AbstractStringResourceMatcher
{
CaseSensitiveEndsWithMatcher(String value, Map<String, String> options)
{
- super(value, options, true);
+ super(value, options);
}
@Override
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
return StringUtils.endsWith(resourceValue,
getExpandedValue(evalContext));
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return true; // isPrefixMatch() is always true for endsWith
+ }
+
int getPriority() { return 3 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0); }
}
final class CaseInsensitiveEndsWithMatcher extends
AbstractStringResourceMatcher {
CaseInsensitiveEndsWithMatcher(String value, Map<String, String>
options) {
- super(value, options, false);
+ super(value, options);
}
@Override
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
return StringUtils.endsWithIgnoreCase(resourceValue,
getExpandedValue(evalContext));
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return true; // isPrefixMatch() is always true for endsWith
+ }
+
int getPriority() { return 4 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0); }
}
@@ -525,7 +578,7 @@ final class QuotedCaseSensitiveEndsWithMatcher extends
AbstractStringResourceMat
private final String quoteChars;
QuotedCaseSensitiveEndsWithMatcher(String value, Map<String, String>
options, String quoteChars) {
- super(value, options, true);
+ super(value, options);
this.quoteChars = quoteChars;
}
@@ -539,31 +592,48 @@ final class QuotedCaseSensitiveEndsWithMatcher extends
AbstractStringResourceMat
}
}
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return true; // isPrefixMatch() is always true for endsWith
+ }
+
int getPriority() { return 4 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0); }
}
final class CaseSensitiveWildcardMatcher extends AbstractStringResourceMatcher
{
CaseSensitiveWildcardMatcher(String value, Map<String, String> options)
{
- super(value, options, true);
+ super(value, options);
}
@Override
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
return FilenameUtils.wildcardMatch(resourceValue,
getExpandedValue(evalContext), IOCase.SENSITIVE);
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return ResourceMatcher.wildcardPrefixMatch(resourceValue,
getExpandedValue(evalContext), IOCase.SENSITIVE);
+ }
+
int getPriority() { return 5 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0); }
}
final class CaseInsensitiveWildcardMatcher extends
AbstractStringResourceMatcher {
CaseInsensitiveWildcardMatcher(String value, Map<String, String>
options) {
- super(value, options, false);
+ super(value, options);
}
@Override
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
return FilenameUtils.wildcardMatch(resourceValue,
getExpandedValue(evalContext), IOCase.INSENSITIVE);
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return ResourceMatcher.wildcardPrefixMatch(resourceValue,
getExpandedValue(evalContext), IOCase.INSENSITIVE);
+ }
+
int getPriority() {return 6 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0); }
}
@@ -571,7 +641,7 @@ final class QuotedCaseSensitiveWildcardMatcher extends
AbstractStringResourceMat
private final String quoteChars;
QuotedCaseSensitiveWildcardMatcher(String value, Map<String, String>
options, String quoteChars) {
- super(value, options, true);
+ super(value, options);
this.quoteChars = quoteChars;
}
@@ -583,6 +653,13 @@ final class QuotedCaseSensitiveWildcardMatcher extends
AbstractStringResourceMat
return FilenameUtils.wildcardMatch(resourceValue,
getExpandedValue(evalContext), caseSensitivity);
}
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ IOCase caseSensitivity = startsWithAnyChar(resourceValue,
quoteChars) ? IOCase.SENSITIVE : IOCase.INSENSITIVE;
+
+ return ResourceMatcher.wildcardPrefixMatch(resourceValue,
getExpandedValue(evalContext), caseSensitivity);
+ }
+
int getPriority() {return 6 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0); }
}
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java
b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java
index 702cb272f..977fd4941 100644
---
a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java
@@ -21,12 +21,15 @@ package org.apache.ranger.plugin.resourcematcher;
import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
+import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Map;
+import static
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchType.NONE;
+
public class RangerDefaultResourceMatcher extends
RangerAbstractResourceMatcher {
private static final Logger LOG =
LoggerFactory.getLogger(RangerDefaultResourceMatcher.class);
@@ -37,20 +40,54 @@ public class RangerDefaultResourceMatcher extends
RangerAbstractResourceMatcher
LOG.debug("==> RangerDefaultResourceMatcher.isMatch(" +
resource + ", " + evalContext + ")");
}
- boolean ret = false;
- boolean allValuesRequested = isAllValuesRequested(resource);
- boolean isPrefixMatch = matchingScope ==
ResourceElementMatchingScope.SELF_OR_PREFIX;
+ ResourceElementMatchType matchType = getMatchType(resource,
matchingScope, evalContext);
+ boolean ret =
ResourceMatcher.isMatch(matchType, matchingScope);
+
+ if (ret == false) {
+ if(LOG.isDebugEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ for (String policyValue: policyValues) {
+ sb.append(policyValue);
+ sb.append(" ");
+ }
+ sb.append("]");
+
+ LOG.debug("RangerDefaultResourceMatcher.isMatch
returns FALSE, (resource=" + resource + ", policyValues=" + sb.toString() +
")");
+ }
+ }
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("<== RangerDefaultResourceMatcher.isMatch(" +
resource + ", " + evalContext + "): " + ret);
+ }
+
+ return ret;
+ }
+
+ @Override
+ public ResourceElementMatchType getMatchType(Object resource,
ResourceElementMatchingScope matchingScope, Map<String, Object> evalContext) {
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==>
RangerDefaultResourceMatcher.getMatchType(" + resource + ", " + evalContext +
")");
+ }
+
+ ResourceElementMatchType ret = NONE;
+ boolean allValuesRequested =
isAllValuesRequested(resource);
+ boolean isPrefixMatch = matchingScope ==
ResourceElementMatchingScope.SELF_OR_PREFIX;
if (isMatchAny || (allValuesRequested && !isPrefixMatch)) {
- ret = isMatchAny;
+ ret = isMatchAny ? ResourceElementMatchType.SELF : NONE;
} else {
if (resource instanceof String) {
String strValue = (String) resource;
for (ResourceMatcher resourceMatcher :
resourceMatchers.getResourceMatchers()) {
- ret = resourceMatcher.isMatch(strValue,
matchingScope, evalContext);
+ ResourceElementMatchType matchType =
resourceMatcher.getMatchType(strValue, matchingScope, evalContext);
- if (ret) {
+ if (matchType != NONE) {
+ ret = matchType;
+ }
+
+ if (ret ==
ResourceElementMatchType.SELF) {
break;
}
}
@@ -60,13 +97,18 @@ public class RangerDefaultResourceMatcher extends
RangerAbstractResourceMatcher
for (ResourceMatcher resourceMatcher :
resourceMatchers.getResourceMatchers()) {
for (String resourceValue :
resourceValues) {
- ret =
resourceMatcher.isMatch(resourceValue, matchingScope, evalContext);
+ ResourceElementMatchType
matchType = resourceMatcher.getMatchType(resourceValue, matchingScope,
evalContext);
+
+ if (matchType != NONE) {
+ ret = matchType;
+ }
- if (ret) {
+ if (ret ==
ResourceElementMatchType.SELF) {
break;
}
}
- if (ret) {
+
+ if (ret ==
ResourceElementMatchType.SELF) {
break;
}
}
@@ -75,22 +117,8 @@ public class RangerDefaultResourceMatcher extends
RangerAbstractResourceMatcher
ret = applyExcludes(allValuesRequested, ret);
- if (ret == false) {
- if(LOG.isDebugEnabled()) {
- StringBuilder sb = new StringBuilder();
- sb.append("[");
- for (String policyValue: policyValues) {
- sb.append(policyValue);
- sb.append(" ");
- }
- sb.append("]");
-
- LOG.debug("RangerDefaultResourceMatcher.isMatch
returns FALSE, (resource=" + resource + ", policyValues=" + sb.toString() +
")");
- }
- }
-
if(LOG.isDebugEnabled()) {
- LOG.debug("<== RangerDefaultResourceMatcher.isMatch(" +
resource + ", " + evalContext + "): " + ret);
+ LOG.debug("<==
RangerDefaultResourceMatcher.getMatchType(" + resource + ", " + evalContext +
"): " + ret);
}
return ret;
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 3c1523c25..d376e9025 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
@@ -130,7 +130,7 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
if (isWildcardPresent) {
ret = new RecursiveWildcardResourceMatcher(policyValue,
getOptions(), pathSeparatorChar, optIgnoreCase,
RangerPathResourceMatcher::isRecursiveWildCardMatch, optIgnoreCase ? 8 : 7);
} else {
- ret = new RecursivePathResourceMatcher(policyValue,
getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::equalsIgnoreCase
: StringUtils::equals, optIgnoreCase ? StringUtils::startsWithIgnoreCase :
StringUtils::startsWith, optIgnoreCase ? 8 : 7);
+ ret = new RecursivePathResourceMatcher(policyValue,
getOptions(), pathSeparatorChar, optIgnoreCase, optIgnoreCase ? 8 : 7);
}
if (optReplaceTokens) {
@@ -263,15 +263,15 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
if (needWildcardMatch) { // test?, test*a*, test*a*b, *test*a
ret = new WildcardResourceMatcher(policyValue,
getOptions(), pathSeparatorChar, optIgnoreCase, FilenameUtils::wildcardMatch,
6);
} else if (wildcardStartIdx == -1) { // test, testa, testab
- ret = new PathResourceMatcher(policyValue,
getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::equalsIgnoreCase
: StringUtils::equals, optIgnoreCase ? 2 : 1, !optIgnoreCase);
+ ret = new PathResourceMatcher(policyValue,
getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::equalsIgnoreCase
: StringUtils::equals, !optIgnoreCase, optIgnoreCase ? 2 : 1);
} else if (wildcardStartIdx == 0) { // *test, **test, *testa,
*testab
String matchStr = policyValue.substring(wildcardEndIdx
+ 1);
- ret = new PathResourceMatcher(matchStr, getOptions(),
pathSeparatorChar, optIgnoreCase ? StringUtils::endsWithIgnoreCase :
StringUtils::endsWith, optIgnoreCase ? 4 : 3, !optIgnoreCase);
+ ret = new PathEndsWithResourceMatcher(matchStr,
getOptions(), pathSeparatorChar, !optIgnoreCase, optIgnoreCase ? 4 : 3);
} else if (wildcardEndIdx != (len - 1)) { // test*a, test*ab
ret = new WildcardResourceMatcher(policyValue,
getOptions(), pathSeparatorChar, optIgnoreCase, FilenameUtils::wildcardMatch,
6);
} else { // test*, test**, testa*, testab*
String matchStr = policyValue.substring(0,
wildcardStartIdx);
- ret = new PathResourceMatcher(matchStr, getOptions(),
pathSeparatorChar, optIgnoreCase ? StringUtils::startsWithIgnoreCase :
StringUtils::startsWith, optIgnoreCase ? 4 : 3, !optIgnoreCase);
+ ret = new PathStartsWithResourceMatcher(matchStr,
getOptions(), pathSeparatorChar, !optIgnoreCase, optIgnoreCase ? 4 : 3);
}
if (optReplaceTokens) {
@@ -298,7 +298,7 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
final int priority;
final boolean isCaseSensitive;
- AbstractPathResourceMatcher(String value, Map<String, String>
options, char pathSeparatorChar, int priority, boolean isCaseSensitive) {
+ AbstractPathResourceMatcher(String value, Map<String, String>
options, char pathSeparatorChar, boolean isCaseSensitive, int priority) {
super(value, options);
this.pathSeparatorChar = pathSeparatorChar;
@@ -308,19 +308,13 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
int getPriority() {
return priority + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0);
}
-
- @Override
- public boolean isPrefixMatch(String resourceValue, Map<String,
Object> evalContext) {
- return isCaseSensitive ?
StringUtils.startsWith(getExpandedValue(evalContext), resourceValue)
- :
StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext), resourceValue);
- }
}
static class PathResourceMatcher extends AbstractPathResourceMatcher {
final BiFunction<String, String, Boolean> function;
- PathResourceMatcher(String value, Map<String, String> options,
char pathSeparatorChar, BiFunction<String, String, Boolean> function, int
priority, boolean isCaseSensitive) {
- super(value, options, pathSeparatorChar, priority,
isCaseSensitive);
+ PathResourceMatcher(String value, Map<String, String> options,
char pathSeparatorChar, BiFunction<String, String, Boolean> function, boolean
isCaseSensitive, int priority) {
+ super(value, options, pathSeparatorChar,
isCaseSensitive, priority);
this.function = function;
}
@@ -328,21 +322,42 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
@Override
boolean isMatch(String resourceValue, Map<String, Object>
evalContext) {
if (LOG.isDebugEnabled()) {
- LOG.debug("==>
PathResourceMatcher.isMatch(resourceValue=" + resourceValue + ", evalContext="
+ evalContext + ")");
+ LOG.debug("==>
PathResourceMatcher.isMatch(resourceValue={}, evalContext={})", resourceValue,
evalContext);
}
String expandedValue = getExpandedValue(evalContext);
boolean ret = function.apply(resourceValue,
expandedValue);
if (LOG.isDebugEnabled()) {
- LOG.debug("<==
PathResourceMatcher.isMatch(resourceValue=" + resourceValue + ",
expandedValue=" + expandedValue + ") : result:[" + ret + "]");
+ LOG.debug("<==
PathResourceMatcher.isMatch(resourceValue={}, expandedValue={}): ret={}",
resourceValue, getExpandedValue(evalContext) , ret );
+ }
+
+ return ret;
+ }
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String,
Object> evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
PathResourceMatcher.isPrefixMatch(resourceValue={}, evalContext={})",
resourceValue, evalContext);
+ }
+
+ boolean ret = isCaseSensitive ?
StringUtils.startsWith(getExpandedValue(evalContext), resourceValue)
+ :
StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext), resourceValue);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
PathResourceMatcher.isPrefixMatch(resourceValue={}, expandedValue={}): ret={}",
resourceValue, getExpandedValue(evalContext) , ret );
}
return ret;
+
}
@Override
public boolean isChildMatch(String resourceValue, Map<String,
Object> evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
PathResourceMatcher.isChildMatch(resourceValue={}, evalContext={})",
resourceValue, evalContext);
+ }
+
boolean ret = false;
String expandedValue =
getExpandedValue(evalContext);
int lastLevelSeparatorIndex =
expandedValue.lastIndexOf(pathSeparatorChar);
@@ -357,9 +372,143 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
ret = function.apply(resourceValue,
shorterExpandedValue);
}
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
PathResourceMatcher.isChildMatch(resourceValue={}, lastLevelSeparatorIndex={}):
ret={}", resourceValue, lastLevelSeparatorIndex, ret );
+ }
+
+ return ret;
+ }
+ }
+
+ static class PathStartsWithResourceMatcher extends
AbstractPathResourceMatcher {
+ PathStartsWithResourceMatcher(String value, Map<String, String>
options, char pathSeparatorChar, boolean isCaseSensitive, int priority) {
+ super(value, options, pathSeparatorChar,
isCaseSensitive, priority);
+ }
+
+ @Override
+ boolean isMatch(String resourceValue, Map<String, Object>
evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
PathStartsWithResourceMatcher.isMatch(resourceValue={}, evalContext={})",
resourceValue, evalContext);
+ }
+
+ boolean ret = isCaseSensitive ?
StringUtils.startsWith(resourceValue, getExpandedValue(evalContext))
+ :
StringUtils.startsWithIgnoreCase(resourceValue, getExpandedValue(evalContext));
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
PathStartsWithResourceMatcher.isMatch(resourceValue={}, expandedValue={}):
ret={}", resourceValue, getExpandedValue(evalContext) , ret );
+ }
+
+ return ret;
+ }
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String,
Object> evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
PathStartsWithResourceMatcher.isPrefixMatch(resourceValue={}, evalContext={})",
resourceValue, evalContext);
+ }
+
+ boolean ret = isCaseSensitive ?
StringUtils.startsWith(getExpandedValue(evalContext), resourceValue)
+ :
StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext), resourceValue);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
PathStartsWithResourceMatcher.isPrefixMatch(resourceValue={},
expandedValue={}): ret={}", resourceValue, getExpandedValue(evalContext) , ret
);
+ }
+
+ return ret;
+ }
+
+ @Override
+ public boolean isChildMatch(String resourceValue, Map<String,
Object> evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
PathStartsWithResourceMatcher.isChildMatch(resourceValue={}, evalContext={})",
resourceValue, evalContext);
+ }
+
+ boolean ret = false;
+ String expandedValue =
getExpandedValue(evalContext);
+ int lastLevelSeparatorIndex =
expandedValue.lastIndexOf(pathSeparatorChar);
+
+ if (lastLevelSeparatorIndex != -1) {
+ String shorterExpandedValue =
expandedValue.substring(0, lastLevelSeparatorIndex);
+
+ if
(resourceValue.charAt(resourceValue.length()-1) == pathSeparatorChar) {
+ resourceValue =
resourceValue.substring(0, resourceValue.length()-1);
+ }
+
+ ret = isCaseSensitive ?
StringUtils.startsWith(resourceValue, shorterExpandedValue)
+ :
StringUtils.startsWithIgnoreCase(resourceValue, shorterExpandedValue);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
PathStartsWithResourceMatcher.isChildMatch(resourceValue={},
lastLevelSeparatorIndex={}): ret={}", resourceValue, lastLevelSeparatorIndex,
ret );
+ }
+
+ return ret;
+ }
+ }
+
+ static class PathEndsWithResourceMatcher extends
AbstractPathResourceMatcher {
+ PathEndsWithResourceMatcher(String value, Map<String, String>
options, char pathSeparatorChar, boolean isCaseSensitive, int priority) {
+ super(value, options, pathSeparatorChar,
isCaseSensitive, priority);
+ }
+
+ @Override
+ boolean isMatch(String resourceValue, Map<String, Object>
evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
PathEndsWithResourceMatcher.isMatch(resourceValue={}, evalContext={})",
resourceValue, evalContext);
+ }
+
+ boolean ret = isCaseSensitive ?
StringUtils.endsWith(resourceValue, getExpandedValue(evalContext))
+ :
StringUtils.endsWithIgnoreCase(resourceValue, getExpandedValue(evalContext));
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
PathEndsWithResourceMatcher.isMatch(resourceValue={}, expandedValue={}):
ret={}", resourceValue, getExpandedValue(evalContext) , ret );
+ }
+
+ return ret;
+ }
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String,
Object> evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
PathEndsWithResourceMatcher.isPrefixMatch(resourceValue={}, evalContext={})",
resourceValue, evalContext);
+ }
+
+ boolean ret = true; // isPrefixMatch() is always true
for endsWith
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
PathEndsWithResourceMatcher.isPrefixMatch(resourceValue={}, expandedValue={}):
ret={}", resourceValue, getExpandedValue(evalContext) , ret );
+ }
+
return ret;
}
+ @Override
+ public boolean isChildMatch(String resourceValue, Map<String,
Object> evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
PathEndsWithResourceMatcher.isChildMatch(resourceValue={}, evalContext={})",
resourceValue, evalContext);
+ }
+
+ boolean ret = false;
+ String expandedValue =
getExpandedValue(evalContext);
+ int lastLevelSeparatorIndex =
expandedValue.lastIndexOf(pathSeparatorChar);
+
+ if (lastLevelSeparatorIndex != -1) {
+ String shorterExpandedValue =
expandedValue.substring(0, lastLevelSeparatorIndex);
+
+ if
(resourceValue.charAt(resourceValue.length()-1) == pathSeparatorChar) {
+ resourceValue =
resourceValue.substring(0, resourceValue.length()-1);
+ }
+
+ ret = isCaseSensitive ?
StringUtils.endsWith(resourceValue, shorterExpandedValue)
+ :
StringUtils.endsWithIgnoreCase(resourceValue, shorterExpandedValue);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
PathEndsWithResourceMatcher.isChildMatch(resourceValue={},
lastLevelSeparatorIndex={}): ret={}", resourceValue, lastLevelSeparatorIndex,
ret );
+ }
+
+ return ret;
+ }
}
static class WildcardResourceMatcher extends
AbstractPathResourceMatcher {
@@ -367,14 +516,14 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
final IOCase ioCase;
WildcardResourceMatcher(String value, Map<String, String>
options, char pathSeparatorChar, boolean optIgnoreCase, TriFunction<String,
String, IOCase, Boolean> function, int priority) {
- super(value, options, pathSeparatorChar, priority,
!optIgnoreCase);
+ super(value, options, pathSeparatorChar,
!optIgnoreCase, priority);
this.function = function;
this.ioCase = optIgnoreCase ? IOCase.INSENSITIVE :
IOCase.SENSITIVE;
}
@Override
- boolean isMatch(String resourceValue, Map<String, Object>
evalContext) {
+ public boolean isMatch(String resourceValue, Map<String,
Object> evalContext) {
if (LOG.isDebugEnabled()) {
LOG.debug("==>
WildcardResourceMatcher.isMatch(resourceValue=" + resourceValue + ",
evalContext=" + evalContext + ")");
}
@@ -388,6 +537,20 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
return ret;
}
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String,
Object> evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
WildcardResourceMatcher.isPrefixMatch(resourceValue=" + resourceValue + ",
evalContext=" + evalContext + ")");
+ }
+
+ boolean ret =
ResourceMatcher.wildcardPrefixMatch(resourceValue,
getExpandedValue(evalContext), ioCase);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
WildcardResourceMatcher.isPrefixMatch(resourceValue=" + resourceValue + ",
expandedValue=" + getExpandedValue(evalContext) + ") : result:[" + ret + "]");
+ }
+ return ret;
+ }
+
@Override
public boolean isChildMatch(String resourceValue, Map<String,
Object> evalContext) {
boolean ret = false;
@@ -414,7 +577,7 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
String[] wildcardPathElements;
RecursiveWildcardResourceMatcher(String value, Map<String,
String> options, char pathSeparatorChar, boolean optIgnoreCase,
QuintFunction<String, String, Character, IOCase, Boolean, String[]> function,
int priority) {
- super(value, options, pathSeparatorChar, priority,
!optIgnoreCase);
+ super(value, options, pathSeparatorChar,
!optIgnoreCase, priority);
this.function = function;
this.ioCase = optIgnoreCase ? IOCase.INSENSITIVE :
IOCase.SENSITIVE;
@@ -444,6 +607,20 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
return ret;
}
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String,
Object> evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
RecursiveWildcardResourceMatcher.isPrefixMatch(resourceValue=" + resourceValue
+ ", evalContext=" + evalContext + ")");
+ }
+
+ boolean ret =
ResourceMatcher.wildcardPrefixMatch(resourceValue,
getExpandedValue(evalContext), ioCase);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
RecursiveWildcardResourceMatcher.isPrefixMatch(resourceValue=" + resourceValue
+ ", expandedValue=" + getExpandedValue(evalContext) + ") : result:[" + ret +
"]");
+ }
+ return ret;
+ }
+
@Override
public boolean isChildMatch(String resourceValue, Map<String,
Object> evalContext) {
boolean ret = false;
@@ -470,14 +647,16 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
String valueWithoutSeparator;
String valueWithSeparator;
+ final IOCase ioCase;
final BiFunction<String, String, Boolean> primaryFunction;
final BiFunction<String, String, Boolean> fallbackFunction;
- 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,
true);
+ RecursivePathResourceMatcher(String value, Map<String, String>
options, char pathSeparatorChar, boolean optIgnoreCase, int priority) {
+ super(value, options, pathSeparatorChar, true,
priority);
- this.primaryFunction = primaryFunction;
- this.fallbackFunction = fallbackFunction;
+ this.ioCase = optIgnoreCase ?
IOCase.INSENSITIVE : IOCase.SENSITIVE;
+ this.primaryFunction = optIgnoreCase ?
StringUtils::equalsIgnoreCase : StringUtils::equals;
+ this.fallbackFunction = optIgnoreCase ?
StringUtils::startsWithIgnoreCase : StringUtils::startsWith;
}
String getStringToCompare(String policyValue) {
@@ -520,6 +699,20 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
return ret;
}
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String,
Object> evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==>
RecursiveWildcardResourceMatcher.isPrefixMatch(resourceValue=" + resourceValue
+ ", evalContext=" + evalContext + ")");
+ }
+
+ boolean ret =
ResourceMatcher.wildcardPrefixMatch(resourceValue,
getExpandedValue(evalContext), ioCase);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<==
RecursiveWildcardResourceMatcher.isPrefixMatch(resourceValue=" + resourceValue
+ ", expandedValue=" + getExpandedValue(evalContext) + ") : result:[" + ret +
"]");
+ }
+ return ret;
+ }
+
@Override
public boolean isChildMatch(String resourceValue, Map<String,
Object> evalContext) {
boolean ret = false;
@@ -534,7 +727,7 @@ public class RangerPathResourceMatcher extends
RangerDefaultResourceMatcher {
}
noSeparator = valueWithoutSeparator;
}
- final int lastLevelSeparatorIndex =
noSeparator.lastIndexOf(pathSeparatorChar);
+ final int lastLevelSeparatorIndex = noSeparator != null
? noSeparator.lastIndexOf(pathSeparatorChar) : -1;
if (lastLevelSeparatorIndex != -1) {
final String shorterExpandedValue =
noSeparator.substring(0, lastLevelSeparatorIndex);
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java
b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java
index c4ce30d36..ec22e01bf 100644
---
a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java
@@ -22,6 +22,7 @@ package org.apache.ranger.plugin.resourcematcher;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
+import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchType;
import java.util.Map;
@@ -34,6 +35,8 @@ public interface RangerResourceMatcher {
boolean isMatchAny();
+ ResourceElementMatchType getMatchType(Object resource,
ResourceElementMatchingScope matchingScope, Map<String, Object> evalContext);
+
boolean isMatch(Object resource, ResourceElementMatchingScope
matchingScope, Map<String, Object> evalContext);
boolean isCompleteMatch(String resource, Map<String, Object>
evalContext);
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 ce73b3006..057563696 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
@@ -237,7 +237,7 @@ public class RangerURLResourceMatcher extends
RangerDefaultResourceMatcher {
final class CaseSensitiveURLRecursiveWildcardMatcher extends
AbstractStringResourceMatcher {
private final char levelSeparatorChar;
CaseSensitiveURLRecursiveWildcardMatcher(String value, Map<String, String>
options, char levelSeparatorChar) {
- super(value, options, true);
+ super(value, options);
this.levelSeparatorChar = levelSeparatorChar;
}
@@ -245,13 +245,19 @@ final class CaseSensitiveURLRecursiveWildcardMatcher
extends AbstractStringResou
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
return
RangerURLResourceMatcher.isRecursiveWildCardMatch(resourceValue,
getExpandedValue(evalContext), levelSeparatorChar, IOCase.SENSITIVE);
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return ResourceMatcher.wildcardPrefixMatch(resourceValue,
getExpandedValue(evalContext), IOCase.SENSITIVE);
+ }
+
int getPriority() { return 7 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0);}
}
final class CaseInsensitiveURLRecursiveWildcardMatcher extends
AbstractStringResourceMatcher {
private final char levelSeparatorChar;
CaseInsensitiveURLRecursiveWildcardMatcher(String value, Map<String,
String> options, char levelSeparatorChar) {
- super(value, options, false);
+ super(value, options);
this.levelSeparatorChar = levelSeparatorChar;
}
@@ -259,6 +265,12 @@ final class CaseInsensitiveURLRecursiveWildcardMatcher
extends AbstractStringRes
boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
return
RangerURLResourceMatcher.isRecursiveWildCardMatch(resourceValue,
getExpandedValue(evalContext), levelSeparatorChar, IOCase.INSENSITIVE);
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return ResourceMatcher.wildcardPrefixMatch(resourceValue,
getExpandedValue(evalContext), IOCase.INSENSITIVE);
+ }
+
int getPriority() { return 8 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0);}
}
@@ -268,8 +280,8 @@ abstract class RecursiveMatcher extends
AbstractStringResourceMatcher {
String valueWithoutSeparator;
String valueWithSeparator;
- RecursiveMatcher(String value, Map<String, String> options, char
levelSeparatorChar, boolean isCaseSensitive) {
- super(value, options, isCaseSensitive);
+ RecursiveMatcher(String value, Map<String, String> options, char
levelSeparatorChar) {
+ super(value, options);
this.levelSeparatorChar = levelSeparatorChar;
}
@@ -284,7 +296,7 @@ abstract class RecursiveMatcher extends
AbstractStringResourceMatcher {
final class CaseSensitiveURLRecursiveMatcher extends RecursiveMatcher {
CaseSensitiveURLRecursiveMatcher(String value, Map<String, String>
options, char levelSeparatorChar) {
- super(value, options, levelSeparatorChar, true);
+ super(value, options, levelSeparatorChar);
}
@Override
@@ -311,12 +323,18 @@ final class CaseSensitiveURLRecursiveMatcher extends
RecursiveMatcher {
return ret;
}
+
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return StringUtils.startsWith(getExpandedValue(evalContext),
resourceValue);
+ }
+
int getPriority() { return 7 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0);}
}
final class CaseInsensitiveURLRecursiveMatcher extends RecursiveMatcher {
CaseInsensitiveURLRecursiveMatcher(String value, Map<String, String>
options, char levelSeparatorChar) {
- super(value, options, levelSeparatorChar, false);
+ super(value, options, levelSeparatorChar);
}
@Override
@@ -344,5 +362,10 @@ final class CaseInsensitiveURLRecursiveMatcher extends
RecursiveMatcher {
return ret;
}
+ @Override
+ public boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext) {
+ return StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext),
resourceValue);
+ }
+
int getPriority() { return 8 + (getNeedsDynamicEval() ?
DYNAMIC_EVALUATION_PENALTY : 0);}
}
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 ad0942fbe..77245eae1 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
@@ -19,6 +19,7 @@
package org.apache.ranger.plugin.resourcematcher;
+import org.apache.commons.io.IOCase;
import org.apache.commons.lang.StringUtils;
import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchType;
@@ -30,8 +31,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
import java.util.Map;
+import java.util.Stack;
abstract class ResourceMatcher {
private static final Logger LOG =
LoggerFactory.getLogger(ResourceMatcher.class);
@@ -60,19 +65,8 @@ abstract class ResourceMatcher {
final boolean isMatch(String resourceValue, ResourceElementMatchingScope
matchingScope, Map<String, Object> evalContext) {
final ResourceElementMatchType matchType = getMatchType(resourceValue,
matchingScope, evalContext);
- final boolean ret;
-
- if (matchType == ResourceElementMatchType.SELF) {
- ret = true;
- } else if (matchType == ResourceElementMatchType.PREFIX) {
- ret = matchingScope == ResourceElementMatchingScope.SELF_OR_PREFIX;
- } else if (matchType == ResourceElementMatchType.CHILD) {
- ret = matchingScope == ResourceElementMatchingScope.SELF_OR_CHILD;
- } else {
- ret = false;
- }
- return ret;
+ return isMatch(matchType, matchingScope);
}
final ResourceElementMatchType getMatchType(String resourceValue,
ResourceElementMatchingScope matchingScope, Map<String, Object> evalContext) {
@@ -152,6 +146,153 @@ abstract class ResourceMatcher {
return ret;
}
+ public static boolean isMatch(ResourceElementMatchType matchType,
ResourceElementMatchingScope matchingScope) {
+ final boolean ret;
+
+ switch (matchType) {
+ case SELF:
+ ret = true;
+ break;
+
+ case CHILD:
+ ret = matchingScope ==
ResourceElementMatchingScope.SELF_OR_CHILD;
+ break;
+
+ case PREFIX:
+ ret = matchingScope ==
ResourceElementMatchingScope.SELF_OR_PREFIX;
+ break;
+
+ default:
+ LOG.error("invalid ResourceElementMatchType: {}}", matchType);
+
+ ret = false;
+ }
+
+ return ret;
+ }
+
+ // modified version of FilenameUtils.wildcardMatch(), to check if value is
a prefix match for wildcardMatcher
+ public static boolean wildcardPrefixMatch(String value, String
wildcardMatcher, IOCase caseSensitivity) {
+ if (value == null && wildcardMatcher == null) {
+ return true;
+ } else if (value == null || wildcardMatcher == null) {
+ return false;
+ }
+
+ if (caseSensitivity == null) {
+ caseSensitivity = IOCase.SENSITIVE;
+ }
+
+ List<String> wcsTokens = splitOnTokens(wildcardMatcher);
+ boolean anyChars = false;
+ int textIdx = 0;
+ int wcsIdx = 0;
+ Stack<int[]> backtrack = new Stack<>();
+
+ do {
+ if (backtrack.size() > 0) {
+ int[] array = backtrack.pop();
+
+ wcsIdx = array[0];
+ textIdx = array[1];
+ anyChars = true;
+ }
+
+ for(; wcsIdx < wcsTokens.size(); ++wcsIdx) {
+ String wcsToken = wcsTokens.get(wcsIdx);
+
+ if (wcsToken.equals("?")) {
+ ++textIdx;
+
+ if (textIdx > value.length()) {
+ break;
+ }
+
+ anyChars = false;
+ } else if (wcsToken.equals("*")) {
+ anyChars = true;
+
+ if (wcsIdx == wcsTokens.size() - 1) {
+ textIdx = value.length();
+ }
+ } else {
+ // changes from FilenameUtils.wildcardMatch(): added
following 3 lines to check if value is a prefix match for wildcardMatcher
+ if (wcsToken.length() > (value.length() - textIdx)) {
+ wcsToken = wcsToken.substring(0, value.length() -
textIdx);
+ }
+
+ if (anyChars) {
+ textIdx = caseSensitivity.checkIndexOf(value, textIdx,
wcsToken);
+
+ if (textIdx == -1) {
+ break;
+ }
+
+ int repeat = caseSensitivity.checkIndexOf(value,
textIdx + 1, wcsToken);
+
+ if (repeat >= 0) {
+ backtrack.push(new int[]{wcsIdx, repeat});
+ }
+ } else if (!caseSensitivity.checkRegionMatches(value,
textIdx, wcsToken)) {
+ break;
+ }
+
+ textIdx += wcsToken.length();
+
+ anyChars = false;
+ }
+ }
+
+ // changes from FilenameUtils.wildcardMatch(): replaced the
condition in 'if' below to check if value is a prefix match for wildcardMatcher
+ // original if: if (wcsIdx == wcsTokens.size() && textIdx ==
value.length())
+ if (wcsIdx == wcsTokens.size() || textIdx == value.length()) {
+ return true;
+ }
+ } while (backtrack.size() > 0);
+
+ return anyChars;
+ }
+
+ static List<String> splitOnTokens(String text) {
+ if (text.indexOf(63) == -1 && text.indexOf(42) == -1) {
+ return Collections.singletonList(text);
+ } else {
+ char[] array = text.toCharArray();
+ List<String> list = new ArrayList<>(2);
+ StringBuilder buffer = new StringBuilder();
+ char prevChar = 0;
+ char[] arr$ = array;
+ int len$ = array.length;
+
+ for(int i$ = 0; i$ < len$; ++i$) {
+ char ch = arr$[i$];
+
+ if (ch != '?' && ch != '*') {
+ buffer.append(ch);
+ } else {
+ if (buffer.length() != 0) {
+ list.add(buffer.toString());
+ buffer.setLength(0);
+ }
+
+ if (ch == '?') {
+ list.add("?");
+ } else if (prevChar != '*') {
+ list.add("*");
+ }
+ }
+
+ prevChar = ch;
+ }
+
+ if (buffer.length() != 0) {
+ list.add(buffer.toString());
+ }
+
+ return list;
+ }
+ }
+
public static class PriorityComparator implements
Comparator<ResourceMatcher>, Serializable {
@Override
public int compare(ResourceMatcher me, ResourceMatcher other) {
diff --git
a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcherTest.java
b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcherTest.java
index 767795e81..b6864183d 100644
---
a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcherTest.java
+++
b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcherTest.java
@@ -19,7 +19,9 @@
package org.apache.ranger.plugin.resourcematcher;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
+import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchType;
import org.junit.Test;
import java.util.Map;
@@ -47,5 +49,12 @@ public class RangerAbstractResourceMatcherTest {
fail("This method is not expected to be used by test!");
return false;
}
+
+ @Override
+ public ResourceElementMatchType getMatchType(Object resource,
ResourceElementMatchingScope matchingScope, Map<String, Object> evalContext) {
+ fail("This method is not expected to be used by test!");
+ return RangerAccessRequest.ResourceElementMatchType.NONE;
+ }
+
}
}
diff --git
a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcherTest.java
b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcherTest.java
index e00bc834d..8a297bde0 100644
---
a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcherTest.java
+++
b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcherTest.java
@@ -23,6 +23,7 @@ import com.google.common.collect.Lists;
import org.apache.ranger.plugin.model.RangerPolicy;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
+import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchType;
import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
import org.junit.Test;
@@ -30,43 +31,132 @@ import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.*;
+import static
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchType.*;
public class RangerDefaultResourceMatcherTest {
Object[][] data = {
- // { resource, policy, excludes, result
- { "*", "*", false, true, "user" }, // resource is all values
- { "*", "*", true, false, "user" },
- { "*", "a*", false, false, "user" }, // but, policy is not match
any
- { "*", "a*", true, false, "user" }, // ==> compare with above:
exclude flag has no effect here
- { "a*", "a", false, false, "user" }, // resource has regex marker!
- { "a*", "a", true, true, "user" },
- { "a", "a", false, true, "user" }, // exact match
- { "a", "a", true, false, "user" },
- { "a1", "a*", false, true, "user" }, // trivial regex match
- { "a1", "a*", true, false, "user" },
+ // { resource, policy, excludes, matchType, result, user }
+ { "*", "*", false, SELF, true, "user" }, // resource is all
values
+ { "*", "*", true, NONE, false, "user" },
+ { "*", "a*", false, NONE, false, "user" }, // but, policy is not
match any
+ { "*", "a*", true, NONE, false, "user" }, // ==> compare with
above: exclude flag has no effect here
+ { "a*", "a", false, NONE, false, "user" }, // resource has regex
marker!
+ { "a*", "a", true, SELF, true, "user" },
+ { "a", "a", false, SELF, true, "user" }, // exact match
+ { "a", "a", true, NONE, false, "user" },
+ { "a1", "a*", false, SELF, true, "user" }, // trivial regex match
+ { "a1", "a*", true, NONE, false, "user" },
+
+ // matchScope=SELF, excludes=false
+ { "*", "*", false, SELF, true, "user" }, // resource is all
values
+ { "a*", "*", false, SELF, true, "user" }, // resource has
regex, policy matches
+ { "a*", "a", false, NONE, false, "user" }, // resource has
regex, policy does not match
+ { "*", "a*", false, NONE, false, "user" }, // resource has
regex, policy does not match
+ { "a*", "a*", false, SELF, true, "user" }, // resource has
regex, policy matches
+ { "a?", "a*", false, SELF, true, "user" }, // resource has
regex, policy matches
+ { "a*b", "a*", false, SELF, true, "user" }, // resource has
regex, policy matches
+ { "a?b", "a*", false, SELF, true, "user" }, // resource has
regex, policy matches
+ { "a*b", "a*b", false, SELF, true, "user" }, // resource has
regex, policy matches
+ { "a?b", "a?b", false, SELF, true, "user" }, // resource has
regex, policy matches
+ { "a1b", "a1b", false, SELF, true, "user" }, // exact match
+ { "a1b", "a*", false, SELF, true, "user" }, // regex match -
suffix
+ { "a1b", "*b", false, SELF, true, "user" }, // regex match -
prefix
+ { "a1b", "*1*", false, SELF, true, "user" }, // regex match
+ { "a1b", "a?b", false, SELF, true, "user" }, // regex match -
single char
+ { "a", "abc", false, NONE, false, "user" }, // policy has more
than resource
+ { "ab", "abc", false, NONE, false, "user" }, // policy has more
than resource
+ { "ab", "*c", false, NONE, false, "user" }, // policy has more
than resource
+ { "*b", "a*bc", false, NONE, false, "user" }, // policy has more
than resource
+ { "a*b", "a*bc", false, NONE, false, "user" }, // policy has more
than resource
+
+ // matchScope=SELF, excludes=true
+ { "*", "*", true, NONE, false, "user" },
+ { "a*", "*", true, NONE, false, "user" },
+ { "a*", "a", true, SELF, true, "user" },
+ { "*", "a*", true, NONE, false, "user" }, // ==> compare with
above: exclude flag has no effect here
+ { "a*", "a*", true, NONE, false, "user" },
+ { "a?", "a*", true, NONE, false, "user" },
+ { "a*b", "a*", true, NONE, false, "user" },
+ { "a?b", "a*", true, NONE, false, "user" },
+ { "a*b", "a*b", true, NONE, false, "user" },
+ { "a?b", "a?b", true, NONE, false, "user" },
+ { "a1b", "a1b", true, NONE, false, "user" },
+ { "a1b", "a*", true, NONE, false, "user" },
+ { "a1b", "*b", true, NONE, false, "user" },
+ { "a1b", "*1*", true, NONE, false, "user" },
+ { "a1b", "a?b", true, NONE, false, "user" },
+ { "a", "abc", true, SELF, true, "user" },
+ { "ab", "abc", true, SELF, true, "user" },
+ { "ab", "*c", true, SELF, true, "user" },
+ { "*b", "a*bc", true, SELF, true, "user" },
+ { "a*b", "a*bc", true, SELF, true, "user" },
+ };
+
+ Object[][] dataForPrefixMatch = {
+ // { resource, policy, excludes, matchType, result, user }
+ { "a", "abc", false, PREFIX, true, "user" },
+ { "ab", "abc", false, PREFIX, true, "user" },
+ { "ab", "*c", false, PREFIX, true, "user" },
+ { "a", "a*c", false, PREFIX, true, "user" },
+ { "ab", "a*c", false, PREFIX, true, "user" },
+ { "abc", "a*c", false, SELF, true, "user" },
+ { "abcd", "a*c", false, PREFIX, true, "user" },
+ { "abcd", "a*c*d", false, SELF, true, "user" },
+ { "abcd", "a*c*de", false, PREFIX, true, "user" },
+ { "acbd", "ab*c", false, NONE, false, "user" },
+ { "b", "ab*c", false, NONE, false, "user" },
+ { "a", "ab*", false, PREFIX, true, "user" },
+ { "b", "ab*", false, NONE, false, "user" },
};
@Test
public void testIsMatch() throws Exception {
+ ResourceElementMatchingScope matchScope =
ResourceElementMatchingScope.SELF;
+
for (Object[] row : data) {
- String resource = (String)row[0];
- String policyValue = (String)row[1];
- boolean excludes = (boolean)row[2];
- boolean result = (boolean)row[3];
- String user = (String) row[4];
+ String resource = (String)row[0];
+ String policyValue = (String)row[1];
+ boolean excludes = (boolean)row[2];
+ ResourceElementMatchType matchType = (ResourceElementMatchType)
row[3];
+ boolean result = (boolean)row[4];
+ String user = (String) row[5];
+ Map<String, Object> evalContext = new HashMap<>();
- Map<String, Object> evalContext = new HashMap<>();
RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
MatcherWrapper matcher = new MatcherWrapper(policyValue, excludes);
- assertEquals(getMessage(row), result, matcher.isMatch(resource,
ResourceElementMatchingScope.SELF, evalContext));
+
+ assertEquals(getMessage(row), matchType,
matcher.getMatchType(resource, matchScope, evalContext));
+ assertEquals(getMessage(row), result, matcher.isMatch(resource,
matchScope, evalContext));
+ }
+ }
+
+ @Test
+ public void testIsPrefixMatch() {
+ ResourceElementMatchingScope matchScope =
ResourceElementMatchingScope.SELF_OR_PREFIX;
+
+ for (Object[] row : dataForPrefixMatch) {
+ String resource = (String)row[0];
+ String policyValue = (String)row[1];
+ boolean excludes = (boolean)row[2];
+ ResourceElementMatchType matchType = (ResourceElementMatchType)
row[3];
+ boolean result = (boolean)row[4];
+ String user = (String) row[5];
+ Map<String, Object> evalContext = new HashMap<>();
+
+ RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
+
+ MatcherWrapper matcher = new MatcherWrapper(policyValue, excludes);
+
+ assertEquals(getMessage(row), matchType,
matcher.getMatchType(resource, matchScope, evalContext));
+ assertEquals(getMessage(row), result, matcher.isMatch(resource,
matchScope, evalContext));
}
}
String getMessage(Object[] row) {
- return String.format("Resource=%s, Policy=%s, excludes=%s, result=%s",
- (String)row[0], (String)row[1], (boolean)row[2],
(boolean)row[3]);
+ return String.format("Resource=%s, Policy=%s, excludes=%s,
matchScope=%s, matchType=%s, result=%s",
+ row[0], row[1], row[2], row[3], row[4], row[5]);
}
static class MatcherWrapper extends RangerDefaultResourceMatcher {
@@ -74,7 +164,7 @@ public class RangerDefaultResourceMatcherTest {
RangerResourceDef resourceDef = new RangerResourceDef();
Map<String, String> matcherOptions = new HashMap<>();
- matcherOptions.put(OPTION_WILD_CARD,
Boolean.toString(policyValue.contains(WILDCARD_ASTERISK)));
+ matcherOptions.put(OPTION_WILD_CARD,
Boolean.toString(policyValue.contains(WILDCARD_ASTERISK) ||
policyValue.contains(WILDCARD_QUESTION_MARK)));
matcherOptions.put(OPTION_IGNORE_CASE, Boolean.toString(false));
resourceDef.setMatcherOptions(matcherOptions);
diff --git
a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcherTest.java
b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcherTest.java
index ed02be674..3727b30d4 100644
---
a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcherTest.java
+++
b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcherTest.java
@@ -94,6 +94,59 @@ public class RangerPathResourceMatcherTest {
{ "/app/hbase/test.db", "/app/hbase/test.db/tmp/test.t*", true,
false, false, "user" },
};
+ Object[][] dataForSelfOrPrefixScope = {
+ // { resource, policy, optWildcard, recursive, result
+ { "/", "/app/hive/test.db", true, false, true,
"user" },
+ { "/app", "/app/hive/test.db", true, false, true,
"user" },
+ { "/app/", "/app/hive/test.db", true, false, true,
"user" },
+ { "/app/hive", "/app/hive/test.db", true, false, true,
"user" },
+ { "/app/hive/", "/app/hive/test.db", true, false, true,
"user" },
+ { "/app/hive/test.db", "/app/hive/test.db", true, false, true,
"user" },
+ { "/", "/app/*/test.db", true, false, true,
"user" },
+ { "/app", "/app/*/test.db", true, false, true,
"user" },
+ { "/app/", "/app/*/test.db", true, false, true,
"user" },
+ { "/app/hive", "/app/*/test.db", true, false, true,
"user" },
+ { "/app/hive/", "/app/*/test.db", true, false, true,
"user" },
+ { "/app/hive/test.db", "/app/*/test.db", true, false, true,
"user" },
+ { "/", "*/hive/test.db", true, false, true,
"user" },
+ { "/app", "*/hive/test.db", true, false, true,
"user" },
+ { "/app/", "*/hive/test.db", true, false, true,
"user" },
+ { "/app/hive", "*/hive/test.db", true, false, true,
"user" },
+ { "/app/hive/", "*/hive/test.db", true, false, true,
"user" },
+ { "/app/hive/test.db", "*/hive/test.db", true, false, true,
"user" },
+ { "/", "/*", true, false, true,
"user" },
+ { "/app", "/*", true, false, true,
"user" },
+ { "/app/", "/*", true, false, true,
"user" },
+ { "/app/hive", "/*", true, false, true,
"user" },
+ { "/app/hive/", "/*", true, false, true,
"user" },
+ { "/app/hive/test.db", "/*", true, false, true,
"user" },
+
+ { "/", "/app/hive/test.db", true, true, true,
"user" },
+ { "/app", "/app/hive/test.db", true, true, true,
"user" },
+ { "/app/", "/app/hive/test.db", true, true, true,
"user" },
+ { "/app/hive", "/app/hive/test.db", true, true, true,
"user" },
+ { "/app/hive/", "/app/hive/test.db", true, true, true,
"user" },
+ { "/app/hive/test.db", "/app/hive/test.db", true, true, true,
"user" },
+ { "/", "/app/*/test.db", true, true, true,
"user" },
+ { "/app", "/app/*/test.db", true, true, true,
"user" },
+ { "/app/", "/app/*/test.db", true, true, true,
"user" },
+ { "/app/hive", "/app/*/test.db", true, true, true,
"user" },
+ { "/app/hive/", "/app/*/test.db", true, true, true,
"user" },
+ { "/app/hive/test.db", "/app/*/test.db", true, true, true,
"user" },
+ { "/", "*/hive/test.db", true, true, true,
"user" },
+ { "/app", "*/hive/test.db", true, true, true,
"user" },
+ { "/app/", "*/hive/test.db", true, true, true,
"user" },
+ { "/app/hive", "*/hive/test.db", true, true, true,
"user" },
+ { "/app/hive/", "*/hive/test.db", true, true, true,
"user" },
+ { "/app/hive/test.db", "*/hive/test.db", true, true, true,
"user" },
+ { "/", "/", true, true, true,
"user" },
+ { "/app", "/", true, true, true,
"user" },
+ { "/app/", "/", true, true, true,
"user" },
+ { "/app/hive", "/", true, true, true,
"user" },
+ { "/app/hive/", "/", true, true, true,
"user" },
+ { "/app/hive/test.db", "/", true, true, true,
"user" },
+ };
+
@Test
public void testIsMatch() throws Exception {
for (Object[] row : data) {
@@ -130,6 +183,26 @@ public class RangerPathResourceMatcherTest {
}
}
+ @Test
+ public void testIsMatchForSelfOrPrefixScope() {
+ ResourceElementMatchingScope matchScope =
ResourceElementMatchingScope.SELF_OR_PREFIX;
+
+ for (Object[] row : dataForSelfOrPrefixScope) {
+ String resource = (String)row[0];
+ String policyValue = (String)row[1];
+ boolean optWildcard = (boolean)row[2];
+ boolean isRecursive = (boolean)row[3];
+ boolean result = (boolean)row[4];
+ String user = (String) row[5];
+ Map<String, Object> evalContext = new HashMap<>();
+
+ RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
+
+ MatcherWrapper matcher = new MatcherWrapper(policyValue,
optWildcard, isRecursive);
+ assertEquals(getMessage(row), result, matcher.isMatch(resource,
matchScope, evalContext));
+ }
+ }
+
String getMessage(Object[] row) {
return String.format("Resource=%s, Policy=%s, optWildcard=%s,
recursive=%s, result=%s",
(String)row[0], (String)row[1], (boolean)row[2],
(boolean)row[3], (boolean)row[4]);
diff --git
a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcherTest.java
b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcherTest.java
index 904cb61b2..cc7307615 100644
---
a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcherTest.java
+++
b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcherTest.java
@@ -53,6 +53,60 @@ public class RangerURLResourceMatcherTest {
{ "://apps/warehouse/data/emp.db",
"hdfs://app/*", true, true, false, "user" }
};
+
+ Object[][] dataForSelfOrPrefixScope = {
+ // { resource, policy, optWildcard, recursive, result
+ { "hdfs://hostname:8020/",
"hdfs://hostname:8020/app/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app",
"hdfs://hostname:8020/app/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/",
"hdfs://hostname:8020/app/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive",
"hdfs://hostname:8020/app/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive/",
"hdfs://hostname:8020/app/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive/test.db",
"hdfs://hostname:8020/app/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/",
"hdfs://hostname:8020/app/*/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app",
"hdfs://hostname:8020/app/*/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/",
"hdfs://hostname:8020/app/*/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive",
"hdfs://hostname:8020/app/*/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive/",
"hdfs://hostname:8020/app/*/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive/test.db",
"hdfs://hostname:8020/app/*/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/",
"hdfs://hostname:8020*/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app",
"hdfs://hostname:8020*/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/",
"hdfs://hostname:8020*/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive",
"hdfs://hostname:8020*/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive/",
"hdfs://hostname:8020*/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive/test.db",
"hdfs://hostname:8020*/hive/test.db", true, false, true, "user" },
+ { "hdfs://hostname:8020/",
"hdfs://hostname:8020/*", true, false, true, "user" },
+ { "hdfs://hostname:8020/app",
"hdfs://hostname:8020/*", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/",
"hdfs://hostname:8020/*", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive",
"hdfs://hostname:8020/*", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive/",
"hdfs://hostname:8020/*", true, false, true, "user" },
+ { "hdfs://hostname:8020/app/hive/test.db",
"hdfs://hostname:8020/*", true, false, true, "user" },
+
+ { "hdfs://hostname:8020/",
"hdfs://hostname:8020/app/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app",
"hdfs://hostname:8020/app/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/",
"hdfs://hostname:8020/app/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive",
"hdfs://hostname:8020/app/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive/",
"hdfs://hostname:8020/app/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive/test.db",
"hdfs://hostname:8020/app/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/",
"hdfs://hostname:8020/app/*/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app",
"hdfs://hostname:8020/app/*/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/",
"hdfs://hostname:8020/app/*/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive",
"hdfs://hostname:8020/app/*/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive/",
"hdfs://hostname:8020/app/*/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive/test.db",
"hdfs://hostname:8020/app/*/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/",
"hdfs://hostname:8020*/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app",
"hdfs://hostname:8020*/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/",
"hdfs://hostname:8020*/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive",
"hdfs://hostname:8020*/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive/",
"hdfs://hostname:8020*/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive/test.db",
"hdfs://hostname:8020*/hive/test.db", true, true, true, "user" },
+ { "hdfs://hostname:8020/",
"hdfs://hostname:8020/", true, true, true, "user" },
+ { "hdfs://hostname:8020/app",
"hdfs://hostname:8020/", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/",
"hdfs://hostname:8020/", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive",
"hdfs://hostname:8020/", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive/",
"hdfs://hostname:8020/", true, true, true, "user" },
+ { "hdfs://hostname:8020/app/hive/test.db",
"hdfs://hostname:8020/", true, true, true, "user" },
+ };
+
@Test
public void testIsMatch() throws Exception {
for (Object[] row : data) {
@@ -71,6 +125,25 @@ public class RangerURLResourceMatcherTest {
}
}
+ @Test
+ public void testIsPrefixMatch() {
+ for (Object[] row : dataForSelfOrPrefixScope) {
+ String resource = (String)row[0];
+ String policyValue = (String)row[1];
+ boolean optWildcard = (boolean)row[2];
+ boolean isRecursive = (boolean)row[3];
+ boolean result = (boolean)row[4];
+ String user = (String) row[5];
+
+ Map<String, Object> evalContext = new HashMap<>();
+
+ RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
+
+ MatcherWrapper matcher = new MatcherWrapper(policyValue,
optWildcard, isRecursive);
+ assertEquals(getMessage(row), result, matcher.isMatch(resource,
ResourceElementMatchingScope.SELF_OR_PREFIX, evalContext));
+ }
+ }
+
String getMessage(Object[] row) {
return String.format("Resource=%s, Policy=%s, optWildcard=%s,
recursive=%s, result=%s",
(String)row[0], (String)row[1], (boolean)row[2],
(boolean)row[3], (boolean)row[4]);