Updated Branches: refs/heads/master fe5fb70f6 -> 1824f7808
SENTRY-35: Create sentry-provider-policy-search module (Gregory Chanan via Shreepadma Venugopalan) Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/1824f780 Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/1824f780 Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/1824f780 Branch: refs/heads/master Commit: 1824f780837c9e616af5b9e0ae4f1f82c46df6fa Parents: fe5fb70 Author: Shreepadma Venugopalan <shreepa...@apache.org> Authored: Tue Oct 15 17:25:04 2013 -0700 Committer: Shreepadma Venugopalan <shreepa...@apache.org> Committed: Tue Oct 15 17:25:04 2013 -0700 ---------------------------------------------------------------------- .../sentry-provider-policy-search/pom.xml | 20 +++ .../search/SimpleSearchPolicyEngine.java | 114 ++++++++++++ .../search/AbstractTestSearchPolicyEngine.java | 133 ++++++++++++++ .../search/SearchPolicyFileBackend.java | 26 +++ ...SearchAuthorizationProviderGeneralCases.java | 179 +++++++++++++++++++ ...SearchAuthorizationProviderSpecialCases.java | 81 +++++++++ .../search/TestSearchPolicyEngineDFS.java | 81 +++++++++ .../search/TestSearchPolicyEngineLocalFS.java | 43 +++++ .../search/TestSearchPolicyNegative.java | 111 ++++++++++++ .../src/test/resources/log4j.properties | 31 ++++ .../src/test/resources/test-authz-provider.ini | 31 ++++ 11 files changed, 850 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/pom.xml ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/pom.xml b/sentry-provider/sentry-provider-policy-search/pom.xml index 5156c2c..80db002 100644 --- a/sentry-provider/sentry-provider-policy-search/pom.xml +++ b/sentry-provider/sentry-provider-policy-search/pom.xml @@ -34,6 +34,15 @@ limitations under the License. <scope>test</scope> </dependency> <dependency> + <groupId>org.apache.hadoop</groupId> + <artifactId>hadoop-common</artifactId> + </dependency> + <dependency> + <groupId>org.apache.hadoop</groupId> + <artifactId>hadoop-minicluster</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </dependency> @@ -59,8 +68,19 @@ limitations under the License. </dependency> <dependency> <groupId>org.apache.sentry</groupId> + <artifactId>sentry-provider-common</artifactId> + </dependency> + <dependency> + <groupId>org.apache.sentry</groupId> <artifactId>sentry-provider-file</artifactId> </dependency> + <dependency> + <groupId>org.apache.sentry</groupId> + <artifactId>sentry-provider-common</artifactId> + <scope>test</scope> + <type>test-jar</type> + <version>${project.version}</version> + </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/src/main/java/org/apache/sentry/provider/search/SimpleSearchPolicyEngine.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/src/main/java/org/apache/sentry/provider/search/SimpleSearchPolicyEngine.java b/sentry-provider/sentry-provider-policy-search/src/main/java/org/apache/sentry/provider/search/SimpleSearchPolicyEngine.java new file mode 100644 index 0000000..7d37660 --- /dev/null +++ b/sentry-provider/sentry-provider-policy-search/src/main/java/org/apache/sentry/provider/search/SimpleSearchPolicyEngine.java @@ -0,0 +1,114 @@ +/* + * 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.search; + +import javax.annotation.Nullable; + +import java.io.IOException; +import java.util.List; +import java.util.Map.Entry; +import org.apache.shiro.config.ConfigurationException; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.provider.common.PermissionFactory; +import org.apache.sentry.provider.common.PolicyEngine; +import org.apache.sentry.provider.common.ProviderBackend; +import org.apache.sentry.provider.common.Roles; +import org.apache.sentry.provider.common.RoleValidator; +import org.apache.sentry.provider.file.SimpleFileProviderBackend; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.annotations.VisibleForTesting; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.Lists; + +/** + * A PolicyEngine for a search service. + */ +public class SimpleSearchPolicyEngine implements PolicyEngine { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SimpleSearchPolicyEngine.class); + + private ProviderBackend providerBackend; + + public SimpleSearchPolicyEngine(ProviderBackend providerBackend) { + List<? extends RoleValidator> validators = + Lists.newArrayList(new CollectionRequiredInRole()); + this.providerBackend = providerBackend; + this.providerBackend.process(validators); + + if (!this.providerBackend.getRoles().getPerDatabaseRoles().isEmpty()) { + throw new ConfigurationException( + "SimpleSearchPolicyEngine does not support per-database roles, " + + "but per-database roles were specified. Ignoring."); + } + } + + /* + * Note: finalize is final because constructor throws exception, see: + * OBJ11-J. + */ + public final void finalize() { + // do nothing + } + + /** + * {@inheritDoc} + */ + @Override + public PermissionFactory getPermissionFactory() { + return new SearchWildcardPermission.SearchWildcardPermissionFactory(); + } + + /** + * {@inheritDoc} + */ + @Override + public ImmutableSetMultimap<String, String> getPermissions(List<? extends Authorizable> authorizables, List<String> groups) { + if(LOGGER.isDebugEnabled()) { + LOGGER.debug("Getting permissions for {}", groups); + } + ImmutableSetMultimap.Builder<String, String> resultBuilder = ImmutableSetMultimap.builder(); + for(String group : groups) { + resultBuilder.putAll(group, getSearchRoles(group,providerBackend.getRoles())); + } + ImmutableSetMultimap<String, String> result = resultBuilder.build(); + if(LOGGER.isDebugEnabled()) { + LOGGER.debug("result = " + result); + } + return result; + } + + private ImmutableSet<String> getSearchRoles(String group, Roles roles) { + ImmutableSetMultimap<String, String> globalRoles = roles.getGlobalRoles(); + ImmutableSet.Builder<String> resultBuilder = ImmutableSet.builder(); + + if(globalRoles.containsKey(group)) { + resultBuilder.addAll(globalRoles.get(group)); + } + ImmutableSet<String> result = resultBuilder.build(); + if(LOGGER.isDebugEnabled()) { + LOGGER.debug("Group {}, Result {}", + new Object[]{ group, result}); + } + return result; + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/AbstractTestSearchPolicyEngine.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/AbstractTestSearchPolicyEngine.java b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/AbstractTestSearchPolicyEngine.java new file mode 100644 index 0000000..0583a51 --- /dev/null +++ b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/AbstractTestSearchPolicyEngine.java @@ -0,0 +1,133 @@ +/* + * 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.search; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import junit.framework.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.core.model.search.Collection; +import org.apache.sentry.provider.common.PolicyEngine; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.io.Files; + +public abstract class AbstractTestSearchPolicyEngine { + private static final String ANALYST_PURCHASES_UPDATE = "collection=purchases->action=update"; + private static final String ANALYST_ANALYST1_ALL = "collection=analyst1"; + private static final String ANALYST_JRANALYST1_ACTION_ALL = "collection=jranalyst1->action=*"; + private static final String ANALYST_TMPCOLLECTION_UPDATE = "collection=tmpcollection->action=update"; + private static final String ANALYST_TMPCOLLECTION_QUERY = "collection=tmpcollection->action=query"; + private static final String JRANALYST_JRANALYST1_ALL = "collection=jranalyst1"; + private static final String JRANALYST_PURCHASES_PARTIAL_QUERY = "collection=purchases_partial->action=query"; + private static final String ADMIN_COLLECTION_ALL = "collection=*"; + + private PolicyEngine policy; + private static File baseDir; + private List<Authorizable> authorizables = Lists.newArrayList(); + + @BeforeClass + public static void setupClazz() throws IOException { + baseDir = Files.createTempDir(); + } + + @AfterClass + public static void teardownClazz() throws IOException { + if(baseDir != null) { + FileUtils.deleteQuietly(baseDir); + } + } + + protected void setPolicy(PolicyEngine policy) { + this.policy = policy; + } + protected static File getBaseDir() { + return baseDir; + } + @Before + public void setup() throws IOException { + afterSetup(); + } + @After + public void teardown() throws IOException { + beforeTeardown(); + } + protected void afterSetup() throws IOException { + + } + + protected void beforeTeardown() throws IOException { + + } + + @Test + public void testManager() throws Exception { + Set<String> expected = Sets.newTreeSet(Sets.newHashSet( + ANALYST_PURCHASES_UPDATE, ANALYST_ANALYST1_ALL, + ANALYST_JRANALYST1_ACTION_ALL, ANALYST_TMPCOLLECTION_UPDATE, + ANALYST_TMPCOLLECTION_QUERY, JRANALYST_JRANALYST1_ALL, + JRANALYST_PURCHASES_PARTIAL_QUERY)); + Assert.assertEquals(expected.toString(), + new TreeSet<String>(policy.getPermissions(authorizables, list("manager")).values()) + .toString()); + } + + @Test + public void testAnalyst() throws Exception { + Set<String> expected = Sets.newTreeSet(Sets.newHashSet( + ANALYST_PURCHASES_UPDATE, ANALYST_ANALYST1_ALL, + ANALYST_JRANALYST1_ACTION_ALL, ANALYST_TMPCOLLECTION_UPDATE, + ANALYST_TMPCOLLECTION_QUERY)); + Assert.assertEquals(expected.toString(), + new TreeSet<String>(policy.getPermissions(authorizables, list("analyst")).values()) + .toString()); + } + + @Test + public void testJuniorAnalyst() throws Exception { + Set<String> expected = Sets.newTreeSet(Sets + .newHashSet(JRANALYST_JRANALYST1_ALL, + JRANALYST_PURCHASES_PARTIAL_QUERY)); + Assert.assertEquals(expected.toString(), + new TreeSet<String>(policy.getPermissions(authorizables, list("jranalyst")).values()) + .toString()); + } + + @Test + public void testAdmin() throws Exception { + Set<String> expected = Sets.newTreeSet(Sets.newHashSet(ADMIN_COLLECTION_ALL)); + Assert.assertEquals(expected.toString(), + new TreeSet<String>(policy.getPermissions(authorizables, list("admin")).values()) + .toString()); + } + + private static List<String> list(String... values) { + return Lists.newArrayList(values); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/SearchPolicyFileBackend.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/SearchPolicyFileBackend.java b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/SearchPolicyFileBackend.java new file mode 100644 index 0000000..db331ab --- /dev/null +++ b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/SearchPolicyFileBackend.java @@ -0,0 +1,26 @@ +/* + * 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.search; + +import java.io.IOException; +import org.apache.sentry.provider.file.SimpleFileProviderBackend; + +public class SearchPolicyFileBackend extends SimpleSearchPolicyEngine { + public SearchPolicyFileBackend(String resource) throws IOException{ + super(new SimpleFileProviderBackend(resource)); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchAuthorizationProviderGeneralCases.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchAuthorizationProviderGeneralCases.java b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchAuthorizationProviderGeneralCases.java new file mode 100644 index 0000000..95d436f --- /dev/null +++ b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchAuthorizationProviderGeneralCases.java @@ -0,0 +1,179 @@ +/* + * 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.search; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import junit.framework.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.sentry.core.common.Action; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.core.common.Subject; +import org.apache.sentry.core.model.search.SearchConstants; +import org.apache.sentry.core.model.search.SearchModelAction; +import org.apache.sentry.core.model.search.Collection; +import org.apache.sentry.provider.common.MockGroupMappingServiceProvider; +import org.apache.sentry.provider.file.HadoopGroupResourceAuthorizationProvider; +import org.apache.sentry.provider.file.PolicyFiles; +import org.apache.sentry.provider.file.ResourceAuthorizationProvider; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Objects; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.io.Files; + + +public class TestSearchAuthorizationProviderGeneralCases { + + private static final Logger LOGGER = LoggerFactory + .getLogger(TestSearchAuthorizationProviderGeneralCases.class); + + private static final Multimap<String, String> USER_TO_GROUP_MAP = HashMultimap + .create(); + + private static final Subject SUB_ADMIN = new Subject("admin1"); + private static final Subject SUB_MANAGER = new Subject("manager1"); + private static final Subject SUB_ANALYST = new Subject("analyst1"); + private static final Subject SUB_JUNIOR_ANALYST = new Subject("jranalyst1"); + + private static final Collection COLL_PURCHASES = new Collection("purchases"); + private static final Collection COLL_ANALYST1 = new Collection("analyst1"); + private static final Collection COLL_JRANALYST1 = new Collection("jranalyst1"); + private static final Collection COLL_TMP = new Collection("tmpcollection"); + private static final Collection COLL_PURCHASES_PARTIAL = new Collection("purchases_partial"); + + private static final SearchModelAction ALL = SearchModelAction.ALL; + private static final SearchModelAction QUERY = SearchModelAction.QUERY; + private static final SearchModelAction UPDATE = SearchModelAction.UPDATE; + + static { + USER_TO_GROUP_MAP.putAll(SUB_ADMIN.getName(), Arrays.asList("admin")); + USER_TO_GROUP_MAP.putAll(SUB_MANAGER.getName(), Arrays.asList("manager")); + USER_TO_GROUP_MAP.putAll(SUB_ANALYST.getName(), Arrays.asList("analyst")); + USER_TO_GROUP_MAP.putAll(SUB_JUNIOR_ANALYST.getName(), + Arrays.asList("jranalyst")); + } + + private final ResourceAuthorizationProvider authzProvider; + private File baseDir; + + public TestSearchAuthorizationProviderGeneralCases() throws IOException { + baseDir = Files.createTempDir(); + PolicyFiles.copyToDir(baseDir, "test-authz-provider.ini"); + authzProvider = new HadoopGroupResourceAuthorizationProvider( + new SearchPolicyFileBackend(new File(baseDir, "test-authz-provider.ini").getPath()), + new MockGroupMappingServiceProvider(USER_TO_GROUP_MAP)); + + } + + @After + public void teardown() { + if(baseDir != null) { + FileUtils.deleteQuietly(baseDir); + } + } + + private void doTestAuthProviderOnCollection(Subject subject, + Collection collection, Set<? extends Action> expectedPass) throws Exception { + Set<SearchModelAction> allActions = EnumSet.of(SearchModelAction.ALL, SearchModelAction.QUERY, SearchModelAction.UPDATE); + for(SearchModelAction action : allActions) { + doTestResourceAuthorizationProvider(subject, collection, + EnumSet.of(action), expectedPass.contains(action)); + } + } + + private void doTestResourceAuthorizationProvider(Subject subject, + Collection collection, + Set<? extends Action> privileges, boolean expected) throws Exception { + List<Authorizable> authzHierarchy = Arrays.asList(new Authorizable[] { + collection + }); + Objects.ToStringHelper helper = Objects.toStringHelper("TestParameters"); + helper.add("Subject", subject).add("Collection", collection) + .add("Privileges", privileges).add("authzHierarchy", authzHierarchy); + LOGGER.info("Running with " + helper.toString()); + Assert.assertEquals(helper.toString(), expected, + authzProvider.hasAccess(subject, authzHierarchy, privileges)); + LOGGER.info("Passed " + helper.toString()); + } + + @Test + public void testAdmin() throws Exception { + Set<SearchModelAction> allActions = EnumSet.allOf(SearchModelAction.class); + doTestAuthProviderOnCollection(SUB_ADMIN, COLL_PURCHASES, allActions); + doTestAuthProviderOnCollection(SUB_ADMIN, COLL_ANALYST1, allActions); + doTestAuthProviderOnCollection(SUB_ADMIN, COLL_JRANALYST1, allActions); + doTestAuthProviderOnCollection(SUB_ADMIN, COLL_TMP, allActions); + doTestAuthProviderOnCollection(SUB_ADMIN, COLL_PURCHASES_PARTIAL, allActions); + } + + @Test + public void testManager() throws Exception { + Set<SearchModelAction> updateOnly = EnumSet.of(SearchModelAction.UPDATE); + doTestAuthProviderOnCollection(SUB_MANAGER, COLL_PURCHASES, updateOnly); + + Set<SearchModelAction> allActions = EnumSet.allOf(SearchModelAction.class); + doTestAuthProviderOnCollection(SUB_MANAGER, COLL_ANALYST1, allActions); + doTestAuthProviderOnCollection(SUB_MANAGER, COLL_JRANALYST1, allActions); + + Set<SearchModelAction> queryUpdateOnly = EnumSet.of(QUERY, UPDATE); + doTestAuthProviderOnCollection(SUB_MANAGER, COLL_TMP, queryUpdateOnly); + + Set<SearchModelAction> queryOnly = EnumSet.of(SearchModelAction.QUERY); + doTestAuthProviderOnCollection(SUB_MANAGER, COLL_PURCHASES_PARTIAL, queryOnly); + } + + @Test + public void testAnalyst() throws Exception { + Set<SearchModelAction> updateOnly = EnumSet.of(SearchModelAction.UPDATE); + doTestAuthProviderOnCollection(SUB_ANALYST, COLL_PURCHASES, updateOnly); + + Set<SearchModelAction> allActions = EnumSet.allOf(SearchModelAction.class); + doTestAuthProviderOnCollection(SUB_ANALYST, COLL_ANALYST1, allActions); + doTestAuthProviderOnCollection(SUB_ANALYST, COLL_JRANALYST1, allActions); + + Set<SearchModelAction> queryUpdateOnly = EnumSet.of(QUERY, UPDATE); + doTestAuthProviderOnCollection(SUB_ANALYST, COLL_TMP, queryUpdateOnly); + + Set<SearchModelAction> noActions = EnumSet.noneOf(SearchModelAction.class); + doTestAuthProviderOnCollection(SUB_ANALYST, COLL_PURCHASES_PARTIAL, noActions); + } + + @Test + public void testJuniorAnalyst() throws Exception { + Set<SearchModelAction> allActions = EnumSet.allOf(SearchModelAction.class); + doTestAuthProviderOnCollection(SUB_JUNIOR_ANALYST, COLL_JRANALYST1, allActions); + + Set<SearchModelAction> queryOnly = EnumSet.of(SearchModelAction.QUERY); + doTestAuthProviderOnCollection(SUB_JUNIOR_ANALYST, COLL_PURCHASES_PARTIAL, queryOnly); + + Set<SearchModelAction> noActions = EnumSet.noneOf(SearchModelAction.class); + doTestAuthProviderOnCollection(SUB_JUNIOR_ANALYST, COLL_PURCHASES, noActions); + doTestAuthProviderOnCollection(SUB_JUNIOR_ANALYST, COLL_ANALYST1, noActions); + doTestAuthProviderOnCollection(SUB_JUNIOR_ANALYST, COLL_TMP, noActions); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchAuthorizationProviderSpecialCases.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchAuthorizationProviderSpecialCases.java b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchAuthorizationProviderSpecialCases.java new file mode 100644 index 0000000..0163275 --- /dev/null +++ b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchAuthorizationProviderSpecialCases.java @@ -0,0 +1,81 @@ + /* + * 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.search; + +import java.io.File; +import java.io.IOException; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import junit.framework.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.core.common.AuthorizationProvider; +import org.apache.sentry.core.common.Action; +import org.apache.sentry.core.common.Subject; +import org.apache.sentry.core.model.search.Collection; +import org.apache.sentry.core.model.search.SearchModelAction; +import org.apache.sentry.provider.file.LocalGroupResourceAuthorizationProvider; +import org.apache.sentry.provider.file.PolicyFile; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.io.Files; + +public class TestSearchAuthorizationProviderSpecialCases { + private AuthorizationProvider authzProvider; + private PolicyFile policyFile; + private File baseDir; + private File iniFile; + private String initResource; + @Before + public void setup() throws IOException { + baseDir = Files.createTempDir(); + iniFile = new File(baseDir, "policy.ini"); + initResource = "file://" + iniFile.getPath(); + policyFile = new PolicyFile(); + } + + @After + public void teardown() throws IOException { + if(baseDir != null) { + FileUtils.deleteQuietly(baseDir); + } + } + + @Test + public void testDuplicateEntries() throws Exception { + Subject user1 = new Subject("user1"); + Collection collection1 = new Collection("collection1"); + Set<? extends Action> actions = EnumSet.allOf(SearchModelAction.class); + policyFile.addGroupsToUser(user1.getName(), true, "group1", "group1") + .addRolesToGroup("group1", true, "role1", "role1") + .addPermissionsToRole("role1", true, "collection=" + collection1.getName(), + "collection=" + collection1.getName()); + policyFile.write(iniFile); + SearchPolicyFileBackend policy = new SearchPolicyFileBackend(initResource); + authzProvider = new LocalGroupResourceAuthorizationProvider(initResource, policy); + List<? extends Authorizable> authorizableHierarchy = ImmutableList.of(collection1); + Assert.assertTrue(authorizableHierarchy.toString(), + authzProvider.hasAccess(user1, authorizableHierarchy, actions)); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyEngineDFS.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyEngineDFS.java b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyEngineDFS.java new file mode 100644 index 0000000..a17c82f --- /dev/null +++ b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyEngineDFS.java @@ -0,0 +1,81 @@ +/* + * 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.search; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import junit.framework.Assert; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hdfs.MiniDFSCluster; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.provider.file.PolicyFile; +import org.apache.sentry.provider.file.PolicyFiles; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.Lists; +import com.google.common.io.Files; + +public class TestSearchPolicyEngineDFS extends AbstractTestSearchPolicyEngine { + + private static MiniDFSCluster dfsCluster; + private static FileSystem fileSystem; + private static Path root; + private static Path etc; + + @BeforeClass + public static void setupLocalClazz() throws IOException { + File baseDir = getBaseDir(); + Assert.assertNotNull(baseDir); + File dfsDir = new File(baseDir, "dfs"); + Assert.assertTrue(dfsDir.isDirectory() || dfsDir.mkdirs()); + Configuration conf = new Configuration(); + conf.set(MiniDFSCluster.HDFS_MINIDFS_BASEDIR, dfsDir.getPath()); + dfsCluster = new MiniDFSCluster.Builder(conf).numDataNodes(2).build(); + fileSystem = dfsCluster.getFileSystem(); + root = new Path(fileSystem.getUri().toString()); + etc = new Path(root, "/etc"); + fileSystem.mkdirs(etc); + } + + @AfterClass + public static void teardownLocalClazz() { + if(dfsCluster != null) { + dfsCluster.shutdown(); + } + } + + @Override + protected void afterSetup() throws IOException { + fileSystem.delete(etc, true); + fileSystem.mkdirs(etc); + PolicyFiles.copyToDir(fileSystem, etc, "test-authz-provider.ini"); + setPolicy(new SearchPolicyFileBackend(new Path(etc, "test-authz-provider.ini").toString())); + } + + @Override + protected void beforeTeardown() throws IOException { + fileSystem.delete(etc, true); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyEngineLocalFS.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyEngineLocalFS.java b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyEngineLocalFS.java new file mode 100644 index 0000000..d85051b --- /dev/null +++ b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyEngineLocalFS.java @@ -0,0 +1,43 @@ +/* + * 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.search; + +import java.io.File; +import java.io.IOException; + +import junit.framework.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.sentry.provider.file.PolicyFiles; + +public class TestSearchPolicyEngineLocalFS extends AbstractTestSearchPolicyEngine { + + @Override + protected void afterSetup() throws IOException { + File baseDir = getBaseDir(); + Assert.assertNotNull(baseDir); + Assert.assertTrue(baseDir.isDirectory() || baseDir.mkdirs()); + PolicyFiles.copyToDir(baseDir, "test-authz-provider.ini"); + setPolicy(new SearchPolicyFileBackend(new File(baseDir, "test-authz-provider.ini").getPath())); + } + @Override + protected void beforeTeardown() throws IOException { + File baseDir = getBaseDir(); + Assert.assertNotNull(baseDir); + FileUtils.deleteQuietly(baseDir); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyNegative.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyNegative.java b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyNegative.java new file mode 100644 index 0000000..665591a --- /dev/null +++ b/sentry-provider/sentry-provider-policy-search/src/test/java/org/apache/sentry/provider/search/TestSearchPolicyNegative.java @@ -0,0 +1,111 @@ +/* + * 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.search; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; + +import junit.framework.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.shiro.config.ConfigurationException; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.core.model.search.Collection; +import org.apache.sentry.provider.common.PolicyEngine; +import org.apache.sentry.provider.file.PolicyFile; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.io.Files; + +public class TestSearchPolicyNegative { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory + .getLogger(TestSearchPolicyNegative.class); + + private File baseDir; + private File globalPolicyFile; + private File otherPolicyFile; + + @Before + public void setup() { + baseDir = Files.createTempDir(); + globalPolicyFile = new File(baseDir, "global.ini"); + otherPolicyFile = new File(baseDir, "other.ini"); + } + + @After + public void teardown() { + if(baseDir != null) { + FileUtils.deleteQuietly(baseDir); + } + } + + private void append(String from, File to) throws IOException { + Files.append(from + "\n", to, Charsets.UTF_8); + } + + @Test + public void testPerDbFileException() throws Exception { + append("[databases]", globalPolicyFile); + append("other_group_db = " + otherPolicyFile.getPath(), globalPolicyFile); + append("[groups]", otherPolicyFile); + append("other_group = malicious_role", otherPolicyFile); + append("[roles]", otherPolicyFile); + append("malicious_role = collection=*", otherPolicyFile); + try { + PolicyEngine policy = new SearchPolicyFileBackend(globalPolicyFile.getPath()); + Assert.fail("Excepted ConfigurationException"); + } catch (ConfigurationException ce) {} + } + + @Test + public void testCollectionRequiredInRole() throws Exception { + append("[groups]", globalPolicyFile); + append("group = malicious_role", globalPolicyFile); + append("[roles]", globalPolicyFile); + append("malicious_role = action=query", globalPolicyFile); + PolicyEngine policy = new SearchPolicyFileBackend(globalPolicyFile.getPath()); + ImmutableSet<String> permissions = policy.getPermissions( + Arrays.asList(new Authorizable[] { + new Collection("collection1"), + }), Lists.newArrayList("group")).get("group"); + Assert.assertTrue(permissions.toString(), permissions.isEmpty()); + } + + @Test + public void testGroupIncorrect() throws Exception { + append("[groups]", globalPolicyFile); + append("group = malicious_role", globalPolicyFile); + append("[roles]", globalPolicyFile); + append("malicious_role = collection=*", globalPolicyFile); + PolicyEngine policy = new SearchPolicyFileBackend(globalPolicyFile.getPath()); + ImmutableSet<String> permissions = policy.getPermissions( + Arrays.asList(new Authorizable[] { + Collection.ALL + }), Lists.newArrayList("incorrectGroup")).get("incorrectGroup"); + Assert.assertTrue(permissions.toString(), permissions.isEmpty()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/src/test/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/src/test/resources/log4j.properties b/sentry-provider/sentry-provider-policy-search/src/test/resources/log4j.properties new file mode 100644 index 0000000..c41373c --- /dev/null +++ b/sentry-provider/sentry-provider-policy-search/src/test/resources/log4j.properties @@ -0,0 +1,31 @@ +# +# 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. +# + +# Define some default values that can be overridden by system properties. +# +# For testing, it may also be convenient to specify + +log4j.rootLogger=DEBUG,console + +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.target=System.err +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%d (%t) [%p - %l] %m%n + +log4j.logger.org.apache.hadoop.conf.Configuration=INFO http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1824f780/sentry-provider/sentry-provider-policy-search/src/test/resources/test-authz-provider.ini ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-policy-search/src/test/resources/test-authz-provider.ini b/sentry-provider/sentry-provider-policy-search/src/test/resources/test-authz-provider.ini new file mode 100644 index 0000000..8af8162 --- /dev/null +++ b/sentry-provider/sentry-provider-policy-search/src/test/resources/test-authz-provider.ini @@ -0,0 +1,31 @@ +# 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. + +[groups] +manager = analyst_role, junior_analyst_role +analyst = analyst_role +jranalyst = junior_analyst_role +admin = admin + +[roles] +analyst_role = collection=purchases->action=update, \ + collection=analyst1, \ + collection=jranalyst1->action=*, \ + collection=tmpcollection->action=update, \ + collection=tmpcollection->action=query +junior_analyst_role = collection=jranalyst1, collection=purchases_partial->action=query +admin = collection=*