Repository: sentry Updated Branches: refs/heads/SENTRY-1205 8f453adfc -> 38098b461
SENTRY-1291: SimpleCacheProviderBackend.getPrivileges should return the permission based on authorizationhierarchy (Hao Hao, Reviewed by: Lenni Kuff, Colin Ma) Change-Id: I8e69f9f55c2a63a718eb5e63bd75ee2070735cab Project: http://git-wip-us.apache.org/repos/asf/sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/42744cc9 Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/42744cc9 Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/42744cc9 Branch: refs/heads/SENTRY-1205 Commit: 42744cc97918fdd528a53745b7518957edd1506d Parents: 8f453ad Author: hahao <[email protected]> Authored: Wed Jun 1 14:40:49 2016 -0700 Committer: hahao <[email protected]> Committed: Wed Jun 1 14:40:49 2016 -0700 ---------------------------------------------------------------------- .../hive/TestCommonPrivilegeForHive.java | 19 ++- .../kafka/TestKafkaWildcardPrivilege.java | 7 + .../solr/TestCommonPrivilegeForSearch.java | 7 + .../sqoop/TestCommonPrivilegeForSqoop.java | 7 + .../sentry/policy/common/CommonPrivilege.java | 18 +++ .../apache/sentry/policy/common/Privilege.java | 14 ++ .../engine/common/CommonPolicyEngine.java | 4 +- .../indexer/IndexerWildcardPrivilege.java | 15 ++ .../indexer/TestCommonPrivilegeForIndexer.java | 7 + .../sentry/provider/cache/PrivilegeCache.java | 11 +- .../cache/SimpleCacheProviderBackend.java | 2 +- .../provider/cache/SimplePrivilegeCache.java | 162 ++++++++++++++++++- .../provider/cache/PrivilegeCacheTestImpl.java | 7 + .../cache/TestSimplePrivilegeCache.java | 90 +++++++++++ .../generic/SentryGenericProviderBackend.java | 2 +- 15 files changed, 363 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/privilege/hive/TestCommonPrivilegeForHive.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/privilege/hive/TestCommonPrivilegeForHive.java b/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/privilege/hive/TestCommonPrivilegeForHive.java index c719802..6a8b871 100644 --- a/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/privilege/hive/TestCommonPrivilegeForHive.java +++ b/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/privilege/hive/TestCommonPrivilegeForHive.java @@ -16,7 +16,6 @@ */ package org.apache.sentry.privilege.hive; -import junit.framework.Assert; import org.apache.sentry.core.common.Model; import org.apache.sentry.core.common.utils.KeyValue; import org.apache.sentry.core.common.utils.PathUtils; @@ -28,8 +27,11 @@ import org.apache.sentry.policy.common.Privilege; import org.junit.Before; import org.junit.Test; +import java.util.List; + import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.assertEquals; public class TestCommonPrivilegeForHive { @@ -209,13 +211,19 @@ public class TestCommonPrivilegeForHive { public boolean implies(Privilege p, Model m) { return false; } + + @Override + public List<KeyValue> getAuthorizable() { + return null; + } + }; assertFalse(ROLE_SERVER_SERVER1_DB_ALL.implies(null, hivePrivilegeModel)); assertFalse(ROLE_SERVER_SERVER1_DB_ALL.implies(p, hivePrivilegeModel)); assertFalse(ROLE_SERVER_SERVER1_DB_ALL.equals(null)); assertFalse(ROLE_SERVER_SERVER1_DB_ALL.equals(p)); - Assert.assertEquals(ROLE_SERVER_SERVER1_DB_ALL.hashCode(), + assertEquals(ROLE_SERVER_SERVER1_DB_ALL.hashCode(), create(ROLE_SERVER_SERVER1_DB_ALL.toString()).hashCode()); } @@ -261,6 +269,13 @@ public class TestCommonPrivilegeForHive { } @Test + public void testGetAuthz() throws Exception { + CommonPrivilege dbAll = create(new KeyValue("server", "server1"), + new KeyValue("db", "db1"), new KeyValue("action", "ALL")); + assertEquals(2, dbAll.getAuthorizable().size()); + } + + @Test public void testImpliesURINegative() throws Exception { // relative path assertFalse(PathUtils.impliesURI("hdfs://namenode:8020/path", "hdfs://namenode:8020/path/to/../../other")); http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/privilege/kafka/TestKafkaWildcardPrivilege.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/privilege/kafka/TestKafkaWildcardPrivilege.java b/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/privilege/kafka/TestKafkaWildcardPrivilege.java index a616f67..0a0e2f0 100644 --- a/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/privilege/kafka/TestKafkaWildcardPrivilege.java +++ b/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/privilege/kafka/TestKafkaWildcardPrivilege.java @@ -30,6 +30,8 @@ import org.apache.sentry.policy.common.Privilege; import org.junit.Before; import org.junit.Test; +import java.util.List; + public class TestKafkaWildcardPrivilege { private Model kafkaPrivilegeModel; @@ -137,6 +139,11 @@ public class TestKafkaWildcardPrivilege { public boolean implies(Privilege p, Model model) { return false; } + + @Override + public List<KeyValue> getAuthorizable() { + return null; + } }; Privilege topic1 = create(new KeyValue("HOST", "host"), new KeyValue("TOPIC", "topic1")); assertFalse(topic1.implies(null, kafkaPrivilegeModel)); http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/privilege/solr/TestCommonPrivilegeForSearch.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/privilege/solr/TestCommonPrivilegeForSearch.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/privilege/solr/TestCommonPrivilegeForSearch.java index 294091c..de6d6e0 100644 --- a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/privilege/solr/TestCommonPrivilegeForSearch.java +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/privilege/solr/TestCommonPrivilegeForSearch.java @@ -26,6 +26,8 @@ import org.apache.sentry.policy.common.Privilege; import org.junit.Before; import org.junit.Test; +import java.util.List; + import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -163,6 +165,11 @@ public class TestCommonPrivilegeForSearch { public boolean implies(Privilege p, Model m) { return false; } + + @Override + public List<KeyValue> getAuthorizable() { + return null; + } }; Privilege collection1 = create(new KeyValue("collection", "coll1")); assertFalse(collection1.implies(null, searchPrivilegeModel)); http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-binding/sentry-binding-sqoop/src/test/java/org/apache/sentry/privilege/sqoop/TestCommonPrivilegeForSqoop.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-sqoop/src/test/java/org/apache/sentry/privilege/sqoop/TestCommonPrivilegeForSqoop.java b/sentry-binding/sentry-binding-sqoop/src/test/java/org/apache/sentry/privilege/sqoop/TestCommonPrivilegeForSqoop.java index 92e9290..94e9919 100644 --- a/sentry-binding/sentry-binding-sqoop/src/test/java/org/apache/sentry/privilege/sqoop/TestCommonPrivilegeForSqoop.java +++ b/sentry-binding/sentry-binding-sqoop/src/test/java/org/apache/sentry/privilege/sqoop/TestCommonPrivilegeForSqoop.java @@ -26,6 +26,8 @@ import org.apache.sentry.policy.common.Privilege; import org.junit.Before; import org.junit.Test; +import java.util.List; + import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -145,6 +147,11 @@ public class TestCommonPrivilegeForSqoop { public boolean implies(Privilege p, Model m) { return false; } + + @Override + public List<KeyValue> getAuthorizable() { + return null; + } }; Privilege job1 = create(new KeyValue("SERVER", "server"), new KeyValue("JOB", "job1")); assertFalse(job1.implies(null, sqoopPrivilegeModel)); http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/CommonPrivilege.java ---------------------------------------------------------------------- diff --git a/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/CommonPrivilege.java b/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/CommonPrivilege.java index dedd908..e227535 100644 --- a/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/CommonPrivilege.java +++ b/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/CommonPrivilege.java @@ -27,6 +27,7 @@ import org.apache.sentry.core.common.utils.KeyValue; import org.apache.sentry.core.common.utils.PathUtils; import org.apache.sentry.core.common.utils.SentryConstants; +import java.util.ArrayList; import java.util.List; // The class is used to compare the privilege @@ -112,6 +113,23 @@ public class CommonPrivilege implements Privilege { return true; } + @Override + public List<KeyValue> getAuthorizable() { + List<KeyValue> authorizable = new ArrayList<>(); + + for (KeyValue part : parts) { + + // Authorizeable is the same as privileges but should exclude action + if (!SentryConstants.PRIVILEGE_NAME.equalsIgnoreCase(part.getKey())) { + KeyValue keyValue = new KeyValue(part.getKey().toLowerCase(), + part.getValue().toLowerCase()); + authorizable.add(keyValue); + } + } + + return authorizable; + } + // The method is used for compare the value of resource by the ImplyMethodType. // for Hive, databaseName, tableName, columnName will be compared using String.equal(wildcard support) // url will be compared using PathUtils.impliesURI http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/Privilege.java ---------------------------------------------------------------------- diff --git a/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/Privilege.java b/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/Privilege.java index e9f4609..6c2737a 100644 --- a/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/Privilege.java +++ b/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/Privilege.java @@ -17,7 +17,21 @@ package org.apache.sentry.policy.common; import org.apache.sentry.core.common.Model; +import org.apache.sentry.core.common.utils.KeyValue; + +import java.util.List; public interface Privilege { + + /** + * To check if implies another privilege based on the model. + **/ boolean implies(Privilege p, Model model); + + + /** + * Return the list of authorizeable of the privilege. + * @return List of Authorizeable + */ + List<KeyValue> getAuthorizable(); } http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-policy/sentry-policy-engine/src/main/java/org/apache/sentry/policy/engine/common/CommonPolicyEngine.java ---------------------------------------------------------------------- diff --git a/sentry-policy/sentry-policy-engine/src/main/java/org/apache/sentry/policy/engine/common/CommonPolicyEngine.java b/sentry-policy/sentry-policy-engine/src/main/java/org/apache/sentry/policy/engine/common/CommonPolicyEngine.java index ee25427..a819bb0 100644 --- a/sentry-policy/sentry-policy-engine/src/main/java/org/apache/sentry/policy/engine/common/CommonPolicyEngine.java +++ b/sentry-policy/sentry-policy-engine/src/main/java/org/apache/sentry/policy/engine/common/CommonPolicyEngine.java @@ -72,7 +72,7 @@ public class CommonPolicyEngine implements PolicyEngine { LOGGER.debug("Getting permissions for {}", groups); } - ImmutableSet<String> result = providerBackend.getPrivileges(groups, roleSet); + ImmutableSet<String> result = providerBackend.getPrivileges(groups, roleSet, authorizableHierarchy); if(LOGGER.isDebugEnabled()) { LOGGER.debug("result = " + result); } @@ -85,7 +85,7 @@ public class CommonPolicyEngine implements PolicyEngine { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Getting permissions for groups: {}, users: {}", groups, users); } - ImmutableSet<String> result = providerBackend.getPrivileges(groups, users, roleSet); + ImmutableSet<String> result = providerBackend.getPrivileges(groups, users, roleSet, authorizableHierarchy); if (LOGGER.isDebugEnabled()) { LOGGER.debug("result = " + result); } http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-policy/sentry-policy-indexer/src/main/java/org/apache/sentry/policy/indexer/IndexerWildcardPrivilege.java ---------------------------------------------------------------------- diff --git a/sentry-policy/sentry-policy-indexer/src/main/java/org/apache/sentry/policy/indexer/IndexerWildcardPrivilege.java b/sentry-policy/sentry-policy-indexer/src/main/java/org/apache/sentry/policy/indexer/IndexerWildcardPrivilege.java index 71d2a66..10e3496 100644 --- a/sentry-policy/sentry-policy-indexer/src/main/java/org/apache/sentry/policy/indexer/IndexerWildcardPrivilege.java +++ b/sentry-policy/sentry-policy-indexer/src/main/java/org/apache/sentry/policy/indexer/IndexerWildcardPrivilege.java @@ -21,6 +21,8 @@ package org.apache.sentry.policy.indexer; +import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import org.apache.sentry.core.common.Model; @@ -104,6 +106,19 @@ public class IndexerWildcardPrivilege implements Privilege { return true; } + @Override + public List<KeyValue> getAuthorizable() { + List<KeyValue> authorizable = new LinkedList<>(); + + for (KeyValue part : parts) { + if (!SentryConstants.PRIVILEGE_NAME.equalsIgnoreCase(part.getKey())) { + authorizable.add(part); + } + } + + return authorizable; + } + private boolean impliesKeyValue(KeyValue policyPart, KeyValue requestPart) { Preconditions.checkState(policyPart.getKey().equalsIgnoreCase(requestPart.getKey()), "Please report, this method should not be called with two different keys"); http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-policy/sentry-policy-indexer/src/test/java/org/apache/sentry/policy/indexer/TestCommonPrivilegeForIndexer.java ---------------------------------------------------------------------- diff --git a/sentry-policy/sentry-policy-indexer/src/test/java/org/apache/sentry/policy/indexer/TestCommonPrivilegeForIndexer.java b/sentry-policy/sentry-policy-indexer/src/test/java/org/apache/sentry/policy/indexer/TestCommonPrivilegeForIndexer.java index 2a3bde7..aa8aa5f 100644 --- a/sentry-policy/sentry-policy-indexer/src/test/java/org/apache/sentry/policy/indexer/TestCommonPrivilegeForIndexer.java +++ b/sentry-policy/sentry-policy-indexer/src/test/java/org/apache/sentry/policy/indexer/TestCommonPrivilegeForIndexer.java @@ -26,6 +26,8 @@ import org.apache.sentry.policy.common.Privilege; import org.junit.Before; import org.junit.Test; +import java.util.List; + import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -163,6 +165,11 @@ public class TestCommonPrivilegeForIndexer { public boolean implies(Privilege p, Model model) { return false; } + + @Override + public List<KeyValue> getAuthorizable() { + return null; + } }; CommonPrivilege indexer1 = create(new KeyValue("indexer", "index1")); assertFalse(indexer1.implies(null, indexerPrivilegeModel)); http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/PrivilegeCache.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/PrivilegeCache.java b/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/PrivilegeCache.java index 28c5b76..4bb6d32 100644 --- a/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/PrivilegeCache.java +++ b/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/PrivilegeCache.java @@ -20,6 +20,7 @@ package org.apache.sentry.provider.cache; import java.util.Set; import org.apache.sentry.core.common.ActiveRoleSet; +import org.apache.sentry.core.common.Authorizable; public interface PrivilegeCache { /** @@ -31,10 +32,18 @@ public interface PrivilegeCache { /** * Get the privileges for the give set of groups and users with the give active - * roles from the cache. + * roles from the cache. For performance issue, it is recommended to use + * listPrivileges with authorization hierarchy */ + @Deprecated Set<String> listPrivileges(Set<String> groups, Set<String> users, ActiveRoleSet roleSet); + /** + * Get the privileges for the give set of groups and users with the give active + * roles and authorization hierarchy from the cache. + */ + Set<String> listPrivileges(Set<String> groups, Set<String> users, ActiveRoleSet roleSet, + Authorizable... authorizationhierarchy); void close(); } http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/SimpleCacheProviderBackend.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/SimpleCacheProviderBackend.java b/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/SimpleCacheProviderBackend.java index b3db752..ddb4ec5 100644 --- a/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/SimpleCacheProviderBackend.java +++ b/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/SimpleCacheProviderBackend.java @@ -73,7 +73,7 @@ public class SimpleCacheProviderBackend implements ProviderBackend { "Backend has not been properly initialized"); } return ImmutableSet.copyOf(cacheHandle.listPrivileges(groups, users, - roleSet)); + roleSet, authorizableHierarchy)); } @Override http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/SimplePrivilegeCache.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/SimplePrivilegeCache.java b/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/SimplePrivilegeCache.java index dd0c39a..0ad4616 100644 --- a/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/SimplePrivilegeCache.java +++ b/sentry-provider/sentry-provider-cache/src/main/java/org/apache/sentry/provider/cache/SimplePrivilegeCache.java @@ -17,20 +17,85 @@ package org.apache.sentry.provider.cache; import org.apache.sentry.core.common.ActiveRoleSet; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.core.common.utils.SentryConstants; +import org.apache.sentry.core.common.utils.KeyValue; +import org.apache.sentry.core.model.db.DBModelAuthorizable.AuthorizableType; +import org.apache.sentry.policy.common.CommonPrivilege; +import org.apache.sentry.policy.common.Privilege; -import java.util.HashSet; import java.util.Set; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import java.util.LinkedList; /* * The class is used for saving and getting user's privileges when do the hive command like "show tables". - * This will enhance the performance for the hive metadata filter. + * This will enhance the performance for the hive metadata filter. This class is not thread safe. */ public class SimplePrivilegeCache implements PrivilegeCache { private Set<String> cachedPrivileges; + // <Authorizable, Set<PrivilegeObject>> map, this is a cache for mapping authorizable + // to corresponding set of privilege objects. + // e.g. (server=server1->database=b1, (server=server1->database=b1->action=insert)) + private final Map<String, Set<String>> cachedAuthzPrivileges = new HashMap<>(); + + // <AuthorizableType, Set<AuthorizableValue>> wild card map + private final Map<String, Set<String>> wildCardAuthz = new HashMap<>(); + public SimplePrivilegeCache(Set<String> cachedPrivileges) { this.cachedPrivileges = cachedPrivileges; + + for (String cachedPrivilege : cachedPrivileges) { + Privilege privilege = new CommonPrivilege(cachedPrivilege); + List<KeyValue> authorizable = privilege.getAuthorizable(); + String authzString = getAuthzString(authorizable); + updateWildCardAuthzMap(authorizable); + + Set<String> authzPrivileges = cachedAuthzPrivileges.get(authzString); + if (authzPrivileges == null) { + authzPrivileges = new HashSet(); + cachedAuthzPrivileges.put(authzString, authzPrivileges); + } + authzPrivileges.add(cachedPrivilege); + } + } + + private String getAuthzString(List<KeyValue> authoriable) { + List<KeyValue> authz = new LinkedList<>(); + for (KeyValue auth : authoriable) { + + // For authorizable e.g. sever=server1->uri=hdfs://namenode:8020/path/, + // use sever=server1 as the key of cachedAuthzPrivileges, since + // cannot do string matchinf on URI paths. + if (!AuthorizableType.URI.toString().equalsIgnoreCase(auth.getKey())) { + authz.add(auth); + } + } + + return SentryConstants.AUTHORIZABLE_JOINER.join(authz); + } + + private void updateWildCardAuthzMap(List<KeyValue> authz) { + for (KeyValue auth : authz) { + String authKey = auth.getKey().toLowerCase(); + String authValue = auth.getValue().toLowerCase(); + Set<String> authzValue = wildCardAuthz.get(authKey); + + if (authzValue != null ) { + if (!authzValue.contains(authValue)) { + authzValue.add(authValue); + } + } else { + authzValue = new HashSet<>(); + authzValue.add(authValue); + wildCardAuthz.put(authKey, authzValue); + } + } } // return the cached privileges @@ -56,4 +121,97 @@ public class SimplePrivilegeCache implements PrivilegeCache { } return cachedPrivileges; } + + @Override + public Set<String> listPrivileges(Set<String> groups, Set<String> users, ActiveRoleSet roleSet, + Authorizable... authorizationHierarchy) { + Set<String> privileges = new HashSet<>(); + Set<StringBuilder> authzKeys = getAuthzKeys(authorizationHierarchy); + for (StringBuilder authzKey : authzKeys) { + if (cachedAuthzPrivileges.get(authzKey.toString()) != null) { + privileges.addAll(cachedAuthzPrivileges.get(authzKey.toString())); + } + } + + return privileges; + } + + /** + * Get authoriables from the <Authorizable, Set<PrivilegeObject>> cache map, + * based on the authorizable hierarchy. This logic follows Privilege.implies. + * e.g. given authorizable hierarchy:server=server1->db=db1, returns matched + * privileges including server=server1;server=*;server=server1->db=db1;server=server1->db=*. + * @param authorizationHierarchy + * @return + */ + private Set<StringBuilder> getAuthzKeys(Authorizable... authorizationHierarchy) { + Set<StringBuilder> targets = new HashSet<>(); + for (Authorizable auth : authorizationHierarchy) { + String authzType = auth.getTypeName().toLowerCase(); + String authzName = auth.getName().toLowerCase(); + + // No op for URI authorizable type. + if (authzType.equalsIgnoreCase(AuthorizableType.URI.toString())) { + continue; + } + // If authorizable name is a wild card, need to add all possible authorizable objects + // basesd on the authorizable type. + if (authzName.equals(SentryConstants.RESOURCE_WILDCARD_VALUE) || + authzName.equals(SentryConstants.RESOURCE_WILDCARD_VALUE_SOME)|| + authzName.equals(SentryConstants.RESOURCE_WILDCARD_VALUE_ALL)) { + Set<String> wildcardValues = wildCardAuthz.get(authzType); + + if (wildcardValues != null && wildcardValues.size() > 0) { + Set<StringBuilder> newTargets = new HashSet<>(targets); + for (StringBuilder target : targets) { + for (String wildcardValue : wildcardValues) { + newTargets.add(addAuthz(target, authzType, wildcardValue)); + } + } + + targets = newTargets; + } else { + return targets; + } + } else { + if (targets.isEmpty()) { + targets.add(addAuthz(new StringBuilder(), authzType, authzName)); + + // Add wild card * search, e.g server=*, server=ALL + targets.add(addAuthz(new StringBuilder(), authzType, + SentryConstants.RESOURCE_WILDCARD_VALUE.toLowerCase())); + targets.add(addAuthz(new StringBuilder(), authzType, + SentryConstants.RESOURCE_WILDCARD_VALUE_ALL.toLowerCase())); + } else { + Set<StringBuilder> newTargets = new HashSet<>(targets); + + for (StringBuilder target : targets) { + newTargets.add(addAuthz(target, authzType, authzName)); + + // Add wild card * search, e.g server=server1->db=*, server=server1->db=ALL + newTargets.add(addAuthz(target, authzType, + SentryConstants.RESOURCE_WILDCARD_VALUE.toLowerCase())); + newTargets.add(addAuthz(target, authzType, + SentryConstants.RESOURCE_WILDCARD_VALUE_ALL.toLowerCase())); + } + + targets = newTargets; + } + } + } + + return targets; + } + + private StringBuilder addAuthz(StringBuilder authorizable, String authzType, String authzName) { + StringBuilder newAuthrizable = new StringBuilder(authorizable); + if (newAuthrizable.length() > 0) { + newAuthrizable.append(SentryConstants.AUTHORIZABLE_SEPARATOR); + newAuthrizable.append(SentryConstants.KV_JOINER.join(authzType, authzName)); + } else { + newAuthrizable.append(SentryConstants.KV_JOINER.join(authzType, authzName)); + } + + return newAuthrizable; + } } http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-provider/sentry-provider-cache/src/test/java/org/apache/sentry/provider/cache/PrivilegeCacheTestImpl.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-cache/src/test/java/org/apache/sentry/provider/cache/PrivilegeCacheTestImpl.java b/sentry-provider/sentry-provider-cache/src/test/java/org/apache/sentry/provider/cache/PrivilegeCacheTestImpl.java index 79e047e..361f273 100644 --- a/sentry-provider/sentry-provider-cache/src/test/java/org/apache/sentry/provider/cache/PrivilegeCacheTestImpl.java +++ b/sentry-provider/sentry-provider-cache/src/test/java/org/apache/sentry/provider/cache/PrivilegeCacheTestImpl.java @@ -25,6 +25,7 @@ import java.util.Set; import org.apache.commons.io.FileUtils; import org.apache.hadoop.conf.Configuration; import org.apache.sentry.core.common.ActiveRoleSet; +import org.apache.sentry.core.common.Authorizable; import org.apache.sentry.provider.common.ProviderBackendContext; import org.apache.sentry.provider.file.PolicyFiles; import org.apache.sentry.provider.file.SimpleFileProviderBackend; @@ -65,4 +66,10 @@ public class PrivilegeCacheTestImpl implements PrivilegeCache { public Set<String> listPrivileges(Set<String> groups, Set<String> users, ActiveRoleSet roleSet) { return backend.getPrivileges(groups, users, roleSet); } + + @Override + public Set<String> listPrivileges(Set<String> groups, Set<String> users, ActiveRoleSet roleSet, + Authorizable... authorizationhierarchy) { + return backend.getPrivileges(groups, users, roleSet, authorizationhierarchy); + } } http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-provider/sentry-provider-cache/src/test/java/org/apache/sentry/provider/cache/TestSimplePrivilegeCache.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-cache/src/test/java/org/apache/sentry/provider/cache/TestSimplePrivilegeCache.java b/sentry-provider/sentry-provider-cache/src/test/java/org/apache/sentry/provider/cache/TestSimplePrivilegeCache.java new file mode 100644 index 0000000..891c1d9 --- /dev/null +++ b/sentry-provider/sentry-provider-cache/src/test/java/org/apache/sentry/provider/cache/TestSimplePrivilegeCache.java @@ -0,0 +1,90 @@ +/* + * 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.sentry.provider.cache; + +import com.google.common.collect.Sets; +import org.apache.sentry.core.common.utils.KeyValue; +import org.apache.sentry.core.common.utils.SentryConstants; +import org.apache.sentry.core.model.db.Database; +import org.apache.sentry.core.model.db.Table; +import org.apache.sentry.policy.common.CommonPrivilege; +import org.junit.Test; + +import org.apache.sentry.core.model.db.Server; + +import static org.junit.Assert.assertEquals; + +public class TestSimplePrivilegeCache { + + @Test + public void testListPrivilegesCaseSensitivity() { + CommonPrivilege dbSelect = create(new KeyValue("Server", "Server1"), + new KeyValue("db", "db1"), new KeyValue("action", "SELECT")); + + SimplePrivilegeCache cache = new SimplePrivilegeCache(Sets.newHashSet(dbSelect.toString())); + assertEquals(1, cache.listPrivileges(null, null, null, + new Server("server1"), new Database("db1")).size()); + } + + @Test + public void testListPrivilegesWildCard() { + CommonPrivilege t1D1Select = create(new KeyValue("Server", "server1"), + new KeyValue("db", "db1"), new KeyValue("table", "t1"), new KeyValue("action", "SELECT")); + CommonPrivilege t1D2Select = create(new KeyValue("Server", "server1"), + new KeyValue("db", "db2"), new KeyValue("table", "t1"), new KeyValue("action", "SELECT")); + CommonPrivilege t2Select = create(new KeyValue("Server", "server1"), + new KeyValue("db", "db1"), new KeyValue("table", "t2"), new KeyValue("action", "SELECT")); + CommonPrivilege wildCardTable = create(new KeyValue("Server", "server1"), + new KeyValue("db", "db1"), new KeyValue("table", "*"), new KeyValue("action", "SELECT")); + CommonPrivilege allTable = create(new KeyValue("Server", "server1"), + new KeyValue("db", "db1"), new KeyValue("table", "ALL"), new KeyValue("action", "SELECT")); + CommonPrivilege allDatabase = create(new KeyValue("Server", "server1"), + new KeyValue("db", "*")); + CommonPrivilege colSelect = create(new KeyValue("Server", "server1"), + new KeyValue("db", "db1"), new KeyValue("table", "t1"), new KeyValue("col", "c1"), new KeyValue("action", "SELECT")); + + SimplePrivilegeCache cache = new SimplePrivilegeCache(Sets.newHashSet(t1D1Select.toString(), + t1D2Select.toString(), t2Select.toString(), wildCardTable.toString(), allTable.toString(), + allDatabase.toString(), colSelect.toString())); + + assertEquals(0, cache.listPrivileges(null, null, null, new Server("server1")).size()); + assertEquals(1, cache.listPrivileges(null, null, null, new Server("server1"), new Database("db1")).size()); + assertEquals(1, cache.listPrivileges(null, null, null, new Server("server1"), new Database("db2")).size()); + assertEquals(4, cache.listPrivileges(null, null, null, new Server("server1"), new Database("db1"), new Table("t1")).size()); + } + + @Test + public void testListPrivilegesURI() { + CommonPrivilege uri1Select = create(new KeyValue("Server", "server1"), + new KeyValue("uri", "hdfs:///uri/path1")); + CommonPrivilege uri2Select = create(new KeyValue("Server", "server1"), + new KeyValue("uri", "hdfs:///uri/path2")); + + SimplePrivilegeCache cache = new SimplePrivilegeCache(Sets.newHashSet(uri1Select.toString(), + uri2Select.toString())); + + assertEquals(2, cache.listPrivileges(null, null, null, new Server("server1")).size()); + } + + static CommonPrivilege create(KeyValue... keyValues) { + return create(SentryConstants.AUTHORIZABLE_JOINER.join(keyValues)); + } + + static CommonPrivilege create(String s) { + return new CommonPrivilege(s); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/42744cc9/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/SentryGenericProviderBackend.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/SentryGenericProviderBackend.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/SentryGenericProviderBackend.java index 1d1da5e..134012d 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/SentryGenericProviderBackend.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/SentryGenericProviderBackend.java @@ -182,7 +182,7 @@ public class SentryGenericProviderBackend extends CacheProvider implements Provi public ImmutableSet<String> getPrivileges(Set<String> groups, Set<String> users, ActiveRoleSet roleSet, Authorizable... authorizableHierarchy) { // SentryGenericProviderBackend doesn't support getPrivileges for user now. - return getPrivileges(groups, roleSet, authorizableHierarchy); + return getPrivileges(groups, roleSet); } @Override
