This is an automated email from the ASF dual-hosted git repository. rmani pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push: new 12208bd Ranger Hive authorizer enhancement to enable Hive policies based on resource owners 12208bd is described below commit 12208bd5392d0e93d2d49cf77237498aaaced779 Author: rmani <rm...@hortonworks.com> AuthorDate: Thu Aug 15 23:05:59 2019 -0700 Ranger Hive authorizer enhancement to enable Hive policies based on resource owners --- .../ranger/plugin/util/GrantRevokeRequest.java | 23 +++ .../service-defs/ranger-servicedef-hive.json | 6 +- .../plugin/policyengine/TestPolicyEngine.java | 7 + .../test_policyengine_hive_default_policies.json | 187 +++++++++++++++++++++ .../hive/authorizer/RangerHiveAuthorizer.java | 80 ++++++++- pom.xml | 2 +- .../java/org/apache/ranger/rest/ServiceREST.java | 12 +- 7 files changed, 302 insertions(+), 15 deletions(-) diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/GrantRevokeRequest.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/GrantRevokeRequest.java index 2795906..870ec96 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/util/GrantRevokeRequest.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/GrantRevokeRequest.java @@ -60,6 +60,7 @@ public class GrantRevokeRequest implements Serializable { private String sessionId; private String clusterName; private String zoneName; + private String ownerUser; public GrantRevokeRequest() { this(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); @@ -76,6 +77,13 @@ public class GrantRevokeRequest implements Serializable { Set<String> groups, Set<String> roles, Set<String> accessTypes, Boolean delegateAdmin, Boolean enableAudit, Boolean replaceExistingPermissions, Boolean isRecursive, String clientIPAddress, String clientType, String requestData, String sessionId, String clusterName, String zoneName) { + this(grantor, grantorGroups, resource, users, groups, roles, accessTypes, delegateAdmin, enableAudit, replaceExistingPermissions, isRecursive, clientIPAddress, clientType, requestData, sessionId, clusterName, zoneName, null); + } + + public GrantRevokeRequest(String grantor, Set<String> grantorGroups, Map<String, String> resource, Set<String> users, + Set<String> groups, Set<String> roles, Set<String> accessTypes, Boolean delegateAdmin, Boolean enableAudit, + Boolean replaceExistingPermissions, Boolean isRecursive, String clientIPAddress, + String clientType, String requestData, String sessionId, String clusterName, String zoneName, String ownerUser) { setGrantor(grantor); setGrantorGroups(grantorGroups); setResource(resource); @@ -93,6 +101,7 @@ public class GrantRevokeRequest implements Serializable { setSessionId(sessionId); setClusterName(clusterName); setZoneName(zoneName); + setOwnerUser(ownerUser); } /** @@ -222,6 +231,20 @@ public class GrantRevokeRequest implements Serializable { } /** + * @return the ownerUser + */ + public String getOwnerUser() { + return ownerUser; + } + + /** + * @param ownerUser the ownerUser to set + */ + public void setOwnerUser(String ownerUser) { + this.ownerUser = ownerUser; + } + + /** * @return the replaceExistingPermissions */ public Boolean getReplaceExistingPermissions() { diff --git a/agents-common/src/main/resources/service-defs/ranger-servicedef-hive.json b/agents-common/src/main/resources/service-defs/ranger-servicedef-hive.json index 7408cbc..5722e09 100644 --- a/agents-common/src/main/resources/service-defs/ranger-servicedef-hive.json +++ b/agents-common/src/main/resources/service-defs/ranger-servicedef-hive.json @@ -23,7 +23,8 @@ "validationMessage": "", "uiHint":"", "label": "Hive Database", - "description": "Hive Database" + "description": "Hive Database", + "isValidLeaf": true }, { @@ -42,7 +43,8 @@ "validationMessage": "", "uiHint":"", "label": "Hive Table", - "description": "Hive Table" + "description": "Hive Table", + "isValidLeaf": true }, { diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java index d1e0c23..7180675 100644 --- a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java +++ b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java @@ -383,6 +383,13 @@ public class TestPolicyEngine { runTestsFromResourceFiles(conditionsTestResourceFiles); } + @Test + public void testPolicyEngine_with_owner() { + String[] conditionsTestResourceFiles = { "/policyengine/test_policyengine_hive_default_policies.json" }; + + runTestsFromResourceFiles(conditionsTestResourceFiles); + } + private void runTestsFromResourceFiles(String[] resourceNames) { for(String resourceName : resourceNames) { InputStream inStream = this.getClass().getResourceAsStream(resourceName); diff --git a/agents-common/src/test/resources/policyengine/test_policyengine_hive_default_policies.json b/agents-common/src/test/resources/policyengine/test_policyengine_hive_default_policies.json new file mode 100644 index 0000000..aec8a75 --- /dev/null +++ b/agents-common/src/test/resources/policyengine/test_policyengine_hive_default_policies.json @@ -0,0 +1,187 @@ +{ + "serviceName":"hivedev", + + "original-serviceDef":{ + "name":"hive", + "id":3, + "resources":[ + {"name":"database","level":1,"mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":{"wildCard":true, "ignoreCase":true},"label":"Hive Database","description":"Hive Database"}, + {"name":"url","level":1,"mandatory":true,"lookupSupported":false,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":{"wildCard":true, "ignoreCase":true},"label":"URL","description":"URL"}, + {"name":"hiveservice","level":1,"mandatory":true,"lookupSupported":false,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":{"wildCard":true, "ignoreCase":true},"label":"HiveService","description":"HiveService"}, + {"name":"table","level":2,"parent":"database","mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":{"wildCard":true, "ignoreCase":true},"label":"Hive Table","description":"Hive Table"}, + {"name":"udf","level":2,"parent":"database","mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":{"wildCard":true, "ignoreCase":true},"label":"Hive UDF","description":"Hive UDF"}, + {"name":"column","level":3,"parent":"table","mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher","matcherOptions":{"wildCard":true, "ignoreCase":true},"label":"Hive Column","description":"Hive Column"} + ], + "accessTypes":[ + {"name":"select","label":"Select"}, + {"name":"update","label":"Update"}, + {"name":"create","label":"Create"}, + {"name":"drop","label":"Drop"}, + {"name":"alter","label":"Alter"}, + {"name":"index","label":"Index"}, + {"name":"lock","label":"Lock"}, + {"name":"read","label":"Read"}, + {"name":"write","label":"Write"}, + {"name":"repladmin","label":"ReplAdmin"}, + {"name":"serviceadmin","label":"ServiceAdmin"}, + {"name":"all","label":"All", + "impliedGrants": ["select", "update", "create", "drop", "alter", "index", "lock", "read", "write", "repladmin", "serviceadmin"] + } + ] + }, + + "serviceDef": { + "id":3, + "name": "hive", + "implClass": "org.apache.ranger.services.hive.RangerServiceHive", + "label": "Hive Server2", + "description": "Hive Server2", + "guid": "3e1afb5a-184a-4e82-9d9c-87a5cacc243c", + + "resources": [ + {"itemId": 1, "name": "database", "type": "string", "level": 10, "parent": "", "mandatory": true, "lookupSupported": true, "recursiveSupported": false, "excludesSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard":true, "ignoreCase":true }, "validationRegEx":"", "validationMessage": "", "uiHint":"", "label": "Hive Database", "description": "Hive Database", "isValidLeaf": true}, + {"itemId": 2, "name": "table", "type": "string", "level": 20, "parent": "database", "mandatory": true, "lookupSupported": true, "recursiveSupported": false, "excludesSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard":true, "ignoreCase":true }, "validationRegEx":"", "validationMessage": "", "uiHint":"", "label": "Hive Table", "description": "Hive Table", "isValidLeaf": true}, + {"itemId": 3, "name": "udf", "type": "string", "level": 20, "parent": "database", "mandatory": true, "lookupSupported": true, "recursiveSupported": false, "excludesSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard":true, "ignoreCase":true }, "validationRegEx":"", "validationMessage": "", "uiHint":"", "label": "Hive UDF", "description": "Hive UDF", "isValidLeaf": true}, + {"itemId": 4, "name": "column", "type": "string", "level": 30, "parent": "table", "mandatory": true, "lookupSupported": true, "recursiveSupported": false, "excludesSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard":true, "ignoreCase":true }, "validationRegEx":"", "validationMessage": "", "uiHint":"", "label": "Hive Column", "description": "Hive Column", "isValidLeaf": true}, + {"itemId": 5, "name": "url", "type": "string", "level": 10, "parent": "", "mandatory": true, "lookupSupported": false, "recursiveSupported": true, "excludesSupported": false, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher", "matcherOptions": { "wildCard":true, "ignoreCase":false }, "validationRegEx":"", "validationMessage": "", "uiHint":"", "label": "URL", "description": "URL", "isValidLeaf": true} + ], + + "accessTypes": [ + {"itemId": 1, "name": "select", "label": "select"}, + {"itemId": 2, "name": "update", "label": "update"}, + {"itemId": 3, "name": "create", "label": "Create"}, + {"itemId": 4, "name": "drop", "label": "Drop"}, + {"itemId": 5, "name": "alter", "label": "Alter"}, + {"itemId": 6, "name": "index", "label": "Index"}, + {"itemId": 7, "name": "lock", "label": "Lock"}, + {"itemId": 8, "name": "all", "label": "All", + "impliedGrants": ["select", "update", "create", "drop", "alter", "index", "lock", "read", "write"]}, + {"itemId": 9, "name": "read", "label": "Read"}, + {"itemId": 10, "name": "write", "label": "Write"} + ], + + "configs": [ + {"itemId": 1, "name": "username", "type": "string", "mandatory": true, "validationRegEx":"", "validationMessage": "", "uiHint":"", "label": "Username"}, + {"itemId": 2, "name": "password", "type": "password", "mandatory": true, "validationRegEx":"", "validationMessage": "", "uiHint":"", "label": "Password"}, + {"itemId": 3, "name": "jdbc.driverClassName", "type": "string", "mandatory": true, "validationRegEx":"", "validationMessage": "", "uiHint":"", "defaultValue": "org.apache.hive.jdbc.HiveDriver"}, + {"itemId": 4, "name": "jdbc.url", "type": "string", "mandatory": true, "defaultValue": "", "validationRegEx":"", "validationMessage": "", "uiHint":""}, + {"itemId": 5, "name": "commonNameForCertificate", "type": "string", "mandatory": false, "validationRegEx":"", "validationMessage": "", "uiHint":"", "label": "Common Name for Certificate"} + ], + + "enums": [ + ], + + "contextEnrichers": [ + {"itemId":1, "name" : "GeolocationEnricher_format_long", "enricher" : "org.apache.ranger.plugin.contextenricher.RangerFileBasedGeolocationProvider", "enricherOptions" : {"FilePath":"/etc/ranger/geo/geo_long.txt", "ForceRead":"false", "IPInDotFormat":"false","geolocation.meta.prefix": "FORMAT_LONG_"}}, + {"itemId":2, "name" : "GeolocationEnricher_format_dot", "enricher" : "org.apache.ranger.plugin.contextenricher.RangerFileBasedGeolocationProvider", "enricherOptions" : {"FilePath":"/etc/ranger/geo/geo.txt", "ForceRead":"false", "IPInDotFormat":"true","geolocation.meta.prefix": "FORMAT_DOT_"}} + ], + + "policyConditions": [ + {"itemId":1, "name":"ScriptConditionEvaluator", "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions" : {"engineName":"JavaScript"}, "label":"Script", "description": "Script to execute"}, + { "itemId": 2, "name":"country", "evaluator":"org.apache.ranger.plugin.conditionevaluator.RangerSimpleMatcher", "evaluatorOptions":{"CONTEXT_NAME":"country"}}, + {"itemId":3, "name":"not-accessed-together", "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerHiveResourcesNotAccessedTogetherCondition", "evaluatorOptions" : {}, "label":"Not Accessed Together?", "description": "List of Hive resources"}, + {"itemId":4, "name":"accessed-together", "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerHiveResourcesAccessedTogetherCondition", "evaluatorOptions" : {"ui.isMultiline":"false" }, "label":"Accessed Together?", "description": "List of Hive resources"} + ], + + "dataMaskDef": { + "accessTypes": [ + {"name": "select"} + ], + "resources": [ + {"itemId": 1, "name": "database", "type": "string", "level": 10, "parent": "", "mandatory": true, "lookupSupported": true, "matcherOptions": {"wildCard": "false"}, "uiHint":"{ \"singleValue\":true }", "isValidLeaf": false}, + {"itemId": 2, "name": "table", "type": "string", "level": 20, "parent": "database", "mandatory": true, "lookupSupported": true, "matcherOptions": {"wildCard": "false"}, "uiHint":"{ \"singleValue\":true }", "isValidLeaf": false}, + {"itemId": 4, "name": "column", "type": "string", "level": 30, "parent": "table", "mandatory": true, "lookupSupported": true, "matcherOptions": {"wildCard": "false"}, "uiHint":"{ \"singleValue\":true }", "isValidLeaf": true} + ], + "maskTypes": [ + {"itemId": 1, "name": "MASK", "label": "Redact", "description": "Replace lowercase with 'x', uppercase with 'X', digits with '0'", "transformer": "mask({col})", "dataMaskOptions": {}}, + {"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": 12, "name": "MASK_DATE_SHOW_YEAR", "label": "Date: show only year", "description": "Date: show only year", "transformer": "mask({col}, 'x', 'x', 'x', -1, '1', 1, 0, -1)"}, + {"itemId": 13, "name": "CUSTOM", "label": "Custom", "description": "Custom"} + ] + }, + + "rowFilterDef": { + "accessTypes": [ + {"name": "select"} + ], + "resources": [ + {"itemId": 1, "name": "database", "type": "string", "level": 10, "parent": "", "mandatory": true, "lookupSupported": true, "matcherOptions": {"wildCard": "false"}, "uiHint": "{ \"singleValue\":true }", "isValidLeaf": false}, + {"itemId": 2, "name": "table", "type": "string", "level": 20, "parent": "database", "mandatory": true, "lookupSupported": true, "matcherOptions": {"wildCard": "false"}, "uiHint": "{ \"singleValue\":true }", "isValidLeaf": true} + ] + } + }, + + "policies":[ + {"id":1,"name":"database=*,table=*,column=* - audit-all-access","isEnabled":true,"isAuditEnabled":true, + "resources":{"database":{"values":["*"]},"table":{"values":["*"]},"column":{"values":["*"]}}, + "policyItems":[ + {"accesses":[],"users":[],"groups":["public"],"delegateAdmin":false} + ] + } + , + {"id":2,"name":"database=* - allow anyone to create database; grant owner all access ","isEnabled":true,"isAuditEnabled":true, + "resources":{"database":{"values":["*"]}}, + "policyItems":[ + {"accesses":[{"type":"create","isAllowed":true}],"groups":["public"],"delegateAdmin":false}, + {"accesses":[{"type":"all","isAllowed":true}],"users":["{OWNER}"],"delegateAdmin":false} + ] + }, + {"id":3,"name":"database=*,table=* - allow owner all access to table","isEnabled":true,"isAuditEnabled":true, + "resources":{"database":{"values":["*"]},"table":{"values":["*"]}}, + "policyItems":[ + {"accesses":[{"type":"all","isAllowed":true}],"users":["{OWNER}"],"delegateAdmin":false} + ] + }, + {"id":4,"name":"database=*;table=*;column=* - allow owner all access to column","isEnabled":true,"isAuditEnabled":true, + "resources":{"database":{"values":["*"]},"table":{"values":["*"]},"column":{"values":["*"]}}, + "policyItems":[ + {"accesses":[{"type":"all","isAllowed":true}],"users":["{OWNER}"],"delegateAdmin":false} + ] + } + ], + + "tests":[ + {"name":"ALLOW 'create db-1;' for user1", + "request":{ + "resource":{"elements":{"database":"db-1"}}, + "accessType":"create","user":"user1","userGroups":["users"],"requestData":"create db-1 for user1" + }, + "result":{"isAudited":true,"isAllowed":true,"policyId":2} + } + , + {"name":"ALLOW 'create db-1.tbl-1;' for user1 with ownerUser=user1", + "request":{ + "resource":{"elements":{"database":"db-1", "table":"tbl-1"},"ownerUser":"user1"}, + "accessType":"create","user":"user1","userGroups":["users"],"requestData":"create db-1.tbl-1;' for user1 - ownerUser=user1" + }, + "result":{"isAudited":true,"isAllowed":true,"policyId":3} + } + , + {"name":"DENY 'create db-1.tbl-1;' for user2 with ownerUser=user1", + "request":{ + "resource":{"elements":{"database":"db-1", "table":"tbl-1"},"ownerUser":"user1"}, + "accessType":"create","user":"user2","userGroups":["users"],"requestData":"create db-1.tbl-1;' for user2 - ownerUser=user1" + }, + "result":{"isAudited":true,"isAllowed":false,"policyId":-1} + }, + {"name":"ALLOW 'select db-1.tbl-1.col-1;' for user1 with ownerUser=user1", + "request":{ + "resource":{"elements":{"database":"db-1", "table":"tbl-1", "column":"col-1"},"ownerUser":"user1"}, + "accessType":"select","user":"user1","userGroups":["users"],"requestData":"select db-1.tbl-1.col-1;' for user1 - ownerUser=user1" + }, + "result":{"isAudited":true,"isAllowed":true,"policyId":4} + }, + {"name":"DENY 'select db-1.tbl-1.col-1;' for user2 with ownerUser=user1", + "request":{ + "resource":{"elements":{"database":"db-1", "table":"tbl-1", "column":"col-1"},"ownerUser":"user1"}, + "accessType":"select","user":"user2","userGroups":["users"],"requestData":"select db-1.tbl-1.col-1;' for user2 - ownerUser=user1" + }, + "result":{"isAudited":true,"isAllowed":false,"policyId":-1} + } + ] +} + diff --git a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java index 7c3e3ab..ff6f6a7 100644 --- a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java +++ b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java @@ -487,6 +487,10 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { HivePrincipal grantorPrincipal, boolean grantOption) throws HiveAuthzPluginException, HiveAccessControlException { + if (LOG.isDebugEnabled()) { + LOG.debug("grantPrivileges() => HivePrivilegeObject:" + toString(hivePrivObject, new StringBuilder()) + "grantorPrincipal: " + grantorPrincipal + "hivePrincipals" + hivePrincipals + "hivePrivileges" + hivePrivileges); + } + if(! RangerHivePlugin.UpdateXaPoliciesOnGrantRevoke) { throw new HiveAuthzPluginException("GRANT/REVOKE not supported in Ranger HiveAuthorizer. Please use Ranger Security Admin to setup access control."); } @@ -494,7 +498,8 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { RangerHiveAuditHandler auditHandler = new RangerHiveAuditHandler(); try { - RangerHiveResource resource = getHiveResource(HiveOperationType.GRANT_PRIVILEGE, hivePrivObject); + List<HivePrivilegeObject> outputs = new ArrayList<>(Arrays.asList(hivePrivObject)); + RangerHiveResource resource = getHiveResource(HiveOperationType.GRANT_PRIVILEGE, hivePrivObject, null, outputs); GrantRevokeRequest request = createGrantRevokeData(resource, hivePrincipals, hivePrivileges, grantorPrincipal, grantOption); LOG.info("grantPrivileges(): " + request); @@ -534,7 +539,8 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { RangerHiveAuditHandler auditHandler = new RangerHiveAuditHandler(); try { - RangerHiveResource resource = getHiveResource(HiveOperationType.REVOKE_PRIVILEGE, hivePrivObject); + List<HivePrivilegeObject> outputs = new ArrayList<>(Arrays.asList(hivePrivObject)); + RangerHiveResource resource = getHiveResource(HiveOperationType.REVOKE_PRIVILEGE, hivePrivObject, null, outputs); GrantRevokeRequest request = createGrantRevokeData(resource, hivePrincipals, hivePrivileges, grantorPrincipal, grantOption); LOG.info("revokePrivileges(): " + request); @@ -598,7 +604,7 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { if(!CollectionUtils.isEmpty(inputHObjs)) { for(HivePrivilegeObject hiveObj : inputHObjs) { - RangerHiveResource resource = getHiveResource(hiveOpType, hiveObj); + RangerHiveResource resource = getHiveResource(hiveOpType, hiveObj, inputHObjs, outputHObjs); if (resource == null) { // possible if input object/object is of a kind that we don't currently authorize continue; @@ -659,7 +665,7 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { if(!CollectionUtils.isEmpty(outputHObjs)) { for(HivePrivilegeObject hiveObj : outputHObjs) { - RangerHiveResource resource = getHiveResource(hiveOpType, hiveObj); + RangerHiveResource resource = getHiveResource(hiveOpType, hiveObj, inputHObjs, outputHObjs); if (resource == null) { // possible if input object/object is of a kind that we don't currently authorize continue; @@ -1168,7 +1174,9 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { private RangerHiveResource getHiveResource(HiveOperationType hiveOpType, - HivePrivilegeObject hiveObj) { + HivePrivilegeObject hiveObj, + List<HivePrivilegeObject> inputs, + List<HivePrivilegeObject> outputs) { RangerHiveResource ret = null; HiveObjectType objectType = getObjectType(hiveObj, hiveOpType); @@ -1176,18 +1184,36 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { switch(objectType) { case DATABASE: ret = new RangerHiveResource(objectType, hiveObj.getDbname()); + if (!isCreateOperation(hiveOpType)) { + ret.setOwnerUser(hiveObj.getOwnerName()); + } break; case TABLE: case VIEW: + case FUNCTION: + ret = new RangerHiveResource(objectType, hiveObj.getDbname(), hiveObj.getObjectName()); + + String ownerName = hiveObj.getOwnerName(); + + if (isCreateOperation(hiveOpType)) { + HivePrivilegeObject dbObject = getDatabaseObject(hiveObj.getDbname(), inputs, outputs); + if (dbObject != null) { + ownerName = dbObject.getOwnerName(); + } + } + + ret.setOwnerUser(ownerName); + break; + case PARTITION: case INDEX: - case FUNCTION: ret = new RangerHiveResource(objectType, hiveObj.getDbname(), hiveObj.getObjectName()); break; case COLUMN: ret = new RangerHiveResource(objectType, hiveObj.getDbname(), hiveObj.getObjectName(), StringUtils.join(hiveObj.getColumns(), COLUMN_SEP)); + ret.setOwnerUser(hiveObj.getOwnerName()); break; case URI: @@ -1210,6 +1236,44 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { return ret; } + private boolean isCreateOperation(HiveOperationType hiveOpType){ + boolean ret = false; + switch (hiveOpType) { + case CREATETABLE: + case CREATEVIEW: + case CREATETABLE_AS_SELECT: + case CREATE_MATERIALIZED_VIEW: + case CREATEFUNCTION: + ret = true; + break; + } + return ret; + } + + private HivePrivilegeObject getDatabaseObject(String dbName, List<HivePrivilegeObject> inputs, List<HivePrivilegeObject> outputs) { + HivePrivilegeObject ret = null; + + if (CollectionUtils.isNotEmpty(outputs)) { + for (HivePrivilegeObject hiveOutPrivObj : outputs) { + if (hiveOutPrivObj.getType() == HivePrivilegeObjectType.DATABASE + && dbName.equalsIgnoreCase(hiveOutPrivObj.getDbname())) { + ret = hiveOutPrivObj; + } + } + } + + if (ret == null && CollectionUtils.isNotEmpty(inputs)) { + for (HivePrivilegeObject hiveInPrivObj : inputs) { + if (hiveInPrivObj.getType() == HivePrivilegeObjectType.DATABASE + && dbName.equalsIgnoreCase(hiveInPrivObj.getDbname())) { + ret = hiveInPrivObj; + } + } + } + + return ret; + } + private HiveObjectType getObjectType(HivePrivilegeObject hiveObj, HiveOperationType hiveOpType) { HiveObjectType objType = HiveObjectType.NONE; String hiveOpTypeName = hiveOpType.name().toLowerCase(); @@ -1859,7 +1923,7 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { mapResource.put(RangerHiveResource.KEY_DATABASE, database); mapResource.put(RangerHiveResource.KEY_TABLE, table); mapResource.put(RangerHiveResource.KEY_COLUMN, column); - + ret.setOwnerUser(resource.getOwnerUser()); ret.setResource(mapResource); SessionState ss = SessionState.get(); @@ -2368,7 +2432,6 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { sb.append(", 'user':").append(this.getCurrentUserGroupInfo().getUserName()); sb.append(", 'groups':[").append(StringUtil.toString(this.getCurrentUserGroupInfo().getGroupNames())).append("]"); - sb.append("}"); return sb.toString(); @@ -2396,6 +2459,7 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { sb.append(", 'partKeys':[").append(StringUtil.toString(privObj.getPartKeys())).append("]"); sb.append(", 'commandParams':[").append(StringUtil.toString(privObj.getCommandParams())).append("]"); sb.append(", 'actionType':").append(privObj.getActionType().toString()); + sb.append(", 'owner':").append(privObj.getOwnerName()); sb.append("}"); return sb; diff --git a/pom.xml b/pom.xml index 13d5a5b..8e3a92c 100644 --- a/pom.xml +++ b/pom.xml @@ -119,7 +119,7 @@ <ozone.version>0.4.0-alpha</ozone.version> <hamcrest.all.version>1.3</hamcrest.all.version> <hbase.version>2.0.2</hbase.version> - <hive.version>3.1.0</hive.version> + <hive.version>4.0.0-SNAPSHOT</hive.version> <hbase-shaded-protobuf>2.0.0</hbase-shaded-protobuf> <hbase-shaded-netty>2.0.0</hbase-shaded-netty> <hbase-shaded-miscellaneous>2.0.0</hbase-shaded-miscellaneous> diff --git a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java index af74daf..e7b3172 100644 --- a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java +++ b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java @@ -1204,7 +1204,8 @@ public class ServiceREST { validateGrantRevokeRequest(grantRequest); String userName = grantRequest.getGrantor(); Set<String> userGroups = CollectionUtils.isNotEmpty(grantRequest.getGrantorGroups()) ? grantRequest.getGrantorGroups() : userMgr.getGroupsForUser(userName); - RangerAccessResource resource = new RangerAccessResourceImpl(StringUtil.toStringObjectMap(grantRequest.getResource())); + String ownerUser = grantRequest.getOwnerUser(); + RangerAccessResource resource = new RangerAccessResourceImpl(StringUtil.toStringObjectMap(grantRequest.getResource()), ownerUser); VXUser vxUser = xUserService.getXUserByUserName(userName); if(vxUser.getUserRoleList().contains(RangerConstants.ROLE_ADMIN_AUDITOR) || vxUser.getUserRoleList().contains(RangerConstants.ROLE_KEY_ADMIN_AUDITOR)){ VXResponse vXResponse = new VXResponse(); @@ -1314,7 +1315,8 @@ public class ServiceREST { String userName = grantRequest.getGrantor(); Set<String> userGroups = CollectionUtils.isNotEmpty(grantRequest.getGrantorGroups()) ? grantRequest.getGrantorGroups() : userMgr.getGroupsForUser(userName); - RangerAccessResource resource = new RangerAccessResourceImpl(StringUtil.toStringObjectMap(grantRequest.getResource())); + String ownerUser = grantRequest.getOwnerUser(); + RangerAccessResource resource = new RangerAccessResourceImpl(StringUtil.toStringObjectMap(grantRequest.getResource()), ownerUser); boolean isAdmin = hasAdminAccess(serviceName, userName, userGroups, resource); XXService xService = daoManager.getXXService().findByName(serviceName); @@ -1431,7 +1433,8 @@ public class ServiceREST { String userName = revokeRequest.getGrantor(); Set<String> userGroups = CollectionUtils.isNotEmpty(revokeRequest.getGrantorGroups()) ? revokeRequest.getGrantorGroups() : userMgr.getGroupsForUser(userName); - RangerAccessResource resource = new RangerAccessResourceImpl(StringUtil.toStringObjectMap(revokeRequest.getResource())); + String ownerUser = revokeRequest.getOwnerUser(); + RangerAccessResource resource = new RangerAccessResourceImpl(StringUtil.toStringObjectMap(revokeRequest.getResource()), ownerUser); VXUser vxUser = xUserService.getXUserByUserName(userName); if(vxUser.getUserRoleList().contains(RangerConstants.ROLE_ADMIN_AUDITOR) || vxUser.getUserRoleList().contains(RangerConstants.ROLE_KEY_ADMIN_AUDITOR)){ VXResponse vXResponse = new VXResponse(); @@ -1502,7 +1505,8 @@ public class ServiceREST { String userName = revokeRequest.getGrantor(); Set<String> userGroups = CollectionUtils.isNotEmpty(revokeRequest.getGrantorGroups()) ? revokeRequest.getGrantorGroups() : userMgr.getGroupsForUser(userName); - RangerAccessResource resource = new RangerAccessResourceImpl(StringUtil.toStringObjectMap(revokeRequest.getResource())); + String ownerUser = revokeRequest.getOwnerUser(); + RangerAccessResource resource = new RangerAccessResourceImpl(StringUtil.toStringObjectMap(revokeRequest.getResource()), ownerUser); boolean isAdmin = hasAdminAccess(serviceName, userName, userGroups, resource); boolean isAllowed = false; boolean isKeyAdmin = bizUtil.isKeyAdmin();