Repository: incubator-ranger
Updated Branches:
  refs/heads/master a39c00f95 -> c659d9aa7


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceTrie.java
----------------------------------------------------------------------
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceTrie.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceTrie.java
index 2079487..b5c8fb0 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceTrie.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceTrie.java
@@ -53,13 +53,25 @@ public class RangerResourceTrie<T extends 
RangerPolicyResourceEvaluator> {
         }
 
         Map<String, String> matcherOptions = resourceDef.getMatcherOptions();
-        String              strIgnoreCase  = matcherOptions != null ? 
matcherOptions.get(RangerAbstractResourceMatcher.OPTION_IGNORE_CASE) : null;
-        String              strWildcard    = matcherOptions != null ? 
matcherOptions.get(RangerAbstractResourceMatcher.OPTION_WILD_CARD) : null;
+
+        boolean optReplaceTokens = 
RangerAbstractResourceMatcher.getOptionReplaceTokens(matcherOptions);
+
+        String tokenReplaceSpecialChars = "";
+
+        if(optReplaceTokens) {
+            char delimiterStart  = 
RangerAbstractResourceMatcher.getOptionDelimiterStart(matcherOptions);
+            char delimiterEnd    = 
RangerAbstractResourceMatcher.getOptionDelimiterEnd(matcherOptions);
+            char delimiterEscape = 
RangerAbstractResourceMatcher.getOptionDelimiterEscape(matcherOptions);
+
+            tokenReplaceSpecialChars += delimiterStart;
+            tokenReplaceSpecialChars += delimiterEnd;
+            tokenReplaceSpecialChars += delimiterEscape;
+        }
 
         this.resourceName  = resourceDef.getName();
