Repository: incubator-ranger Updated Branches: refs/heads/master d804499ae -> ff347709c
RANGER-238 Filter database and table listing per users permissions. Signed-off-by: Madhan Neethiraj <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/ff347709 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/ff347709 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/ff347709 Branch: refs/heads/master Commit: ff347709cfc04f1d90f1744fec89762d736698f7 Parents: d804499 Author: Alok Lal <[email protected]> Authored: Thu Mar 19 19:01:59 2015 -0700 Committer: Madhan Neethiraj <[email protected]> Committed: Tue Mar 31 13:11:31 2015 -0700 ---------------------------------------------------------------------- .../RangerDefaultPolicyEvaluator.java | 99 ++++---- .../policyengine/test_policyengine_hive.json | 47 ++++ hbase-agent/pom.xml | 3 +- hdfs-agent/pom.xml | 3 +- hive-agent/pom.xml | 3 +- .../authorizer/RangerHiveAccessRequest.java | 18 +- .../hive/authorizer/RangerHiveAuditHandler.java | 149 +++++++----- .../hive/authorizer/RangerHiveAuthorizer.java | 238 +++++++++++++++---- ranger-util/.gitignore | 1 + ranger_solrj/pom.xml | 1 - ugsync/pom.xml | 3 +- unixauthclient/pom.xml | 3 +- unixauthservice/pom.xml | 3 +- 13 files changed, 415 insertions(+), 156 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java index 76e50cb..fb80675 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java @@ -19,7 +19,14 @@ package org.apache.ranger.plugin.policyevaluator; -import com.google.common.base.Strings; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -35,13 +42,14 @@ import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef; import org.apache.ranger.plugin.model.RangerServiceDef.RangerPolicyConditionDef; import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessResource; import org.apache.ranger.plugin.policyengine.RangerAccessResult; import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; -import org.apache.ranger.plugin.policyengine.RangerAccessResource; import org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher; import org.apache.ranger.plugin.resourcematcher.RangerResourceMatcher; -import java.util.*; +import com.google.common.base.Strings; +import com.google.common.collect.Sets; public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator { @@ -271,7 +279,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator protected void evaluatePolicyItemsForAccess(RangerAccessRequest request, RangerAccessResult result) { if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyEvaluator.evaluatePolicyItemsForAccess()"); + LOG.debug("==> RangerDefaultPolicyEvaluator.evaluatePolicyItemsForAccess(" + request + ", " + result + ")"); } String accessType = request.getAccessType(); if (StringUtils.isEmpty(accessType)) { @@ -333,7 +341,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator break; } if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyEvaluator.evaluatePolicyItemsForAccess()"); + LOG.debug("<== RangerDefaultPolicyEvaluator.evaluatePolicyItemsForAccess(" + request + ", " + result + ")"); } } @@ -437,46 +445,53 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator if(LOG.isDebugEnabled()) { LOG.debug("==> RangerDefaultPolicyEvaluator.matchResourceHead(" + resource + ")"); } - - boolean ret = false; - - RangerServiceDef serviceDef = getServiceDef(); - - if(serviceDef != null && serviceDef.getResources() != null) { - int numMatched = 0; - int numUnmatched = 0; - - for(RangerResourceDef resourceDef : serviceDef.getResources()) { - String resourceName = resourceDef.getName(); - String resourceValue = resource == null ? null : resource.getValue(resourceName); - RangerResourceMatcher matcher = matchers == null ? null : matchers.get(resourceName); - - if(numUnmatched > 0) { // no further values are expected in the resource - if(! StringUtils.isEmpty(resourceValue)) { - break; - } - - numUnmatched++; - continue; - } else { - boolean isMatch = false; - - // when no value exists for a resourceName, consider it a match only if (policy doesn't have a matcher OR matcher allows no-value resource) - if(StringUtils.isEmpty(resourceValue)) { - isMatch = matcher == null || matcher.isMatch(resourceValue); - } else { - isMatch = matcher != null && matcher.isMatch(resourceValue); - } - - if(isMatch) { - numMatched++; - } else { - numUnmatched++; + boolean ret; + + if (resource == null || CollectionUtils.isEmpty(resource.getKeys())) { // sanity-check, firewalling + LOG.debug("matchResourceHead: resource was null/empty!"); + ret = true; // null resource matches anything + } else if (getServiceDef() == null) { // sanity-check, firewalling + LOG.debug("matchResourceHead: service-def was null!"); + ret = false; // null policy can never match a non-empty resource + } else if (getPolicy() == null || getPolicy().getResources() == null) { + LOG.debug("matchResourceHead: policy or its resources were null!"); + ret = false; // null policy can never match a non-empty resource + } else if (matchers == null || matchers.size() != getPolicy().getResources().size()) { // sanity-check, firewalling + LOG.debug("matchResourceHead: matchers could be found for some of the policy resources"); + ret = false; // empty policy can never match a non-empty resources and can't be evaluated meaningfully in matchers are absent + } else { + if (!Sets.difference(resource.getKeys(), matchers.keySet()).isEmpty()) { // e.g. avoid using udf policy for resource that has more than db specified and vice-versa + LOG.debug("matchResourceHead: resource/policy resource-keys mismatch. policy is incompatible with resource; can't match."); + ret = false; + } else { + Set<String> policyResourceNames = matchers.keySet(); + boolean skipped = false; + boolean matched = true; + Iterator<RangerResourceDef> iterator = getServiceDef().getResources().iterator(); + while (iterator.hasNext() && matched) { + RangerResourceDef resourceDef = iterator.next(); + String resourceName = resourceDef.getName(); + // we only work with resources that are relevant to this policy + if (policyResourceNames.contains(resourceName)) { + String resourceValue = resource.getValue(resourceName); + if (StringUtils.isEmpty(resourceValue)) { + if (LOG.isDebugEnabled()) { + LOG.debug("Skipping matching for " + resourceName + " since it is null/empty on resource"); + } + skipped = true; // once we skip a level all lower levels must be skippable, too + } else if (skipped == true) { + LOG.debug("matchResourceHead: found a lower level resource when a higer level resource was absent!"); + matched = false; + } else if (!matchers.get(resourceName).isMatch(resourceValue)) { + if (LOG.isDebugEnabled()) { + LOG.debug("matchResourceHead: matcher for " + resourceName + " failed"); + } + matched = false; + } } } + ret = matched; } - - ret = (numMatched > 0) && serviceDef.getResources().size() == (numMatched + numUnmatched); } if(LOG.isDebugEnabled()) { http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/agents-common/src/test/resources/policyengine/test_policyengine_hive.json ---------------------------------------------------------------------- diff --git a/agents-common/src/test/resources/policyengine/test_policyengine_hive.json b/agents-common/src/test/resources/policyengine/test_policyengine_hive.json index 8ca7071..9cf20b9 100644 --- a/agents-common/src/test/resources/policyengine/test_policyengine_hive.json +++ b/agents-common/src/test/resources/policyengine/test_policyengine_hive.json @@ -38,6 +38,13 @@ {"accesses":[{"type":"create","isAllowed":true},{"type":"drop","isAllowed":true}],"users":["admin"],"groups":["admin"],"delegateAdmin":true} ] } + , + {"id":3,"name":"db=db1; table=tbl*; column=*","isEnabled":true,"isAuditEnabled":true, + "resources":{"database":{"values":["db1"]},"table":{"values":["tbl*"]},"column":{"values":["*"]}}, + "policyItems":[ + {"accesses":[{"type":"select","isAllowed":true}],"users":["user1","user2"],"groups":["group1","group2"],"delegateAdmin":false} + ] + } ], "tests":[ @@ -256,6 +263,46 @@ }, "result":{"isAudited":true,"isAllowed":false,"policyId":-1} } + , + {"name":"DENY '_any access to db1/table1' for user1: table-level mismatch", + "request":{ + "resource":{"elements":{"database":"db1", "table":"table1"}}, + "accessType":"","user":"user1","userGroups":["users"],"requestData":"show columns in table1 from db1;" + }, + "result":{"isAudited":false,"isAllowed":false,"policyId":-1} + } + , + {"name":"DENY '_any access to db1/_/col1' for user1: table not specified but column was specified", + "request":{ + "resource":{"elements":{"database":"db1", "column":"col1"}}, + "accessType":"","user":"user1","userGroups":["users"],"requestData":"fictional use case when request specified a lower level resource by skipping intermediate resource" + }, + "result":{"isAudited":false,"isAllowed":false,"policyId":-1} + } + , + {"name":"ALLOW '_any access to db1' for user1: match when request has less levels than policy", + "request":{ + "resource":{"elements":{"database":"db1"}}, + "accessType":"","user":"user1","userGroups":["users"],"requestData":"use db1" + }, + "result":{"isAudited":true,"isAllowed":true,"policyId":3} + } + , + {"name":"ALLOW '_any access to db1/table1' for user1: match when request has same levels as policy", + "request":{ + "resource":{"elements":{"database":"db1", "table":"tbl1"}}, + "accessType":"","user":"user1","userGroups":["users"],"requestData":"describe db1.tbl1" + }, + "result":{"isAudited":true,"isAllowed":true,"policyId":3} + } + , + {"name":"ALLOW '_any access to db1/tbl1/col1' for user1: match when request has more specific levels than policy", + "request":{ + "resource":{"elements":{"database":"db1", "table":"tbl1", "column":"col1"}}, + "accessType":"","user":"user1","userGroups":["users"],"requestData":"fictional case: request for any match today happens only at a higher levels" + }, + "result":{"isAudited":true,"isAllowed":true,"policyId":3} + } ] } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/hbase-agent/pom.xml ---------------------------------------------------------------------- diff --git a/hbase-agent/pom.xml b/hbase-agent/pom.xml index 5c74b94..b4664f3 100644 --- a/hbase-agent/pom.xml +++ b/hbase-agent/pom.xml @@ -55,8 +55,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>${gson.version}</version> - </dependency> + </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/hdfs-agent/pom.xml ---------------------------------------------------------------------- diff --git a/hdfs-agent/pom.xml b/hdfs-agent/pom.xml index 6ebf633..d1f42a7 100644 --- a/hdfs-agent/pom.xml +++ b/hdfs-agent/pom.xml @@ -35,8 +35,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>${gson.version}</version> - </dependency> + </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/hive-agent/pom.xml ---------------------------------------------------------------------- diff --git a/hive-agent/pom.xml b/hive-agent/pom.xml index 1c556db..752b37b 100644 --- a/hive-agent/pom.xml +++ b/hive-agent/pom.xml @@ -90,8 +90,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>${gson.version}</version> - </dependency> + </dependency> <dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-metastore</artifactId> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAccessRequest.java ---------------------------------------------------------------------- diff --git a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAccessRequest.java b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAccessRequest.java index 39f5773..1f7ae4d 100644 --- a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAccessRequest.java +++ b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAccessRequest.java @@ -39,7 +39,7 @@ public class RangerHiveAccessRequest extends RangerAccessRequestImpl { public RangerHiveAccessRequest(RangerHiveResource resource, String user, Set<String> userGroups, - HiveOperationType hiveOpType, + String hiveOpTypeName, HiveAccessType accessType, HiveAuthzContext context, HiveAuthzSessionContext sessionContext) { @@ -47,7 +47,7 @@ public class RangerHiveAccessRequest extends RangerAccessRequestImpl { this.setUser(user); this.setUserGroups(userGroups); this.setAccessTime(StringUtil.getUTCDate()); - this.setAction(hiveOpType.name()); + this.setAction(hiveOpTypeName); if(context != null) { this.setClientIPAddress(context.getIpAddress()); @@ -70,6 +70,20 @@ public class RangerHiveAccessRequest extends RangerAccessRequestImpl { } } + public RangerHiveAccessRequest(RangerHiveResource resource, + String user, + Set<String> userGroups, + HiveOperationType hiveOpType, + HiveAccessType accessType, + HiveAuthzContext context, + HiveAuthzSessionContext sessionContext) { + this(resource, user, userGroups, hiveOpType.name(), accessType, context, sessionContext); + } + + public RangerHiveAccessRequest(RangerHiveResource resource, String user, Set<String> groups, HiveAuthzContext context, HiveAuthzSessionContext sessionContext) { + this(resource, user, groups, "OTHER", HiveAccessType.USE, context, sessionContext); + } + public HiveAccessType getHiveAccessType() { return accessType; } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuditHandler.java ---------------------------------------------------------------------- diff --git a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuditHandler.java b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuditHandler.java index 7110861..4d2d40f 100644 --- a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuditHandler.java +++ b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuditHandler.java @@ -22,8 +22,11 @@ package org.apache.ranger.authorization.hive.authorizer; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveOperationType; import org.apache.ranger.audit.model.AuthzAuditEvent; import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; import org.apache.ranger.authorization.hadoop.constants.RangerHadoopConstants; @@ -31,6 +34,8 @@ import org.apache.ranger.authorization.utils.StringUtil; import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import com.google.common.collect.Lists; + public class RangerHiveAuditHandler extends RangerDefaultAuditHandler { private static final String RangerModuleName = RangerConfiguration.getInstance().get(RangerHadoopConstants.AUDITLOG_RANGER_MODULE_ACL_NAME_PROP , RangerHadoopConstants.DEFAULT_RANGER_MODULE_ACL_NAME) ; @@ -40,18 +45,12 @@ public class RangerHiveAuditHandler extends RangerDefaultAuditHandler { public RangerHiveAuditHandler() { super(); } - - @Override - public void logAudit(RangerAccessResult result) { - if(! result.getIsAudited()) { - return; - } - - AuthzAuditEvent auditEvent = new AuthzAuditEvent(); - + + AuthzAuditEvent createAuditEvent(RangerAccessResult result, String accessType, String resourcePath) { RangerHiveAccessRequest request = (RangerHiveAccessRequest)result.getAccessRequest(); RangerHiveResource resource = (RangerHiveResource)request.getResource(); + AuthzAuditEvent auditEvent = new AuthzAuditEvent(); auditEvent.setAclEnforcer(RangerModuleName); auditEvent.setSessionId(request.getSessionId()); auditEvent.setResourceType("@" + StringUtil.toLower(resource.getObjectType().name())); // to be consistent with earlier release @@ -67,66 +66,108 @@ public class RangerHiveAuditHandler extends RangerDefaultAuditHandler { auditEvent.setRepositoryName(result.getServiceName()) ; auditEvent.setRequestData(request.getRequestData()); auditEvent.setResourcePath(resource != null ? resource.getAsString(result.getServiceDef()) : null); + + return auditEvent; + } + + AuthzAuditEvent createAuditEvent(RangerAccessResult result) { + + RangerHiveAccessRequest request = (RangerHiveAccessRequest)result.getAccessRequest(); + RangerHiveResource resource = (RangerHiveResource)request.getResource(); + String accessType = request.getHiveAccessType().toString(); + String resourcePath = resource != null ? resource.getAsString(result.getServiceDef()) : null; + return createAuditEvent(result, accessType, resourcePath); + } + + public List<AuthzAuditEvent> createAuditEvents(Collection<RangerAccessResult> results) { + Map<Long, AuthzAuditEvent> auditEvents = new HashMap<Long, AuthzAuditEvent>(); + Iterator<RangerAccessResult> iterator = results.iterator(); + AuthzAuditEvent deniedAuditEvent = null; + while (iterator.hasNext() && deniedAuditEvent == null) { + RangerAccessResult result = iterator.next(); + if(result.getIsAudited()) { + if (!result.getIsAllowed()) { + deniedAuditEvent = createAuditEvent(result); + } else { + long policyId = result.getPolicyId(); + if (auditEvents.containsKey(policyId)) { // add this result to existing event by updating column values + AuthzAuditEvent auditEvent = auditEvents.get(policyId); + RangerHiveAccessRequest request = (RangerHiveAccessRequest)result.getAccessRequest(); + RangerHiveResource resource = (RangerHiveResource)request.getResource(); + String resourcePath = auditEvent.getResourcePath() + "," + resource.getColumn(); + auditEvent.setResourcePath(resourcePath); + } else { // new event as this approval was due to a different policy. + AuthzAuditEvent auditEvent = createAuditEvent(result); + auditEvents.put(policyId, auditEvent); + } + } + } + } + List<AuthzAuditEvent> result; + if (deniedAuditEvent == null) { + result = new ArrayList<>(auditEvents.values()); + } else { + result = Lists.newArrayList(deniedAuditEvent); + } + + return result; + } + + @Override + public void logAudit(RangerAccessResult result) { + if(! result.getIsAudited()) { + return; + } + AuthzAuditEvent auditEvent = createAuditEvent(result); addAuthzAuditEvent(auditEvent); } - /* + /** * This method is expected to be called ONLY to process the results for multiple-columns in a table. * To ensure this, RangerHiveAuthorizer should call isAccessAllowed(Collection<requests>) only for this condition */ @Override public void logAudit(Collection<RangerAccessResult> results) { - Map<Long, AuthzAuditEvent> auditEvents = new HashMap<Long, AuthzAuditEvent>(); - - for(RangerAccessResult result : results) { - if(! result.getIsAudited()) { - continue; - } - - RangerHiveAccessRequest request = (RangerHiveAccessRequest)result.getAccessRequest(); - RangerHiveResource resource = (RangerHiveResource)request.getResource(); - AuthzAuditEvent auditEvent = auditEvents.get(result.getPolicyId()); - - if(auditEvent == null) { - auditEvent = new AuthzAuditEvent(); - auditEvents.put(result.getPolicyId(), auditEvent); - - auditEvent.setAclEnforcer(RangerModuleName); - auditEvent.setSessionId(request.getSessionId()); - auditEvent.setResourceType("@" + StringUtil.toLower(resource.getObjectType().name())); // to be consistent with earlier release - auditEvent.setAccessType(request.getHiveAccessType().toString()); - auditEvent.setAction(request.getAction()); - auditEvent.setUser(request.getUser()); - auditEvent.setAccessResult((short)(result.getIsAllowed() ? 1 : 0)); - auditEvent.setPolicyId(result.getPolicyId()); - auditEvent.setClientIP(request.getClientIPAddress()); - auditEvent.setClientType(request.getClientType()); - auditEvent.setEventTime(request.getAccessTime()); - auditEvent.setRepositoryType(result.getServiceType()); - auditEvent.setRepositoryName(result.getServiceName()) ; - auditEvent.setRequestData(request.getRequestData()); - - auditEvent.setResourcePath(resource != null ? resource.getAsString(result.getServiceDef()) : null); - } else if(result.getIsAllowed()){ - auditEvent.setResourcePath(auditEvent.getResourcePath() + "," + resource.getColumn()); - } else { - auditEvent.setResourcePath(resource != null ? resource.getAsString(result.getServiceDef()) : null); - } - - if(!result.getIsAllowed()) { - auditEvent.setResourcePath(resource != null ? resource.getAsString(result.getServiceDef()) : null); + List<AuthzAuditEvent> auditEvents = createAuditEvents(results); + for(AuthzAuditEvent auditEvent : auditEvents) { + addAuthzAuditEvent(auditEvent); + } + } - break; - } + public void logAuditEventForFiltering(RangerAccessResult result, HiveOperationType hiveOpType) { + + if(! result.getIsAudited()) { + return; } + + RangerHiveAccessRequest request = (RangerHiveAccessRequest)result.getAccessRequest(); + RangerHiveResource resource = (RangerHiveResource)request.getResource(); + String resourcePath = resource.getObjectType().toString(); + String accessType = getAccessTypeForMetaOperation(hiveOpType); + + AuthzAuditEvent auditEvent = createAuditEvent(result, accessType, resourcePath); - for(AuthzAuditEvent auditEvent : auditEvents.values()) { - addAuthzAuditEvent(auditEvent); + addAuthzAuditEvent(auditEvent); + } + + String getAccessTypeForMetaOperation(HiveOperationType hiveOperationType) { + String result; + switch (hiveOperationType) { + case SHOWDATABASES: + result = "SHOW DATABASES"; + break; + case SHOWTABLES: + result = "SHOW TABLES"; + break; + default: + result = "OTHER METADATA OP"; + break; } + return result; } - public void logAuditEventForDfs(String userName, String dfsCommand, boolean accessGranted, int repositoryType, String repositoryName) { + public void logAuditEventForDfs(String userName, String dfsCommand, boolean accessGranted, int repositoryType, String repositoryName) { AuthzAuditEvent auditEvent = new AuthzAuditEvent(); auditEvent.setAclEnforcer(RangerModuleName); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java ---------------------------------------------------------------------- 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 121177d..bca8858 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 @@ -283,51 +283,73 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { } } - for(RangerHiveAccessRequest request : requests) { - RangerHiveResource resource = (RangerHiveResource)request.getResource(); - RangerAccessResult result = null; - - if(resource.getObjectType() == HiveObjectType.COLUMN && StringUtils.contains(resource.getColumn(), COLUMN_SEP)) { - List<RangerAccessRequest> colRequests = new ArrayList<RangerAccessRequest>(); - - String[] columns = StringUtils.split(resource.getColumn(), COLUMN_SEP); - - for(String column : columns) { - if (column != null) { - column = column.trim(); - } - if(StringUtils.isEmpty(column)) { - continue; - } - - RangerHiveResource colResource = new RangerHiveResource(HiveObjectType.COLUMN, resource.getDatabase(), resource.getTable(), column); - - RangerHiveAccessRequest colRequest = request.copy(); - colRequest.setResource(colResource); - - colRequests.add(colRequest); - } - - Collection<RangerAccessResult> colResults = hivePlugin.isAccessAllowed(colRequests, auditHandler); - - if(colResults != null) { - for(RangerAccessResult colResult : colResults) { - result = colResult; - - if(!result.getIsAllowed()) { - break; + if (isMetaDataOperation(hiveOpType)) { + RangerHiveResource resource = getHiveResource(hiveOpType); + RangerHiveAccessRequest request = new RangerHiveAccessRequest(resource, user, groups, context, sessionContext); + RangerAccessResult result = hivePlugin.isAccessAllowed(request); + if (result == null) { + LOG.error("Internal error: null RangerAccessResult object received back from isAccessAllowed()!"); + throw new HiveAccessControlException(String.format("Permission denied: user [%s] does not have [%s] privilege", + user, hiveOpType)); + } else if (!result.getIsAllowed()) { + String path = resource.getAsString(result.getServiceDef()); + throw new HiveAccessControlException(String.format("Permission denied: user [%s] does not have [%s] privilege on [%s]", + user, hiveOpType.name(), path)); + } else { + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("[%s] allowed on resource[%s]: request[%s], result[%s]", hiveOpType, resource, request, result)); + } + if (result.getIsAudited()) { + auditHandler.logAuditEventForFiltering(result, hiveOpType); + } + } + } else { + for(RangerHiveAccessRequest request : requests) { + RangerHiveResource resource = (RangerHiveResource)request.getResource(); + RangerAccessResult result = null; + + if(resource.getObjectType() == HiveObjectType.COLUMN && StringUtils.contains(resource.getColumn(), COLUMN_SEP)) { + List<RangerAccessRequest> colRequests = new ArrayList<RangerAccessRequest>(); + + String[] columns = StringUtils.split(resource.getColumn(), COLUMN_SEP); + + for(String column : columns) { + if (column != null) { + column = column.trim(); + } + if(StringUtils.isEmpty(column.trim())) { + continue; } + + RangerHiveResource colResource = new RangerHiveResource(HiveObjectType.COLUMN, resource.getDatabase(), resource.getTable(), column); + + RangerHiveAccessRequest colRequest = request.copy(); + colRequest.setResource(colResource); + + colRequests.add(colRequest); } - } - } else { - result = hivePlugin.isAccessAllowed(request, auditHandler); - } - - if(result != null && !result.getIsAllowed()) { - String path = resource != null ? resource.getAsString(result.getServiceDef()) : null; - throw new HiveAccessControlException(String.format("Permission denied: user [%s] does not have [%s] privilege on [%s]", - user, request.getHiveAccessType().name(), path)); + Collection<RangerAccessResult> colResults = hivePlugin.isAccessAllowed(colRequests, auditHandler); + + if(colResults != null) { + for(RangerAccessResult colResult : colResults) { + result = colResult; + + if(!result.getIsAllowed()) { + break; + } + } + } + } else { + result = hivePlugin.isAccessAllowed(request, auditHandler); + } + + if(result != null && !result.getIsAllowed()) { + String path = resource != null ? resource.getAsString(result.getServiceDef()) : null; + + throw new HiveAccessControlException(String.format("Permission denied: user [%s] does not have [%s] privilege on [%s]", + user, request.getHiveAccessType().name(), path)); + } } } } finally { @@ -335,6 +357,29 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { } } + boolean isMetaDataOperation(HiveOperationType hiveOpType) { + boolean result; + + switch (hiveOpType) { + /* + * Uncomment this part when hive bug is resolved. + * + case SHOWTABLES: + result = true; + break; + * + */ + case SHOWDATABASES: // we don't want to authorize for show databases either since any call with _any privilages runs into a problem. + case SHOWTABLES: // currently does not work since we don't get the database name in the context to do this check correctly. + case DESCDATABASE: // currently does not work since we don't get the database name in the context to do this check correctly. + default: + result = false; + break; + } + return result; + } + + /** * Check if user has privileges to do this action on these objects * @param objs @@ -347,13 +392,116 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { public List<HivePrivilegeObject> filterListCmdObjects(List<HivePrivilegeObject> objs, HiveAuthzContext context) throws HiveAuthzPluginException, HiveAccessControlException { + + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("==> filterListCmdObjects(%s, %s)", objs, context)); + } + List<HivePrivilegeObject> ret = null; - // TODO: only the objects the user has access-to should be added to 'ret' - ret = objs; - + // bail out early if nothing is there to validate! + if (objs == null) { + LOG.debug("filterListCmdObjects: meta objects list was null!"); + } else if (objs.isEmpty()) { + LOG.debug("filterListCmdObjects: meta objects list was empty!"); + ret = objs; + } else if (getCurrentUserGroupInfo() == null) { + /* + * This is null for metastore and there doesn't seem to be a way to tell if one is running as metastore or hiveserver2! + */ + LOG.warn("filterListCmdObjects: user information not available"); + ret = objs; + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("filterListCmdObjects: number of input objects[" + objs.size() + "]"); + } + // get user/group info + UserGroupInformation ugi = getCurrentUserGroupInfo(); // we know this can't be null since we checked it above! + HiveAuthzSessionContext sessionContext = getHiveAuthzSessionContext(); + String user = ugi.getShortUserName(); + Set<String> groups = Sets.newHashSet(ugi.getGroupNames()); + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("filterListCmdObjects: user[%s], groups%s", user, groups)); + } + + if (ret == null) { // if we got any items to filter then we can't return back a null. We must return back a list even if its empty. + ret = new ArrayList<HivePrivilegeObject>(objs.size()); + } + for (HivePrivilegeObject privilegeObject : objs) { + if (LOG.isDebugEnabled()) { + HivePrivObjectActionType actionType = privilegeObject.getActionType(); + HivePrivilegeObjectType objectType = privilegeObject.getType(); + String objectName = privilegeObject.getObjectName(); + String dbName = privilegeObject.getDbname(); + List<String> columns = privilegeObject.getColumns(); + List<String> partitionKeys = privilegeObject.getPartKeys(); + String commandString = context.getCommandString(); + String ipAddress = context.getIpAddress(); + + final String format = "filterListCmdObjects: actionType[%s], objectType[%s], objectName[%s], dbName[%s], columns[%s], partitionKeys[%s]; context: commandString[%s], ipAddress[%s]"; + LOG.debug(String.format(format, actionType, objectType, objectName, dbName, columns, partitionKeys, commandString, ipAddress)); + } + + RangerHiveResource resource = createHiveResource(privilegeObject); + RangerHiveAccessRequest request = new RangerHiveAccessRequest(resource, user, groups, context, sessionContext); + RangerAccessResult result = hivePlugin.isAccessAllowed(request); + if (result == null) { + LOG.error("filterListCmdObjects: Internal error: null RangerAccessResult object received back from isAccessAllowed()!"); + } else if (!result.getIsAllowed()) { + if (!LOG.isDebugEnabled()) { + String path = resource.getAsString(result.getServiceDef()); + LOG.debug(String.format("filterListCmdObjects: Permission denied: user [%s] does not have [%s] privilege on [%s]", user, request.getHiveAccessType().name(), path)); + } + } else { + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("filterListCmdObjects: resource[%s]: allowed!: request[%s], result[%s]", resource, request, result)); + } + ret.add(privilegeObject); + } + } + } + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("filterListCmdObjects: number of output objects[%d]", ret == null ? 0: ret.size())); + LOG.debug(String.format("<== filterListCmdObjects(%s, %s): %s", objs, context, ret)); + } + return ret; } + + RangerHiveResource getHiveResource(HiveOperationType hiveOperationType) { + RangerHiveResource hiveResource; + switch (hiveOperationType) { + case SHOWDATABASES: + case SHOWTABLES: + // any database + hiveResource = new RangerHiveResource(HiveObjectType.DATABASE, null); + break; + default: + hiveResource = null; + } + return hiveResource; + } + + RangerHiveResource createHiveResource(HivePrivilegeObject privilegeObject) { + RangerHiveResource resource = null; + + HivePrivilegeObjectType objectType = privilegeObject.getType(); + String objectName = privilegeObject.getObjectName(); + String dbName = privilegeObject.getDbname(); + + switch(objectType) { + case DATABASE: + resource = new RangerHiveResource(HiveObjectType.DATABASE, objectName); + break; + case TABLE_OR_VIEW: + resource = new RangerHiveResource(HiveObjectType.TABLE, dbName, objectName); + break; + default: + LOG.warn("RangerHiveAuthorizer.getHiveResource: unexpected objectType:" + objectType); + } + return resource; + } + private RangerHiveResource getHiveResource(HiveOperationType hiveOpType, HivePrivilegeObject hiveObj) { http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/ranger-util/.gitignore ---------------------------------------------------------------------- diff --git a/ranger-util/.gitignore b/ranger-util/.gitignore index ffdf566..88be44f 100644 --- a/ranger-util/.gitignore +++ b/ranger-util/.gitignore @@ -2,3 +2,4 @@ /target/ /bin/ .settings/ +gen/ http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/ranger_solrj/pom.xml ---------------------------------------------------------------------- diff --git a/ranger_solrj/pom.xml b/ranger_solrj/pom.xml index 1924e87..58527f4 100644 --- a/ranger_solrj/pom.xml +++ b/ranger_solrj/pom.xml @@ -7,7 +7,6 @@ <artifactId>ranger</artifactId> <version>0.5.0</version> </parent> - <groupId>org.apache.ranger</groupId> <artifactId>ranger_solrj</artifactId> <version>0.5.0</version> <name>ranger_solrj</name> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/ugsync/pom.xml ---------------------------------------------------------------------- diff --git a/ugsync/pom.xml b/ugsync/pom.xml index aee6e7a..55bc4c3 100644 --- a/ugsync/pom.xml +++ b/ugsync/pom.xml @@ -42,8 +42,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>${gson.version}</version> - </dependency> + </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-bundle</artifactId> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/unixauthclient/pom.xml ---------------------------------------------------------------------- diff --git a/unixauthclient/pom.xml b/unixauthclient/pom.xml index b296d33..721cf0f 100644 --- a/unixauthclient/pom.xml +++ b/unixauthclient/pom.xml @@ -43,8 +43,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>${gson.version}</version> - </dependency> + </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-bundle</artifactId> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ff347709/unixauthservice/pom.xml ---------------------------------------------------------------------- diff --git a/unixauthservice/pom.xml b/unixauthservice/pom.xml index 920b2cd..89c0a81 100644 --- a/unixauthservice/pom.xml +++ b/unixauthservice/pom.xml @@ -49,8 +49,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>${gson.version}</version> - </dependency> + </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-bundle</artifactId>
