diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDataShareEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDataShareEvaluator.java index d02ef6abde..43282e9baa 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDataShareEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDataShareEvaluator.java @@ -127,7 +127,7 @@ public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls boolean isConditional = conditionEvaluator != null; for (GdsSharedResourceEvaluator evaluator : evaluators) { - evaluator.getResourceACLs(request, acls, isConditional, dshidEvaluators); + evaluator.getResourceACLs(request, acls, isConditional, this, dshidEvaluators); } } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDatasetEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDatasetEvaluator.java index 9bdff2ce96..088d2c727d 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDatasetEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDatasetEvaluator.java @@ -149,7 +149,7 @@ public void evaluate(RangerAccessRequest request, GdsAccessResult result, Collec LOG.debug("<== GdsDatasetEvaluator.evaluate({}, {}, {})", request, result, projectsToEval); } - public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set allowedAccessTypes) { + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, GdsDataShareEvaluator dshEvaluator, GdsSharedResourceEvaluator sharedResourceEvaluator, GdsDshidEvaluator dshidEvaluator) { if (isActive()) { acls.getDatasets().add(getName()); @@ -157,16 +157,40 @@ public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls GdsDatasetAccessRequest datasetRequest = new GdsDatasetAccessRequest(getId(), gdsServiceDef, request); for (RangerPolicyEvaluator policyEvaluator : policyEvaluators) { - policyEvaluator.getResourceACLs(datasetRequest, acls, isConditional, allowedAccessTypes, RangerPolicyResourceMatcher.MatchType.SELF, null); + policyEvaluator.getResourceACLs(datasetRequest, acls, isConditional, sharedResourceEvaluator.getAllowedAccessTypes(), RangerPolicyResourceMatcher.MatchType.SELF, null); } } for (GdsDipEvaluator dipEvaluator : dipEvaluators) { - dipEvaluator.getResourceACLs(request, acls, isConditional, allowedAccessTypes); + dipEvaluator.getResourceACLs(request, acls, isConditional, sharedResourceEvaluator, dshEvaluator, dshidEvaluator.getDatasetEvaluator()); } } } + public void getResourceMasks(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, GdsSharedResourceEvaluator sharedResourceEvaluator, GdsDataShareEvaluator dshEvaluator) { + if (isActive()) { + acls.getDatasets().add(getName()); + + if (!policyEvaluators.isEmpty()) { + isConditional = isConditional || scheduleEvaluator != null; + + GdsDatasetAccessRequest datasetRequest = new GdsDatasetAccessRequest(getId(), gdsServiceDef, request); + + for (RangerPolicyEvaluator policyEvaluator : policyEvaluators) { + boolean isPolicyConditional = isConditional || policyEvaluator.getPolicyConditionsCount() != 0 || policyEvaluator.getValidityScheduleEvaluatorsCount() != 0; + + // TODO: updated acls with masks from sharedResourceEvaluator and dshEvaluator + } + } + + /* TODO: + for (GdsDipEvaluator dipEvaluator : dipEvaluators) { + dipEvaluator.getResourceMasks(request, acls, isConditional, sharedResourceEvaluator, dshEvaluator, this); + } + */ + } + } + public boolean hasReference(Set users, Set groups, Set roles) { boolean ret = false; diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDipEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDipEvaluator.java index 891f0591c3..d67dc92d97 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDipEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDipEvaluator.java @@ -27,8 +27,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Set; - public class GdsDipEvaluator { private static final Logger LOG = LoggerFactory.getLogger(GdsDipEvaluator.class); @@ -79,12 +77,12 @@ public boolean isAllowed(RangerAccessRequest request) { return ret; } - public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set allowedAccessTypes) { + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, GdsSharedResourceEvaluator sharedResourceEvaluator, GdsDataShareEvaluator dshEvaluator, GdsDatasetEvaluator dsEvaluator) { LOG.debug("==> GdsDipEvaluator.getResourceACLs({}, {})", request, acls); isConditional = isConditional || scheduleEvaluator != null; - projectEvaluator.getResourceACLs(request, acls, isConditional, allowedAccessTypes); + projectEvaluator.getResourceACLs(request, acls, isConditional, dshEvaluator, sharedResourceEvaluator, this); LOG.debug("<== GdsDipEvaluator.getResourceACLs({}, {})", request, acls); } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDshidEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDshidEvaluator.java index a1f942a820..16ec19f1a6 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDshidEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDshidEvaluator.java @@ -27,8 +27,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Set; - public class GdsDshidEvaluator { private static final Logger LOG = LoggerFactory.getLogger(GdsDshidEvaluator.class); @@ -79,13 +77,23 @@ public boolean isAllowed(RangerAccessRequest request) { return ret; } - public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set allowedAccessTypes) { + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, GdsDataShareEvaluator dshEvaluator, GdsSharedResourceEvaluator sharedResourceEvaluator) { LOG.debug("==> GdsDshidEvaluator.getResourceACLs({}, {})", request, acls); isConditional = isConditional || scheduleEvaluator != null; - datasetEvaluator.getResourceACLs(request, acls, isConditional, allowedAccessTypes); + datasetEvaluator.getResourceACLs(request, acls, isConditional, dshEvaluator, sharedResourceEvaluator, this); LOG.debug("<== GdsDshidEvaluator.getResourceACLs({}, {})", request, acls); } + + public void getResourceMasks(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, GdsSharedResourceEvaluator sharedResourceEvaluator, GdsDataShareEvaluator dshEvaluator) { + LOG.debug("==> GdsDshidEvaluator.getResourceMasks({}, {})", request, acls); + + isConditional = isConditional || scheduleEvaluator != null; + + datasetEvaluator.getResourceMasks(request, acls, isConditional, sharedResourceEvaluator, dshEvaluator); + + LOG.debug("<== GdsDshidEvaluator.getResourceMasks({}, {})", request, acls); + } } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsPolicyEngine.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsPolicyEngine.java index 2540eec961..9970773a3e 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsPolicyEngine.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsPolicyEngine.java @@ -95,7 +95,7 @@ public GdsAccessResult evaluate(RangerAccessRequest request) { evaluate(request, RangerPolicy.POLICY_TYPE_ACCESS, ret); - if (ret.getIsAllowed()) { + if (serviceDefHelper.isDataMaskSupported() && ret.getIsAllowed()) { evaluate(request, RangerPolicy.POLICY_TYPE_DATAMASK, ret); } @@ -128,6 +128,14 @@ public RangerResourceACLs getResourceACLs(RangerAccessRequest request) { getDataShareResources(request, RangerPolicy.POLICY_TYPE_ACCESS).keySet().forEach(e -> e.getResourceACLs(request, ret)); + if (serviceDefHelper.isDataMaskSupported()) { + getDataShareResources(request, RangerPolicy.POLICY_TYPE_DATAMASK).keySet().forEach(e -> e.getResourceACLs(request, ret)); + } + + if (serviceDefHelper.isRowFilterSupported()) { + getDataShareResources(request, RangerPolicy.POLICY_TYPE_ROWFILTER).keySet().forEach(e -> e.getResourceACLs(request, ret)); + } + ret.finalizeAcls(); return ret; diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsProjectEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsProjectEvaluator.java index f72258a140..93c218872b 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsProjectEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsProjectEvaluator.java @@ -137,7 +137,21 @@ public void evaluate(RangerAccessRequest request, GdsAccessResult result) { LOG.debug("<== GdsDatasetEvaluator.evaluate({}, {})", request, result); } - public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set allowedAccessTypes) { + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, GdsDataShareEvaluator dshEvaluator, GdsSharedResourceEvaluator sharedResourceEvaluator, GdsDipEvaluator dipEvaluator) { + if (isActive()) { + acls.getProjects().add(getName()); + + if (!policyEvaluators.isEmpty()) { + GdsProjectAccessRequest projectRequest = new GdsProjectAccessRequest(getId(), gdsServiceDef, request); + + for (RangerPolicyEvaluator policyEvaluator : policyEvaluators) { + policyEvaluator.getResourceACLs(projectRequest, acls, isConditional, sharedResourceEvaluator.getAllowedAccessTypes(), RangerPolicyResourceMatcher.MatchType.SELF, null); + } + } + } + } + + public void getResourceMasks(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set allowedAccessTypes) { if (isActive()) { acls.getProjects().add(getName()); diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsSharedResourceEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsSharedResourceEvaluator.java index 99d0e15331..de11729b70 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsSharedResourceEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsSharedResourceEvaluator.java @@ -205,7 +205,7 @@ public boolean isAllowed(RangerAccessRequest request) { return ret; } - public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, List dshidEvaluators) { + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, GdsDataShareEvaluator dshEvaluator, List dshidEvaluators) { LOG.debug("==> GdsSharedResourceEvaluator.getResourceACLs({}, {})", request, acls); boolean isResourceMatch = policyResourceMatcher.isMatch(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext()); @@ -214,13 +214,31 @@ public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls isConditional = isConditional || conditionEvaluator != null; for (GdsDshidEvaluator dshidEvaluator : dshidEvaluators) { - dshidEvaluator.getResourceACLs(request, acls, isConditional, getAllowedAccessTypes()); + dshidEvaluator.getResourceACLs(request, acls, isConditional, dshEvaluator, this); } + + // TODO: get mask and row-filter } LOG.debug("<== GdsSharedResourceEvaluator.getResourceACLs({}, {})", request, acls); } + public void getResourceMasks(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, GdsDataShareEvaluator dshEvaluator, List dshidEvaluators) { + LOG.debug("==> GdsSharedResourceEvaluator.getResourceMasks({}, {})", request, acls); + + boolean isResourceMatch = policyResourceMatcher.isMatch(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext()); + + if (isResourceMatch) { + isConditional = isConditional || conditionEvaluator != null; + + for (GdsDshidEvaluator dshidEvaluator : dshidEvaluators) { + dshidEvaluator.getResourceMasks(request, acls, isConditional, this, dshEvaluator); + } + } + + LOG.debug("<== GdsSharedResourceEvaluator.getResourceMasks({}, {})", request, acls); + } + public RangerPolicyItemRowFilterInfo getRowFilter() { return resource.getRowFilter(); } diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java index 5b52aaf79e..3faea812b7 100644 --- a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java +++ b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java @@ -25,6 +25,8 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig; import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceMatchingScope; import org.apache.ranger.plugin.policyengine.RangerResourceACLs.DataMaskResult; @@ -42,6 +44,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -124,11 +127,164 @@ private void runTests(InputStreamReader reader, String testName) { RangerResourceACLs acls = policyEngine.getResourceACLs(request); - assertEquals(oneTest.name + ": userACLs mismatch", oneTest.userPermissions, acls.getUserACLs()); - assertEquals(oneTest.name + ": groupACLs mismatch", oneTest.groupPermissions, acls.getGroupACLs()); - assertEquals(oneTest.name + ": roleACLs mismatch", oneTest.rolePermissions, acls.getRoleACLs()); - assertEquals(oneTest.name + ": rowFilters mismatch", oneTest.rowFilters, acls.getRowFilters()); - assertEquals(oneTest.name + ": dataMasks mismatch", oneTest.dataMasks, acls.getDataMasks()); + boolean userACLsMatched = true; + boolean groupACLsMatched = true; + boolean roleACLsMatched = true; + boolean rowFiltersMatched = true; + boolean dataMaskingMatched = true; + + if (MapUtils.isNotEmpty(acls.getUserACLs()) && MapUtils.isNotEmpty(oneTest.userPermissions)) { + assertEquals("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name + " - userACLsMatched", oneTest.userPermissions.size(), acls.getUserACLs().size()); + + for (Map.Entry> entry : + acls.getUserACLs().entrySet()) { + String userName = entry.getKey(); + Map expected = oneTest.userPermissions.get(userName); + if (MapUtils.isNotEmpty(entry.getValue()) && MapUtils.isNotEmpty(expected)) { + // Compare + for (Map.Entry privilege : entry.getValue().entrySet()) { + if (StringUtils.equals(RangerPolicyEngine.ADMIN_ACCESS, privilege.getKey())) { + continue; + } + RangerResourceACLs.AccessResult expectedResult = expected.get(privilege.getKey()); + if (expectedResult == null) { + userACLsMatched = false; + break; + } else if (!expectedResult.equals(privilege.getValue())) { + userACLsMatched = false; + break; + } + } + } else if (!(MapUtils.isEmpty(entry.getValue()) && MapUtils.isEmpty(expected))) { + Set privileges = entry.getValue().keySet(); + + userACLsMatched = privileges.size() == 1 && privileges.contains(RangerPolicyEngine.ADMIN_ACCESS); + + break; + } + + if (!userACLsMatched) { + break; + } + } + } else if (!(MapUtils.isEmpty(acls.getUserACLs()) && MapUtils.isEmpty(oneTest.userPermissions))) { + userACLsMatched = false; + } + + if (acls.getDataMasks().isEmpty()) { + dataMaskingMatched = (oneTest.dataMasks == null || oneTest.dataMasks.isEmpty()); + } else if (acls.getDataMasks().size() != (oneTest.dataMasks == null ? 0 : oneTest.dataMasks.size())) { + dataMaskingMatched = false; + } else { + for (int i = 0; i < acls.getDataMasks().size(); i++) { + DataMaskResult found = acls.getDataMasks().get(i); + DataMaskResult expected = oneTest.dataMasks.get(i); + + dataMaskingMatched = found.equals(expected); + + if (!dataMaskingMatched) { + break; + } + } + } + + if (acls.getRowFilters().isEmpty()) { + rowFiltersMatched = (oneTest.rowFilters == null || oneTest.rowFilters.isEmpty()); + } else if (acls.getRowFilters().size() != (oneTest.rowFilters == null ? 0 : oneTest.rowFilters.size())) { + rowFiltersMatched = false; + } else { + for (int i = 0; i < acls.getRowFilters().size(); i++) { + RowFilterResult found = acls.getRowFilters().get(i); + RowFilterResult expected = oneTest.rowFilters.get(i); + + rowFiltersMatched = found.equals(expected); + + if (!rowFiltersMatched) { + break; + } + } + } + + if (MapUtils.isNotEmpty(acls.getGroupACLs()) && MapUtils.isNotEmpty(oneTest.groupPermissions)) { + assertEquals("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name + " - groupACLsMatched", oneTest.groupPermissions.size(), acls.getGroupACLs().size()); + + for (Map.Entry> entry : + acls.getGroupACLs().entrySet()) { + String groupName = entry.getKey(); + Map expected = oneTest.groupPermissions.get(groupName); + if (MapUtils.isNotEmpty(entry.getValue()) && MapUtils.isNotEmpty(expected)) { + // Compare + for (Map.Entry privilege : entry.getValue().entrySet()) { + if (StringUtils.equals(RangerPolicyEngine.ADMIN_ACCESS, privilege.getKey())) { + continue; + } + RangerResourceACLs.AccessResult expectedResult = expected.get(privilege.getKey()); + if (expectedResult == null) { + groupACLsMatched = false; + break; + } else if (!expectedResult.equals(privilege.getValue())) { + groupACLsMatched = false; + break; + } + } + } else if (!(MapUtils.isEmpty(entry.getValue()) && MapUtils.isEmpty(expected))) { + Set privileges = entry.getValue().keySet(); + + groupACLsMatched = privileges.size() == 1 && privileges.contains(RangerPolicyEngine.ADMIN_ACCESS); + + break; + } + + if (!groupACLsMatched) { + break; + } + } + } else if (!(MapUtils.isEmpty(acls.getGroupACLs()) && MapUtils.isEmpty(oneTest.groupPermissions))) { + groupACLsMatched = false; + } + + if (MapUtils.isNotEmpty(acls.getRoleACLs()) && MapUtils.isNotEmpty(oneTest.rolePermissions)) { + assertEquals("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name + " - roleACLsMatched", oneTest.rolePermissions.size(), acls.getRoleACLs().size()); + + for (Map.Entry> entry : + acls.getRoleACLs().entrySet()) { + String roleName = entry.getKey(); + Map expected = oneTest.rolePermissions.get(roleName); + if (MapUtils.isNotEmpty(entry.getValue()) && MapUtils.isNotEmpty(expected)) { + // Compare + for (Map.Entry privilege : entry.getValue().entrySet()) { + if (StringUtils.equals(RangerPolicyEngine.ADMIN_ACCESS, privilege.getKey())) { + continue; + } + RangerResourceACLs.AccessResult expectedResult = expected.get(privilege.getKey()); + if (expectedResult == null) { + roleACLsMatched = false; + break; + } else if (!expectedResult.equals(privilege.getValue())) { + roleACLsMatched = false; + break; + } + } + } else if (!(MapUtils.isEmpty(entry.getValue()) && MapUtils.isEmpty(expected))) { + Set privileges = entry.getValue().keySet(); + + roleACLsMatched = privileges.size() == 1 && privileges.contains(RangerPolicyEngine.ADMIN_ACCESS); + + break; + } + if (!roleACLsMatched) { + break; + } + } + } else if (!(MapUtils.isEmpty(acls.getRoleACLs()) && MapUtils.isEmpty(oneTest.rolePermissions))) { + roleACLsMatched = false; + } + + assertTrue("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name + " - userACLsMatched", userACLsMatched); + assertTrue("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name + " - groupACLsMatched", groupACLsMatched); + assertTrue("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name + " - roleACLsMatched", roleACLsMatched); + assertTrue("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name + " - rowFiltersMatched", rowFiltersMatched); + assertTrue("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name + " - dataMaskingMatched", dataMaskingMatched); }); } } diff --git a/agents-common/src/test/resources/policyengine/test_aclprovider_default.json b/agents-common/src/test/resources/policyengine/test_aclprovider_default.json index 105630d5e0..5434fd28c9 100644 --- a/agents-common/src/test/resources/policyengine/test_aclprovider_default.json +++ b/agents-common/src/test/resources/policyengine/test_aclprovider_default.json @@ -583,13 +583,11 @@ "tests": [ { "name": "{USER} macro in database name", "resource": { "elements": { "database": "user_madhan", "table": "test_tbl1" } }, - "groupPermissions": { "public": { "select": { "result": 2, "isFinal": true }, "update": { "result": 2, "isFinal": true } } }, - "userPermissions": {}, "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "groupPermissions": { "public": { "select": { "result": 2, "isFinal": true }, "update": { "result": 2, "isFinal": true } } } }, { "name": "${{USER.dept}} macro in database name", "resource": { "elements": { "database": "dept_engg", "table": "test_tbl1" } }, - "groupPermissions": { "public": { "select": { "result": 2, "isFinal": true } }, "engg": { "select": { "result": 1, "isFinal": true } } }, - "userPermissions": {}, "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "groupPermissions": { "public": { "select": { "result": 2, "isFinal": true } }, "engg": { "select": { "result": 1, "isFinal": true } } } }, { "name": "denyAllElse-test", @@ -599,83 +597,74 @@ "user2": {"select": {"result": -1, "isFinal": true}, "update": {"result": -1, "isFinal": true},"create": {"result": -1, "isFinal": true},"drop": {"result": -1, "isFinal": true},"alter": {"result": -1, "isFinal": true},"index": {"result": -1, "isFinal": true},"lock": {"result": -1, "isFinal": true}}, "user3": {"select": {"result": 1, "isFinal": true}, "update": {"result": 1, "isFinal": true},"create": {"result": 1, "isFinal": true},"drop": {"result": 1, "isFinal": true},"alter": {"result": 1, "isFinal": true},"index": {"result": 1, "isFinal": true},"lock": {"result": -1, "isFinal": true}}}, "groupPermissions": {"public": {"select": {"result": 2, "isFinal": true}, "update": {"result": 2, "isFinal": true},"create": {"result": 2, "isFinal": true},"drop": {"result": 2, "isFinal": true},"alter": {"result": 2, "isFinal": true},"index": {"result": 2, "isFinal": true},"lock": {"result": -1, "isFinal": true}}}, - "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "rolePermissions": {} }, { "name": "all-deny-test", "resource": {"elements":{"database":"hr", "udf":"udf" }}, "userPermissions": {}, - "groupPermissions": {"public": {"select":{"result":-1, "isFinal":true},"create":{"result":-1, "isFinal":true},"_admin":{"result":-1, "isFinal":true}}}, - "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "groupPermissions": {"public": {"select":{"result":-1, "isFinal":true},"create":{"result":-1, "isFinal":true}}} }, { "name": "no-deny-test", "resource": {"elements":{"database":"default", "table":"test1", "column":"column2"}}, - "userPermissions": {"user1":{"select":{"result":1, "isFinal":true}}, "user2":{"select":{"result":1, "isFinal":true}}, "admin":{"create":{"result":1, "isFinal":true},"drop":{"result":1, "isFinal":true},"_admin":{"result":1, "isFinal":true}}}, - "groupPermissions": {"group1": {"select":{"result":1, "isFinal":true}}, "group2": {"select":{"result":1, "isFinal":true}},"cluster-admin": {"create":{"result":1, "isFinal":true},"drop":{"result":1, "isFinal":true}, "_admin":{"result":1, "isFinal":true}}}, - "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "userPermissions": {"user1":{"select":{"result":1, "isFinal":true}}, "user2":{"select":{"result":1, "isFinal":true}}, "admin":{"create":{"result":1, "isFinal":true},"drop":{"result":1, "isFinal":true}}}, + "groupPermissions": {"group1": {"select":{"result":1, "isFinal":true}}, "group2": {"select":{"result":1, "isFinal":true}},"cluster-admin": {"create":{"result":1, "isFinal":true},"drop":{"result":1, "isFinal":true}}} }, { "name": "partial-deny-test", "resource": {"elements":{"database":"default", "table":"test2", "column":"column2"}}, - "userPermissions": {"user1":{"select":{"result":1, "isFinal":true}}, "user2":{"select":{"result":-1, "isFinal":true},"create":{"result":-1, "isFinal":true}}, "user3":{"select":{"result":1, "isFinal":true},"create":{"result":-1, "isFinal":true}},"user4":{"select":{"result":-1, "isFinal":true},"create":{"result":-1, "isFinal":true}},"admin":{"create":{"result":1, "isFinal":true},"drop":{"result":1, "isFinal":true},"_admin":{"result":1, "isFinal":true}}}, - "groupPermissions": {"group1": {"select":{"result":1, "isFinal":true}}, "group2": {"select":{"result":1, "isFinal":true}},"group3": {"select":{"result":-1, "isFinal":true},"create":{"result":-1, "isFinal":true}},"cluster-admin": {"create":{"result":1, "isFinal":true},"drop":{"result":1, "isFinal":true},"_admin":{"result":1, "isFinal":true}}}, - "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "userPermissions": {"user1":{"select":{"result":1, "isFinal":true}}, "user2":{"select":{"result":-1, "isFinal":true},"create":{"result":-1, "isFinal":true}}, "user3":{"select":{"result":1, "isFinal":true},"create":{"result":-1, "isFinal":true}},"user4":{"select":{"result":-1, "isFinal":true},"create":{"result":-1, "isFinal":true}},"admin":{"create":{"result":1, "isFinal":true},"drop":{"result":1, "isFinal":true}}}, + "groupPermissions": {"group1": {"select":{"result":1, "isFinal":true}}, "group2": {"select":{"result":1, "isFinal":true}},"group3": {"select":{"result":-1, "isFinal":true},"create":{"result":-1, "isFinal":true}},"cluster-admin": {"create":{"result":1, "isFinal":true},"drop":{"result":1, "isFinal":true}}} }, { "name": "conditional-deny-test", "resource": {"elements":{"database":"finance", "table":"fin_1", "column":"salary"}}, - "userPermissions": {"user1":{"select":{"result":1, "isFinal":true},"_admin":{"result":1, "isFinal":true}}, "user2":{"select":{"result":1, "isFinal":true},"_admin":{"result":1, "isFinal":true}}, "user3":{"select":{"result":2, "isFinal":true},"_admin":{"result":2, "isFinal":true}} }, - "groupPermissions": {"finance-controller": {"select":{"result":1, "isFinal":true},"_admin":{"result":1, "isFinal":true}}, "cluster-admin": {"select":{"result":2, "isFinal":true},"_admin":{"result":2, "isFinal":true}}}, - "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "userPermissions": {"user1":{"select":{"result":1, "isFinal":true}}, "user2":{"select":{"result":1, "isFinal":true}}, "user3":{"select":{"result":2, "isFinal":true}} }, + "groupPermissions": {"finance-controller": {"select":{"result":1, "isFinal":true}}, "cluster-admin": {"select":{"result":2, "isFinal":true}}} }, { "name": "conditional-tag-only-test-descendant", "resource": {"elements":{"database":"finance", "table":"sales"}}, "resourceMatchingScope": "SELF_OR_DESCENDANTS", - "userPermissions": {"hive":{"select":{"result":-1, "isFinal":true},"create":{"result":1, "isFinal":true}}, "admin":{"select":{"result":-1, "isFinal":true}} }, - "groupPermissions": {"public": {"index":{"result":2, "isFinal":true}}}, - "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "userPermissions": {"hive":{"select":{"result":-1, "isFinal":true},"create":{"result":1, "isFinal":true}, "drop":{"result":-1, "isFinal":true}}, "admin":{"select":{"result":-1, "isFinal":true}} }, + "groupPermissions": {"public": {"index":{"result":2, "isFinal":true}}} }, { "name": "all-types-of-policy-items", "resource": {"elements":{"database":"default", "table":"table", "column":"column"}}, - "userPermissions": {"user1":{"select":{"result":2, "isFinal":true}, "_admin":{"result":2, "isFinal":true}}, "user2":{"select":{"result":2, "isFinal":true}, "_admin":{"result":2, "isFinal":true}}, "user3":{"select":{"result":2, "isFinal":true}, "_admin":{"result":2, "isFinal":true}}, "user4":{"select":{"result":2, "isFinal":true}, "_admin":{"result":2, "isFinal":true}} }, - "groupPermissions": {"public": {"select":{"result":2, "isFinal":true}, "_admin":{"result":2, "isFinal":true}}, "cluster-admin": {"select":{"result":2, "isFinal":true}, "_admin":{"result":2, "isFinal":true}}}, - "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "userPermissions": {"user1":{"select":{"result":2, "isFinal":true}}, "user2":{"select":{"result":2, "isFinal":true}}, "user3":{"select":{"result":2, "isFinal":true}}, "user4":{"select":{"result":2, "isFinal":true}} }, + "groupPermissions": {"public": {"select":{"result":2, "isFinal":true}}, "cluster-admin": {"select":{"result":2, "isFinal":true}}} }, { "name": "public-allow-test", "resource": {"elements":{"database":"finance", "table":"accounts", "column": "status" }}, - "userPermissions": {"john":{"select":{"result":2, "isFinal":true}, "update":{"result":2, "isFinal":true}, "_admin":{"result": 2, "isFinal": true}}, "jane":{"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true}, "_admin":{"result": 2, "isFinal": true}}}, - "groupPermissions": {"public": {"select":{"result":2, "isFinal":true}}, "accounting": {"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true},"_admin":{"result":2, "isFinal":true}}, "admin": {"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true},"_admin":{"result":2, "isFinal":true}}, "housekeeping":{"select":{"result":-1, "isFinal":true}}}, - "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "userPermissions": {"john":{"select":{"result":2, "isFinal":true}, "update":{"result":2, "isFinal":true}}, "jane":{"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true}}}, + "groupPermissions": {"public": {"select":{"result":2, "isFinal":true}}, "accounting": {"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true}}, "admin": {"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true}}, "housekeeping":{"select":{"result":-1, "isFinal":true}}} }, { "name": "public-allow-test-next", "resource": {"elements":{"database":"finance", "table":"accounts", "column": "amount" }}, - "userPermissions": {"john":{"select":{"result":2, "isFinal":true}, "update":{"result":2, "isFinal":true}, "_admin":{"result":2, "isFinal":true}}, "jane":{"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true}, "_admin":{"result":2, "isFinal":true}}}, - "groupPermissions": {"public": {"select":{"result":2, "isFinal":true}}, "accounting": {"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true},"_admin":{"result":2, "isFinal":true}}, "admin": {"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true},"_admin":{"result":2, "isFinal":true}}, "housekeeping":{"drop":{"result":-1, "isFinal":true}}}, - "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "userPermissions": {"john":{"select":{"result":2, "isFinal":true}, "update":{"result":2, "isFinal":true}}, "jane":{"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true}}}, + "groupPermissions": {"public": {"select":{"result":2, "isFinal":true}}, "accounting": {"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true}}, "admin": {"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true}}, "housekeeping":{"drop":{"result":-1, "isFinal":true}}} }, { "name": "conditions-in-exceptions-test", "resource": {"elements":{"database":"db1", "table":"tbl1", "column": "col1" }}, "userPermissions": {"john":{"select":{"result":2, "isFinal":true}, "update":{"result":2, "isFinal":true}}, "jane":{"select":{"result":2, "isFinal":true},"update":{"result":2, "isFinal":true}}, "adam":{"drop":{"result":2, "isFinal":true}}, "eve":{"drop":{"result":2, "isFinal":true}}}, - "groupPermissions": {}, "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "groupPermissions": {} }, { "name": "conditions-in-some-exceptions-test", "resource": {"elements":{"database":"db2", "table":"tbl2", "column": "col2" }}, "userPermissions": {"john":{"select":{"result":1, "isFinal":true}, "update":{"result":-1, "isFinal":true}}, "jane":{"select":{"result":1, "isFinal":true},"update":{"result":1, "isFinal":true}}, "adam":{"drop":{"result":2, "isFinal":true}}, "eve":{"drop":{"result":2, "isFinal":true}}}, - "groupPermissions": {}, "rolePermissions": {}, "dataMasks": [], "rowFilters": [] + "groupPermissions": {} }, { "name": "roles-test", "resource": {"elements":{"database":"db3", "table":"tbl3", "column": "col3" }}, "userPermissions": {"john":{"select":{"result":1, "isFinal":true}, "update":{"result":1, "isFinal":true}}, "jane":{"select":{"result":1, "isFinal":true},"update":{"result":1, "isFinal":true}}, "adam":{"drop":{"result":-1, "isFinal":true}}, "eve":{"drop":{"result":-1, "isFinal":true}}}, - "rolePermissions": {"tarzan":{"select":{"result":1, "isFinal":true}, "update":{"result":1, "isFinal":true}}, "eden":{"drop":{"result":-1, "isFinal":true}}}, - "groupPermissions": {}, "dataMasks": [], "rowFilters": [] + "rolePermissions": {"tarzan":{"select":{"result":1, "isFinal":true}, "update":{"result":1, "isFinal":true}}, "eden":{"drop":{"result":-1, "isFinal":true}}} } ] } diff --git a/agents-common/src/test/resources/policyengine/test_aclprovider_hdfs.json b/agents-common/src/test/resources/policyengine/test_aclprovider_hdfs.json index 37a06787dc..9526763a2f 100644 --- a/agents-common/src/test/resources/policyengine/test_aclprovider_hdfs.json +++ b/agents-common/src/test/resources/policyengine/test_aclprovider_hdfs.json @@ -107,20 +107,23 @@ { "name": "test-finance-restricted", "resource": {"elements":{"path":"/finance/restricted"}}, + "userPermissions": {}, "groupPermissions": {"finance": {"read": {"result": 1, "isFinal": true}}}, - "userPermissions": {}, "rolePermissions": {}, "rowFilters": [], "dataMasks": [] + "rolePermissions": {} }, { "name": "test-finance-limited", "resource": {"elements":{"path":"/finance/limited"}}, + "userPermissions": {}, "groupPermissions": {"stewards": {"read": {"result": 1, "isFinal": true}}}, - "userPermissions": {}, "rolePermissions": {}, "rowFilters": [], "dataMasks": [] + "rolePermissions": {} }, { "name": "test-anything-under-public", "resource": {"elements":{"path":"/public/anything"}}, + "userPermissions": {}, "groupPermissions": {"public": {"read": {"result": 1, "isFinal": true}, "execute": {"result": 1, "isFinal": true}}}, - "userPermissions": {}, "rolePermissions": {}, "rowFilters": [], "dataMasks": [] + "rolePermissions": {} } ] } diff --git a/agents-common/src/test/resources/policyengine/test_aclprovider_mask_filter.json b/agents-common/src/test/resources/policyengine/test_aclprovider_mask_filter.json index ae9c04a6f3..c8f7acf5e2 100644 --- a/agents-common/src/test/resources/policyengine/test_aclprovider_mask_filter.json +++ b/agents-common/src/test/resources/policyengine/test_aclprovider_mask_filter.json @@ -326,8 +326,7 @@ {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"SHUFFLE"}}, {"users":["user1"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"HASH"}}, {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"MASK"}} - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, {"name":"mask: hr.employee.date_of_birth", "resource":{"elements":{"database":"hr", "table":"employee", "column":"date_of_birth"}}, @@ -335,64 +334,56 @@ {"users":["user1"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"MASK"}}, {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"SHUFFLE"}}, {"users":["user3"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"LAST_4"}, "isConditional": true} - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, {"name":"mask: hr.employee.project - conditional: validity-schedule", "resource":{"elements":{"database":"hr", "table":"employee", "column":"project"}}, "dataMasks": [ {"users":["user1"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"MASK"}, "isConditional": true}, {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"HASH"}, "isConditional": true} - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, {"name":"mask: employee.personal.city - tag-based: RESTRICTED", "resource":{"elements":{"database":"employee", "table":"personal", "column":"city"}}, "dataMasks": [ {"users":["user1"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"MASK"}}, {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"HASH"}} - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, {"name":"mask: employee.personal.mrn - tag-based: DATA_QUALITY; conditional", "resource":{"elements":{"database":"employee", "table":"personal", "column":"mrn"}}, "dataMasks": [ {"users":["user1"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"MASK"}, "isConditional": true}, {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"HASH"}, "isConditional": true} - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, {"name":"mask: employee.personal.address - tag-based: RESTRICTED-FINAL; conditional: validity-schedule", "resource":{"elements":{"database":"employee", "table":"personal", "column":"address"}}, "dataMasks": [ {"users":["user1"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"MASK"}, "isConditional": true}, {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"HASH"}, "isConditional": true} - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, {"name":"mask: finance.forecast.revenue - tag-based: RESTRICTED; conditional: tag-validity-period", "resource":{"elements":{"database":"finance", "table":"forecast", "column":"revenue"}}, "dataMasks": [ {"users":["user1"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"MASK"}, "isConditional": true}, {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "maskInfo":{"dataMaskType":"HASH"}, "isConditional": true} - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, { "name": "mask: test_db.dept_hr.col1: conditional", "resource": { "elements": { "database": "test_db", "table":"dept_hr", "column":"col1" } }, "dataMasks": [ { "users": [ ], "groups": [ "public" ], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK_NONE" }, "isConditional": true }, { "users": [ ], "groups": [ "public" ], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK_HASH" }, "isConditional": false } - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, {"name":"row-filter: employee.personal", "resource":{"elements":{"database":"employee", "table":"personal"}}, "rowFilters":[ {"users":["user1"], "groups":[], "roles":[], "accessTypes":["select"], "filterInfo":{"filterExpr":"location='US'"}}, {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "filterInfo":{"filterExpr":"location='CA'"}} - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "dataMasks": [] + ] }, {"name":"row-filter: hr.employee", "resource":{"elements":{"database":"hr", "table":"employee"}}, @@ -400,24 +391,21 @@ {"users":["user1"], "groups":[], "roles":[], "accessTypes":["select"], "filterInfo":{"filterExpr":"dept='production'"}}, {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "filterInfo":{"filterExpr":"dept='purchase'"}}, {"users":["user3"], "groups":[], "roles":[], "accessTypes":["select"], "filterInfo":{"filterExpr":"location='GR'"}, "isConditional": true} - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "dataMasks": [] + ] }, {"name":"row-filter: hr.employee2 - conditional: validity-schedule", "resource":{"elements":{"database":"hr", "table":"employee2"}}, "rowFilters":[ {"users":["user1"], "groups":[], "roles":[], "accessTypes":["select"], "filterInfo":{"filterExpr":"dept='production'"}, "isConditional": true}, {"users":["user2"], "groups":[], "roles":[], "accessTypes":["select"], "filterInfo":{"filterExpr":"dept='purchase'"}, "isConditional": true} - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "dataMasks": [] + ] }, { "name": "row-filter: test_db.dept_hr: conditional", "resource": { "elements": { "database": "test_db", "table":"dept_hr" } }, "rowFilters": [ { "users": [], "groups": [ "public" ], "roles": [], "accessTypes": [ "select" ], "filterInfo": { "filterExpr": "1 = 1" }, "isConditional": true }, { "users": [], "groups": [ "public" ], "roles": [], "accessTypes": [ "select" ], "filterInfo": { "filterExpr": "dept != 'hr'" }, "isConditional": false } - ], - "userPermissions": {}, "groupPermissions": {}, "rolePermissions": {}, "dataMasks": [] + ] } ] } diff --git a/agents-common/src/test/resources/policyengine/test_aclprovider_resource_hierarchy_tags.json b/agents-common/src/test/resources/policyengine/test_aclprovider_resource_hierarchy_tags.json index 4e9d29229f..206a6563d0 100644 --- a/agents-common/src/test/resources/policyengine/test_aclprovider_resource_hierarchy_tags.json +++ b/agents-common/src/test/resources/policyengine/test_aclprovider_resource_hierarchy_tags.json @@ -150,8 +150,7 @@ "tests": [ { "name": "table: db1.tbl1", "resource": { "elements": { "database": "db1", "table": "tbl1" } }, - "userPermissions": { "test-user": { "select": { "result": 1, "isFinal": true } } }, - "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [], "dataMasks": [] + "userPermissions": { "test-user": { "select": { "result": 1, "isFinal": true } } } }, { "name": "column: db1.tbl1.SSN", "resource": { "elements": { "database": "db1", "table": "tbl1", "column": "SSN" } }, @@ -160,8 +159,7 @@ {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "SHUFFLE" }, "isConditional": true }, {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK" }, "isConditional": true }, {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK_HASH" }, "isConditional": true } - ], - "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, { "name": "column: db1.tbl1.Age", "resource": { "elements": { "database": "db1", "table": "tbl1", "column": "Age" } }, @@ -170,8 +168,7 @@ {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "SHUFFLE" }, "isConditional": true }, {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK" }, "isConditional": true }, {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK_HASH" }, "isConditional": true } - ], - "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, { "name": "column: db1.tbl1.Name", "resource": { "elements": { "database": "db1", "table": "tbl1", "column": "Name" } }, @@ -180,18 +177,15 @@ {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "SHUFFLE" }, "isConditional": true }, {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK" }, "isConditional": true }, {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK_HASH" }, "isConditional": true } - ], - "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, { "name": "database: db2", "resource": { "elements": { "database": "db2" } }, - "userPermissions": { "test-user": { "select": { "result": 1, "isFinal": true } } }, - "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [], "dataMasks": [] + "userPermissions": { "test-user": { "select": { "result": 1, "isFinal": true } } } }, { "name": "table: db2.tbl1", "resource": { "elements": { "database": "db2", "table": "tbl1" } }, - "userPermissions": { "test-user": { "select": { "result": 1, "isFinal": true } } }, - "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [], "dataMasks": [] + "userPermissions": { "test-user": { "select": { "result": 1, "isFinal": true } } } }, { "name": "column: db2.tbl1.Name", "resource": { "elements": { "database": "db2", "table": "tbl1", "column": "Name" } }, @@ -200,21 +194,18 @@ {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "SHUFFLE" }, "isConditional": true }, {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK" }, "isConditional": true }, {"users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK_HASH" }, "isConditional": true } - ], - "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] }, { "name": "database: order", "resource": { "elements": { "database": "order" } }, - "userPermissions": { "dba": { "create": { "result": 1, "isFinal": true } } }, - "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [], "dataMasks": [] + "userPermissions": { "dba": { "create": { "result": 1, "isFinal": true } } } }, { "name": "table: order.customer", "resource": { "elements": { "database": "order", "table": "customer" } }, "userPermissions": { "test-user": { "select": { "result": 1, "isFinal": true } }, "dba": { "create": { "result": 1, "isFinal": true } } - }, - "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [], "dataMasks": [] + } }, { "name": "column: order.customer.address", "resource": { "elements": { "database": "order", "table": "customer", "column": "address" } }, @@ -225,8 +216,7 @@ "dataMasks": [ { "users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK_NONE" }, "isConditional": false }, { "users": [ "test-user" ], "groups": [], "roles": [], "accessTypes": [ "select" ], "maskInfo": { "dataMaskType": "MASK_HASH" }, "isConditional": false } - ], - "groupPermissions": {}, "rolePermissions": {}, "rowFilters": [] + ] } ] } diff --git a/authz-api/src/main/java/org/apache/ranger/authz/model/RangerAuthzResult.java b/authz-api/src/main/java/org/apache/ranger/authz/model/RangerAuthzResult.java index af15f0818a..4c6470660e 100644 --- a/authz-api/src/main/java/org/apache/ranger/authz/model/RangerAuthzResult.java +++ b/authz-api/src/main/java/org/apache/ranger/authz/model/RangerAuthzResult.java @@ -106,12 +106,12 @@ public String toString() { @JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonIgnoreProperties(ignoreUnknown = true) public static class PermissionResult { - private String permission; - private AccessResult access; - private DataMaskResult dataMask; - private RowFilterResult rowFilter; - private Map subResources; - private Map additionalInfo; + private String permission; + private AccessResult access; + private DataMaskResult dataMask; + private RowFilterResult rowFilter; + private Map additionalInfo; + private Map subResources; public PermissionResult() { } @@ -120,14 +120,20 @@ public PermissionResult(String permission) { this(permission, null, null); } - public PermissionResult(String permission, AccessResult access) { - this(permission, access, null); + public PermissionResult(String permission, ResultInfo result) { + this(permission, result, null); } - public PermissionResult(String permission, AccessResult access, Map additionalInfo) { - this.permission = permission; - this.access = access; - this.additionalInfo = additionalInfo; + public PermissionResult(String permission, ResultInfo result, Map subResources) { + this.permission = permission; + this.subResources = subResources; + + if (result != null) { + this.access = result.getAccess(); + this.dataMask = result.getDataMask(); + this.rowFilter = result.getRowFilter(); + this.additionalInfo = result.getAdditionalInfo(); + } } // Getters and Setters @@ -163,21 +169,29 @@ public void setRowFilter(RowFilterResult rowFilter) { this.rowFilter = rowFilter; } - public Map getSubResources() { + public Map getAdditionalInfo() { + return additionalInfo; + } + + public void setAdditionalInfo(Map additionalInfo) { + this.additionalInfo = additionalInfo; + } + + public Map getSubResources() { return subResources; } - public void setSubResources(Map subResources) { + public void setSubResources(Map subResources) { this.subResources = subResources; } - public PermissionResult getdSubResourceResult(String resourceName) { - Map subResources = getSubResources(); + public ResultInfo getSubResourceResult(String resourceName) { + Map subResources = getSubResources(); return subResources != null ? subResources.get(resourceName) : null; } - public void addSubResourceResult(String resourceName, PermissionResult result) { + public void addSubResourceResult(String resourceName, ResultInfo result) { if (subResources == null) { subResources = new HashMap<>(); } @@ -185,6 +199,85 @@ public void addSubResourceResult(String resourceName, PermissionResult result) { subResources.put(resourceName, result); } + @Override + public int hashCode() { + return Objects.hash(permission, access, dataMask, rowFilter, additionalInfo, subResources); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (o == null || getClass() != o.getClass()) { + return false; + } + + PermissionResult that = (PermissionResult) o; + + return Objects.equals(permission, that.permission) && + Objects.equals(access, that.access) && + Objects.equals(dataMask, that.dataMask) && + Objects.equals(rowFilter, that.rowFilter) && + Objects.equals(additionalInfo, that.additionalInfo) && + Objects.equals(subResources, that.subResources); + } + + @Override + public String toString() { + return "PermissionResult{" + + "permission='" + permission + '\'' + + ", access=" + access + + ", dataMask=" + dataMask + + ", rowFilter=" + rowFilter + + ", additionalInfo=" + additionalInfo + + ", subResources=" + subResources + + '}'; + } + } + + @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @JsonIgnoreProperties(ignoreUnknown = true) + public static class ResultInfo { + private AccessResult access; + private DataMaskResult dataMask; + private RowFilterResult rowFilter; + private Map additionalInfo; + + public ResultInfo() { + } + + public ResultInfo(AccessResult access, DataMaskResult dataMask, RowFilterResult rowFilter, Map additionalInfo) { + this.access = access; + this.dataMask = dataMask; + this.rowFilter = rowFilter; + this.additionalInfo = additionalInfo; + } + + public AccessResult getAccess() { + return access; + } + + public void setAccess(AccessResult access) { + this.access = access; + } + + public DataMaskResult getDataMask() { + return dataMask; + } + + public void setDataMask(DataMaskResult dataMask) { + this.dataMask = dataMask; + } + + public RowFilterResult getRowFilter() { + return rowFilter; + } + + public void setRowFilter(RowFilterResult rowFilter) { + this.rowFilter = rowFilter; + } + public Map getAdditionalInfo() { return additionalInfo; } @@ -195,7 +288,7 @@ public void setAdditionalInfo(Map additionalInfo) { @Override public int hashCode() { - return Objects.hash(permission, access, dataMask, rowFilter, subResources, additionalInfo); + return Objects.hash(access, dataMask, rowFilter, additionalInfo); } @Override @@ -206,24 +299,20 @@ public boolean equals(Object o) { return false; } - PermissionResult that = (PermissionResult) o; + ResultInfo that = (ResultInfo) o; - return Objects.equals(permission, that.permission) && - Objects.equals(access, that.access) && + return Objects.equals(access, that.access) && Objects.equals(dataMask, that.dataMask) && Objects.equals(rowFilter, that.rowFilter) && - Objects.equals(subResources, that.subResources) && Objects.equals(additionalInfo, that.additionalInfo); } @Override public String toString() { - return "PermissionResult{" + - "permission='" + permission + '\'' + - ", access=" + access + + return "ResultInfo{" + + "access=" + access + ", dataMask=" + dataMask + ", rowFilter=" + rowFilter + - ", subResources=" + subResources + ", additionalInfo=" + additionalInfo + '}'; } diff --git a/authz-embedded/pom.xml b/authz-embedded/pom.xml new file mode 100644 index 0000000000..05377ee94c --- /dev/null +++ b/authz-embedded/pom.xml @@ -0,0 +1,80 @@ + + + + 4.0.0 + + + org.apache.ranger + ranger + 3.0.0-SNAPSHOT + .. + + + authz-embedded + Ranger Authorization - Embedded + + + UTF-8 + + + + + org.apache.commons + commons-lang3 + ${commons.lang3.version} + + + + org.apache.ranger + ranger-audit-dest-hdfs + ${project.version} + + + + org.apache.ranger + ranger-audit-dest-solr + ${project.version} + + + + org.apache.ranger + ranger-authz-api + ${project.version} + + + + org.apache.ranger + ranger-plugins-common + ${project.version} + + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + diff --git a/authz-embedded/src/conf/ranger-authz-embedded.properties b/authz-embedded/src/conf/ranger-authz-embedded.properties new file mode 100644 index 0000000000..9cd62fe72f --- /dev/null +++ b/authz-embedded/src/conf/ranger-authz-embedded.properties @@ -0,0 +1,64 @@ +# +# 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. +# + +ranger.authz.init.services=dev_hdfs,dev_hive,dev_kafka + +# Default service name for each service type - used when authz requests don't specify service name +ranger.authz.servicetype.hdfs.default.service=dev_hdfs +ranger.authz.servicetype.ozone.default.service=dev_ozone +ranger.authz.servicetype.hive.default.service=dev_hive +ranger.authz.servicetype.hbase.default.service=dev_hbase +ranger.authz.servicetype.trino.default.service=dev_trino +ranger.authz.servicetype.kafka.default.service=dev_kafka + +# Default source for policy information +ranger.authz.default.policy.source.impl=org.apache.ranger.admin.client.RangerAdminRESTClient +ranger.authz.default.policy.rest.url=http://localhost:6080 +ranger.authz.default.policy.rest.ssl.config.file=/etc/hive/conf/ranger-policymgr-ssl.xml +ranger.authz.default.policy.rest.client.connection.timeoutMs=120000 +ranger.authz.default.policy.rest.client.read.timeoutMs=30000 +ranger.authz.default.policy.pollIntervalMs=30000 +ranger.authz.default.policy.cache.dir=/etc/ranger/policycache + +# Alternate source for policy information: embedded resources +# ranger.authz.default.policy.source.impl=org.apache.ranger.admin.client.EmbeddedResourcePolicySource +# ranger.authz.default.policy.source.embedded_resource.path=/test_hive + +# Alternate source for policy information: local file resources +# ranger.authz.default.policy.source.impl=org.apache.ranger.admin.client.EmbeddedResourcePolicySource +# ranger.authz.default.policy.source.embedded_resource.path=/test_hive + + +# Audit configurations +# Audit destination: HDFS +ranger.authz.audit.destination.hdfs=enabled +ranger.authz.audit.destination.hdfs.dir=hdfs://nameservice1/ranger/audit +ranger.authz.audit.destination.hdfs.subdir=%app-type%/%time:yyyyMMdd% +ranger.authz.audit.destination.hdfs.filename.format=ranger_audit_%hostname%.log +ranger.authz.audit.destination.hdfs.file.rollover.sec=86400 + +# Audit destination: Solr +ranger.authz.audit.destination.solr=enabled +ranger.authz.audit.destination.solr.urls=http://localhost:8983/solr +ranger.authz.audit.destination.solr.zookeepers= +ranger.authz.audit.destination.solr.collection=ranger_audits + +# Audit destination: Log4j +ranger.authz.audit.destination.log4j=enabled +ranger.authz.audit.destination.log4j.logger=ranger_audit + diff --git a/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzAuditHandler.java b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzAuditHandler.java new file mode 100644 index 0000000000..37dbcf376f --- /dev/null +++ b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzAuditHandler.java @@ -0,0 +1,68 @@ +/* + * 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.authz.embedded; + +import org.apache.ranger.audit.model.AuthzAuditEvent; +import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.service.RangerBasePlugin; + +import java.util.ArrayList; +import java.util.Collection; + +public class RangerAuthzAuditHandler extends RangerDefaultAuditHandler implements AutoCloseable { + private final RangerBasePlugin plugin; + private final Collection auditEvents = new ArrayList<>(); + private boolean deniedExists; + + public RangerAuthzAuditHandler(RangerBasePlugin plugin) { + super(); + + this.plugin = plugin; + } + + @Override + public void processResult(RangerAccessResult result) { + AuthzAuditEvent auditEvent = getAuthzEvents(result); + + // in case denied access, log only the first denied access; ignore all others + if (auditEvent != null && !deniedExists) { + auditEvent.setAgentId(plugin.getAppId()); + + if (result.getIsAccessDetermined() && !result.getIsAllowed()) { + deniedExists = true; + + auditEvents.clear(); + } + + auditEvents.add(auditEvent); + } + } + + @Override + public void processResults(Collection results) { + results.forEach(this::processResult); + } + + @Override + public void close() { + auditEvents.forEach(super::logAuthzAudit); + } +} diff --git a/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzConfig.java b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzConfig.java new file mode 100644 index 0000000000..291562f130 --- /dev/null +++ b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzConfig.java @@ -0,0 +1,137 @@ +/* + * 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.authz.embedded; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Properties; + +public class RangerAuthzConfig { + public static final String PROP_PREFIX_INIT_SERVICES = "ranger.authz.init.services"; + public static final String PROP_PREFIX_DEFAULT = "ranger.authz.default."; + public static final String PROP_PREFIX_AUDIT = "ranger.authz.audit."; + public static final String PROP_PREFIX_SERVICE = "ranger.authz.service."; + public static final String PROP_PREFIX_SERVICE_TYPE = "ranger.authz.servicetype."; + + private final Properties properties; + + public RangerAuthzConfig(Properties properties) { + this.properties = properties; + } + + public String[] getInitServices() { + String initServices = properties.getProperty(PROP_PREFIX_INIT_SERVICES); + + if (StringUtils.isBlank(initServices)) { + return new String[0]; + } + + return initServices.split(","); + } + + public Properties getAuditProperties() { + Properties ret = new Properties(); + + for (String propName : properties.stringPropertyNames()) { + if (propName.startsWith(PROP_PREFIX_AUDIT)) { + String propValue = properties.getProperty(propName); + String propSuffix = propName.substring(PROP_PREFIX_AUDIT.length()); + String pluginPropName = "xasecure.audit." + propSuffix; + + ret.setProperty(pluginPropName, propValue); + } + } + + return ret; + } + + public Properties getServiceProperties(String serviceName, String serviceType) { + Properties ret = new Properties(); + + if (StringUtils.isBlank(serviceType)) { + serviceType = getServiceTypeForService(serviceName); + } + + String pluginPropPrefix = "ranger.plugin." + serviceType + "."; + + // collect default properties + for (String propName : properties.stringPropertyNames()) { + if (propName.startsWith(PROP_PREFIX_DEFAULT)) { + String propValue = properties.getProperty(propName); + String propSuffix = propName.substring(PROP_PREFIX_DEFAULT.length()); + String pluginPropName = pluginPropPrefix + propSuffix; + + ret.setProperty(pluginPropName, propValue); + } + } + + // collect service-type level properties + if (StringUtils.isNotBlank(serviceType)) { + String svcTypePropPrefix = PROP_PREFIX_SERVICE_TYPE + serviceType + "."; + + for (String propName : properties.stringPropertyNames()) { + if (propName.startsWith(svcTypePropPrefix)) { + String propValue = properties.getProperty(propName); + String propSuffix = propName.substring(svcTypePropPrefix.length()); + String pluginPropName = pluginPropPrefix + propSuffix; + + ret.setProperty(pluginPropName, propValue); + } + } + } + + // collect service-level properties + String svcPropPrefix = PROP_PREFIX_SERVICE + serviceName + "."; + + for (String propName : properties.stringPropertyNames()) { + if (propName.startsWith(svcPropPrefix)) { + String propValue = properties.getProperty(propName); + String propSuffix = propName.substring(svcPropPrefix.length()); + String pluginPropName = pluginPropPrefix + propSuffix; + + ret.setProperty(pluginPropName, propValue); + } + } + + return ret; + } + + public String getServiceTypeForService(String serviceName) { + return properties.getProperty(PROP_PREFIX_SERVICE + serviceName + ".servicetype"); + } + + public String getDefaultServiceNameForServiceType(String serviceType) { + return properties.getProperty(PROP_PREFIX_SERVICE_TYPE + serviceType + ".default.service"); + } + + /* + private void collectPluginProperties(String prefix, Properties serviceProps) { + for (String propName : properties.stringPropertyNames()) { + if (propName.startsWith(prefix)) { + String propValue = properties.getProperty(propName); + + String pluginPropName = propName.substring(prefix.length()); + + serviceProps.setProperty(pluginPropName, propValue); + } + } + } + */ +} diff --git a/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzPlugin.java b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzPlugin.java new file mode 100644 index 0000000000..ba0a55af7c --- /dev/null +++ b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzPlugin.java @@ -0,0 +1,409 @@ +/* + * 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.authz.embedded; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig; +import org.apache.ranger.authz.api.RangerAuthzApiErrorCode; +import org.apache.ranger.authz.api.RangerAuthzException; +import org.apache.ranger.authz.model.RangerAccessContext; +import org.apache.ranger.authz.model.RangerAccessInfo; +import org.apache.ranger.authz.model.RangerAuthzRequest; +import org.apache.ranger.authz.model.RangerAuthzResult; +import org.apache.ranger.authz.model.RangerAuthzResult.AccessDecision; +import org.apache.ranger.authz.model.RangerAuthzResult.AccessResult; +import org.apache.ranger.authz.model.RangerAuthzResult.DataMaskResult; +import org.apache.ranger.authz.model.RangerAuthzResult.PermissionResult; +import org.apache.ranger.authz.model.RangerAuthzResult.PolicyInfo; +import org.apache.ranger.authz.model.RangerAuthzResult.ResultInfo; +import org.apache.ranger.authz.model.RangerAuthzResult.RowFilterResult; +import org.apache.ranger.authz.model.RangerResourceInfo; +import org.apache.ranger.authz.model.RangerResourcePermissions; +import org.apache.ranger.authz.model.RangerUserInfo; +import org.apache.ranger.authz.util.RangerResourceNameParser; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResource; +import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerResourceACLs; +import org.apache.ranger.plugin.service.RangerBasePlugin; +import org.apache.ranger.plugin.util.RangerAccessRequestUtil; +import org.apache.ranger.plugin.util.ServicePolicies; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.Set; + +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.ACCESS_ALLOWED; +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.ACCESS_CONDITIONAL; +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.ACCESS_DENIED; + +public class RangerAuthzPlugin { + private static final Logger LOG = LoggerFactory.getLogger(RangerAuthzPlugin.class); + + private final RangerBasePlugin plugin; + private final Map rrnTemplates = new HashMap<>(); + + public RangerAuthzPlugin(String serviceType, String serviceName, Properties properties) { + plugin = new RangerBasePlugin(getPluginConfig(serviceType, serviceName, properties)) { + @Override + public void setPolicies(ServicePolicies policies) { + super.setPolicies(policies); + + updateResourceTemplates(); + } + }; + + plugin.init(); + } + + public void cleanup() { + plugin.cleanup(); + } + + public RangerAuthzResult authorize(RangerAuthzRequest request, RangerAuthzAuditHandler auditHandler) throws RangerAuthzException { + RangerUserInfo userInfo = request.getUser(); + RangerAccessInfo access = request.getAccess(); + RangerAccessContext context = request.getContext(); + Set permissions = access.getPermissions(); + RangerAuthzResult ret = new RangerAuthzResult(request.getRequestId(), new HashMap<>(permissions.size())); + RangerAccessResource resource = getResource(access.getResource().getName(), access.getResource().getAttributes()); + RangerAccessRequestImpl accessRequest = new RangerAccessRequestImpl(resource, null, userInfo.getName(), userInfo.getGroups(), userInfo.getRoles()); + + initializeRequest(accessRequest, context); + + boolean hasDeny = false; + boolean hasAllow = false; + boolean hasNotDetermined = false; + + for (String permission : permissions) { + accessRequest.setAccessType(permission); + accessRequest.setContext(new HashMap<>(context.getAdditionalInfo())); + + ResultInfo result = evaluate(accessRequest, auditHandler); + PermissionResult permResult = new PermissionResult(permission, result); + + if (CollectionUtils.isNotEmpty(access.getResource().getSubResources())) { + permResult.setAccess(new AccessResult()); // when sub-resources are evaluated, top-level resource's access is derived from sub-resources + permResult.setSubResources(new HashMap<>(access.getResource().getSubResources().size())); + + for (String subResourceName : access.getResource().getSubResources()) { + accessRequest.setResource(getSubResource(resource, subResourceName)); + accessRequest.setContext(new HashMap<>(context.getAdditionalInfo())); // reset the context + + ResultInfo subResourceResult = evaluate(accessRequest, auditHandler); + + updateResult(subResourceResult.getAccess(), permResult.getAccess()); + + permResult.getSubResources().put(subResourceName, subResourceResult); + } + } + + if (permResult.getAccess().getDecision() == AccessDecision.DENY) { + permResult.setDataMask(null); + permResult.setRowFilter(null); + } + + ret.getPermissions().put(permission, permResult); + + AccessDecision permDecision = permResult.getAccess() == null ? AccessDecision.NOT_DETERMINED : permResult.getAccess().getDecision(); + + if (permDecision == AccessDecision.DENY) { + hasDeny = true; + } else if (permDecision == AccessDecision.ALLOW) { + hasAllow = true; + } else { + hasNotDetermined = true; + } + } + + if (hasDeny) { + ret.setDecision(AccessDecision.DENY); + } else if (hasNotDetermined) { + ret.setDecision(AccessDecision.NOT_DETERMINED); + } else if (hasAllow) { + ret.setDecision(AccessDecision.ALLOW); + } + + return ret; + } + + public RangerResourcePermissions getResourcePermissions(RangerResourceInfo resource, RangerAccessContext context) throws RangerAuthzException { + RangerResourcePermissions ret = new RangerResourcePermissions(); + RangerAccessRequestImpl request = new RangerAccessRequestImpl(); + + ret.setResource(resource); + request.setResource(getResource(resource.getName(), null)); + initializeRequest(request, context); + + RangerResourceACLs acls = plugin.getResourceACLs(request); + + if (acls != null) { + for (Map.Entry> entry : acls.getUserACLs().entrySet()) { + String userName = entry.getKey(); + Map userAcls = entry.getValue(); + + if (userAcls != null) { + for (Map.Entry aclEntry : userAcls.entrySet()) { + String permission = aclEntry.getKey(); + RangerResourceACLs.AccessResult acl = aclEntry.getValue(); + + ret.setUserPermission(userName, permission, new PermissionResult(permission, new ResultInfo(toAccessResult(acl), null, null, null))); + } + } + } + + for (Map.Entry> entry : acls.getGroupACLs().entrySet()) { + String groupName = entry.getKey(); + Map groupAcls = entry.getValue(); + + if (groupAcls != null) { + for (Map.Entry aclEntry : groupAcls.entrySet()) { + String permission = aclEntry.getKey(); + RangerResourceACLs.AccessResult acl = aclEntry.getValue(); + + ret.setGroupPermission(groupName, permission, new PermissionResult(permission, new ResultInfo(toAccessResult(acl), null, null, null))); + } + } + } + + for (Map.Entry> entry : acls.getRoleACLs().entrySet()) { + String roleName = entry.getKey(); + Map roleAcls = entry.getValue(); + + if (roleAcls != null) { + for (Map.Entry aclEntry : roleAcls.entrySet()) { + String permission = aclEntry.getKey(); + RangerResourceACLs.AccessResult acl = aclEntry.getValue(); + + ret.setRolePermission(roleName, permission, new PermissionResult(permission, new ResultInfo(toAccessResult(acl), null, null, null))); + } + } + } + } + + return ret; + } + + RangerBasePlugin getPlugin() { + return plugin; + } + + private RangerAccessResource getResource(String resource, Map attributes) throws RangerAuthzException { + Map resourceMap = getResourceAsMap(resource); + Object ownerName = attributes != null ? attributes.get(RangerAccessRequestUtil.KEY_OWNER) : null; + + return new RangerAccessResourceImpl(resourceMap, ownerName != null ? ownerName.toString() : null); + } + + private RangerAccessResource getSubResource(RangerAccessResource parent, String subResourceName) { + Map elements = new HashMap<>(parent.getAsMap()); + + if (StringUtils.isNotBlank(subResourceName)) { + String[] parts = subResourceName.split(":", 2); + + elements.put(parts[0], parts.length > 1 ? parts[1] : ""); + } + + return new RangerAccessResourceImpl(elements, parent.getOwnerUser()); + } + + private void initializeRequest(RangerAccessRequestImpl request, RangerAccessContext context) { + request.setAccessTime(new Date(context.getAccessTime())); + request.setClientIPAddress(context.getClientIpAddress()); + request.setForwardedAddresses(context.getForwardedIpAddresses()); + request.setClientType(getClientType(context.getAdditionalInfo())); + request.setClusterType(getClusterType(context.getAdditionalInfo())); + request.setClusterName(getClusterName(context.getAdditionalInfo())); + request.setRequestData(getRequestData(context.getAdditionalInfo())); + request.setContext(new HashMap<>(context.getAdditionalInfo())); + } + + private String getClientType(Map context) { + Object ret = context != null ? context.get(RangerAccessContext.CONTEXT_INFO_CLIENT_TYPE) : null; + + return ret != null ? ret.toString() : null; + } + + private String getClusterType(Map context) { + Object ret = context != null ? context.get(RangerAccessContext.CONTEXT_INFO_CLUSTER_TYPE) : null; + + return ret != null ? ret.toString() : null; + } + + private String getClusterName(Map context) { + Object ret = context != null ? context.get(RangerAccessContext.CONTEXT_INFO_CLUSTER_NAME) : null; + + return ret != null ? ret.toString() : null; + } + + private String getRequestData(Map context) { + Object ret = context != null ? context.get(RangerAccessContext.CONTEXT_INFO_REQUEST_DATA) : null; + + return ret != null ? ret.toString() : null; + } + + private void updateResult(AccessResult from, AccessResult to) { + if (from == null || to == null || from.getDecision() == null || + to.getDecision() == from.getDecision() || // no change in decision + to.getDecision() == AccessDecision.DENY) { // don't override earlier DENY + return; + } + + if (to.getDecision() == null || from.getDecision() == AccessDecision.DENY || from.getDecision() == AccessDecision.NOT_DETERMINED) { + to.setDecision(from.getDecision()); + to.setPolicy(from.getPolicy()); + } + } + + private ResultInfo toPermissionResult(RangerAccessResult result) { + ResultInfo ret = new ResultInfo(toAccessResult(result), null, null, null); + + if (result.getPolicyType() == RangerPolicy.POLICY_TYPE_DATAMASK) { + ret.setDataMask(new DataMaskResult(result.getMaskType(), result.getMaskedValue(), ret.getAccess().getPolicy())); + } else if (result.getPolicyType() == RangerPolicy.POLICY_TYPE_ROWFILTER) { + ret.setRowFilter(new RowFilterResult(result.getFilterExpr(), ret.getAccess().getPolicy())); + } + + return ret; + } + + private AccessResult toAccessResult(RangerResourceACLs.AccessResult result) { + AccessResult ret = new AccessResult(); + + if (result != null) { + if (result.getIsFinal()) { + if (result.getResult() == ACCESS_ALLOWED) { + ret.setDecision(AccessDecision.ALLOW); + } else if (result.getResult() == ACCESS_DENIED) { + ret.setDecision(AccessDecision.DENY); + } else if (result.getResult() == ACCESS_CONDITIONAL) { + ret.setDecision(AccessDecision.DENY); // TODO: introduce a new AccessDecision.CONDITIONAL + } else { + ret.setDecision(AccessDecision.NOT_DETERMINED); + } + } else { + ret.setDecision(AccessDecision.NOT_DETERMINED); + } + + if (result.getPolicy() != null) { + ret.setPolicy(new PolicyInfo(result.getPolicy().getId(), result.getPolicy().getVersion())); + } else { + ret.setPolicy(null); + } + } + + return ret; + } + + private AccessResult toAccessResult(RangerAccessResult result) { + AccessResult ret = new AccessResult(); + + if (result.getIsAccessDetermined()) { + ret.setDecision(result.getIsAllowed() ? AccessDecision.ALLOW : AccessDecision.DENY); + } else { + ret.setDecision(AccessDecision.NOT_DETERMINED); + } + + ret.setPolicy(toPolicyInfo(result)); + + return ret; + } + + private PolicyInfo toPolicyInfo(RangerAccessResult result) { + return new PolicyInfo(result.getPolicyId(), result.getPolicyVersion()); + } + + private ResultInfo evaluate(RangerAccessRequest request, RangerAuthzAuditHandler auditHandler) { + RangerAccessResult result = plugin.isAccessAllowed(request, auditHandler); + ResultInfo ret = toPermissionResult(result); + + if (plugin.getServiceDefHelper().isRowFilterSupported(request.getResource().getKeys())) { + RangerAccessResult rowFilterResult = plugin.evalRowFilterPolicies(request, auditHandler); + + if (rowFilterResult != null && rowFilterResult.getIsAccessDetermined() && StringUtils.isNotBlank(rowFilterResult.getFilterExpr())) { + ret.setRowFilter(new RowFilterResult(rowFilterResult.getFilterExpr(), toPolicyInfo(rowFilterResult))); + } + } + + if (plugin.getServiceDefHelper().isDataMaskSupported(request.getResource().getKeys())) { + RangerAccessResult dataMaskResult = plugin.evalDataMaskPolicies(request, auditHandler); + + if (dataMaskResult != null && dataMaskResult.getIsAccessDetermined() && StringUtils.isNotBlank(dataMaskResult.getMaskType())) { + ret.setDataMask(new DataMaskResult(dataMaskResult.getMaskType(), dataMaskResult.getMaskedValue(), toPolicyInfo(dataMaskResult))); + } + } + + return ret; + } + + private Map getResourceAsMap(String resource) throws RangerAuthzException { + String[] resourceParts = resource.split(":", 2); + String resourceType = resourceParts.length > 0 ? resourceParts[0] : null; + String resourceValue = resourceParts.length > 1 ? resourceParts[1] : null; + RangerResourceNameParser template = rrnTemplates.get(resourceType); + + if (template == null) { + throw new RangerAuthzException(RangerAuthzApiErrorCode.INVALID_REQUEST_RESOURCE_TYPE_NOT_FOUND, resourceType); + } + + Map ret = template.parseToMap(resourceValue); + + if (ret == null) { + throw new RangerAuthzException(RangerAuthzApiErrorCode.INVALID_REQUEST_RESOURCE_VALUE_FOR_TYPE, resourceValue, resourceType); + } + + return (Map) ret; + } + + private void updateResourceTemplates() { + RangerServiceDefHelper serviceDefHelper = plugin.getServiceDefHelper(); + + if (serviceDefHelper != null) { + for (String resourceType : serviceDefHelper.getAllResourceNames()) { + String rrnTemplate = serviceDefHelper.getRrnTemplate(resourceType); + RangerResourceNameParser existing = rrnTemplates.get(resourceType); + + if (existing == null || !Objects.equals(existing.getTemplate(), rrnTemplate)) { + LOG.info("updateResourceTemplates(): resourceType={} updated to rrnTemplate={}", resourceType, rrnTemplate); + + try { + rrnTemplates.put(resourceType, new RangerResourceNameParser(rrnTemplate)); + } catch (RangerAuthzException excp) { + LOG.warn("updateResourceTemplates(): failed to create resource template for resourceType={}, rrnTemplate={}", resourceType, rrnTemplate, excp); + } + } + } + } + } + + private static RangerPluginConfig getPluginConfig(String serviceType, String serviceName, Properties properties) { + return new RangerPluginConfig(serviceType, serviceName, null, properties); + } +} diff --git a/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthorizer.java b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthorizer.java new file mode 100644 index 0000000000..839bb73ea2 --- /dev/null +++ b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthorizer.java @@ -0,0 +1,202 @@ +/* + * 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.authz.embedded; + +import org.apache.commons.lang3.StringUtils; +import org.apache.ranger.audit.provider.AuditProviderFactory; +import org.apache.ranger.authz.api.RangerAuthorizer; +import org.apache.ranger.authz.api.RangerAuthzException; +import org.apache.ranger.authz.model.RangerAccessContext; +import org.apache.ranger.authz.model.RangerAccessInfo; +import org.apache.ranger.authz.model.RangerAuthzRequest; +import org.apache.ranger.authz.model.RangerAuthzResult; +import org.apache.ranger.authz.model.RangerAuthzResult.AccessDecision; +import org.apache.ranger.authz.model.RangerMultiAuthzRequest; +import org.apache.ranger.authz.model.RangerMultiAuthzResult; +import org.apache.ranger.authz.model.RangerResourceInfo; +import org.apache.ranger.authz.model.RangerResourcePermissions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import static org.apache.ranger.authz.api.RangerAuthzApiErrorCode.INVALID_REQUEST_SERVICE_NAME_OR_TYPE_MANDATORY; +import static org.apache.ranger.authz.embedded.RangerEmbeddedAuthzErrorCode.NO_DEFAULT_SERVICE_FOR_SERVICE_TYPE; +import static org.apache.ranger.authz.embedded.RangerEmbeddedAuthzErrorCode.NO_SERVICE_TYPE_FOR_SERVICE; + +public class RangerEmbeddedAuthorizer extends RangerAuthorizer { + private static final Logger LOG = LoggerFactory.getLogger(RangerEmbeddedAuthorizer.class); + + private final RangerAuthzConfig config; + private final Map plugins = new HashMap<>(); + + public RangerEmbeddedAuthorizer(Properties properties) { + super(properties); + + this.config = new RangerAuthzConfig(properties); + } + + public void init() throws RangerAuthzException { + AuditProviderFactory.getInstance().init(config.getAuditProperties(), "ranger-authz"); + + String[] initServices = config.getInitServices(); + + for (String serviceName : initServices) { + String serviceType = config.getServiceTypeForService(serviceName); + + getOrCreatePlugin(serviceName, serviceType); + } + } + + @Override + public void close() { + for (RangerAuthzPlugin plugin : plugins.values()) { + plugin.cleanup(); + } + + plugins.clear(); + } + + @Override + public RangerAuthzResult authorize(RangerAuthzRequest request) throws RangerAuthzException { + validateRequest(request); + + RangerAuthzPlugin plugin = getOrCreatePlugin(request.getContext().getServiceName(), request.getContext().getServiceType()); + + try (RangerAuthzAuditHandler auditHandler = new RangerAuthzAuditHandler(plugin.getPlugin())) { + return authorize(request, plugin, auditHandler); + } + } + + @Override + public RangerMultiAuthzResult authorize(RangerMultiAuthzRequest request) throws RangerAuthzException { + validateRequest(request); + + RangerAuthzPlugin plugin = getOrCreatePlugin(request.getContext().getServiceName(), request.getContext().getServiceType()); + RangerMultiAuthzResult result = new RangerMultiAuthzResult(request.getRequestId()); + + if (request.getAccesses() != null) { + int allowedCount = 0; + int deniedCount = 0; + int notDeterminedCount = 0; + + result.setAccesses(new ArrayList<>(request.getAccesses().size())); + + try (RangerAuthzAuditHandler auditHandler = new RangerAuthzAuditHandler(plugin.getPlugin())) { + for (RangerAccessInfo accessInfo : request.getAccesses()) { + RangerAuthzRequest authzRequest = new RangerAuthzRequest(null, request.getUser(), accessInfo, request.getContext()); + RangerAuthzResult authzResult = authorize(authzRequest, plugin, auditHandler); + + if (authzResult.getDecision() == AccessDecision.ALLOW) { + allowedCount++; + } else if (authzResult.getDecision() == AccessDecision.DENY) { + deniedCount++; + } else if (authzResult.getDecision() == AccessDecision.NOT_DETERMINED) { + notDeterminedCount++; + } + + result.getAccesses().add(authzResult); + } + } + + if (allowedCount == request.getAccesses().size()) { + result.setDecision(AccessDecision.ALLOW); + } else if (deniedCount == request.getAccesses().size()) { + result.setDecision(AccessDecision.DENY); + } else if (notDeterminedCount == request.getAccesses().size()) { + result.setDecision(AccessDecision.NOT_DETERMINED); + } else { + result.setDecision(AccessDecision.PARTIAL); + } + } + + return result; + } + + @Override + public RangerResourcePermissions getResourcePermissions(RangerResourceInfo resource, RangerAccessContext context) throws RangerAuthzException { + validateAccessContext(context); + + RangerAuthzPlugin plugin = getOrCreatePlugin(context.getServiceName(), context.getServiceType()); + + return plugin.getResourcePermissions(resource, context); + } + + @Override + protected void validateAccessContext(RangerAccessContext context) throws RangerAuthzException { + super.validateAccessContext(context); + + String serviceName = context.getServiceName(); + String serviceType = context.getServiceType(); + + if (StringUtils.isBlank(serviceName)) { + if (StringUtils.isBlank(serviceType)) { + throw new RangerAuthzException(INVALID_REQUEST_SERVICE_NAME_OR_TYPE_MANDATORY); + } + + serviceName = config.getDefaultServiceNameForServiceType(serviceType); + + if (StringUtils.isBlank(serviceName)) { + throw new RangerAuthzException(NO_DEFAULT_SERVICE_FOR_SERVICE_TYPE, serviceName); + } + + context.setServiceName(serviceName); + } + + if (StringUtils.isBlank(serviceType)) { + serviceType = config.getServiceTypeForService(serviceName); + + if (StringUtils.isBlank(serviceType)) { + throw new RangerAuthzException(NO_SERVICE_TYPE_FOR_SERVICE, serviceName); + } + + context.setServiceType(serviceType); + } + } + + private RangerAuthzResult authorize(RangerAuthzRequest request, RangerAuthzPlugin plugin, RangerAuthzAuditHandler auditHandler) throws RangerAuthzException { + return plugin.authorize(request, auditHandler); + } + + private RangerAuthzPlugin getOrCreatePlugin(String serviceName, String serviceType) throws RangerAuthzException { + RangerAuthzPlugin ret = plugins.get(serviceName); + + if (ret == null) { + synchronized (plugins) { + ret = plugins.get(serviceName); + + if (ret == null) { + Properties pluginProperties = this.config.getServiceProperties(serviceName, serviceType); + + LOG.debug("properties for service {}: {}", serviceName, pluginProperties); + + ret = new RangerAuthzPlugin(serviceType, serviceName, pluginProperties); + + plugins.put(serviceName, ret); + } + } + } + + return ret; + } +} diff --git a/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthzErrorCode.java b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthzErrorCode.java new file mode 100644 index 0000000000..4028298216 --- /dev/null +++ b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthzErrorCode.java @@ -0,0 +1,63 @@ +/* + * 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.authz.embedded; + +import org.apache.ranger.authz.api.RangerAuthzErrorCode; + +public enum RangerEmbeddedAuthzErrorCode implements RangerAuthzErrorCode { + NO_SERVICE_TYPE_FOR_SERVICE(400, "00-001", "No service type found for service {0}"), + NO_DEFAULT_SERVICE_FOR_SERVICE_TYPE(400, "00-002", "No default service found for service type {0}"), + + FAILED_TO_CONTACT_AUTHZ_SERVICE(404, "00-001", "Failed to contact authorization service"), + FAILED_TO_GET_SERVICE_POLICIES(404, "00-002", "Failed to retrieve policies for service {0}"); + + private static final String ERROR_CODE_MODULE_PREFIX = "E_AUTHZ-"; + + private final int httpStatusCode; + private final String code; + private final String message; + + RangerEmbeddedAuthzErrorCode(int httpStatusCode, String code, String message) { + this.httpStatusCode = httpStatusCode; + this.code = String.format("%s-%3d-%s", ERROR_CODE_MODULE_PREFIX, httpStatusCode, code); + this.message = message; + } + + public int getHttpStatusCode() { + return httpStatusCode; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return "RangerEmbeddedAuthzErrorCode{" + + "httpStatusCode=" + httpStatusCode + + ", code='" + code + '\'' + + ", message='" + message + '\'' + + '}'; + } +} diff --git a/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestEmbeddedAuthorizer.java b/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestEmbeddedAuthorizer.java new file mode 100644 index 0000000000..5636ae3c20 --- /dev/null +++ b/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestEmbeddedAuthorizer.java @@ -0,0 +1,205 @@ +/* + * 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.authz.embedded; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.ranger.authz.model.RangerAccessContext; +import org.apache.ranger.authz.model.RangerAuthzRequest; +import org.apache.ranger.authz.model.RangerAuthzResult; +import org.apache.ranger.authz.model.RangerMultiAuthzRequest; +import org.apache.ranger.authz.model.RangerMultiAuthzResult; +import org.apache.ranger.authz.model.RangerResourceInfo; +import org.apache.ranger.authz.model.RangerResourcePermissions; +import org.junit.jupiter.api.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.List; +import java.util.Properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TestEmbeddedAuthorizer { + private static final TypeReference> TYPE_LIST_TEST_AUTHZ_DATA = new TypeReference>() {}; + private static final TypeReference> TYPE_LIST_TEST_MULTI_AUTHZ_DATA = new TypeReference>() {}; + private static final TypeReference> TYPE_LIST_TEST_RESOURCE_PERMISSIONS_DATA = new TypeReference>() {}; + + @Test + public void testAuthzS3() throws Exception { + runAuthzTest("test_s3"); + } + + @Test + public void testMultiAuthzS3() throws Exception { + runMultiAuthzTest("test_s3"); + } + + @Test + public void testResourcePermissionsS3() throws Exception { + runResourcePermissionsTest("test_s3"); + } + + @Test + public void testAuthzHive() throws Exception { + runAuthzTest("test_hive"); + } + + @Test + public void testResourcePermissionsHive() throws Exception { + runResourcePermissionsTest("test_hive"); + } + + private void runResourcePermissionsTest(String testName) throws Exception { + String propertiesPath = "/" + testName + "/ranger-embedded-authz.properties"; + String testsPath = "/" + testName + "/tests_resource_permissions.json"; + + RangerEmbeddedAuthorizer authorizer = null; + + try { + authorizer = new RangerEmbeddedAuthorizer(loadProperties(propertiesPath)); + + authorizer.init(); + + for (TestResourcePermissionsData test : loadTestResourcePermissionsData(testsPath)) { + if (test.resource == null || test.context == null || test.permissions == null) { + continue; + } + + RangerResourcePermissions permissions = authorizer.getResourcePermissions(test.resource, test.context); + + assertEquals(test.permissions, permissions, "Resource permissions do not match for resource=" + test.resource); + } + } finally { + if (authorizer != null) { + authorizer.close(); + } + } + } + + private void runAuthzTest(String testName) throws Exception { + String propertiesPath = "/" + testName + "/ranger-embedded-authz.properties"; + String testsPath = "/" + testName + "/tests_authz.json"; + + RangerEmbeddedAuthorizer authorizer = null; + + try { + authorizer = new RangerEmbeddedAuthorizer(loadProperties(propertiesPath)); + + authorizer.init(); + + for (TestAuthzData test : loadTestAuthzData(testsPath)) { + if (test.request == null || test.result == null) { + continue; + } + + RangerAuthzRequest request = test.request; + RangerAuthzResult expected = test.result; + RangerAuthzResult result = authorizer.authorize(request); + + assertEquals(expected, result); + } + } finally { + if (authorizer != null) { + authorizer.close(); + } + } + } + + private void runMultiAuthzTest(String testName) throws Exception { + String propertiesPath = "/" + testName + "/ranger-embedded-authz.properties"; + String testsPath = "/" + testName + "/tests_multi_authz.json"; + + RangerEmbeddedAuthorizer authorizer = null; + + try { + authorizer = new RangerEmbeddedAuthorizer(loadProperties(propertiesPath)); + + authorizer.init(); + + for (TestMultiAuthzData test : loadTestMultiAuthzData(testsPath)) { + if (test.request == null || test.result == null) { + continue; + } + + RangerMultiAuthzRequest request = test.request; + RangerMultiAuthzResult expected = test.result; + RangerMultiAuthzResult result = authorizer.authorize(request); + + assertEquals(expected, result); + } + } finally { + if (authorizer != null) { + authorizer.close(); + } + } + } + + private Properties loadProperties(String resourcePath) throws Exception { + Properties properties = new Properties(); + + try (InputStream in = getClass().getResourceAsStream(resourcePath)) { + properties.load(in); + } + + return properties; + } + + private List loadTestAuthzData(String resourcePath) throws Exception { + ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + try (InputStream in = getClass().getResourceAsStream(resourcePath)) { + return mapper.readValue(in, TYPE_LIST_TEST_AUTHZ_DATA); + } + } + + private List loadTestMultiAuthzData(String resourcePath) throws Exception { + ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + try (InputStream in = getClass().getResourceAsStream(resourcePath)) { + return in != null ? mapper.readValue(in, TYPE_LIST_TEST_MULTI_AUTHZ_DATA) : Collections.emptyList(); + } + } + + private List loadTestResourcePermissionsData(String resourcePath) throws Exception { + ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + try (InputStream in = getClass().getResourceAsStream(resourcePath)) { + return in != null ? mapper.readValue(in, TYPE_LIST_TEST_RESOURCE_PERMISSIONS_DATA) : Collections.emptyList(); + } + } + + private static class TestAuthzData { + public RangerAuthzRequest request; + public RangerAuthzResult result; + } + + private static class TestMultiAuthzData { + public RangerMultiAuthzRequest request; + public RangerMultiAuthzResult result; + } + + private static class TestResourcePermissionsData { + public RangerResourceInfo resource; + public RangerAccessContext context; + public RangerResourcePermissions permissions; + } +} diff --git a/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestRangerAuthzConfig.java b/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestRangerAuthzConfig.java new file mode 100644 index 0000000000..fd9c77a1bd --- /dev/null +++ b/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestRangerAuthzConfig.java @@ -0,0 +1,231 @@ +/* + * 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.authz.embedded; + +import org.junit.jupiter.api.Test; + +import java.util.Properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class TestRangerAuthzConfig { + @Test + public void testEmptyConfig() { + RangerAuthzConfig config = new RangerAuthzConfig(new Properties()); + + assertTrue(config.getServiceProperties("dev_hive", "hive").isEmpty()); + assertTrue(config.getServiceProperties("prod_hive", "hive").isEmpty()); + assertTrue(config.getServiceProperties("dev_hdfs", "hdfs").isEmpty()); + assertTrue(config.getAuditProperties().isEmpty()); + } + + @Test + public void testDefaultConfigs() { + RangerAuthzConfig config = new RangerAuthzConfig(createDefaultProperties()); + + validateDevHiveProperties(config.getServiceProperties("dev_hive", "hive")); + validateProdHiveProperties(config.getServiceProperties("prod_hive", "hive")); + validateDevHdfsProperties(config.getServiceProperties("dev_hdfs", "hdfs")); + } + + @Test + public void testAuditConfigsV2() { + RangerAuthzConfig config = new RangerAuthzConfig(createAuditV2Properties()); + Properties auditProperties = config.getAuditProperties(); + + assertEquals(23, auditProperties.size()); + + validateAuditConfigV2(auditProperties); + } + + @Test + public void testAuditConfigsV3() { + RangerAuthzConfig config = new RangerAuthzConfig(createAuditV3Properties()); + Properties auditProperties = config.getAuditProperties(); + + assertEquals(10, auditProperties.size()); + + validateAuditConfigV3(auditProperties); + } + + @Test + public void testAllAuthzConfigs() { + RangerAuthzConfig config = new RangerAuthzConfig(createAllAuthzProperties()); + + validateDevHiveProperties(config.getServiceProperties("dev_hive", "hive")); + validateProdHiveProperties(config.getServiceProperties("prod_hive", "hive")); + validateDevHdfsProperties(config.getServiceProperties("dev_hdfs", "hdfs")); + validateAuditConfigV2(config.getAuditProperties()); + validateAuditConfigV3(config.getAuditProperties()); + } + + private void validateDevHiveProperties(Properties prop) { + assertEquals(7, prop.size()); + assertEquals("org.apache.ranger.admin.client.RangerAdminRESTClient", prop.getProperty("ranger.plugin.hive.policy.source.impl")); + assertEquals("http://localhost:6080", prop.getProperty("ranger.plugin.hive.policy.rest.url")); + assertEquals("/etc/hive/conf/ranger-policymgr-ssl.xml", prop.getProperty("ranger.plugin.hive.policy.rest.ssl.config.file")); + assertEquals("120000", prop.getProperty("ranger.plugin.hive.policy.rest.client.connection.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hive.policy.rest.client.read.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hive.policy.pollIntervalMs")); + assertEquals("/etc/ranger/policycache", prop.getProperty("ranger.plugin.hive.policy.cache.dir")); + } + + private void validateProdHiveProperties(Properties prop) { + assertEquals(7, prop.size()); + assertEquals("org.apache.ranger.admin.client.RangerAdminRESTClient", prop.getProperty("ranger.plugin.hive.policy.source.impl")); + assertEquals("http://localhost:6080", prop.getProperty("ranger.plugin.hive.policy.rest.url")); + assertEquals("/etc/hive/conf/ranger-policymgr-ssl.xml", prop.getProperty("ranger.plugin.hive.policy.rest.ssl.config.file")); + assertEquals("120000", prop.getProperty("ranger.plugin.hive.policy.rest.client.connection.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hive.policy.rest.client.read.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hive.policy.pollIntervalMs")); + assertEquals("/etc/ranger/policycache", prop.getProperty("ranger.plugin.hive.policy.cache.dir")); + } + + private void validateDevHdfsProperties(Properties prop) { + assertEquals(7, prop.size()); + assertEquals("org.apache.ranger.admin.client.RangerAdminRESTClient", prop.getProperty("ranger.plugin.hdfs.policy.source.impl")); + assertEquals("http://localhost:6080", prop.getProperty("ranger.plugin.hdfs.policy.rest.url")); + assertEquals("/etc/hive/conf/ranger-policymgr-ssl.xml", prop.getProperty("ranger.plugin.hdfs.policy.rest.ssl.config.file")); + assertEquals("120000", prop.getProperty("ranger.plugin.hdfs.policy.rest.client.connection.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hdfs.policy.rest.client.read.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hdfs.policy.pollIntervalMs")); + assertEquals("/etc/ranger/policycache", prop.getProperty("ranger.plugin.hdfs.policy.cache.dir")); + } + + private void validateAuditConfigV2(Properties prop) { + assertEquals("true", prop.getProperty("xasecure.audit.is.enabled")); + assertEquals("false", prop.getProperty("xasecure.audit.hdfs.is.enabled")); + assertEquals("true", prop.getProperty("xasecure.audit.solr.is.enabled")); + assertEquals("false", prop.getProperty("xasecure.audit.log4j.is.enabled")); + + assertEquals("true", prop.getProperty("xasecure.audit.hdfs.is.async")); + assertEquals("1048576", prop.getProperty("xasecure.audit.hdfs.async.max.queue.size")); + assertEquals("30000", prop.getProperty("xasecure.audit.hdfs.async.max.flush.interval.ms")); + assertEquals("hdfs://namenode:8020/ranger/audit/%app-type%/%time:yyyyMMdd%", prop.getProperty("xasecure.audit.hdfs.config.destination.directory")); + assertEquals("%hostname%-audit.log", prop.getProperty("xasecure.audit.hdfs.config.destination.file")); + assertEquals("900", prop.getProperty("xasecure.audit.hdfs.config.destination.flush.interval.seconds")); + assertEquals("86400", prop.getProperty("xasecure.audit.hdfs.config.destination.rollover.interval.seconds")); + assertEquals("60", prop.getProperty("xasecure.audit.hdfs.config.destination.open.retry.interval.seconds")); + assertEquals("/var/log/hbase/audit/%app-type%", prop.getProperty("xasecure.audit.hdfs.config.local.buffer.directory")); + assertEquals("%time:yyyyMMdd-HHmm.ss%.log", prop.getProperty("xasecure.audit.hdfs.config.local.buffer.file")); + assertEquals("8192", prop.getProperty("xasecure.audit.hdfs.config.local.buffer.file.buffer.size.bytes")); + assertEquals("60", prop.getProperty("xasecure.audit.hdfs.config.local.buffer.flush.interval.seconds")); + assertEquals("600", prop.getProperty("xasecure.audit.hdfs.config.local.buffer.rollover.interval.seconds")); + assertEquals("/var/log/hbase/audit/archive/%app-type%", prop.getProperty("xasecure.audit.hdfs.config.local.archive.directory")); + assertEquals("10", prop.getProperty("xasecure.audit.hdfs.config.local.archive.max.file.count")); + + assertEquals("true", prop.getProperty("xasecure.audit.solr.is.async")); + assertEquals("1", prop.getProperty("xasecure.audit.solr.async.max.queue.size")); + assertEquals("1000", prop.getProperty("xasecure.audit.solr.async.max.flush.interval.ms")); + assertEquals("http://localhost:6083/solr/ranger_audits", prop.getProperty("xasecure.audit.solr.solr_url")); + } + + private void validateAuditConfigV3(Properties props) { + assertEquals("true", props.getProperty("xasecure.audit.is.enabled")); + assertEquals("false", props.getProperty("xasecure.audit.destination.hdfs")); + assertEquals("true", props.getProperty("xasecure.audit.destination.solr")); + assertEquals("false", props.getProperty("xasecure.audit.destination.log4j")); + + assertEquals("hdfs://namenode:8020/ranger/audit", props.getProperty("xasecure.audit.destination.hdfs.dir")); + assertEquals("%app-type%/%time:yyyyMMdd%", props.getProperty("xasecure.audit.destination.hdfs.subdir")); + assertEquals("%app-type%_ranger_audit_%hostname%.log", props.getProperty("xasecure.audit.destination.hdfs.filename.format")); + assertEquals("org.apache.ranger.audit.utils.RangerJSONAuditWriter", props.getProperty("xasecure.audit.destination.hdfs.filewriter.impl")); + + assertEquals("http://localhost:6083/solr/ranger_audits", props.getProperty("xasecure.audit.destination.solr.urls")); + assertEquals("ranger_audits", props.getProperty("xasecure.audit.destination.solr.collection")); + } + + private static Properties createDefaultProperties() { + Properties props = new Properties(); + + props.setProperty("ranger.authz.default.policy.source.impl", "org.apache.ranger.admin.client.RangerAdminRESTClient"); + props.setProperty("ranger.authz.default.policy.rest.url", "http://localhost:6080"); + props.setProperty("ranger.authz.default.policy.rest.ssl.config.file", "/etc/hive/conf/ranger-policymgr-ssl.xml"); + props.setProperty("ranger.authz.default.policy.rest.client.connection.timeoutMs", "120000"); + props.setProperty("ranger.authz.default.policy.rest.client.read.timeoutMs", "30000"); + props.setProperty("ranger.authz.default.policy.pollIntervalMs", "30000"); + props.setProperty("ranger.authz.default.policy.cache.dir", "/etc/ranger/policycache"); + + return props; + } + + private static Properties createAuditV2Properties() { + Properties props = new Properties(); + + props.setProperty("ranger.authz.audit.is.enabled", "true"); + props.setProperty("ranger.authz.audit.hdfs.is.enabled", "false"); + props.setProperty("ranger.authz.audit.solr.is.enabled", "true"); + props.setProperty("ranger.authz.audit.log4j.is.enabled", "false"); + + props.setProperty("ranger.authz.audit.hdfs.is.async", "true"); + props.setProperty("ranger.authz.audit.hdfs.async.max.queue.size", "1048576"); + props.setProperty("ranger.authz.audit.hdfs.async.max.flush.interval.ms", "30000"); + props.setProperty("ranger.authz.audit.hdfs.config.destination.directory", "hdfs://namenode:8020/ranger/audit/%app-type%/%time:yyyyMMdd%"); + props.setProperty("ranger.authz.audit.hdfs.config.destination.file", "%hostname%-audit.log"); + props.setProperty("ranger.authz.audit.hdfs.config.destination.flush.interval.seconds", "900"); + props.setProperty("ranger.authz.audit.hdfs.config.destination.rollover.interval.seconds", "86400"); + props.setProperty("ranger.authz.audit.hdfs.config.destination.open.retry.interval.seconds", "60"); + props.setProperty("ranger.authz.audit.hdfs.config.local.buffer.directory", "/var/log/hbase/audit/%app-type%"); + props.setProperty("ranger.authz.audit.hdfs.config.local.buffer.file", "%time:yyyyMMdd-HHmm.ss%.log"); + props.setProperty("ranger.authz.audit.hdfs.config.local.buffer.file.buffer.size.bytes", "8192"); + props.setProperty("ranger.authz.audit.hdfs.config.local.buffer.flush.interval.seconds", "60"); + props.setProperty("ranger.authz.audit.hdfs.config.local.buffer.rollover.interval.seconds", "600"); + props.setProperty("ranger.authz.audit.hdfs.config.local.archive.directory", "/var/log/hbase/audit/archive/%app-type%"); + props.setProperty("ranger.authz.audit.hdfs.config.local.archive.max.file.count", "10"); + + props.setProperty("ranger.authz.audit.solr.is.async", "true"); + props.setProperty("ranger.authz.audit.solr.async.max.queue.size", "1"); + props.setProperty("ranger.authz.audit.solr.async.max.flush.interval.ms", "1000"); + props.setProperty("ranger.authz.audit.solr.solr_url", "http://localhost:6083/solr/ranger_audits"); + + return props; + } + + private static Properties createAuditV3Properties() { + Properties props = new Properties(); + + props.setProperty("ranger.authz.audit.is.enabled", "true"); + props.setProperty("ranger.authz.audit.destination.hdfs", "false"); + props.setProperty("ranger.authz.audit.destination.solr", "true"); + props.setProperty("ranger.authz.audit.destination.log4j", "false"); + + props.setProperty("ranger.authz.audit.destination.hdfs.dir", "hdfs://namenode:8020/ranger/audit"); + props.setProperty("ranger.authz.audit.destination.hdfs.subdir", "%app-type%/%time:yyyyMMdd%"); + props.setProperty("ranger.authz.audit.destination.hdfs.filename.format", "%app-type%_ranger_audit_%hostname%.log"); + props.setProperty("ranger.authz.audit.destination.hdfs.filewriter.impl", "org.apache.ranger.audit.utils.RangerJSONAuditWriter"); + + props.setProperty("ranger.authz.audit.destination.solr.urls", "http://localhost:6083/solr/ranger_audits"); + props.setProperty("ranger.authz.audit.destination.solr.collection", "ranger_audits"); + + return props; + } + + private static Properties createAllAuthzProperties() { + Properties props = createDefaultProperties(); + + props.putAll(createAuditV2Properties()); + props.putAll(createAuditV3Properties()); + + props.setProperty("ranger.authz.service.hive.service.name", "dev_hive"); + + return props; + } +} diff --git a/authz-embedded/src/test/resources/test_hive/README.txt b/authz-embedded/src/test/resources/test_hive/README.txt new file mode 100644 index 0000000000..478a600f39 --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/README.txt @@ -0,0 +1,26 @@ +1. Test Setup + 1. database=mydb, table=tbl1, column=* + user=tbl1-r-user, permission=select + user=tbl1-rw-user, permission=select,update + 2. database=mydb, table=tbl2, column=* + user=tbl2-r-user, permission=select + user=tbl2-rw-user, permission=select,update + 3. database=mydb, table=*, column=* + user=all-tbl-r-user, permission=select + 4. database=mydb, table=tbl_tag1, column=* + tag=TAG1 + user=tag1-r-user, permission=select + user=tag1-rw-user, permission=select,update + 5. database=mydb, table=tbl_tag2, column=* + tag=TAG2 + user=tag2-r-user, permission=select + user=tag2-rw-user, permission=select,update + 6. database=mydb, table=tbl_ds1, column=* + dataset=ds1 + user=ds1-r-user, permission=select + 6. database=mydb, table=tbl_ds2, column=* + dataset=ds2 + user=ds2-r-user, permission=select + 7. database=mydb, table=tbl_ds3, column=col1,col2,col3 + dataset=ds3, col1=mask_hash, row-filter=(year=current_year()) + user=ds3-r-user, permission=select diff --git a/authz-embedded/src/test/resources/test_hive/hive_dev_hive.json b/authz-embedded/src/test/resources/test_hive/hive_dev_hive.json new file mode 100644 index 0000000000..975b9dcaac --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/hive_dev_hive.json @@ -0,0 +1,266 @@ +{ + "serviceId": 5, "serviceName": "dev_hive", "policyVersion": 15, + "policies": [ + { + "id": 1, "name": "mydb.tbl1", "version": 1, + "resources": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl1" ] }, "column": { "values": [ "*" ] } }, + "policyItems": [ + { "accesses": [ { "type": "select" } ], "users": [ "tbl1-r-user" ] }, + { "accesses": [ { "type": "select" }, { "type": "update" } ], "users": [ "tbl1-rw-user" ] } + ] + }, + { + "id": 2, "name": "mydb.tbl2", "version": 1, + "resources": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl2" ] }, "column": { "values": [ "*" ] } }, + "policyItems": [ + { "accesses": [ { "type": "select" } ], "users": [ "tbl2-r-user" ] }, + { "accesses": [ { "type": "select" }, { "type": "update" } ], "users": [ "tbl2-rw-user" ] } + ] + }, + { + "id": 3, "name": "mydb.*.*", "version": 2, + "resources": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "*" ] }, "column": { "values": [ "*" ] } }, + "policyItems": [ + { "accesses": [ { "type": "select" } ], "users": [ "all-tbl-r-user" ] } + ] + } + ], + "serviceDef": { + "id": 3, "name": "hive", "displayName": "Hadoop SQL", "label": "Hadoop SQL", "description": "Hadoop SQL", "implClass": "org.apache.ranger.services.hive.RangerServiceHive", "version": 1, + "resources": [ + { + "itemId": 1, "name": "database", "description": "Hive Database", "label": "Hive Database", "type": "string", "level": 10, + "excludesSupported": true, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + }, + { + "itemId": 2, "name": "table", "description": "Hive Table", "label": "Hive Table", "type": "string", "parent": "database", "level": 20, + "excludesSupported": true, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + }, + { + "itemId": 3, "name": "udf", "description": "Hive UDF", "label": "Hive UDF", "type": "string", "parent": "database", "level": 20, + "excludesSupported": true, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + }, + { + "itemId": 4, "name": "column", "description": "Hive Column", "label": "Hive Column", "type": "string", "parent": "table", "level": 30, + "excludesSupported": true, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + }, + { + "itemId": 5, "name": "url", "description": "URL", "label": "URL", "type": "string", "parent": "", "level": 10, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": true, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerURLResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "true" } + }, + { + "itemId": 6, "name": "hiveservice", "description": "Hive Service", "label": "Hive Service", "type": "string", "parent": "", "level": 10, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "true" } + }, + { + "itemId": 7, "name": "global", "description": "Global", "label": "Global", "type": "string", "parent": "", "level": 10, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "true" } + } + ], + "accessTypes": [ + { "itemId": 1, "name": "select", "label": "select", "category": "READ" }, + { "itemId": 2, "name": "update", "label": "update", "category": "UPDATE" }, + { "itemId": 3, "name": "create", "label": "Create", "category": "CREATE" }, + { "itemId": 4, "name": "drop", "label": "Drop", "category": "DELETE" }, + { "itemId": 5, "name": "alter", "label": "Alter", "category": "CREATE" }, + { "itemId": 6, "name": "index", "label": "Index", "category": "MANAGE" }, + { "itemId": 7, "name": "lock", "label": "Lock", "category": "MANAGE" }, + { "itemId": 8, "name": "all", "label": "All", "impliedGrants": [ "select", "update", "create", "drop", "alter", "index", "lock", "read", "write", "repladmin", "serviceadmin", "refresh" ] }, + { "itemId": 9, "name": "read", "label": "Read", "category": "READ" }, + { "itemId": 10, "name": "write", "label": "Write", "category": "UPDATE" }, + { "itemId": 11, "name": "repladmin", "label": "ReplAdmin", "category": "MANAGE" }, + { "itemId": 12, "name": "serviceadmin", "label": "Service Admin", "category": "MANAGE" }, + { "itemId": 13, "name": "tempudfadmin", "label": "Temporary UDF Admin", "category": "MANAGE" }, + { "itemId": 14, "name": "refresh", "label": "Refresh", "category": "MANAGE" } + ], + "policyConditions": [ + { + "itemId": 1, "name": "_expression", "description": "Boolean expression", "label": "Enter boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" }, + "uiHint": "{ \"isMultiline\":true }" + } + ], + "configs": [ + { "itemId": 1, "name": "username", "label": "Username", "mandatory": true, "type": "string" }, + { "itemId": 2, "name": "password", "label": "Password", "mandatory": true, "type": "password" }, + { "itemId": 3, "name": "jdbc.driverClassName", "label": "jdbc.driverClassName", "mandatory": true, "type": "string", "defaultValue": "org.apache.hive.jdbc.HiveDriver" }, + { "itemId": 4, "name": "jdbc.url", "label": "jdbc.url" , "mandatory": true, "type": "string" }, + { "itemId": 5, "name": "commonNameForCertificate", "label": "Common Name for Certificate", "mandatory": false, "type": "string" }, + { "itemId": 6, "name": "ranger.plugin.audit.filters", "label": "Ranger Default Audit Filters", "mandatory": false, "type": "string", "defaultValue": "[ {'accessResult': 'DENIED', 'isAudited': true} ]" } + ], + "options": { "enableDenyAndExceptionsInPolicies": "true", "enableTagBasedPolicies": "true" }, + "markerAccessTypes": [ + { "itemId": 101, "label": "_CREATE", "name": "_CREATE", "impliedGrants": [ "create", "alter" ] }, + { "itemId": 102, "label": "_READ", "name": "_READ", "impliedGrants": [ "select", "read" ] }, + { "itemId": 103, "label": "_UPDATE", "name": "_UPDATE", "impliedGrants": [ "update", "write" ] }, + { "itemId": 104, "label": "_DELETE", "name": "_DELETE", "impliedGrants": [ "drop" ] }, + { "itemId": 105, "label": "_MANAGE", "name": "_MANAGE", "impliedGrants": [ "tempudfadmin", "serviceadmin", "index", "lock", "refresh", "repladmin" ] }, + { "itemId": 106, "label": "_ALL", "name": "_ALL", "impliedGrants": [ "drop", "all", "select", "read", "update", "index", "refresh", "tempudfadmin", "serviceadmin", "create", "lock", "repladmin", "write", "alter" ] } + ], + "dataMaskDef": { + "accessTypes": [ + { "itemId": 1, "name": "select", "label": "select", "category": "READ" } + ], + "resources": [ + { + "itemId": 1, "name": "database", "description": "Hive Database", "label": "Hive Database", "type": "string", "level": 10, + "excludesSupported": false, "isValidLeaf": false, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + }, + { + "itemId": 2, "name": "table", "description": "Hive Table", "label": "Hive Table", "type": "string", "parent": "database", "level": 20, + "excludesSupported": false, "isValidLeaf": false, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + }, + { + "itemId": 4, "name": "column", "description": "Hive Column", "label": "Hive Column", "type": "string", "parent": "table", "level": 30, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + } + ], + "maskTypes": [ + { "itemId": 1, "name": "MASK", "label": "Redact", "description": "Replace lowercase with 'x', uppercase with 'X', digits with '0'", "transformer": "mask({col})" }, + { "itemId": 2, "name": "MASK_SHOW_LAST_4", "label": "Partial mask: show last 4", "description": "Show last 4 characters; replace rest with 'x'", "transformer": "mask_show_last_n({col}, 4, 'x', 'x', 'x', -1, '1')" }, + { "itemId": 3, "name": "MASK_SHOW_FIRST_4", "label": "Partial mask: show first 4", "description": "Show first 4 characters; replace rest with 'x'", "transformer": "mask_show_first_n({col}, 4, 'x', 'x', 'x', -1, '1')" }, + { "itemId": 4, "name": "MASK_HASH", "label": "Hash", "description": "Hash the value", "transformer": "mask_hash({col})"}, + { "itemId": 5, "name": "MASK_NULL", "label": "Nullify", "description": "Replace with NULL" }, + { "itemId": 6, "name": "MASK_NONE", "label": "Unmasked (retain original value)", "description": "No masking" }, + { "itemId": 7, "name": "MASK_DATE_SHOW_YEAR", "label": "Date: show only year", "transformer": "mask({col}, 'x', 'x', 'x', -1, '1', 1, 0, -1)", "description": "Date: show only year" }, + { "itemId": 8, "name": "CUSTOM", "label": "Custom", "description": "Custom" } + ] + }, + "rowFilterDef": { + "accessTypes": [ + { "itemId": 1, "name": "select", "label": "select", "category": "READ" } + ], + "resources": [ + { + "itemId": 1, "name": "database", "description": "Hive Database", "label": "Hive Database", "type": "string", "level": 10, + "excludesSupported": false, "isValidLeaf": false, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + }, + { + "itemId": 2, "name": "table", "description": "Hive Table", "label": "Hive Table", "type": "string", "parent": "database", "level": 20, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + } + ] + } + }, + "tagPolicies": { + "serviceId": 3, "serviceName": "dev_tag", "policyVersion": 3, + "policies": [ + { + "id": 11, "name": "TAG1", "version": 1, + "resources": { "tag": { "values": [ "TAG1" ] } }, + "policyItems": [ + { "accesses": [ { "type": "select" } ], "users": [ "all-tag-r-user", "tag1-r-user" ] }, + { "accesses": [ { "type": "select" }, { "type": "update" } ], "users": [ "tag1-rw-user" ] } + ] + }, + { + "id": 12, "name": "TAG2", "version": 1, + "resources": { "tag": { "values": [ "TAG2" ] } }, + "policyItems": [ + { "accesses": [ { "type": "select" } ], "users": [ "all-tag-r-user", "tag2-r-user" ] }, + { "accesses": [ { "type": "select" }, { "type": "update" } ], "users": [ "tag2-rw-user" ] } + ] + }, + { + "id": 13, "name": "TAG-X", "version": 1, + "resources": { "tag": { "values": [ "TAG-X" ] } }, + "policyItems": [ + { "accesses": [ { "isAllowed": true, "type": "select" } ], "users": [ "all-tag-r-user" ] } + ] + } + ], + "serviceDef": { + "id": 100, "name": "tag", "displayName": "tag", "label": "TAG", "description": "TAG Service Definition", "implClass": "org.apache.ranger.services.tag.RangerServiceTag", "version": 21, + "resources": [ + { + "itemId": 1, "name": "tag", "label": "TAG", "description": "TAG", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + } + ], + "accessTypes": [ + { "itemId": 3001, "name": "select", "label": "select", "category": "READ" }, + { "itemId": 3002, "name": "update", "label": "update", "category": "UPDATE" }, + { "itemId": 3003, "name": "create", "label": "Create", "category": "CREATE" }, + { "itemId": 3004, "name": "drop", "label": "Drop", "category": "DELETE" }, + { "itemId": 3005, "name": "alter", "label": "Alter", "category": "CREATE" }, + { "itemId": 3006, "name": "index", "label": "Index", "category": "MANAGE" }, + { "itemId": 3007, "name": "lock", "label": "Lock", "category": "MANAGE" }, + { "itemId": 3008, "name": "all", "label": "All", "impliedGrants": [ "select", "update", "create", "drop", "alter", "index", "lock", "read", "write", "repladmin", "serviceadmin", "refresh" ] }, + { "itemId": 3009, "name": "read", "label": "Read", "category": "READ" }, + { "itemId": 3010, "name": "write", "label": "Write", "category": "UPDATE" }, + { "itemId": 3011, "name": "repladmin", "label": "ReplAdmin", "category": "MANAGE" }, + { "itemId": 3012, "name": "serviceadmin", "label": "Service Admin", "category": "MANAGE" }, + { "itemId": 3013, "name": "tempudfadmin", "label": "Temporary UDF Admin", "category": "MANAGE" }, + { "itemId": 3014, "name": "refresh", "label": "Refresh", "category": "MANAGE" } + ], + "policyConditions": [ + { + "itemId": 1, "name": "accessed-after-expiry", "label": "Accessed after expiry_date (yes/no)?", "description": "Accessed after expiry_date? (yes/no)", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptTemplateConditionEvaluator", "evaluatorOptions": { "scriptTemplate": "ctx.isAccessedAfter('expiry_date');" }, + "uiHint": "{ \"singleValue\":true }" + }, + { + "itemId": 2, "name": "expression", "label": "Enter boolean expression", "description": "Boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" }, + "uiHint": "{ \"isMultiline\":true }" + } + ], + "configs": [ + { "itemId": 1, "name": "ranger.plugin.audit.filters", "label": "Ranger Default Audit Filters", "mandatory": false, "type": "string", "defaultValue": "[ {'accessResult': 'DENIED', 'isAudited': true} ]" } + ], + "contextEnrichers": [ + { "itemId": 1, "name": "TagEnricher", "enricher": "org.apache.ranger.plugin.contextenricher.RangerTagEnricher", "enricherOptions": { "tagRetrieverClassName": "org.apache.ranger.plugin.contextenricher.RangerAdminTagRetriever", "tagRefresherPollingInterval": "60000" } } + ], + "markerAccessTypes": [ + { "itemId": 250101, "label": "_CREATE", "name": "_CREATE", "impliedGrants": [ "create", "alter" ] }, + { "itemId": 250102, "label": "_READ", "name": "_READ", "impliedGrants": [ "select", "read" ] }, + { "itemId": 250103, "label": "_UPDATE", "name": "_UPDATE", "impliedGrants": [ "update", "write" ] }, + { "itemId": 250104, "label": "_DELETE", "name": "_DELETE", "impliedGrants": [ "drop" ] }, + { "itemId": 250105, "label": "_MANAGE", "name": "_MANAGE", "impliedGrants": [ "tempudfadmin", "serviceadmin", "index", "lock", "refresh", "repladmin" ] }, + { "itemId": 250106, "label": "_ALL", "name": "_ALL", "impliedGrants": [ "drop", "all", "select", "read", "update", "index", "refresh", "tempudfadmin", "serviceadmin", "create", "lock", "repladmin", "write", "alter" ] } + ], + "dataMaskDef": { + "accessTypes": [ + { "itemId": 3001, "name": "select", "label": "select", "category": "READ" } + ], + "resources": [ + { + "itemId": 1, "name": "tag", "label": "TAG", "description": "TAG", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + } + ], + "maskTypes": [ + { "itemId": 3001, "name": "hive:MASK", "label": "Redact", "description": "Replace lowercase with 'x', uppercase with 'X', digits with '0'", "transformer": "mask({col})" }, + { "itemId": 3002, "name": "hive:MASK_SHOW_LAST_4", "label": "Partial mask: show last 4", "description": "Show last 4 characters; replace rest with 'x'", "transformer": "mask_show_last_n({col}, 4, 'x', 'x', 'x', -1, '1')" }, + { "itemId": 3003, "name": "hive:MASK_SHOW_FIRST_4", "label": "Partial mask: show first 4", "description": "Show first 4 characters; replace rest with 'x'", "transformer": "mask_show_first_n({col}, 4, 'x', 'x', 'x', -1, '1')" }, + { "itemId": 3004, "name": "hive:MASK_HASH", "label": "Hash", "description": "Hash the value", "transformer": "mask_hash({col})"}, + { "itemId": 3005, "name": "hive:MASK_NULL", "label": "Nullify", "description": "Replace with NULL" }, + { "itemId": 3006, "name": "hive:MASK_NONE", "label": "Unmasked (retain original value)", "description": "No masking" }, + { "itemId": 3007, "name": "hive:MASK_DATE_SHOW_YEAR", "label": "Date: show only year", "transformer": "mask({col}, 'x', 'x', 'x', -1, '1', 1, 0, -1)", "description": "Date: show only year" }, + { "itemId": 3008, "name": "hive:CUSTOM", "label": "Custom", "description": "Custom" } + ] + } + } + } +} diff --git a/authz-embedded/src/test/resources/test_hive/hive_dev_hive_gds.json b/authz-embedded/src/test/resources/test_hive/hive_dev_hive_gds.json new file mode 100644 index 0000000000..93807ed202 --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/hive_dev_hive_gds.json @@ -0,0 +1,112 @@ +{ + "serviceName": "dev_hive", "gdsVersion": 19, + "datasets": [ + { + "id": 1, "name": "ds1", + "policies": [ + { + "id": 41, "name": "DATASET: ds1", "version": 1, + "resources": { "dataset-id": { "values": [ "1" ] } }, + "policyItems": [ + { "accesses": [ { "type": "_READ" } ], "users": [ "ds1-r-user" ] } + ] + } + ] + }, + { + "id": 2, "name": "ds2", + "policies": [ + { + "id": 42, "name": "DATASET: ds2", "version": 1, + "resources": { "dataset-id": { "values": [ "2" ] } }, + "policyItems": [ + { "accesses": [ { "type": "_READ" } ], "users": [ "ds2-r-user" ] } + ] + } + ] + }, + { + "id": 3, "name": "ds3", + "policies": [ + { + "id": 43, "name": "DATASET: ds3", "version": 1, + "resources": { "dataset-id": { "values": [ "3" ] } }, + "policyItems": [ + { "accesses": [ { "type": "_READ" } ], "users": [ "ds3-r-user" ] } + ] + } + ] + } + ], + "dataShares": [ + { "id": 1, "name": "hive-ds1", "defaultAccessTypes": [ "select" ] }, + { "id": 2, "name": "hive-ds2", "defaultAccessTypes": [ "select" ] }, + { "id": 3, "name": "hive-ds3", "defaultAccessTypes": [ "select" ] } + ], + "dshids": [ + { "dataShareId": 1, "datasetId": 1, "status": "ACTIVE" }, + { "dataShareId": 2, "datasetId": 2, "status": "ACTIVE" }, + { "dataShareId": 3, "datasetId": 3, "status": "ACTIVE" } + ], + "resources": [ + { + "id": 1, "name": "mydb.tbl_ds1", "dataShareId": 1, + "resource": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_ds1" ] } } + }, + { + "id": 2, "name": "mydb.tbl_ds2", "dataShareId": 2, + "resource": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_ds2" ] } } + }, + { + "id": 3, "name": "mydb.tbl_ds3", "dataShareId": 3, + "resource": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_ds3" ] } }, "subResource": { "values": [ "col1", "col2", "col3" ] }, "subResourceType": "column", + "rowFilter": { "filterExpr": "year = current_year()" }, + "subResourceMasks": [ + { "values": [ "col1" ], "maskInfo": { "dataMaskType": "MASK_HASH" } } + ] + } + ], + "gdsServiceDef": { + "id": 207, "name": "gds", "label": "GDS", "description": "GDS Service Definition", "displayName": "Governed Data Sharing", "implClass": "org.apache.ranger.services.gds.RangerServiceGds", "version": 1, + "resources": [ + { + "itemId": 1, "name": "dataset-id", "label": "Dataset ID", "description": "Dataset ID", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\": true }" + }, + { + "itemId": 2, "name": "project-id", "label": "Project ID", "description": "Project ID", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\": true }" + } + ], + "accessTypes": [ + { "itemId": 1, "name": "_CREATE", "label": "_CREATE" }, + { "itemId": 2, "name": "_READ", "label": "_READ" }, + { "itemId": 3, "name": "_UPDATE", "label": "_UPDATE" }, + { "itemId": 4, "name": "_DELETE", "label": "_DELETE" }, + { "itemId": 5, "name": "_MANAGE", "label": "_MANAGE" }, + { "itemId": 6, "name": "_ALL", "label": "_ALL" } + ], + "markerAccessTypes": [ + { "itemId": 7, "name": "_CREATE", "label": "_CREATE" }, + { "itemId": 8, "name": "_READ", "label": "_READ" }, + { "itemId": 9, "name": "_UPDATE", "label": "_UPDATE" }, + { "itemId": 10, "name": "_DELETE", "label": "_DELETE" }, + { "itemId": 11, "name": "_MANAGE", "label": "_MANAGE" }, + { "itemId": 12, "name": "_ALL", "label": "_ALL" } + ], + "policyConditions": [ + { + "itemId": 1, "name": "expression", "label": "Enter boolean expression", "description": "Boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" } + }, + { + "itemId": 2, "name": "validitySchedule", "label": "Validity schedule", "description": "Validity schedule", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerValidityScheduleConditionEvaluator" + } + ] + } +} diff --git a/authz-embedded/src/test/resources/test_hive/hive_dev_hive_tag.json b/authz-embedded/src/test/resources/test_hive/hive_dev_hive_tag.json new file mode 100644 index 0000000000..b634b3d2c5 --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/hive_dev_hive_tag.json @@ -0,0 +1,24 @@ +{ + "serviceName":"dev_hive", "tagVersion":2, + "op":"add_or_update", + "tagDefinitions": { + "0": { "name": "TAG-X" }, + "1": { "name": "TAG1" }, + "2": { "name": "TAG2" } + }, + "tags": { + "0": { "type": "TAG-X" }, + "1": { "type": "TAG1" }, + "2": { "type": "TAG2" } + }, + "serviceResources": [ + { "id": 0, "serviceName": "dev_hive", "resourceElements": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_tag-x" ] } } }, + { "id": 1, "serviceName": "dev_hive", "resourceElements": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_tag1" ] } } }, + { "id": 2, "serviceName": "dev_hive", "resourceElements": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_tag2" ] } } } + ], + "resourceToTagIds": { + "0": [ "0" ], + "1": [ "1" ], + "2": [ "2" ] + } +} \ No newline at end of file diff --git a/authz-embedded/src/test/resources/test_hive/ranger-embedded-authz.properties b/authz-embedded/src/test/resources/test_hive/ranger-embedded-authz.properties new file mode 100644 index 0000000000..de0c8d2d32 --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/ranger-embedded-authz.properties @@ -0,0 +1,23 @@ +# 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. + +ranger.authz.init.services=dev_hive + +ranger.authz.service.dev_hive.servicetype=hive + +ranger.authz.default.policy.source.impl=org.apache.ranger.admin.client.EmbeddedResourcePolicySource +ranger.authz.default.policy.source.embedded_resource.path=/test_hive + +ranger.authz.audit.is.enabled=false diff --git a/authz-embedded/src/test/resources/test_hive/tests_authz.json b/authz-embedded/src/test/resources/test_hive/tests_authz.json new file mode 100644 index 0000000000..1d25ef073d --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/tests_authz.json @@ -0,0 +1,829 @@ +[ + { + "comment": "tests for tbl mydb.tbl1" + }, + { + "request": { + "requestId": "tbl1-r-user select mydb/tbl1", + "user": { "name": "tbl1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-r-user select mydb/tbl1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-r-user update mydb/tbl1", + "user": { "name": "tbl1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-r-user update mydb/tbl1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-r-user select,update mydb/tbl1", + "user": { "name": "tbl1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-r-user select,update mydb/tbl1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-rw-user update mydb/tbl1", + "user": { "name": "tbl1-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-rw-user update mydb/tbl1", + "decision": "ALLOW", + "permissions": { + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-rw-user select,update mydb/tbl1", + "user": { "name": "tbl1-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-rw-user select,update mydb/tbl1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-r-user select mydb/tbl1", + "user": { "name": "tbl2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-r-user select mydb/tbl1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-r-user update mydb/tbl1", + "user": { "name": "tbl2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-r-user update mydb/tbl1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + { + "comment": "tests for tbl mydb/tbl2" + }, + { + "request": { + "requestId": "tbl2-r-user select mydb/tbl2", + "user": { "name": "tbl2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-r-user select mydb/tbl2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-r-user update mydb/tbl2", + "user": { "name": "tbl2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-r-user update mydb/tbl2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-r-user select,update mydb/tbl2", + "user": { "name": "tbl2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-r-user select,update mydb/tbl2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-rw-user update mydb/tbl2", + "user": { "name": "tbl2-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-rw-user update mydb/tbl2", + "decision": "ALLOW", + "permissions": { + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-rw-user select,update mydb/tbl2", + "user": { "name": "tbl2-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-rw-user select,update mydb/tbl2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-r-user select mydb/tbl2", + "user": { "name": "tbl1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-r-user select mydb/tbl2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-r-user update mydb/tbl2", + "user": { "name": "tbl1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-r-user update mydb/tbl2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + { + "comment": "tests for tbl mydb/tbl_tag1" + }, + { + "request": { + "requestId": "tag1-r-user select mydb/tbl_tag1", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-r-user select mydb/tbl_tag1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user update mydb/tbl_tag1", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-r-user update mydb/tbl_tag1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user select,update mydb/tbl_tag1", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-r-user select,update mydb/tbl_tag1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-rw-user update mydb/tbl_tag1", + "user": { "name": "tag1-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-rw-user update mydb/tbl_tag1", + "decision": "ALLOW", + "permissions": { + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-rw-user select,update mydb/tbl_tag1", + "user": { "name": "tag1-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-rw-user select,update mydb/tbl_tag1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user select mydb/tbl_tag1", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-r-user select mydb/tbl_tag1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user update mydb/tbl_tag1", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-r-user update mydb/tbl_tag1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl_tag1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl_tag1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl_tag1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl_tag1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for tbl mydb/tbl_tag2" + }, + { + "request": { + "requestId": "tag2-r-user select mydb/tbl_tag2", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-r-user select mydb/tbl_tag2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user update mydb/tbl_tag2", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-r-user update mydb/tbl_tag2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user select,update mydb/tbl_tag2", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-r-user select,update mydb/tbl_tag2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-rw-user update mydb/tbl_tag2", + "user": { "name": "tag2-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-rw-user update mydb/tbl_tag2", + "decision": "ALLOW", + "permissions": { + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-rw-user select,update mydb/tbl_tag2", + "user": { "name": "tag2-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-rw-user select,update mydb/tbl_tag2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user select mydb/tbl_tag2", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-r-user select mydb/tbl_tag2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user update mydb/tbl_tag2", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-r-user update mydb/tbl_tag2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl_tag2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl_tag2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl_tag2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl_tag2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for tbl mydb/tbl_ds1" + }, + { + "request": { + "requestId": "ds1-r-user select mydb/tbl_ds1", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds1-r-user select mydb/tbl_ds1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user update mydb/tbl_ds1", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds1-r-user update mydb/tbl_ds1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user select,update mydb/tbl_ds1", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds1-r-user select,update mydb/tbl_ds1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user select mydb/tbl_ds1", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds2-r-user select mydb/tbl_ds1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user update mydb/tbl_ds1", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds2-r-user update mydb/tbl_ds1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl_ds1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl_ds1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl_ds1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl_ds1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for tbl mydb/tbl_ds2" + }, + { + "request": { + "requestId": "ds2-r-user select mydb/tbl_ds2", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds2-r-user select mydb/tbl_ds2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user update mydb/tbl_ds2", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds2-r-user update mydb/tbl_ds2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user select,update mydb/tbl_ds2", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds2-r-user select,update mydb/tbl_ds2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user select mydb/tbl_ds2", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds1-r-user select mydb/tbl_ds2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user update mydb/tbl_ds2", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds1-r-user update mydb/tbl_ds2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl_ds2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl_ds2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl_ds2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl_ds2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + { + "comment": "tests for tbl mydb/tbl_ds3" + }, + { + "request": { + "requestId": "ds3-r-user select mydb/tbl_ds3", + "user": { "name": "ds3-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds3" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds3-r-user select mydb/tbl_ds3", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds3-r-user select mydb/tbl_ds3 col1,col2,col3", + "user": { "name": "ds3-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds3", "subResources": [ "column:col1", "column:col2", "column:col3" ] }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds3-r-user select mydb/tbl_ds3 col1,col2,col3", + "decision": "ALLOW", + "permissions": { + "select": { + "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 43, "version": 1 } }, "rowFilter": { "filterExpr": "year = current_year()", "policy": { "id": 43, "version": 1 } }, + "subResources": { + "column:col1": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 43, "version": 1 } }, "dataMask": { "maskType": "MASK_HASH", "policy": { "id": 43, "version": 1 } } }, + "column:col2": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 43, "version": 1 } } }, + "column:col3": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 43, "version": 1 } } } + } + } + } + } + } +] diff --git a/authz-embedded/src/test/resources/test_hive/tests_resource_permissions.json b/authz-embedded/src/test/resources/test_hive/tests_resource_permissions.json new file mode 100644 index 0000000000..0fee56e664 --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/tests_resource_permissions.json @@ -0,0 +1,141 @@ +[ + { + "resource": { "name": "table:mydb/tbl1" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl1" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "tbl1-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + }, + "tbl1-rw-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl2" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl2" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "tbl2-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + }, + "tbl2-rw-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl_tag1" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl_tag1" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "all-tag-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + }, + "tag1-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + }, + "tag1-rw-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl_tag2" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl_tag2" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "all-tag-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + }, + "tag2-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + }, + "tag2-rw-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl_ds1" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl_ds1" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "ds1-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl_ds2" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl_ds2" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "ds2-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl_ds3" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl_ds3" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + } + }, + { + "resource": { "name": "column:mydb/tbl_ds3/col1" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "column:mydb/tbl_ds3/col1" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "ds3-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 43, "version": 1 } }, "dataMask": null } + } + } + } + } +] diff --git a/authz-embedded/src/test/resources/test_s3/README.txt b/authz-embedded/src/test/resources/test_s3/README.txt new file mode 100644 index 0000000000..fb6e3640d7 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/README.txt @@ -0,0 +1,23 @@ +1. Test Setup + 1. s3a://mybucket/path/path1/* + user=path1-r-user, permission=read + user=path1-rw-user, permission=read,write + 2. s3a://mybucket/path/path2/* + user=path2-r-user, permission=read + user=path2-rw-user, permission=read,write + 3. s3a://mybucket/* + user=all-path-r-user, permission=read + 4. s3a://mybucket/data/tag1/* + tag=TAG1 + user=tag1-r-user, permission=read + user=tag1-rw-user, permission=read,write + 5. s3a://mybucket/data/tag2 + tag=TAG2 + user=tag2-r-user, permission=read + user=tag2-rw-user, permission=read,write + 6. s3a://mybucket/data/ds1 + dataset=ds1 + user=ds1-r-user, permission=read + 7. s3a://mybucket/data/ds2 + dataset=ds2 + user=ds2-r-user, permission=read diff --git a/authz-embedded/src/test/resources/test_s3/ranger-embedded-authz.properties b/authz-embedded/src/test/resources/test_s3/ranger-embedded-authz.properties new file mode 100644 index 0000000000..6f808a6579 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/ranger-embedded-authz.properties @@ -0,0 +1,23 @@ +# 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. + +ranger.authz.init.services=dev_s3 + +ranger.authz.service.dev_s3.servicetype=s3 + +ranger.authz.default.policy.source.impl=org.apache.ranger.admin.client.EmbeddedResourcePolicySource +ranger.authz.default.policy.source.embedded_resource.path=/test_s3 + +ranger.authz.audit.is.enabled=false diff --git a/authz-embedded/src/test/resources/test_s3/s3_dev_s3.json b/authz-embedded/src/test/resources/test_s3/s3_dev_s3.json new file mode 100644 index 0000000000..77ff001729 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/s3_dev_s3.json @@ -0,0 +1,139 @@ +{ + "serviceId": 1, "serviceName": "dev_s3", "policyVersion": 15, + "policies": [ + { + "id": 1, "name": "mybucket/path/path1", "version": 1, + "resources": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/path1" ], "isRecursive": true } }, + "policyItems": [ + { "accesses": [ { "type": "read" } ], "users": [ "path1-r-user" ] }, + { "accesses": [ { "type": "read" }, { "type": "write" } ], "users": [ "path1-rw-user" ] } + ] + }, + { + "id": 2, "name": "mybucket/path/path2", "version": 1, + "resources": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/path2" ], "isRecursive": true } }, + "policyItems": [ + { "accesses": [ { "type": "read" } ], "users": [ "path2-r-user" ] }, + { "accesses": [ { "type": "read" }, { "type": "write" } ], "users": [ "path2-rw-user" ] } + ] + }, + { + "id": 3, "name": "mybucket/*", "version": 2, + "resources": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "*" ], "isRecursive": true } }, + "policyItems": [ + { "accesses": [ { "type": "read" } ], "users": [ "all-path-r-user" ] } + ] + } + ], + "serviceDef": { + "id": 1, "name": "s3", "displayName": "s3", "label": "AWS S3", "description": "AWS S3", "implClass": "org.apache.ranger.services.s3.RangerServiceS3", "version": 1, + "resources": [ + { + "itemId": 1, "name": "bucket", "description": "S3 Bucket", "label": "S3 Bucket", "type": "string", "level": 10, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + }, + { + "itemId": 2, "name": "path", "description": "HDFS file or directory path", "label": "Resource Path", "type": "path", "parent": "bucket", "level": 20, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": true, "rrnTemplate": "{bucket}/{path}", + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + } + ], + "accessTypes": [ + { "itemId": 1, "name": "read", "label": "Read", "category": "READ"}, + { "itemId": 2, "name": "write", "label": "Write", "category": "UPDATE"}, + { "itemId": 3, "name": "list", "label": "List", "category": "READ"}, + { "itemId": 4, "name": "delete", "label": "Delete", "category": "DELETE"} + ], + "policyConditions": [ + { + "itemId": 1, "name": "_expression", "description": "Boolean expression", "label": "Enter boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" }, + "uiHint": "{ \"isMultiline\":true }" + } + ], + "configs": [ + { "itemId": 1, "name": "ranger.plugin.audit.filters", "label": "Ranger Default Audit Filters", "mandatory": false, "type": "string", "defaultValue": "[ {'accessResult': 'DENIED', 'isAudited': true} ]" } + ], + "options": { "enableDenyAndExceptionsInPolicies": "true", "enableTagBasedPolicies": "true" }, + "markerAccessTypes": [ + { "itemId": 101, "label": "_CREATE", "name": "_CREATE" }, + { "itemId": 102, "label": "_READ", "name": "_READ", "impliedGrants": [ "read", "list" ] }, + { "itemId": 103, "label": "_UPDATE", "name": "_UPDATE", "impliedGrants": [ "write" ] }, + { "itemId": 104, "label": "_DELETE", "name": "_DELETE", "impliedGrants": [ "delete" ] }, + { "itemId": 105, "label": "_MANAGE", "name": "_MANAGE" }, + { "itemId": 106, "label": "_ALL", "name": "_ALL", "impliedGrants": [ "read", "write", "list", "delete" ] } + ] + }, + "tagPolicies": { + "serviceId": 3, "serviceName": "dev_tag", "policyVersion": 3, + "policies": [ + { + "id": 11, "name": "TAG1", "version": 1, + "resources": { "tag": { "values": [ "TAG1" ] } }, + "policyItems": [ + { "accesses": [ { "type": "read" } ], "users": [ "all-tag-r-user", "tag1-r-user" ] }, + { "accesses": [ { "type": "read" }, { "type": "write" } ], "users": [ "tag1-rw-user" ] } + ] + }, + { + "id": 12, "name": "TAG2", "version": 1, + "resources": { "tag": { "values": [ "TAG2" ] } }, + "policyItems": [ + { "accesses": [ { "type": "read" } ], "users": [ "all-tag-r-user", "tag2-r-user" ] }, + { "accesses": [ { "type": "read" }, { "type": "write" } ], "users": [ "tag2-rw-user" ] } + ] + }, + { + "id": 13, "name": "TAG-X", "version": 1, + "resources": { "tag": { "values": [ "TAG-X" ] } }, + "policyItems": [ + { "accesses": [ { "isAllowed": true, "type": "read" } ], "users": [ "all-tag-r-user" ] } + ] + } + ], + "serviceDef": { + "id": 100, "name": "tag", "displayName": "tag", "label": "TAG", "description": "TAG Service Definition", "implClass": "org.apache.ranger.services.tag.RangerServiceTag", "version": 21, + "resources": [ + { + "itemId": 1, "name": "tag", "label": "TAG", "description": "TAG", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + } + ], + "accessTypes": [ + { "itemId": 1001, "name": "read", "label": "Read", "category": "READ"}, + { "itemId": 1002, "name": "write", "label": "Write", "category": "UPDATE"}, + { "itemId": 1003, "name": "list", "label": "List", "category": "READ"}, + { "itemId": 1004, "name": "delete", "label": "Delete", "category": "DELETE"} + ], + "policyConditions": [ + { + "itemId": 1, "name": "accessed-after-expiry", "label": "Accessed after expiry_date (yes/no)?", "description": "Accessed after expiry_date? (yes/no)", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptTemplateConditionEvaluator", "evaluatorOptions": { "scriptTemplate": "ctx.isAccessedAfter('expiry_date');" }, + "uiHint": "{ \"singleValue\":true }" + }, + { + "itemId": 2, "name": "expression", "label": "Enter boolean expression", "description": "Boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" }, + "uiHint": "{ \"isMultiline\":true }" + } + ], + "configs": [ + { "itemId": 1, "name": "ranger.plugin.audit.filters", "label": "Ranger Default Audit Filters", "mandatory": false, "type": "string", "defaultValue": "[ {'accessResult': 'DENIED', 'isAudited': true} ]" } + ], + "contextEnrichers": [ + { "itemId": 1, "name": "TagEnricher", "enricher": "org.apache.ranger.plugin.contextenricher.RangerTagEnricher", "enricherOptions": { "tagRetrieverClassName": "org.apache.ranger.plugin.contextenricher.RangerAdminTagRetriever", "tagRefresherPollingInterval": "60000" } } + ], + "markerAccessTypes": [ + { "itemId": 205208, "label": "_CREATE", "name": "_CREATE" }, + { "itemId": 205209, "label": "_READ", "name": "_READ", "impliedGrants": [ "read", "execute" ] }, + { "itemId": 205210, "label": "_UPDATE", "name": "_UPDATE", "impliedGrants": [ "write" ] }, + { "itemId": 205211, "label": "_DELETE", "name": "_DELETE" }, + { "itemId": 205212, "label": "_MANAGE", "name": "_MANAGE" }, + { "itemId": 205213, "label": "_ALL", "name": "_ALL", "impliedGrants": [ "read", "execute", "write" ] } + ] + } + } +} diff --git a/authz-embedded/src/test/resources/test_s3/s3_dev_s3_gds.json b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_gds.json new file mode 100644 index 0000000000..3a474e8b80 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_gds.json @@ -0,0 +1,90 @@ +{ + "serviceName": "dev_s3", "gdsVersion": 19, + "datasets": [ + { + "id": 1, "name": "ds1", + "policies": [ + { + "id": 41, "name": "DATASET: ds1", "version": 1, + "resources": { "dataset-id": { "values": [ "1" ] } }, + "policyItems": [ + { "accesses": [ { "type": "_READ" } ], "users": [ "ds1-r-user" ] } + ] + } + ] + }, + { + "id": 2, "name": "ds2", + "policies": [ + { + "id": 42, "name": "DATASET: ds2", "version": 1, + "resources": { "dataset-id": { "values": [ "2" ] } }, + "policyItems": [ + { "accesses": [ { "type": "_READ" } ], "users": [ "ds2-r-user" ] } + ] + } + ] + } + ], + "dataShares": [ + { "id": 1, "name": "s3-ds1", "defaultAccessTypes": [ "read" ] }, + { "id": 2, "name": "s3-ds2", "defaultAccessTypes": [ "read" ] } + ], + "dshids": [ + { "dataShareId": 1, "datasetId": 1, "status": "ACTIVE" }, + { "dataShareId": 2, "datasetId": 2, "status": "ACTIVE" } + ], + "resources": [ + { + "id": 1, "name": "mybucket/data/ds1", "dataShareId": 1, + "resource": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/ds1" ], "isRecursive": true } } + }, + { + "id": 2, "name": "mybucket/data/ds2", "dataShareId": 2, + "resource": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/ds2" ], "isRecursive": true } } + } + ], + "gdsServiceDef": { + "id": 207, "name": "gds", "label": "GDS", "description": "GDS Service Definition", "displayName": "Governed Data Sharing", "implClass": "org.apache.ranger.services.gds.RangerServiceGds", "version": 1, + "resources": [ + { + "itemId": 1, "name": "dataset-id", "label": "Dataset ID", "description": "Dataset ID", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\": true }" + }, + { + "itemId": 2, "name": "project-id", "label": "Project ID", "description": "Project ID", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\": true }" + } + ], + "accessTypes": [ + { "itemId": 1, "name": "_CREATE", "label": "_CREATE" }, + { "itemId": 2, "name": "_READ", "label": "_READ" }, + { "itemId": 3, "name": "_UPDATE", "label": "_UPDATE" }, + { "itemId": 4, "name": "_DELETE", "label": "_DELETE" }, + { "itemId": 5, "name": "_MANAGE", "label": "_MANAGE" }, + { "itemId": 6, "name": "_ALL", "label": "_ALL" } + ], + "markerAccessTypes": [ + { "itemId": 7, "name": "_CREATE", "label": "_CREATE" }, + { "itemId": 8, "name": "_READ", "label": "_READ" }, + { "itemId": 9, "name": "_UPDATE", "label": "_UPDATE" }, + { "itemId": 10, "name": "_DELETE", "label": "_DELETE" }, + { "itemId": 11, "name": "_MANAGE", "label": "_MANAGE" }, + { "itemId": 12, "name": "_ALL", "label": "_ALL" } + ], + "policyConditions": [ + { + "itemId": 1, "name": "expression", "label": "Enter boolean expression", "description": "Boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" } + }, + { + "itemId": 2, "name": "validitySchedule", "label": "Validity schedule", "description": "Validity schedule", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerValidityScheduleConditionEvaluator" + } + ] + } +} diff --git a/authz-embedded/src/test/resources/test_s3/s3_dev_s3_roles.json b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_roles.json new file mode 100644 index 0000000000..d3f34d625c --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_roles.json @@ -0,0 +1,8 @@ +{ + "serviceName":"dev_s3", + "roleVersion":6, + "rangerRoles":[ + { "id": 1, "name":"tag1-readers", "users": [ { "name": "user1" } ], "groups": [ { "name": "group1" } ], "roles": [ { "name": "role1" } ] }, + { "id": 2, "name":"tag1-updaters", "users": [ { "name": "user11" } ], "groups": [ { "name": "group11" } ], "roles": [ { "name": "role11" } ] } + ] +} \ No newline at end of file diff --git a/authz-embedded/src/test/resources/test_s3/s3_dev_s3_tag.json b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_tag.json new file mode 100644 index 0000000000..1ed7eb7fb6 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_tag.json @@ -0,0 +1,20 @@ +{ + "serviceName":"dev_s3", "tagVersion":2, + "op":"add_or_update", + "tagDefinitions": { + "1": { "name": "TAG1" }, + "2": { "name": "TAG2" } + }, + "tags": { + "1": { "type": "TAG1" }, + "2": { "type": "TAG2" } + }, + "serviceResources": [ + { "id": 1, "serviceName": "dev_s3", "resourceElements": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/tag1" ], "isRecursive": true } } }, + { "id": 2, "serviceName": "dev_s3", "resourceElements": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/tag2" ], "isRecursive": true } } } + ], + "resourceToTagIds": { + "1": [ "1" ], + "2": [ "2" ] + } +} \ No newline at end of file diff --git a/authz-embedded/src/test/resources/test_s3/tests_authz.json b/authz-embedded/src/test/resources/test_s3/tests_authz.json new file mode 100644 index 0000000000..aa9da7d63a --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/tests_authz.json @@ -0,0 +1,788 @@ +[ + { + "comment": "tests for path mybucket/data/path1/file.orc" + }, + { + "request": { + "requestId": "path1-r-user read mybucket/data/path1/file.orc", + "user": { "name": "path1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user read mybucket/data/path1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path1-r-user write mybucket/data/path1/file.orc", + "user": { "name": "path1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user write mybucket/data/path1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path1-r-user read,write mybucket/data/path1/file.orc", + "user": { "name": "path1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user read,write mybucket/data/path1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path1-rw-user write mybucket/data/path1/file.orc", + "user": { "name": "path1-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-rw-user write mybucket/data/path1/file.orc", + "decision": "ALLOW", + "permissions": { + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path1-rw-user read,write mybucket/data/path1/file.orc", + "user": { "name": "path1-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-rw-user read,write mybucket/data/path1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path2-r-user read mybucket/data/path1/file.orc", + "user": { "name": "path2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-r-user read mybucket/data/path1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path2-r-user write mybucket/data/path1/file.orc", + "user": { "name": "path2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-r-user write mybucket/data/path1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/path1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/path1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/path1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/path1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + { + "comment": "tests for path mybucket/data/path2/file.orc" + }, + { + "request": { + "requestId": "path2-r-user read mybucket/data/path2/file.orc", + "user": { "name": "path2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-r-user read mybucket/data/path2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path2-r-user write mybucket/data/path2/file.orc", + "user": { "name": "path2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-r-user write mybucket/data/path2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path2-r-user read,write mybucket/data/path2/file.orc", + "user": { "name": "path2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-r-user read,write mybucket/data/path2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path2-rw-user write mybucket/data/path2/file.orc", + "user": { "name": "path2-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-rw-user write mybucket/data/path2/file.orc", + "decision": "ALLOW", + "permissions": { + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path2-rw-user read,write mybucket/data/path2/file.orc", + "user": { "name": "path2-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-rw-user read,write mybucket/data/path2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path1-r-user read mybucket/data/path2/file.orc", + "user": { "name": "path1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user read mybucket/data/path2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path1-r-user write mybucket/data/path2/file.orc", + "user": { "name": "path1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user write mybucket/data/path2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/path2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/path2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/path2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/path2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + { + "comment": "tests for path mybucket/data/tag1/file.orc" + }, + { + "request": { + "requestId": "tag1-r-user read mybucket/data/tag1/file.orc", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-r-user read mybucket/data/tag1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user write mybucket/data/tag1/file.orc", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-r-user write mybucket/data/tag1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user read,write mybucket/data/tag1/file.orc", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-r-user read,write mybucket/data/tag1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-rw-user write mybucket/data/tag1/file.orc", + "user": { "name": "tag1-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-rw-user write mybucket/data/tag1/file.orc", + "decision": "ALLOW", + "permissions": { + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-rw-user read,write mybucket/data/tag1/file.orc", + "user": { "name": "tag1-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-rw-user read,write mybucket/data/tag1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user read mybucket/data/tag1/file.orc", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-r-user read mybucket/data/tag1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user write mybucket/data/tag1/file.orc", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-r-user write mybucket/data/tag1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/tag1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/tag1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/tag1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/tag1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for path mybucket/data/tag2/file.orc" + }, + { + "request": { + "requestId": "tag2-r-user read mybucket/data/tag2/file.orc", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-r-user read mybucket/data/tag2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user write mybucket/data/tag2/file.orc", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-r-user write mybucket/data/tag2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user read,write mybucket/data/tag2/file.orc", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-r-user read,write mybucket/data/tag2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-rw-user write mybucket/data/tag2/file.orc", + "user": { "name": "tag2-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-rw-user write mybucket/data/tag2/file.orc", + "decision": "ALLOW", + "permissions": { + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-rw-user read,write mybucket/data/tag2/file.orc", + "user": { "name": "tag2-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-rw-user read,write mybucket/data/tag2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user read mybucket/data/tag2/file.orc", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-r-user read mybucket/data/tag2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user write mybucket/data/tag2/file.orc", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-r-user write mybucket/data/tag2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/tag2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/tag2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/tag2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/tag2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for path mybucket/data/ds1/file.orc" + }, + { + "request": { + "requestId": "ds1-r-user read mybucket/data/ds1/file.orc", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds1-r-user read mybucket/data/ds1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user write mybucket/data/ds1/file.orc", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds1-r-user write mybucket/data/ds1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user read,write mybucket/data/ds1/file.orc", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds1-r-user read,write mybucket/data/ds1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user read mybucket/data/ds1/file.orc", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds2-r-user read mybucket/data/ds1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user write mybucket/data/ds1/file.orc", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds2-r-user write mybucket/data/ds1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/ds1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/ds1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/ds1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/ds1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for path mybucket/data/ds2/file.orc" + }, + { + "request": { + "requestId": "ds2-r-user read mybucket/data/ds2/file.orc", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds2-r-user read mybucket/data/ds2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user write mybucket/data/ds2/file.orc", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds2-r-user write mybucket/data/ds2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user read,write mybucket/data/ds2/file.orc", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds2-r-user read,write mybucket/data/ds2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user read mybucket/data/ds2/file.orc", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds1-r-user read mybucket/data/ds2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user write mybucket/data/ds2/file.orc", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds1-r-user write mybucket/data/ds2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/ds2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/ds2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/ds2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/ds2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + } +] \ No newline at end of file diff --git a/authz-embedded/src/test/resources/test_s3/tests_multi_authz.json b/authz-embedded/src/test/resources/test_s3/tests_multi_authz.json new file mode 100644 index 0000000000..407aa733a8 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/tests_multi_authz.json @@ -0,0 +1,114 @@ +[ + { + "comment": "tests for path1-r-user" + }, + { + "request": { + "requestId": "path1-r-user read mybucket/data/path1/file.orc", + "user": { "name": "path1-r-user" }, + "accesses": [ + { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] } + ], + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user read mybucket/data/path1/file.orc", + "decision": "ALLOW", + "accesses": [ + { + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + ] + } + }, + { + "request": { + "requestId": "path1-r-user read [mybucket/data/path1/file.orc,mybucket/data/path1/file2.orc]", + "user": { "name": "path1-r-user" }, + "accesses": [ + { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + { "resource": { "name": "path:mybucket/data/path1/file2.orc" }, "action": "read", "permissions": [ "read" ] } + ], + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user read [mybucket/data/path1/file.orc,mybucket/data/path1/file2.orc]", + "decision": "ALLOW", + "accesses": [ + { + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + }, + { + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + ] + } + }, + { + "request": { + "requestId": "path1-r-user [read write] mybucket/data/path1/file.orc", + "user": { "name": "path1-r-user" }, + "accesses": [ + { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] } + ], + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user [read write] mybucket/data/path1/file.orc", + "decision": "PARTIAL", + "accesses": [ + { + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + }, + { + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + ] + } + }, + { + "request": { + "requestId": "path1-r-user write [mybucket/data/path1/file.orc,mybucket/data/path2/file.orc]", + "user": { "name": "path1-r-user" }, + "accesses": [ + { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "write", "permissions": [ "write" ] } + ], + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user write [mybucket/data/path1/file.orc,mybucket/data/path2/file.orc]", + "decision": "DENY", + "accesses": [ + { + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + }, + { + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + ] + } + } +] \ No newline at end of file diff --git a/authz-embedded/src/test/resources/test_s3/tests_resource_permissions.json b/authz-embedded/src/test/resources/test_s3/tests_resource_permissions.json new file mode 100644 index 0000000000..a4b458644a --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/tests_resource_permissions.json @@ -0,0 +1,114 @@ +[ + { + "resource": { "name": "path:mybucket/data/path1/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/path1/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "path1-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + }, + "path1-rw-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "path:mybucket/data/path2/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/path2/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "path2-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + }, + "path2-rw-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "path:mybucket/data/tag1/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/tag1/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "all-tag-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + }, + "tag1-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + }, + "tag1-rw-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "path:mybucket/data/tag2/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/tag2/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "all-tag-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + }, + "tag2-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + }, + "tag2-rw-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "path:mybucket/data/ds1/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/ds1/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "ds1-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "path:mybucket/data/ds2/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/ds2/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "ds2-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } } + } + } + } + } +] \ No newline at end of file diff --git a/pom.xml b/pom.xml index a87336e741..cf47f4ecdc 100644 --- a/pom.xml +++ b/pom.xml @@ -813,6 +813,7 @@ agents-cred agents-installer authz-api + authz-embedded credentialbuilder