-        this.optIgnoreCase = strIgnoreCase != null ? 
Boolean.parseBoolean(strIgnoreCase) : false;
-        this.optWildcard   = strWildcard != null ? 
Boolean.parseBoolean(strWildcard) : false;
-        this.wildcardChars = optWildcard ? DEFAULT_WILDCARD_CHARS : "";
+        this.optIgnoreCase = 
RangerAbstractResourceMatcher.getOptionIgnoreCase(matcherOptions);
+        this.optWildcard   = 
RangerAbstractResourceMatcher.getOptionWildCard(matcherOptions);
+        this.wildcardChars = optWildcard ? DEFAULT_WILDCARD_CHARS + 
tokenReplaceSpecialChars : "" + tokenReplaceSpecialChars;
         this.root          = new TrieNode(Character.valueOf((char)0));
 
         for(T evaluator : evaluators) {
@@ -79,7 +91,7 @@ public class RangerResourceTrie<T extends 
RangerPolicyResourceEvaluator> {
             } else {
                 RangerResourceMatcher resourceMatcher = 
evaluator.getResourceMatcher(resourceName);
 
-                if(resourceMatcher != null && resourceMatcher.isMatchAny()) {
+                if(resourceMatcher != null && (resourceMatcher.isMatchAny())) {
                     root.addWildcardEvaluator(evaluator);
                 } else {
                     if(CollectionUtils.isNotEmpty(policyResource.getValues())) 
{

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java
----------------------------------------------------------------------
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java
index 0a2b451..dbdc935 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java
@@ -110,6 +110,28 @@ public class ServiceDefUtil {
         return ret;
     }
 
+    public static String getOption(Map<String, String> options, String name, 
String defaultValue) {
+        String ret = options != null && name != null ? options.get(name) : 
null;
+
+        if(ret == null) {
+            ret = defaultValue;
+        }
+
+        return ret;
+    }
+
+    public static boolean getBooleanOption(Map<String, String> options, String 
name, boolean defaultValue) {
+        String val = getOption(options, name, null);
+
+        return val == null ? defaultValue : Boolean.parseBoolean(val);
+    }
+
+    public static char getCharOption(Map<String, String> options, String name, 
char defaultValue) {
+        String val = getOption(options, name, null);
+
+        return StringUtils.isEmpty(val) ? defaultValue : val.charAt(0);
+    }
+
     private static void normalizeDataMaskDef(RangerServiceDef serviceDef) {
         if(serviceDef != null && serviceDef.getDataMaskDef() != null) {
             List<RangerResourceDef>   dataMaskResources   = 
serviceDef.getDataMaskDef().getResources();
@@ -282,4 +304,5 @@ public class ServiceDefUtil {
 
         return ret;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/main/java/org/apache/ranger/plugin/util/StringTokenReplacer.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..f7047f3
--- /dev/null
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/StringTokenReplacer.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.plugin.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class StringTokenReplacer {
+    private final char startChar;
+    private final char endChar;
+    private final char escapeChar;
+    private final String tokenPrefix;
+
+    public StringTokenReplacer(char startChar, char endChar, char escapeChar, 
String tokenPrefix) {
+        this.startChar  = startChar;
+        this.endChar    = endChar;
+        this.escapeChar = escapeChar;
+        this.tokenPrefix = tokenPrefix;
+    }
+
+    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)) {
+            return value;
+        }
+
+        StringBuilder ret   = new StringBuilder();
+        StringBuilder token = null;
+
+        for(int i = 0; i < value.length(); i++) {
+            char c = value.charAt(i);
+
+            if(c == escapeChar) {
+                i++;
+                if(i < value.length()) {
+                    c = value.charAt(i);
+                    if(token != null) {
+                        token.append(c);
+                    } else {
+                        ret.append(c);
+                    }
+                }
+                continue;
+            }
+
+            if(token == null) { // not in token
+                if(c == startChar) {
+                    token = new StringBuilder();
+                } else {
+                    ret.append(c);
+                }
+            } else { // in token
+                if(c == endChar) {
+                    String rawToken = token.toString();
+                    if (tokenPrefix.length() == 0 || 
rawToken.startsWith(tokenPrefix)) {
+                        Object replaced = 
RangerAccessRequestUtil.getTokenFromContext(tokens, 
rawToken.substring(tokenPrefix.length()));
+                        if (replaced != null) {
+                            ret.append(replaced.toString());
+                        }
+                    } else {
+                        ret.append(startChar).append(token).append(endChar);
+                    }
+                    token = null;
+                } else {
+                    token.append(c);
+                }
+            }
+        }
+
+        if(token != null) { // if no endChar is found
+            ret.append(startChar).append(token);
+        }
+
+        return ret.toString();
+    }
+
+    public static void main(String[] args) {
+        char                startChar  = '%';
+        char                endChar    = '%';
+        char                escapeChar = '\\';
+        String              tokenPrefix = "ranger:";
+        Map<String, Object> tokens     = new HashMap<String, Object>();
+
+        tokens.put("USER", "testUser");
+        tokens.put("COUNTRY", "USA");
+        tokens.put("STATE", "CA");
+        tokens.put("CITY", "Santa Clara");
+
+        StringTokenReplacer tokenReplacer = new StringTokenReplacer(startChar, 
endChar, escapeChar, tokenPrefix);
+
+        if(args.length == 0) {
+            args = new String[] {
+                    "/home/%USER%/*",
+                    "/home/%ranger:USER%/*",
+                    "tmp_%USER%",
+                    "tmp_%ranger:USER%",
+                    "%USER%_db",
+                    "%ranger:USER%_db",
+                    "\\%USER_db",
+                    "\\%ranger:USER_db",
+                    "\\%USER%_db",
+                    "\\%ranger:USER%_db",
+            };
+        }
+
+        for(String str : args) {
+            System.out.println(str + " ==> " + 
tokenReplacer.replaceTokens(str, tokens));
+        }
+    }}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcherTest.java
----------------------------------------------------------------------
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 48bc6ee..e2c7c27 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
@@ -21,6 +21,8 @@ package org.apache.ranger.plugin.resourcematcher;
 
 import org.junit.Test;
 
+import java.util.Map;
+
 import static org.junit.Assert.*;
 
 public class RangerAbstractResourceMatcherTest {
@@ -40,9 +42,9 @@ public class RangerAbstractResourceMatcherTest {
     static class AbstractMatcherWrapper extends RangerAbstractResourceMatcher {
 
         @Override
-        public boolean isMatch(String resource) {
+        public boolean isMatch(String resource, Map<String, Object> 
evalContext) {
             fail("This method is not expected to be used by test!");
             return false;
         }
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcherTest.java
----------------------------------------------------------------------
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 d2fb62c..7532061 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
@@ -21,24 +21,28 @@ package org.apache.ranger.plugin.resourcematcher;
 
 import com.google.common.collect.Lists;
 import org.apache.ranger.plugin.model.RangerPolicy;
+import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.junit.Test;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import static org.junit.Assert.*;
 
 public class RangerDefaultResourceMatcherTest {
 
     Object[][] data = {
             // { resource, policy, excludes, result
-            { "*",  "*",  false, true },  // resource is all values
-            { "*",  "*",  true,  false },
-            { "*",  "a*", false, false }, // but, policy is not match any
-            { "*",  "a*", true,  false }, // ==> compare with above: exclude 
flag has no effect here
-            { "a*", "a",  false, false }, // resource has regex marker!
-            { "a*", "a",  true,  true },
-            { "a",  "a",  false, true },  // exact match
-            { "a",  "a",  true,  false },
-            { "a1", "a*", false, true },  // trivial regex match
-            { "a1", "a*", true,  false },
+            { "*",  "*",  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" },
     };
 
     @Test
@@ -48,9 +52,13 @@ public class RangerDefaultResourceMatcherTest {
             String policyValue = (String)row[1];
             boolean excludes = (boolean)row[2];
             boolean result = (boolean)row[3];
+            String user = (String) row[4];
+
+            Map<String, Object> evalContext = new HashMap<String, Object>();
+            RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
 
             MatcherWrapper matcher = new MatcherWrapper(policyValue, excludes);
-            assertEquals(getMessage(row), result, matcher.isMatch(resource));
+            assertEquals(getMessage(row), result, matcher.isMatch(resource, 
evalContext));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcherTest.java
----------------------------------------------------------------------
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 c9d207f..da81d81 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
@@ -21,29 +21,33 @@ package org.apache.ranger.plugin.resourcematcher;
 
 import com.google.common.collect.Lists;
 import org.apache.ranger.plugin.model.RangerPolicy;
+import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.junit.Test;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import static org.junit.Assert.assertEquals;
 
 public class RangerPathResourceMatcherTest {
 
     Object[][] data = {
             // { resource, policy, optWildcard, recursive, result
-            { "/app/hive/test.db",    "/",                 true, false, false 
},
-            { "/app/hive/test.db",    "/",                 true, true,  true },
-            { "/app/hive/test.db",    "/*",                true, false, true },
-            { "/app/hbase/test.tbl",  "/*",                true, false, true },
-            { "/app/hive/test.db",    "/app",              true, false, false 
},
-            { "/app/hive/test.db",    "/app/",             true, false, false 
},
-            { "/app/hive/test.db",    "/app/",             true, true,  true },
-            { "/app/hive/test.db",    "/app/*",            true, false, true },
-            { "/app/hbase/test.tbl",  "/app/*",            true, false, true },
-            { "/app/hive/test.db",    "/app/hive/*",       true, false, true },
-            { "/app/hbase/test.tbl",  "/app/hive/*",       true, false, false 
},
-            { "/app/hive/test.db",    "/app/hive/test*",   true, false, true },
-            { "/app/hbase/test.tbl",  "/app/hive/test*",   true, false, false 
},
-            { "/app/hive/test.db",    "/app/hive/test.db", true, false, true },
-            { "/app/hbase/test.tbl",  "/app/hive/test.db", true, false, false 
},
+            { "/app/hive/test.db",    "/",                 true, false, false, 
"user" },
+            { "/app/hive/test.db",    "/",                 true, true,  true, 
"user" },
+            { "/app/hive/test.db",    "/*",                true, false, true, 
"user" },
+            { "/app/hbase/test.tbl",  "/*",                true, false, true, 
"user" },
+            { "/app/hive/test.db",    "/app",              true, false, false, 
"user" },
+            { "/app/hive/test.db",    "/app/",             true, false, false, 
"user" },
+            { "/app/hive/test.db",    "/app/",             true, true,  true, 
"user" },
+            { "/app/hive/test.db",    "/app/*",            true, false, true, 
"user" },
+            { "/app/hbase/test.tbl",  "/app/*",            true, false, true, 
"user" },
+            { "/app/hive/test.db",    "/app/hive/*",       true, false, true, 
"user" },
+            { "/app/hbase/test.tbl",  "/app/hive/*",       true, false, false, 
"user" },
+            { "/app/hive/test.db",    "/app/hive/test*",   true, false, true, 
"user" },
+            { "/app/hbase/test.tbl",  "/app/hive/test*",   true, false, false, 
"user" },
+            { "/app/hive/test.db",    "/app/hive/test.db", true, false, true, 
"user" },
+            { "/app/hbase/test.tbl",  "/app/hive/test.db", true, false, false, 
"user" },
     };
 
     @Test
@@ -54,9 +58,13 @@ public class RangerPathResourceMatcherTest {
             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<String, Object>();
+            RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
 
             MatcherWrapper matcher = new MatcherWrapper(policyValue, 
optWildcard, isRecursive);
-            assertEquals(getMessage(row), result, matcher.isMatch(resource));
+            assertEquals(getMessage(row), result, matcher.isMatch(resource, 
evalContext));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/TestResourceMatcher.java
----------------------------------------------------------------------
diff --git 
a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/TestResourceMatcher.java
 
b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/TestResourceMatcher.java
index 9b870d4..2cb8fde 100644
--- 
a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/TestResourceMatcher.java
+++ 
b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/TestResourceMatcher.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.*;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
@@ -39,7 +40,7 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 
 public class TestResourceMatcher {
-       static Gson               gsonBuilder  = null;
+       static Gson gsonBuilder = null;
 
        @BeforeClass
        public static void setUpBeforeClass() throws Exception {
@@ -74,6 +75,20 @@ public class TestResourceMatcher {
                runTestsFromResourceFiles(tests);
        }
 
+       @Test
+    public void testResourceMatcher_dynamic() throws Exception {
+        String[] tests = { 
"/resourcematcher/test_resourcematcher_dynamic.json"};
+
+        runTestsFromResourceFiles(tests);
+    }
+
+       @Test
+       public void testResourceMatcher_wildcards_as_delimiters() throws 
Exception {
+               String[] tests = { 
"/resourcematcher/test_resourcematcher_wildcards_as_delimiters.json"};
+
+               runTestsFromResourceFiles(tests);
+       }
+
        private void runTestsFromResourceFiles(String[] resourceNames) throws 
Exception {
                for(String resourceName : resourceNames) {
                        InputStream       inStream = 
this.getClass().getResourceAsStream(resourceName);
@@ -97,7 +112,7 @@ public class TestResourceMatcher {
                                }
 
                                boolean expected = oneTest.result;
-                               boolean result   = 
matcher.isMatch(oneTest.input);
+                               boolean result   = 
matcher.isMatch(oneTest.input, oneTest.evalContext);
 
                                assertEquals("isMatch() failed! " + 
testCase.name + ":" + oneTest.name + ": input=" + oneTest.input, expected, 
result);
                        }
@@ -130,6 +145,7 @@ public class TestResourceMatcher {
                        class OneTest {
                                String  name;
                                String  input;
+                               Map<String, Object> evalContext;
                                boolean result;
                        }
                }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/test/resources/policyengine/test_policyengine_hdfs_resourcespec.json
----------------------------------------------------------------------
diff --git 
a/agents-common/src/test/resources/policyengine/test_policyengine_hdfs_resourcespec.json
 
b/agents-common/src/test/resources/policyengine/test_policyengine_hdfs_resourcespec.json
index da0a629..384beb8 100644
--- 
a/agents-common/src/test/resources/policyengine/test_policyengine_hdfs_resourcespec.json
+++ 
b/agents-common/src/test/resources/policyengine/test_policyengine_hdfs_resourcespec.json
@@ -5,7 +5,11 @@
     "name":"hdfs",
     "id":1,
     "resources":[
-    
{"name":"path","type":"path","level":1,"mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher","matcherOptions":{"wildCard":true,
 "ignoreCase":true},"label":"Resource Path","description":"HDFS file or 
directory path"}
+    
{"name":"path","type":"path","level":1,"mandatory":true,"lookupSupported":true,
+      
"matcher":"org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher",
+      "matcherOptions":{"wildCard":true, "ignoreCase":true},
+      "startDelimiterChar": "{", "endDelimiterChar": "}", "escapeChar":"%",
+      "label":"Resource Path","description":"HDFS file or directory path"}
     ],
     "accessTypes":[
       {"name":"read","label":"Read"},
@@ -23,9 +27,33 @@
        
{"accesses":[{"type":"read","isAllowed":true}],"users":[],"groups":["finance"],"delegateAdmin":false,
 "conditions":[ ] }
      ]
     }
+    ,
+    {"id":2,"name":"allow-read-to-{USER} under 
/home/{USER}/","isEnabled":true,"isAuditEnabled":false,
+      "resources":{"path":{"values":["/home/{USER}/"],"isRecursive":true}},
+      "policyItems":[
+        
{"accesses":[{"type":"read","isAllowed":true}],"users":["{USER}"],"groups":[],"delegateAdmin":false,
 "conditions":[ ] }
+      ]
+    }
   ],
 
   "tests":[
+    {"name":"DENY 'read /home/user1/tmp/sales.db' for user=user2",
+      "request":{
+        "resource":{"elements":{"path":"/home/user1/tmp/sales.db"}},
+        "accessType":"read","user":"user2","userGroups":[],"requestData":"DENY 
read /home/user1/tmp/sales.db to user2"
+      },
+      "result":{"isAudited":false,"isAllowed":false,"policyId":-1}
+    }
+    ,
+    {"name":"ALLOW 'read /home/user1/tmp/sales.db' for user=user1",
+      "request":{
+        "resource":{"elements":{"path":"/home/user1/tmp/sales.db"}},
+        
"accessType":"read","user":"user1","userGroups":[],"requestData":"ALLOW read 
/home/user1/tmp/sales.db to user1"
+      },
+      "result":{"isAudited":false,"isAllowed":true,"policyId":2}
+    }
+  ,
+
     {"name":"ALLOW 'read /finance/restricted/tmp/sales.db' for g=finance",
      "request":{
       "resource":{"elements":{"path":"/finance/restricted/tmp/sales.db"}},
@@ -33,6 +61,7 @@
      },
      "result":{"isAudited":true,"isAllowed":true,"policyId":1}
     }
+
   ]
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/test/resources/resourcematcher/test_resourcematcher_default.json
----------------------------------------------------------------------
diff --git 
a/agents-common/src/test/resources/resourcematcher/test_resourcematcher_default.json
 
b/agents-common/src/test/resources/resourcematcher/test_resourcematcher_default.json
index 918c30f..50b4cc3 100644
--- 
a/agents-common/src/test/resources/resourcematcher/test_resourcematcher_default.json
+++ 
b/agents-common/src/test/resources/resourcematcher/test_resourcematcher_default.json
@@ -1,5 +1,28 @@
 {
   "testCases":[
+        {
+            "name":"values={USER}_simple, %{USER}_simple; wildCard=true; 
ignoreCase=true; startDelimiter={, endDelimiter=}, escapeChar=%",
+            "resourceDef":{
+                
"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+                "matcherOptions":{"wildCard":true, "ignoreCase":true, 
"replaceTokens":true, "tokenDelimiterEscape":"%", 
"tokenDelimiterPrefix":"rangerToken:" }
+            },
+            "policyResource":{
+                "values": ["{rangerToken:USER}_simple", "simple_{USER}", 
"{USER}_simple"]
+            },
+            "tests":[
+                { "name":"all-lower","input":"admin_simple", "evalContext": { 
"token:USER": "admin"}, "result":true},
+                { "name":"all-upper","input":"{USER}_SIMPLE", "result":true},
+                { "name":"mixed-case","input":"_SiMpLe", "evalContext": { 
"token:USER": ""}, "result":true},
+                { "name":"invalid-all-lower-wild","input":"other-simple", 
"result":false},
+                { "name":"invalid-all-upper-wild","input":"OTHER-SIMPLE", 
"result":false},
+                { "name":"invalid-mixed-case-wild","input":"OtHeR-SiMpLe", 
"result":false},
+                { "name":"escaped-delimiter","input":"%{USER}_SiMpLe", 
"evalContext": { "token:USER": ""}, "result":false},
+                { 
"name":"not-escaped-delimiter-with-evalContext","input":"{USER}_SiMpLe", 
"evalContext": { "token:USER": ""}, "result":true},
+                { 
"name":"not-escaped-delimiter-no-evalContext","input":"{USER}_SiMpLe", 
"result":true},
+                { "name":"with-no-prefix","input":"simple_admin", 
"evalContext": { "token:USER": "admin"}, "result":false},
+                { 
"name":"with-no-prefix-straight-match","input":"simple_{USER}", "evalContext": 
{ "token:USER": "admin"}, "result":true}
+            ]
+        },
        {
       "name":"value=simple; wildCard=true; ignoreCase=true",
       "resourceDef":{
@@ -350,4 +373,4 @@
       ]
        }
   ]
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/test/resources/resourcematcher/test_resourcematcher_dynamic.json
----------------------------------------------------------------------
diff --git 
a/agents-common/src/test/resources/resourcematcher/test_resourcematcher_dynamic.json
 
b/agents-common/src/test/resources/resourcematcher/test_resourcematcher_dynamic.json
new file mode 100644
index 0000000..168a50f
--- /dev/null
+++ 
b/agents-common/src/test/resources/resourcematcher/test_resourcematcher_dynamic.json
@@ -0,0 +1,33 @@
+{
+  "testCases":[
+         {
+                 "name":"value=/; isRecursive=false; wildCard=true; 
ignoreCase=true",
+                 "resourceDef":{
+                         
"matcher":"org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher",
+                         "matcherOptions":{"wildCard":true, "ignoreCase":true, 
"replaceTokens":true, "tokenDelimiterStart":"%", "tokenDelimiterEnd":"%", 
"tokenDelimiterEscape":"@" }
+                 },
+                 "policyResource":{
+                         "values": ["/abc%xyz%w", "/xyz%somestuff%z", 
"/abc@%xyz@w", "/mad@@%xyy%"],
+                         "isRecursive":false
+                 },
+                 "tests":[
+                         { "name":"exact-path","input":"/mad@new", 
"evalContext": {"token:xyy": "new"}, "result":true}
+                         ,
+                         { "name":"exact-path","input":"/abcw", "evalContext": 
{"token:somestuff": "somethingelse"}, "result":true}
+                         ,
+                         { "name":"exact-path","input":"/abc%xyz%w", 
"evalContext": {"token:somestuff": "somethingelse", "token:xyz":"abcd"}, 
"result":false}
+                         ,
+                         { "name":"exact-path","input":"/abcabcdw", 
"evalContext": {"token:somestuff": "somethingelse", "token:xyz":"abcd"}, 
"result":true}
+                         ,
+                         { "name":"exact-path","input":"/xyzsomethingelsez", 
"evalContext": {"token:somestuff": "somethingelse"}, "result":true}
+                         ,
+                         { "name":"exact-path","input":"/abc@%xyz@w", 
"evalContext": {"token:somestuff": "somethingelse"}, "result":false}
+                         ,
+                         { "name":"exact-path","input":"/abc%xyzw", 
"evalContext": {"token:somestuff": "somethingelse"}, "result":true}
+                         ,
+                         { "name":"exact-path","input":"/abcabcdw", 
"evalContext": {"token:somestuff": "somethingelse", "xyz":"abcd"}, 
"result":false}
+
+                 ]
+         }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/test/resources/resourcematcher/test_resourcematcher_path.json
----------------------------------------------------------------------
diff --git 
a/agents-common/src/test/resources/resourcematcher/test_resourcematcher_path.json
 
b/agents-common/src/test/resources/resourcematcher/test_resourcematcher_path.json
index 25b0eb7..e1730dd 100644
--- 
a/agents-common/src/test/resources/resourcematcher/test_resourcematcher_path.json
+++ 
b/agents-common/src/test/resources/resourcematcher/test_resourcematcher_path.json
@@ -315,4 +315,4 @@
       ]
        }
   ]
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/agents-common/src/test/resources/resourcematcher/test_resourcematcher_wildcards_as_delimiters.json
----------------------------------------------------------------------
diff --git 
a/agents-common/src/test/resources/resourcematcher/test_resourcematcher_wildcards_as_delimiters.json
 
b/agents-common/src/test/resources/resourcematcher/test_resourcematcher_wildcards_as_delimiters.json
new file mode 100644
index 0000000..f896745
--- /dev/null
+++ 
b/agents-common/src/test/resources/resourcematcher/test_resourcematcher_wildcards_as_delimiters.json
@@ -0,0 +1,28 @@
+{
+  "testCases":[
+         {
+                 "name":"value=/; isRecursive=false; wildCard=false; 
ignoreCase=true",
+                 "resourceDef":{
+                         
"matcher":"org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher",
+                         "matcherOptions":{"wildCard":false, 
"ignoreCase":true, "replaceTokens":true, "tokenDelimiterStart":"*", 
"tokenDelimiterEnd":"?", "tokenDelimiterEscape":"@" }
+                 },
+                 "policyResource":{
+                         "values": ["/abc*xyz?w", "/xyz*somestuff?z", 
"/abc@*xyz@w", "/mad@@*xyy?"],
+                         "isRecursive":false
+                 },
+                 "tests":[
+                         { "name":"exact-path","input":"/abc@*xyz@w", 
"evalContext": {"token:somestuff": "somethingelse"}, "result":false}
+                         ,
+                         { "name":"exact-path","input":"/mad@new", 
"evalContext": {"token:xyy": "new"}, "result":true}
+                         ,
+                         { "name":"exact-path","input":"/abcw", "evalContext": 
{"token:somestuff": "somethingelse"}, "result":true}
+                         ,
+                         { "name":"exact-path","input":"/abc*xyz?w", 
"evalContext": {"token:somestuff": "somethingelse", "token:xyz":"abcd"}, 
"result":false}
+                         ,
+                         { "name":"exact-path","input":"/xyzsomethingelsez", 
"evalContext": {"token:somestuff": "somethingelse"}, "result":true}
+                         ,
+                         { "name":"exact-path","input":"/abc*xyzw", 
"evalContext": {"token:somestuff": "somethingelse"}, "result":true}
+                 ]
+         }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
----------------------------------------------------------------------
diff --git 
a/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java 
b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
index 5e8c540..cb50c9f 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
@@ -326,8 +326,8 @@ public class PublicAPIsv2 {
        @POST
        @Path("/api/policy/apply/")
        @Produces({ "application/json", "application/xml" })
-       public RangerPolicy applyPolicy(RangerPolicy policy) { // new API
-               return serviceREST.applyPolicy(policy);
+       public RangerPolicy applyPolicy(RangerPolicy policy, @Context 
HttpServletRequest request) { // new API
+               return serviceREST.applyPolicy(policy, request);
        }
 
        @PUT

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/c659d9aa/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
----------------------------------------------------------------------
diff --git 
a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java 
b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
index 90b146b..26e2906 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
@@ -83,6 +83,7 @@ import org.apache.ranger.plugin.service.ResourceLookupContext;
 import org.apache.ranger.plugin.store.PList;
 import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
 import org.apache.ranger.plugin.util.GrantRevokeRequest;
+import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.apache.ranger.plugin.util.RangerPerfTracer;
 import org.apache.ranger.plugin.util.SearchFilter;
 import org.apache.ranger.plugin.util.ServicePolicies;
@@ -889,7 +890,7 @@ public class ServiceREST {
                                                throw 
restErrorUtil.createGrantRevokeRESTException( "User doesn't have necessary 
permission to grant access");
                                        }
 
-                                       RangerPolicy policy = 
getExactMatchPolicyForResource(serviceName, resource);
+                                       RangerPolicy policy = 
getExactMatchPolicyForResource(serviceName, resource, userName);
        
                                        if(policy != null) {
                                                boolean policyUpdated = false;
@@ -1001,7 +1002,7 @@ public class ServiceREST {
                                        }
 
                                        if (isAllowed) {
-                                               RangerPolicy policy = 
getExactMatchPolicyForResource(serviceName, resource);
+                                               RangerPolicy policy = 
getExactMatchPolicyForResource(serviceName, resource, userName);
 
                                                if(policy != null) {
                                                        boolean policyUpdated = 
false;
@@ -1101,7 +1102,7 @@ public class ServiceREST {
                                                throw 
restErrorUtil.createGrantRevokeRESTException("User doesn't have necessary 
permission to revoke access");
                                        }
 
-                                       RangerPolicy policy = 
getExactMatchPolicyForResource(serviceName, resource);
+                                       RangerPolicy policy = 
getExactMatchPolicyForResource(serviceName, resource, userName);
 
                                        if(policy != null) {
                                                boolean policyUpdated = false;
@@ -1179,7 +1180,7 @@ public class ServiceREST {
                                        }
 
                                        if (isAllowed) {
-                                               RangerPolicy policy = 
getExactMatchPolicyForResource(serviceName, resource);
+                                               RangerPolicy policy = 
getExactMatchPolicyForResource(serviceName, resource, userName);
 
                                                if(policy != null) {
                                                        boolean policyUpdated = 
false;
@@ -1313,7 +1314,7 @@ public class ServiceREST {
        @POST
        @Path("/policies/apply")
        @Produces({ "application/json", "application/xml" })
-       public RangerPolicy applyPolicy(RangerPolicy policy) {
+       public RangerPolicy applyPolicy(RangerPolicy policy, @Context 
HttpServletRequest request) {
                if (LOG.isDebugEnabled()) {
                        LOG.debug("==> ServiceREST.applyPolicy(" + policy + 
")");
                }
@@ -1328,7 +1329,8 @@ public class ServiceREST {
                                        throw new Exception("Applied policy 
contains condition(s); not supported:" + policy);
                                }
 
-                               RangerPolicy existingPolicy = 
getExactMatchPolicyForResource(policy.getService(), policy.getResources());
+                               String user = request.getRemoteUser();
+                               RangerPolicy existingPolicy = 
getExactMatchPolicyForResource(policy.getService(), policy.getResources(), 
StringUtils.isNotBlank(user) ? user :"admin");
 
                                if (existingPolicy == null) {
                                        ret = createPolicy(policy, null);
@@ -1959,14 +1961,18 @@ public class ServiceREST {
                }
        }
 
-       private RangerPolicy getExactMatchPolicyForResource(String serviceName, 
RangerAccessResource resource) throws Exception {
+       private RangerPolicy getExactMatchPolicyForResource(String serviceName, 
RangerAccessResource resource, String user) throws Exception {
                if(LOG.isDebugEnabled()) {
-                       LOG.debug("==> 
ServiceREST.getExactMatchPolicyForResource(" + resource + ")");
+                       LOG.debug("==> 
ServiceREST.getExactMatchPolicyForResource(" + resource + ", " + user + ")");
                }
 
                RangerPolicy       ret          = null;
                RangerPolicyEngine policyEngine = getPolicyEngine(serviceName);
-               List<RangerPolicy> policies     = policyEngine != null ? 
policyEngine.getExactMatchPolicies(resource) : null;
+
+               Map<String, Object> evalContext = new HashMap<String, Object>();
+               RangerAccessRequestUtil.setCurrentUserInContext(evalContext, 
user);
+
+               List<RangerPolicy> policies     = policyEngine != null ? 
policyEngine.getExactMatchPolicies(resource, evalContext) : null;
 
                if(CollectionUtils.isNotEmpty(policies)) {
                        // at this point, ret is a policy in policy-engine; the 
caller might update the policy (for grant/revoke); so get a copy from the store
@@ -1974,20 +1980,24 @@ public class ServiceREST {
                }
 
                if(LOG.isDebugEnabled()) {
-                       LOG.debug("<== 
ServiceREST.getExactMatchPolicyForResource(" + resource + "): " + ret);
+                       LOG.debug("<== 
ServiceREST.getExactMatchPolicyForResource(" + resource + ", " + user + "): " + 
ret);
                }
 
                return ret;
        }
 
-       private RangerPolicy getExactMatchPolicyForResource(String serviceName, 
Map<String, RangerPolicyResource> resources) throws Exception {
+       private RangerPolicy getExactMatchPolicyForResource(String serviceName, 
Map<String, RangerPolicyResource> resources, String user) throws Exception {
                if(LOG.isDebugEnabled()) {
-                       LOG.debug("==> 
ServiceREST.getExactMatchPolicyForResource(" + resources + ")");
+                       LOG.debug("==> 
ServiceREST.getExactMatchPolicyForResource(" + resources + ", " + user + ")");
                }
 
                RangerPolicy       ret          = null;
                RangerPolicyEngine policyEngine = getPolicyEngine(serviceName);
-               List<RangerPolicy> policies     = policyEngine != null ? 
policyEngine.getExactMatchPolicies(resources) : null;
+
+               Map<String, Object> evalContext = new HashMap<String, Object>();
+               RangerAccessRequestUtil.setCurrentUserInContext(evalContext, 
user);
+
+               List<RangerPolicy> policies     = policyEngine != null ? 
policyEngine.getExactMatchPolicies(resources, evalContext) : null;
 
                if(CollectionUtils.isNotEmpty(policies)) {
                        // at this point, ret is a policy in policy-engine; the 
caller might update the policy (for grant/revoke); so get a copy from the store
@@ -1995,7 +2005,7 @@ public class ServiceREST {
                }
 
                if(LOG.isDebugEnabled()) {
-                       LOG.debug("<== 
ServiceREST.getExactMatchPolicyForResource(" + resources + "): " + ret);
+                       LOG.debug("<== 
ServiceREST.getExactMatchPolicyForResource(" + resources + ", " + user + "): " 
+ ret);
                }
 
                return ret;


Reply via email to