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;
