You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by sh...@apache.org on 2013/10/16 18:47:14 UTC
git commit: SENTRY-35: Create sentry-provider-policy-search module
(Gregory Chanan via Shreepadma Venugopalan)
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 <sh...@apache.org>
Authored: Tue Oct 15 17:25:04 2013 -0700
Committer: Shreepadma Venugopalan <sh...@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=*