http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/policy/kafka/TestKafkaPolicyNegative.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/policy/kafka/TestKafkaPolicyNegative.java b/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/policy/kafka/TestKafkaPolicyNegative.java new file mode 100644 index 0000000..fd33b31 --- /dev/null +++ b/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/policy/kafka/TestKafkaPolicyNegative.java @@ -0,0 +1,104 @@ +/* + * 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.policy.kafka; + +import java.io.File; +import java.io.IOException; + +import junit.framework.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.sentry.core.common.ActiveRoleSet; +import org.apache.sentry.policy.common.PolicyEngine; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import com.google.common.io.Files; + +public class TestKafkaPolicyNegative { + private File baseDir; + private File globalPolicyFile; + + @Before + public void setup() { + baseDir = Files.createTempDir(); + globalPolicyFile = new File(baseDir, "global.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 testauthorizedKafkaInPolicyFile() throws Exception { + append("[groups]", globalPolicyFile); + append("other_group = other_role", globalPolicyFile); + append("[roles]", globalPolicyFile); + append("other_role = host=host1->topic=t1->action=read, host=host1->consumergroup=l1->action=read", globalPolicyFile); + PolicyEngine policy = KafkaPolicyTestUtil.createPolicyEngineForTest(globalPolicyFile.getPath()); + //malicious_group has no privilege + ImmutableSet<String> permissions = policy.getAllPrivileges(Sets.newHashSet("malicious_group"), ActiveRoleSet.ALL); + Assert.assertTrue(permissions.toString(), permissions.isEmpty()); + //other_group has two privileges + permissions = policy.getAllPrivileges(Sets.newHashSet("other_group"), ActiveRoleSet.ALL); + Assert.assertTrue(permissions.toString(), permissions.size() == 2); + } + + @Test + public void testNoHostNameConfig() throws Exception { + append("[groups]", globalPolicyFile); + append("other_group = malicious_role", globalPolicyFile); + append("[roles]", globalPolicyFile); + append("malicious_role = topic=t1->action=read", globalPolicyFile); + PolicyEngine policy = KafkaPolicyTestUtil.createPolicyEngineForTest(globalPolicyFile.getPath()); + ImmutableSet<String> permissions = policy.getAllPrivileges(Sets.newHashSet("other_group"), ActiveRoleSet.ALL); + Assert.assertTrue(permissions.toString(), permissions.isEmpty()); + } + + @Test + public void testHostAllName() throws Exception { + append("[groups]", globalPolicyFile); + append("group = malicious_role", globalPolicyFile); + append("[roles]", globalPolicyFile); + append("malicious_role = host=*->action=read", globalPolicyFile); + PolicyEngine policy = KafkaPolicyTestUtil.createPolicyEngineForTest(globalPolicyFile.getPath()); + ImmutableSet<String> permissions = policy.getAllPrivileges(Sets.newHashSet("group"), ActiveRoleSet.ALL); + Assert.assertTrue(permissions.toString(), permissions.size() == 1); + } + + @Test + public void testAll() throws Exception { + append("[groups]", globalPolicyFile); + append("group = malicious_role", globalPolicyFile); + append("[roles]", globalPolicyFile); + append("malicious_role = *", globalPolicyFile); + PolicyEngine policy = KafkaPolicyTestUtil.createPolicyEngineForTest(globalPolicyFile.getPath()); + ImmutableSet<String> permissions = policy.getAllPrivileges(Sets.newHashSet("group"), ActiveRoleSet.ALL); + Assert.assertTrue(permissions.toString(), permissions.isEmpty()); + } +}
http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/policy/kafka/TestKafkaPrivilegeValidator.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/policy/kafka/TestKafkaPrivilegeValidator.java b/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/policy/kafka/TestKafkaPrivilegeValidator.java new file mode 100644 index 0000000..ba66d43 --- /dev/null +++ b/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/policy/kafka/TestKafkaPrivilegeValidator.java @@ -0,0 +1,170 @@ +/* + * 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.policy.kafka; + +import junit.framework.Assert; + +import org.apache.sentry.core.common.validator.PrivilegeValidatorContext; +import org.apache.sentry.core.model.kafka.validator.KafkaPrivilegeValidator; +import org.apache.shiro.config.ConfigurationException; +import org.junit.Test; + +public class TestKafkaPrivilegeValidator { + @Test + public void testOnlyHostResource() { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1")); + } catch (ConfigurationException ex) { + Assert.assertEquals(KafkaPrivilegeValidator.KafkaPrivilegeHelpMsg, ex.getMessage()); + } + } + + @Test + public void testWithoutHostResource() throws Exception { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + testHostResourceIsChecked(kafkaPrivilegeValidator, "cluster=kafka-cluster->action=read"); + testHostResourceIsChecked(kafkaPrivilegeValidator, "topic=t1->action=read"); + testHostResourceIsChecked(kafkaPrivilegeValidator, "consumergroup=g1->action=read"); + } + + private void testHostResourceIsChecked(KafkaPrivilegeValidator kafkaPrivilegeValidator, String privilege) { + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext(privilege)); + Assert.fail("Expected ConfigurationException"); + } catch (ConfigurationException ex) { + Assert.assertEquals("Kafka privilege must begin with host authorizable.\n" + KafkaPrivilegeValidator.KafkaPrivilegeHelpMsg, ex.getMessage()); + } + } + + @Test + public void testValidPrivileges() throws Exception { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1->cluster=kafka-cluster->action=read")); + } catch (ConfigurationException ex) { + Assert.fail("Not expected ConfigurationException"); + } + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1->topic=t1->action=read")); + } catch (ConfigurationException ex) { + Assert.fail("Not expected ConfigurationException"); + } + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1->consumergroup=g1->action=read")); + } catch (ConfigurationException ex) { + Assert.fail("Not expected ConfigurationException"); + } + } + + @Test + public void testInvalidHostResource() throws Exception { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("hhost=host1->cluster=kafka-cluster->action=read")); + Assert.fail("Expected ConfigurationException"); + } catch (ConfigurationException ex) { + } + } + + @Test + public void testInvalidClusterResource() throws Exception { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1->clluster=kafka-cluster->action=read")); + Assert.fail("Expected ConfigurationException"); + } catch (ConfigurationException ex) { + } + } + + @Test + public void testInvalidTopicResource() throws Exception { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1->ttopic=t1->action=read")); + Assert.fail("Expected ConfigurationException"); + } catch (ConfigurationException ex) { + } + } + + @Test + public void testInvalidConsumerGroupResource() throws Exception { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1->coonsumergroup=g1->action=read")); + Assert.fail("Expected ConfigurationException"); + } catch (ConfigurationException ex) { + } + } + + @Test + public void testPrivilegeMustHaveExcatlyOneHost() { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1->host=host2->action=read")); + Assert.fail("Multiple Host resources are not allowed within a Kafka privilege."); + } catch (ConfigurationException ex) { + Assert.assertEquals("Host authorizable can be specified just once in a Kafka privilege.\n" + KafkaPrivilegeValidator.KafkaPrivilegeHelpMsg, ex.getMessage()); + } + } + + @Test + public void testPrivilegeCanNotStartWithAction() { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("action=write->host=host1->topic=t1")); + Assert.fail("Kafka privilege can not start with an action."); + } catch (ConfigurationException ex) { + Assert.assertEquals("Kafka privilege can not start with an action.\n" + KafkaPrivilegeValidator.KafkaPrivilegeHelpMsg, ex.getMessage()); + } + } + + @Test + public void testPrivilegeWithMoreParts() { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1->topic=t1->consumergroup=cg1->action=read")); + Assert.fail("Kafka privilege can have one Host authorizable, at most one non Host authorizable and one action."); + } catch (ConfigurationException ex) { + Assert.assertEquals(KafkaPrivilegeValidator.KafkaPrivilegeHelpMsg, ex.getMessage()); + } + } + + @Test + public void testPrivilegeNotEndingWithAction() { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1->topic=t1->consumergroup=cg1")); + Assert.fail("Kafka privilege must end with a valid action."); + } catch (ConfigurationException ex) { + Assert.assertEquals("Kafka privilege must end with a valid action.\n" + KafkaPrivilegeValidator.KafkaPrivilegeHelpMsg, ex.getMessage()); + } + } + + @Test + public void testPrivilegeNotEndingWithValidAction() { + KafkaPrivilegeValidator kafkaPrivilegeValidator = new KafkaPrivilegeValidator(); + try { + kafkaPrivilegeValidator.validate(new PrivilegeValidatorContext("host=host1->topic=t1->action=bla")); + Assert.fail("Kafka privilege must end with a valid action."); + } catch (ConfigurationException ex) { + Assert.assertEquals("Kafka privilege must end with a valid action.\n" + KafkaPrivilegeValidator.KafkaPrivilegeHelpMsg, ex.getMessage()); + } + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/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 new file mode 100644 index 0000000..a616f67 --- /dev/null +++ b/sentry-binding/sentry-binding-kafka/src/test/java/org/apache/sentry/privilege/kafka/TestKafkaWildcardPrivilege.java @@ -0,0 +1,188 @@ +/* + * 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.privilege.kafka; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import org.apache.sentry.core.common.Model; +import org.apache.sentry.core.common.utils.KeyValue; +import org.apache.sentry.core.common.utils.SentryConstants; +import org.apache.sentry.core.model.kafka.KafkaActionConstant; +import org.apache.sentry.core.model.kafka.KafkaPrivilegeModel; +import org.apache.sentry.policy.common.CommonPrivilege; +import org.apache.sentry.policy.common.Privilege; +import org.junit.Before; +import org.junit.Test; + +public class TestKafkaWildcardPrivilege { + + private Model kafkaPrivilegeModel; + + private static final CommonPrivilege KAFKA_HOST1_ALL = + create(new KeyValue("HOST", "host1"), new KeyValue("action", KafkaActionConstant.ALL)); + private static final CommonPrivilege KAFKA_HOST1_READ = + create(new KeyValue("HOST", "host1"), new KeyValue("action", KafkaActionConstant.READ)); + private static final CommonPrivilege KAFKA_HOST1_WRITE = + create(new KeyValue("HOST", "host1"), new KeyValue("action", KafkaActionConstant.WRITE)); + + private static final CommonPrivilege KAFKA_HOST1_TOPIC1_ALL = + create(new KeyValue("HOST", "host1"), new KeyValue("TOPIC", "topic1"), new KeyValue("action", KafkaActionConstant.ALL)); + private static final CommonPrivilege KAFKA_HOST1_TOPIC1_READ = + create(new KeyValue("HOST", "host1"), new KeyValue("TOPIC", "topic1"), new KeyValue("action", KafkaActionConstant.READ)); + private static final CommonPrivilege KAFKA_HOST1_TOPIC1_WRITE = + create(new KeyValue("HOST", "host1"), new KeyValue("TOPIC", "topic1"), new KeyValue("action", KafkaActionConstant.WRITE)); + + private static final CommonPrivilege KAFKA_HOST1_CLUSTER1_ALL = + create(new KeyValue("HOST", "host1"), new KeyValue("CLUSTER", "cluster1"), new KeyValue("action", KafkaActionConstant.ALL)); + private static final CommonPrivilege KAFKA_HOST1_CLUSTER1_READ = + create(new KeyValue("HOST", "host1"), new KeyValue("CLUSTER", "cluster1"), new KeyValue("action", KafkaActionConstant.READ)); + private static final CommonPrivilege KAFKA_HOST1_CLUSTER1_WRITE = + create(new KeyValue("HOST", "host1"), new KeyValue("CLUSTER", "cluster1"), new KeyValue("action", KafkaActionConstant.WRITE)); + + private static final CommonPrivilege KAFKA_HOST1_GROUP1_ALL = + create(new KeyValue("HOST", "host1"), new KeyValue("GROUP", "cgroup1"), new KeyValue("action", KafkaActionConstant.ALL)); + private static final CommonPrivilege KAFKA_HOST1_GROUP1_READ = + create(new KeyValue("HOST", "host1"), new KeyValue("GROUP", "cgroup1"), new KeyValue("action", KafkaActionConstant.READ)); + private static final CommonPrivilege KAFKA_HOST1_GROUP1_WRITE = + create(new KeyValue("HOST", "host1"), new KeyValue("GROUP", "cgroup1"), new KeyValue("action", KafkaActionConstant.WRITE)); + + @Before + public void prepareData() { + kafkaPrivilegeModel = KafkaPrivilegeModel.getInstance(); + } + + @Test + public void testSimpleAction() throws Exception { + //host + assertFalse(KAFKA_HOST1_WRITE.implies(KAFKA_HOST1_READ, kafkaPrivilegeModel)); + assertFalse(KAFKA_HOST1_READ.implies(KAFKA_HOST1_WRITE, kafkaPrivilegeModel)); + //consumer group + assertFalse(KAFKA_HOST1_GROUP1_WRITE.implies(KAFKA_HOST1_GROUP1_READ, kafkaPrivilegeModel)); + assertFalse(KAFKA_HOST1_GROUP1_READ.implies(KAFKA_HOST1_GROUP1_WRITE, kafkaPrivilegeModel)); + //topic + assertFalse(KAFKA_HOST1_TOPIC1_READ.implies(KAFKA_HOST1_TOPIC1_WRITE, kafkaPrivilegeModel)); + assertFalse(KAFKA_HOST1_TOPIC1_WRITE.implies(KAFKA_HOST1_TOPIC1_READ, kafkaPrivilegeModel)); + //cluster + assertFalse(KAFKA_HOST1_CLUSTER1_READ.implies(KAFKA_HOST1_CLUSTER1_WRITE, kafkaPrivilegeModel)); + assertFalse(KAFKA_HOST1_CLUSTER1_WRITE.implies(KAFKA_HOST1_CLUSTER1_READ, kafkaPrivilegeModel)); + } + + @Test + public void testShorterThanRequest() throws Exception { + //topic + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_TOPIC1_ALL, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_TOPIC1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_TOPIC1_WRITE, kafkaPrivilegeModel)); + + assertFalse(KAFKA_HOST1_WRITE.implies(KAFKA_HOST1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_READ.implies(KAFKA_HOST1_TOPIC1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_WRITE.implies(KAFKA_HOST1_TOPIC1_WRITE, kafkaPrivilegeModel)); + + //cluster + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_CLUSTER1_ALL, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_CLUSTER1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_CLUSTER1_WRITE, kafkaPrivilegeModel)); + + assertTrue(KAFKA_HOST1_READ.implies(KAFKA_HOST1_CLUSTER1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_WRITE.implies(KAFKA_HOST1_CLUSTER1_WRITE, kafkaPrivilegeModel)); + + //consumer group + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_GROUP1_ALL, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_GROUP1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_GROUP1_WRITE, kafkaPrivilegeModel)); + + assertTrue(KAFKA_HOST1_READ.implies(KAFKA_HOST1_GROUP1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_WRITE.implies(KAFKA_HOST1_GROUP1_WRITE, kafkaPrivilegeModel)); + } + + @Test + public void testActionAll() throws Exception { + //host + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_ALL.implies(KAFKA_HOST1_WRITE, kafkaPrivilegeModel)); + + //topic + assertTrue(KAFKA_HOST1_TOPIC1_ALL.implies(KAFKA_HOST1_TOPIC1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_TOPIC1_ALL.implies(KAFKA_HOST1_TOPIC1_WRITE, kafkaPrivilegeModel)); + + //cluster + assertTrue(KAFKA_HOST1_CLUSTER1_ALL.implies(KAFKA_HOST1_CLUSTER1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_CLUSTER1_ALL.implies(KAFKA_HOST1_CLUSTER1_WRITE, kafkaPrivilegeModel)); + + //consumer group + assertTrue(KAFKA_HOST1_GROUP1_ALL.implies(KAFKA_HOST1_GROUP1_READ, kafkaPrivilegeModel)); + assertTrue(KAFKA_HOST1_GROUP1_ALL.implies(KAFKA_HOST1_GROUP1_WRITE, kafkaPrivilegeModel)); + } + + @Test + public void testUnexpected() throws Exception { + Privilege p = new Privilege() { + @Override + public boolean implies(Privilege p, Model model) { + return false; + } + }; + Privilege topic1 = create(new KeyValue("HOST", "host"), new KeyValue("TOPIC", "topic1")); + assertFalse(topic1.implies(null, kafkaPrivilegeModel)); + assertFalse(topic1.implies(p, kafkaPrivilegeModel)); + assertFalse(topic1.equals(null)); + assertFalse(topic1.equals(p)); + } + + @Test(expected=IllegalArgumentException.class) + public void testNullString() throws Exception { + System.out.println(create((String)null)); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyString() throws Exception { + System.out.println(create("")); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyKey() throws Exception { + System.out.println(create(SentryConstants.KV_JOINER.join("", "host1"))); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyValue() throws Exception { + System.out.println(create(SentryConstants.KV_JOINER.join("HOST", ""))); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyPart() throws Exception { + System.out.println(create(SentryConstants.AUTHORIZABLE_JOINER. + join(SentryConstants.KV_JOINER.join("HOST", "host1"), ""))); + } + + @Test(expected=IllegalArgumentException.class) + public void testOnlySeperators() throws Exception { + System.out.println(create(SentryConstants.AUTHORIZABLE_JOINER. + join(SentryConstants.KV_SEPARATOR, SentryConstants.KV_SEPARATOR, + SentryConstants.KV_SEPARATOR))); + } + + 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/d94e900a/sentry-binding/sentry-binding-kafka/src/test/resources/kafka-policy-test-authz-provider.ini ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-kafka/src/test/resources/kafka-policy-test-authz-provider.ini b/sentry-binding/sentry-binding-kafka/src/test/resources/kafka-policy-test-authz-provider.ini new file mode 100644 index 0000000..1951aba --- /dev/null +++ b/sentry-binding/sentry-binding-kafka/src/test/resources/kafka-policy-test-authz-provider.ini @@ -0,0 +1,38 @@ +# 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] +admin_group = admin_all +subadmin_group = admin_host1 +consumer_group0 = consumer_t1_all +consumer_group1 = consumer_t1_host1 +consumer_group2 = consumer_t2_host2 +producer_group0 = producer_t1_all +producer_group1 = producer_t1_host1 +producer_group2 = producer_t2_host2 +consumer_producer_group0 = consumer_producer_t1 + +[roles] +admin_all = host=*->action=all +admin_host1 = host=host1->action=all +consumer_t1_all = host=*->topic=t1->action=read +consumer_t1_host1 = host=host1->topic=t1->action=read +consumer_t2_host2 = host=host2->topic=t2->action=read +producer_t1_all = host=*->topic=t1->action=write +producer_t1_host1 = host=host1->topic=t1->action=write +producer_t2_host2 = host=host2->topic=t2->action=write +consumer_producer_t1 = host=host1->topic=t1->action=all http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-kafka/src/test/resources/sentry-site.xml ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-kafka/src/test/resources/sentry-site.xml b/sentry-binding/sentry-binding-kafka/src/test/resources/sentry-site.xml index 69ce5a7..6383481 100644 --- a/sentry-binding/sentry-binding-kafka/src/test/resources/sentry-site.xml +++ b/sentry-binding/sentry-binding-kafka/src/test/resources/sentry-site.xml @@ -32,7 +32,7 @@ </property> <property> <name>sentry.kafka.policy.engine</name> - <value>org.apache.sentry.policy.kafka.SimpleKafkaPolicyEngine</value> + <value>org.apache.sentry.policy.engine.common.CommonPolicyEngine</value> </property> <property> <name>sentry.kafka.provider.backend</name> http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/pom.xml ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/pom.xml b/sentry-binding/sentry-binding-solr/pom.xml index 3927188..a63a600 100644 --- a/sentry-binding/sentry-binding-solr/pom.xml +++ b/sentry-binding/sentry-binding-solr/pom.xml @@ -56,10 +56,6 @@ limitations under the License. <scope>test</scope> </dependency> <dependency> - <groupId>org.apache.sentry</groupId> - <artifactId>sentry-policy-search</artifactId> - </dependency> - <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <scope>provided</scope> http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java index a6d6c8b..24e5172 100644 --- a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java +++ b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java @@ -36,15 +36,18 @@ import org.apache.sentry.binding.solr.conf.SolrAuthzConf; import org.apache.sentry.binding.solr.conf.SolrAuthzConf.AuthzConfVars; import org.apache.sentry.core.common.Action; import org.apache.sentry.core.common.ActiveRoleSet; +import org.apache.sentry.core.common.Model; 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.core.model.search.SearchPrivilegeModel; import org.apache.sentry.policy.common.PolicyEngine; import org.apache.sentry.provider.common.AuthorizationComponent; import org.apache.sentry.provider.common.AuthorizationProvider; import org.apache.sentry.provider.common.GroupMappingService; import org.apache.sentry.provider.common.HadoopGroupResourceAuthorizationProvider; import org.apache.sentry.provider.common.ProviderBackend; +import org.apache.sentry.provider.common.ProviderBackendContext; import org.apache.sentry.provider.db.generic.SentryGenericProviderBackend; import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient; import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClientFactory; @@ -65,6 +68,7 @@ public class SolrAuthzBinding { public static final String KERBEROS_ENABLED = "solr.hdfs.security.kerberos.enabled"; public static final String KERBEROS_KEYTAB = "solr.hdfs.security.kerberos.keytabfile"; public static final String KERBEROS_PRINCIPAL = "solr.hdfs.security.kerberos.principal"; + private static final String SOLR_POLICY_ENGINE_OLD = "org.apache.sentry.policy.search.SimpleSearchPolicyEngine"; private static final String kerberosEnabledProp = Strings.nullToEmpty(System.getProperty(KERBEROS_ENABLED)).trim(); private static final String keytabProp = Strings.nullToEmpty(System.getProperty(KERBEROS_KEYTAB)).trim(); private static final String principalProp = Strings.nullToEmpty(System.getProperty(KERBEROS_PRINCIPAL)).trim(); @@ -94,14 +98,19 @@ public class SolrAuthzBinding { String resourceName = authzConf.get(AuthzConfVars.AUTHZ_PROVIDER_RESOURCE.getVar()); String providerBackendName = - authzConf.get(AuthzConfVars.AUTHZ_PROVIDER_BACKEND.getVar()); + authzConf.get(AuthzConfVars.AUTHZ_PROVIDER_BACKEND.getVar()); String policyEngineName = - authzConf.get(AuthzConfVars.AUTHZ_POLICY_ENGINE.getVar()); + authzConf.get(AuthzConfVars.AUTHZ_POLICY_ENGINE.getVar(), AuthzConfVars.AUTHZ_POLICY_ENGINE.getDefault()); String serviceName = authzConf.get(SENTRY_SEARCH_SERVICE_KEY, SENTRY_SEARCH_SERVICE_DEFAULT); + // for the backward compatibility + if (SOLR_POLICY_ENGINE_OLD.equals(policyEngineName)) { + policyEngineName = AuthzConfVars.AUTHZ_POLICY_ENGINE.getDefault(); + } + LOG.debug("Using authorization provider " + authProviderName + - " with resource " + resourceName + ", policy engine " - + policyEngineName + ", provider backend " + providerBackendName); + " with resource " + resourceName + ", policy engine " + + policyEngineName + ", provider backend " + providerBackendName); // load the provider backend class if (kerberosEnabledProp.equalsIgnoreCase("true")) { initKerberos(keytabProp, principalProp); @@ -118,11 +127,11 @@ public class SolrAuthzBinding { providerBackendName = SentryGenericProviderBackend.class.getName(); } Constructor<?> providerBackendConstructor = - Class.forName(providerBackendName).getDeclaredConstructor(Configuration.class, String.class); + Class.forName(providerBackendName).getDeclaredConstructor(Configuration.class, String.class); providerBackendConstructor.setAccessible(true); providerBackend = - (ProviderBackend) providerBackendConstructor.newInstance(new Object[] {authzConf, resourceName}); + (ProviderBackend) providerBackendConstructor.newInstance(new Object[] {authzConf, resourceName}); if (providerBackend instanceof SentryGenericProviderBackend) { ((SentryGenericProviderBackend) providerBackend) @@ -130,12 +139,18 @@ public class SolrAuthzBinding { ((SentryGenericProviderBackend) providerBackend).setServiceName(serviceName); } + // Create backend context + ProviderBackendContext context = new ProviderBackendContext(); + context.setAllowPerDatabase(false); + context.setValidators(SearchPrivilegeModel.getInstance().getPrivilegeValidators()); + providerBackend.initialize(context); + // load the policy engine class Constructor<?> policyConstructor = - Class.forName(policyEngineName).getDeclaredConstructor(ProviderBackend.class); + Class.forName(policyEngineName).getDeclaredConstructor(ProviderBackend.class); policyConstructor.setAccessible(true); PolicyEngine policyEngine = - (PolicyEngine) policyConstructor.newInstance(new Object[] {providerBackend}); + (PolicyEngine) policyConstructor.newInstance(new Object[] {providerBackend}); // if unset, set the hadoop auth provider to use new groups, so we don't // conflict with the group mappings that may already be set up @@ -145,9 +160,11 @@ public class SolrAuthzBinding { // load the authz provider class Constructor<?> constrctor = - Class.forName(authProviderName).getDeclaredConstructor(Configuration.class, String.class, PolicyEngine.class); + Class.forName(authProviderName).getDeclaredConstructor(Configuration.class, + String.class, PolicyEngine.class, Model.class); constrctor.setAccessible(true); - return (AuthorizationProvider) constrctor.newInstance(new Object[] {authzConf, resourceName, policyEngine}); + return (AuthorizationProvider) constrctor.newInstance(new Object[] {authzConf, resourceName, + policyEngine, SearchPrivilegeModel.getInstance()}); } http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/conf/SolrAuthzConf.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/conf/SolrAuthzConf.java b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/conf/SolrAuthzConf.java index 227f75e..b31f4fa 100644 --- a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/conf/SolrAuthzConf.java +++ b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/conf/SolrAuthzConf.java @@ -33,7 +33,7 @@ public class SolrAuthzConf extends Configuration { "org.apache.sentry.provider.common.HadoopGroupResourceAuthorizationProvider"), AUTHZ_PROVIDER_RESOURCE("sentry.solr.provider.resource", ""), AUTHZ_PROVIDER_BACKEND("sentry.solr.provider.backend", "org.apache.sentry.provider.file.SimpleFileProviderBackend"), - AUTHZ_POLICY_ENGINE("sentry.solr.policy.engine", "org.apache.sentry.policy.search.SimpleSearchPolicyEngine"); + AUTHZ_POLICY_ENGINE("sentry.solr.policy.engine", "org.apache.sentry.policy.engine.common.CommonPolicyEngine"); private final String varName; private final String defaultVal; http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/AbstractTestSearchPolicyEngine.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/AbstractTestSearchPolicyEngine.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/AbstractTestSearchPolicyEngine.java new file mode 100644 index 0000000..3df6ecf --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/AbstractTestSearchPolicyEngine.java @@ -0,0 +1,129 @@ +/* + * 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.policy.solr; + +import java.io.File; +import java.io.IOException; +import java.util.Set; +import java.util.TreeSet; + +import org.junit.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.sentry.core.common.ActiveRoleSet; +import org.apache.sentry.policy.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.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; + + @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.getPrivileges(set("manager"), ActiveRoleSet.ALL)) + .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.getPrivileges(set("analyst"), ActiveRoleSet.ALL)) + .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.getPrivileges(set("jranalyst"), ActiveRoleSet.ALL)) + .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.getPrivileges(set("admin"), ActiveRoleSet.ALL)) + .toString()); + } + + private static Set<String> set(String... values) { + return Sets.newHashSet(values); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/SearchPolicyTestUtil.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/SearchPolicyTestUtil.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/SearchPolicyTestUtil.java new file mode 100644 index 0000000..e198b5c --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/SearchPolicyTestUtil.java @@ -0,0 +1,45 @@ +/* + * 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.policy.solr; + +import org.apache.hadoop.conf.Configuration; +import org.apache.sentry.core.model.search.SearchPrivilegeModel; +import org.apache.sentry.policy.common.PolicyEngine; +import org.apache.sentry.policy.engine.common.CommonPolicyEngine; +import org.apache.sentry.provider.common.ProviderBackend; +import org.apache.sentry.provider.common.ProviderBackendContext; +import org.apache.sentry.provider.file.SimpleFileProviderBackend; + +import java.io.IOException; + +public class SearchPolicyTestUtil { + + public static PolicyEngine createPolicyEngineForTest(String resource) throws IOException { + + ProviderBackend providerBackend = new SimpleFileProviderBackend(new Configuration(), resource); + + // create backendContext + ProviderBackendContext context = new ProviderBackendContext(); + context.setAllowPerDatabase(false); + context.setValidators(SearchPrivilegeModel.getInstance().getPrivilegeValidators()); + // initialize the backend with the context + providerBackend.initialize(context); + + + return new CommonPolicyEngine(providerBackend); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestCollectionRequiredInRole.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestCollectionRequiredInRole.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestCollectionRequiredInRole.java new file mode 100644 index 0000000..76211dd --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestCollectionRequiredInRole.java @@ -0,0 +1,64 @@ +/* + * 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.policy.solr; + +import org.junit.Assert; + +import org.apache.sentry.core.common.validator.PrivilegeValidatorContext; +import org.apache.sentry.core.model.search.validator.CollectionRequiredInPrivilege; +import org.apache.shiro.config.ConfigurationException; +import org.junit.Test; + +public class TestCollectionRequiredInRole { + + @Test + public void testEmptyRole() throws Exception { + CollectionRequiredInPrivilege collRequiredInRole = new CollectionRequiredInPrivilege(); + + // check no db + try { + collRequiredInRole.validate(new PrivilegeValidatorContext("index=index1")); + Assert.fail("Expected ConfigurationException"); + } catch (ConfigurationException e) { + // expected + } + + // check with db + try { + collRequiredInRole.validate(new PrivilegeValidatorContext("db1","index=index2")); + Assert.fail("Expected ConfigurationException"); + } catch (ConfigurationException e) { + // expected + } + } + + @Test + public void testCollectionWithoutAction() throws Exception { + CollectionRequiredInPrivilege collRequiredInRole = new CollectionRequiredInPrivilege(); + collRequiredInRole.validate(new PrivilegeValidatorContext("collection=nodb")); + collRequiredInRole.validate(new PrivilegeValidatorContext("db2","collection=db")); + } + + @Test + public void testCollectionWithAction() throws Exception { + CollectionRequiredInPrivilege collRequiredInRole = new CollectionRequiredInPrivilege(); + collRequiredInRole.validate(new PrivilegeValidatorContext(null,"collection=nodb->action=query")); + collRequiredInRole.validate(new PrivilegeValidatorContext("db2","collection=db->action=update")); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchAuthorizationProviderGeneralCases.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchAuthorizationProviderGeneralCases.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchAuthorizationProviderGeneralCases.java new file mode 100644 index 0000000..6f7f07a --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchAuthorizationProviderGeneralCases.java @@ -0,0 +1,193 @@ +/* + * 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.policy.solr; + +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 com.google.common.collect.Sets; +import junit.framework.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.sentry.core.common.Action; +import org.apache.sentry.core.common.ActiveRoleSet; +import org.apache.sentry.core.common.Authorizable; +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.core.model.search.SearchPrivilegeModel; +import org.apache.sentry.provider.common.GroupMappingService; +import org.apache.sentry.provider.common.ResourceAuthorizationProvider; +import org.apache.sentry.provider.file.HadoopGroupResourceAuthorizationProvider; +import org.apache.sentry.provider.file.PolicyFiles; +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 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, "solr-policy-test-authz-provider.ini"); + authzProvider = new HadoopGroupResourceAuthorizationProvider( + SearchPolicyTestUtil.createPolicyEngineForTest(new File(baseDir, "solr-policy-test-authz-provider.ini").getPath()), + new MockGroupMappingServiceProvider(USER_TO_GROUP_MAP), SearchPrivilegeModel.getInstance()); + + } + + @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, ActiveRoleSet.ALL)); + 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); + } + + public class MockGroupMappingServiceProvider implements GroupMappingService { + private final Multimap<String, String> userToGroupMap; + + public MockGroupMappingServiceProvider(Multimap<String, String> userToGroupMap) { + this.userToGroupMap = userToGroupMap; + } + + @Override + public Set<String> getGroups(String user) { + return Sets.newHashSet(userToGroupMap.get(user)); + } + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchAuthorizationProviderSpecialCases.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchAuthorizationProviderSpecialCases.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchAuthorizationProviderSpecialCases.java new file mode 100644 index 0000000..371f361 --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchAuthorizationProviderSpecialCases.java @@ -0,0 +1,84 @@ + /* + * 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.policy.solr; + +import java.io.File; +import java.io.IOException; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import org.junit.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.sentry.core.common.Action; +import org.apache.sentry.core.common.ActiveRoleSet; +import org.apache.sentry.core.common.Authorizable; +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.core.model.search.SearchPrivilegeModel; +import org.apache.sentry.policy.common.PolicyEngine; +import org.apache.sentry.provider.common.AuthorizationProvider; +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); + PolicyEngine policy = SearchPolicyTestUtil.createPolicyEngineForTest(initResource); + authzProvider = new LocalGroupResourceAuthorizationProvider(initResource, policy, SearchPrivilegeModel.getInstance()); + List<? extends Authorizable> authorizableHierarchy = ImmutableList.of(collection1); + Assert.assertTrue(authorizableHierarchy.toString(), + authzProvider.hasAccess(user1, authorizableHierarchy, actions, ActiveRoleSet.ALL)); + } + +} http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchModelAuthorizables.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchModelAuthorizables.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchModelAuthorizables.java new file mode 100644 index 0000000..e7da13a --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchModelAuthorizables.java @@ -0,0 +1,54 @@ +/* + * 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.policy.solr; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; + +import org.apache.sentry.core.model.search.Collection; +import org.apache.sentry.core.model.search.SearchModelAuthorizables; +import org.junit.Test; + +public class TestSearchModelAuthorizables { + + @Test + public void testCollection() throws Exception { + Collection coll = (Collection) SearchModelAuthorizables.from("CoLleCtiOn=collection1"); + assertEquals("collection1", coll.getName()); + } + + @Test(expected=IllegalArgumentException.class) + public void testNoKV() throws Exception { + System.out.println(SearchModelAuthorizables.from("nonsense")); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyKey() throws Exception { + System.out.println(SearchModelAuthorizables.from("=v")); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyValue() throws Exception { + System.out.println(SearchModelAuthorizables.from("k=")); + } + + @Test + public void testNotAuthorizable() throws Exception { + assertNull(SearchModelAuthorizables.from("k=v")); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyEngineDFS.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyEngineDFS.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyEngineDFS.java new file mode 100644 index 0000000..3e3aa47 --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyEngineDFS.java @@ -0,0 +1,74 @@ +/* + * 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.policy.solr; + +import java.io.File; +import java.io.IOException; + +import org.junit.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.provider.file.PolicyFiles; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +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, "solr-policy-test-authz-provider.ini"); + setPolicy(SearchPolicyTestUtil.createPolicyEngineForTest(new Path(etc, + "solr-policy-test-authz-provider.ini").toString())); + } + + @Override + protected void beforeTeardown() throws IOException { + fileSystem.delete(etc, true); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyEngineLocalFS.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyEngineLocalFS.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyEngineLocalFS.java new file mode 100644 index 0000000..a7928b5 --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/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.policy.solr; + +import java.io.File; +import java.io.IOException; + +import org.junit.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, "solr-policy-test-authz-provider.ini"); + setPolicy(SearchPolicyTestUtil.createPolicyEngineForTest(new File(baseDir, "solr-policy-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/sentry/blob/d94e900a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyNegative.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyNegative.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyNegative.java new file mode 100644 index 0000000..20fee76 --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/policy/solr/TestSearchPolicyNegative.java @@ -0,0 +1,101 @@ +/* + * 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.policy.solr; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; + +import org.junit.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.sentry.core.common.ActiveRoleSet; +import org.apache.sentry.policy.common.PolicyEngine; +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.Sets; +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 = some_role", otherPolicyFile); + append("[roles]", otherPolicyFile); + append("some_role = collection=c1", otherPolicyFile); + PolicyEngine policy = SearchPolicyTestUtil.createPolicyEngineForTest(globalPolicyFile.getPath()); + Assert.assertEquals(Collections.emptySet(), + policy.getPrivileges(Sets.newHashSet("other_group"), ActiveRoleSet.ALL)); + } + + @Test + public void testCollectionRequiredInRole() throws Exception { + append("[groups]", globalPolicyFile); + append("group = some_role", globalPolicyFile); + append("[roles]", globalPolicyFile); + append("some_role = action=query", globalPolicyFile); + PolicyEngine policy = SearchPolicyTestUtil.createPolicyEngineForTest(globalPolicyFile.getPath()); + ImmutableSet<String> permissions = policy.getPrivileges(Sets.newHashSet("group"), ActiveRoleSet.ALL); + 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 = SearchPolicyTestUtil.createPolicyEngineForTest(globalPolicyFile.getPath()); + ImmutableSet<String> permissions = policy.getPrivileges(Sets.newHashSet("incorrectGroup"), ActiveRoleSet.ALL); + Assert.assertTrue(permissions.toString(), permissions.isEmpty()); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/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 new file mode 100644 index 0000000..294091c --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/privilege/solr/TestCommonPrivilegeForSearch.java @@ -0,0 +1,214 @@ +/* + * 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.privilege.solr; + +import org.apache.sentry.core.common.Model; +import org.apache.sentry.core.common.utils.KeyValue; +import org.apache.sentry.core.common.utils.SentryConstants; +import org.apache.sentry.core.model.search.SearchConstants; +import org.apache.sentry.core.model.search.SearchPrivilegeModel; +import org.apache.sentry.policy.common.CommonPrivilege; +import org.apache.sentry.policy.common.Privilege; +import org.junit.Before; +import org.junit.Test; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +public class TestCommonPrivilegeForSearch { + + private Model searchPrivilegeModel; + + private static final String ALL = SearchConstants.ALL; + + @Before + public void prepareData() { + searchPrivilegeModel = SearchPrivilegeModel.getInstance(); + } + + @Test + public void testSimpleNoAction() throws Exception { + CommonPrivilege collection1 = create(new KeyValue("collection", "coll1")); + CommonPrivilege collection2 = create(new KeyValue("collection", "coll2")); + CommonPrivilege collection1Case = create(new KeyValue("colleCtIon", "coLl1")); + + assertTrue(collection1.implies(collection1, searchPrivilegeModel)); + assertTrue(collection2.implies(collection2, searchPrivilegeModel)); + assertTrue(collection1.implies(collection1Case, searchPrivilegeModel)); + assertTrue(collection1Case.implies(collection1, searchPrivilegeModel)); + + assertFalse(collection1.implies(collection2, searchPrivilegeModel)); + assertFalse(collection1Case.implies(collection2, searchPrivilegeModel)); + assertFalse(collection2.implies(collection1, searchPrivilegeModel)); + assertFalse(collection2.implies(collection1Case, searchPrivilegeModel)); + } + + @Test + public void testSimpleAction() throws Exception { + CommonPrivilege query = + create(new KeyValue("collection", "coll1"), new KeyValue("action", "query")); + CommonPrivilege update = + create(new KeyValue("collection", "coll1"), new KeyValue("action", "update")); + CommonPrivilege queryCase = + create(new KeyValue("colleCtIon", "coLl1"), new KeyValue("AcTiOn", "QuERy")); + + assertTrue(query.implies(query, searchPrivilegeModel)); + assertTrue(update.implies(update, searchPrivilegeModel)); + assertTrue(query.implies(queryCase, searchPrivilegeModel)); + assertTrue(queryCase.implies(query, searchPrivilegeModel)); + + assertFalse(query.implies(update, searchPrivilegeModel)); + assertFalse(queryCase.implies(update, searchPrivilegeModel)); + assertFalse(update.implies(query, searchPrivilegeModel)); + assertFalse(update.implies(queryCase, searchPrivilegeModel)); + } + + @Test + public void testRoleShorterThanRequest() throws Exception { + CommonPrivilege collection1 = create(new KeyValue("collection", "coll1")); + CommonPrivilege query = + create(new KeyValue("collection", "coll1"), new KeyValue("action", "query")); + CommonPrivilege update = + create(new KeyValue("collection", "coll1"), new KeyValue("action", "update")); + CommonPrivilege all = + create(new KeyValue("collection", "coll1"), new KeyValue("action", ALL)); + + assertTrue(collection1.implies(query, searchPrivilegeModel)); + assertTrue(collection1.implies(update, searchPrivilegeModel)); + assertTrue(collection1.implies(all, searchPrivilegeModel)); + + assertFalse(query.implies(collection1, searchPrivilegeModel)); + assertFalse(update.implies(collection1, searchPrivilegeModel)); + assertTrue(all.implies(collection1, searchPrivilegeModel)); + } + + @Test + public void testCollectionAll() throws Exception { + CommonPrivilege collectionAll = create(new KeyValue("collection", ALL)); + CommonPrivilege collection1 = create(new KeyValue("collection", "coll1")); + assertTrue(collectionAll.implies(collection1, searchPrivilegeModel)); + assertTrue(collection1.implies(collectionAll, searchPrivilegeModel)); + + CommonPrivilege allUpdate = + create(new KeyValue("collection", ALL), new KeyValue("action", "update")); + CommonPrivilege allQuery = + create(new KeyValue("collection", ALL), new KeyValue("action", "query")); + CommonPrivilege coll1Update = + create(new KeyValue("collection", "coll1"), new KeyValue("action", "update")); + CommonPrivilege coll1Query = + create(new KeyValue("collection", "coll1"), new KeyValue("action", "query")); + assertTrue(allUpdate.implies(coll1Update, searchPrivilegeModel)); + assertTrue(allQuery.implies(coll1Query, searchPrivilegeModel)); + assertTrue(coll1Update.implies(allUpdate, searchPrivilegeModel)); + assertTrue(coll1Query.implies(allQuery, searchPrivilegeModel)); + assertFalse(allUpdate.implies(coll1Query, searchPrivilegeModel)); + assertFalse(coll1Update.implies(coll1Query, searchPrivilegeModel)); + assertFalse(allQuery.implies(coll1Update, searchPrivilegeModel)); + assertFalse(coll1Query.implies(allUpdate, searchPrivilegeModel)); + assertFalse(allUpdate.implies(allQuery, searchPrivilegeModel)); + assertFalse(allQuery.implies(allUpdate, searchPrivilegeModel)); + assertFalse(coll1Update.implies(coll1Query, searchPrivilegeModel)); + assertFalse(coll1Query.implies(coll1Update, searchPrivilegeModel)); + + // test different length paths + assertTrue(collectionAll.implies(allUpdate, searchPrivilegeModel)); + assertTrue(collectionAll.implies(allQuery, searchPrivilegeModel)); + assertTrue(collectionAll.implies(coll1Update, searchPrivilegeModel)); + assertTrue(collectionAll.implies(coll1Query, searchPrivilegeModel)); + assertFalse(allUpdate.implies(collectionAll, searchPrivilegeModel)); + assertFalse(allQuery.implies(collectionAll, searchPrivilegeModel)); + assertFalse(coll1Update.implies(collectionAll, searchPrivilegeModel)); + assertFalse(coll1Query.implies(collectionAll, searchPrivilegeModel)); + } + + @Test + public void testActionAll() throws Exception { + CommonPrivilege coll1All = + create(new KeyValue("collection", "coll1"), new KeyValue("action", ALL)); + CommonPrivilege coll1Update = + create(new KeyValue("collection", "coll1"), new KeyValue("action", "update")); + CommonPrivilege coll1Query = + create(new KeyValue("collection", "coll1"), new KeyValue("action", "query")); + assertTrue(coll1All.implies(coll1All, searchPrivilegeModel)); + assertTrue(coll1All.implies(coll1Update, searchPrivilegeModel)); + assertTrue(coll1All.implies(coll1Query, searchPrivilegeModel)); + assertFalse(coll1Update.implies(coll1All, searchPrivilegeModel)); + assertFalse(coll1Query.implies(coll1All, searchPrivilegeModel)); + + // test different lengths + CommonPrivilege coll1 = + create(new KeyValue("collection", "coll1")); + assertTrue(coll1All.implies(coll1, searchPrivilegeModel)); + assertTrue(coll1.implies(coll1All, searchPrivilegeModel)); + } + + @Test + public void testUnexpected() throws Exception { + Privilege p = new Privilege() { + @Override + public boolean implies(Privilege p, Model m) { + return false; + } + }; + Privilege collection1 = create(new KeyValue("collection", "coll1")); + assertFalse(collection1.implies(null, searchPrivilegeModel)); + assertFalse(collection1.implies(p, searchPrivilegeModel)); + assertFalse(collection1.equals(null)); + assertFalse(collection1.equals(p)); + } + + @Test(expected=IllegalArgumentException.class) + public void testNullString() throws Exception { + System.out.println(create((String)null)); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyString() throws Exception { + System.out.println(create("")); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyKey() throws Exception { + System.out.println(create(SentryConstants.KV_JOINER.join("collection", ""))); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyValue() throws Exception { + System.out.println(create(SentryConstants.KV_JOINER.join("", "coll1"))); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyPart() throws Exception { + System.out.println(create(SentryConstants.AUTHORIZABLE_JOINER. + join(SentryConstants.KV_JOINER.join("collection1", "coll1"), ""))); + } + + @Test(expected=IllegalArgumentException.class) + public void testOnlySeperators() throws Exception { + System.out.println(create(SentryConstants.AUTHORIZABLE_JOINER. + join(SentryConstants.KV_SEPARATOR, SentryConstants.KV_SEPARATOR, + SentryConstants.KV_SEPARATOR))); + } + + 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/d94e900a/sentry-binding/sentry-binding-solr/src/test/resources/solr-policy-test-authz-provider.ini ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-solr/src/test/resources/solr-policy-test-authz-provider.ini b/sentry-binding/sentry-binding-solr/src/test/resources/solr-policy-test-authz-provider.ini new file mode 100644 index 0000000..8af8162 --- /dev/null +++ b/sentry-binding/sentry-binding-solr/src/test/resources/solr-policy-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=* http://git-wip-us.apache.org/repos/asf/sentry/blob/d94e900a/sentry-binding/sentry-binding-sqoop/pom.xml ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-sqoop/pom.xml b/sentry-binding/sentry-binding-sqoop/pom.xml index 73ddee8..732da26 100644 --- a/sentry-binding/sentry-binding-sqoop/pom.xml +++ b/sentry-binding/sentry-binding-sqoop/pom.xml @@ -59,21 +59,22 @@ limitations under the License. <artifactId>sentry-policy-common</artifactId> </dependency> <dependency> - <groupId>org.apache.sentry</groupId> - <artifactId>sentry-policy-sqoop</artifactId> - </dependency> - <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <scope>provided</scope> </dependency> <dependency> - <groupId>org.apache.sqoop</groupId> - <artifactId>sqoop-common</artifactId> + <groupId>org.apache.sqoop</groupId> + <artifactId>sqoop-common</artifactId> </dependency> <dependency> - <groupId>org.apache.sqoop</groupId> - <artifactId>sqoop-security</artifactId> + <groupId>org.apache.sqoop</groupId> + <artifactId>sqoop-security</artifactId> + </dependency> + <dependency> + <groupId>org.apache.hadoop</groupId> + <artifactId>hadoop-minicluster</artifactId> + <scope>test</scope> </dependency> </dependencies>
