Repository: incubator-sentry Updated Branches: refs/heads/master afe8cd8df -> 540424d50
SENTRY-217: Add Insert and URI tests for Sentry DB provider (Prasad Mujumdar via Sravya Tirukkovalur) Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/540424d5 Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/540424d5 Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/540424d5 Branch: refs/heads/master Commit: 540424d50f84c3ad0bd65370374e3d70c352bb72 Parents: afe8cd8 Author: Sravya Tirukkovalur <[email protected]> Authored: Wed May 21 13:25:31 2014 -0700 Committer: Sravya Tirukkovalur <[email protected]> Committed: Wed May 21 13:27:59 2014 -0700 ---------------------------------------------------------------------- .../apache/hadoop/hive/SentryHiveConstants.java | 4 +- .../hive/ql/exec/SentryGrantRevokeTask.java | 53 +++-- .../ql/exec/SentryHivePrivilegeObjectDesc.java | 42 ++++ .../SentryHiveAuthorizationTaskFactoryImpl.java | 20 +- .../db/service/persistent/SentryStore.java | 4 +- .../db/service/persistent/TestSentryStore.java | 6 +- .../TestSentryStoreToAuthorizable.java | 8 +- sentry-tests/sentry-tests-hive/pom.xml | 85 +++++--- .../dbprovider/AbstractTestWithDbProvider.java | 155 +++++++++++++ .../tests/e2e/dbprovider/TestDbEndToEnd.java | 218 +++++++++++++++++++ 10 files changed, 532 insertions(+), 63 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/540424d5/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/SentryHiveConstants.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/SentryHiveConstants.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/SentryHiveConstants.java index db14b6c..26eea91 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/SentryHiveConstants.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/SentryHiveConstants.java @@ -22,8 +22,8 @@ import java.util.EnumSet; import org.apache.hadoop.hive.ql.security.authorization.Privilege.PrivilegeType; public class SentryHiveConstants { - // TODO add INSERT - public static final EnumSet<PrivilegeType> ALLOWED_PRIVS = EnumSet.of(PrivilegeType.ALL, PrivilegeType.SELECT); + public static final EnumSet<PrivilegeType> ALLOWED_PRIVS = EnumSet.of( + PrivilegeType.ALL, PrivilegeType.SELECT, PrivilegeType.INSERT); public static final String PRIVILEGE_NOT_SUPPORTED = "Sentry does not support privilege: "; public static final String COLUMN_PRIVS_NOT_SUPPORTED = "Sentry users should use views to grant privileges on columns"; http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/540424d5/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/ql/exec/SentryGrantRevokeTask.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/ql/exec/SentryGrantRevokeTask.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/ql/exec/SentryGrantRevokeTask.java index b6f39ad..ec0b658 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/ql/exec/SentryGrantRevokeTask.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/ql/exec/SentryGrantRevokeTask.java @@ -17,9 +17,13 @@ package org.apache.hadoop.hive.ql.exec; * limitations under the License. */ -import com.google.common.base.Preconditions; -import com.google.common.base.Splitter; -import com.google.common.collect.Iterables; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Serializable; +import java.util.List; +import java.util.Set; + import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; @@ -50,15 +54,13 @@ import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient; import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege; import org.apache.sentry.provider.db.service.thrift.TSentryRole; import org.apache.sentry.service.thrift.SentryServiceClientFactory; +import org.apache.sentry.service.thrift.ServiceConstants.PrivilegeScope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Serializable; -import java.util.List; -import java.util.Set; +import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable { private static final Logger LOG = LoggerFactory @@ -313,7 +315,12 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable for (TSentryPrivilege privilege : privileges) { - appendNonNull(builder, privilege.getDbName(), true); + if (PrivilegeScope.URI.name().equalsIgnoreCase( + privilege.getPrivilegeScope())) { + appendNonNull(builder, privilege.getURI(), true); + } else { + appendNonNull(builder, privilege.getDbName(), true); + } appendNonNull(builder, privilege.getTableName()); appendNonNull(builder, null);//getPartValues() appendNonNull(builder, null);//getColumnName() @@ -373,14 +380,24 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable SentryPolicyServiceClient sentryClient, String subject, Set<String> subjectGroups, String server, boolean isGrant, List<PrincipalDesc> principals, - List<PrivilegeDesc> privileges, PrivilegeObjectDesc privSubjectDesc) throws SentryUserException { + List<PrivilegeDesc> privileges, + PrivilegeObjectDesc privSubjectObjDesc) throws SentryUserException { if (privileges == null || privileges.size() == 0) { console.printError("No privilege found."); return RETURN_CODE_FAILURE; } + String dbName = null; String tableName = null; + String uriPath = null; + String serverName = null; try { + if (!(privSubjectObjDesc instanceof SentryHivePrivilegeObjectDesc)) { + throw new HiveException( + "Privilege subject not parsed correctly by Sentry"); + } + SentryHivePrivilegeObjectDesc privSubjectDesc = (SentryHivePrivilegeObjectDesc) privSubjectObjDesc; + if (privSubjectDesc == null) { throw new HiveException("Privilege subject cannot be null"); } @@ -393,6 +410,10 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable DatabaseTable dbTable = parseDBTable(obj); dbName = dbTable.getDatabase(); tableName = dbTable.getTable(); + } else if (privSubjectDesc.getUri()) { + uriPath = privSubjectDesc.getObject(); + } else if (privSubjectDesc.getServer()) { + serverName = privSubjectDesc.getObject(); } else { dbName = privSubjectDesc.getObject(); } @@ -413,7 +434,13 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable } for (PrivilegeDesc privDesc : privileges) { if (isGrant) { - if (tableName == null) { + if (serverName != null) { + sentryClient.grantServerPrivilege(subject, subjectGroups, + princ.getName(), serverName); + } else if (uriPath != null) { + sentryClient.grantURIPrivilege(subject, subjectGroups, + princ.getName(), server, uriPath); + } else if (tableName == null) { sentryClient.grantDatabasePrivilege(subject, subjectGroups, princ.getName(), server, dbName); } else { sentryClient.grantTablePrivilege(subject, subjectGroups, princ.getName(), server, dbName, @@ -503,4 +530,4 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable public String getName() { return "SENTRY"; } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/540424d5/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/ql/exec/SentryHivePrivilegeObjectDesc.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/ql/exec/SentryHivePrivilegeObjectDesc.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/ql/exec/SentryHivePrivilegeObjectDesc.java new file mode 100644 index 0000000..0447e26 --- /dev/null +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/hadoop/hive/ql/exec/SentryHivePrivilegeObjectDesc.java @@ -0,0 +1,42 @@ +/* + * 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.hadoop.hive.ql.exec; + +import org.apache.hadoop.hive.ql.plan.PrivilegeObjectDesc; + +public class SentryHivePrivilegeObjectDesc extends PrivilegeObjectDesc { + private boolean isUri; + private boolean isServer; + + public boolean getUri() { + return isUri; + } + + public void setUri(boolean isUri) { + this.isUri = isUri; + } + + public boolean getServer() { + return isServer; + } + + public void setServer(boolean isServer) { + this.isServer = isServer; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/540424d5/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/SentryHiveAuthorizationTaskFactoryImpl.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/SentryHiveAuthorizationTaskFactoryImpl.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/SentryHiveAuthorizationTaskFactoryImpl.java index 9ca11ae..6d89041 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/SentryHiveAuthorizationTaskFactoryImpl.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/SentryHiveAuthorizationTaskFactoryImpl.java @@ -22,6 +22,7 @@ import org.apache.hadoop.hive.SentryHiveConstants; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.metastore.api.PrincipalType; import org.apache.hadoop.hive.ql.exec.SentryGrantRevokeTask; +import org.apache.hadoop.hive.ql.exec.SentryHivePrivilegeObjectDesc; import org.apache.hadoop.hive.ql.exec.Task; import org.apache.hadoop.hive.ql.exec.TaskFactory; import org.apache.hadoop.hive.ql.hooks.ReadEntity; @@ -114,7 +115,7 @@ public class SentryHiveAuthorizationTaskFactoryImpl implements HiveAuthorization (ASTNode) ast.getChild(0)); List<PrincipalDesc> principalDesc = analyzePrincipalListDef( (ASTNode) ast.getChild(1)); - PrivilegeObjectDesc privilegeObj = null; + SentryHivePrivilegeObjectDesc privilegeObj = null; if (ast.getChildCount() > 2) { for (int i = 2; i < ast.getChildCount(); i++) { @@ -291,20 +292,27 @@ public class SentryHiveAuthorizationTaskFactoryImpl implements HiveAuthorization return createTask(new DDLWork(inputs, outputs, showRolesDesc)); } - private PrivilegeObjectDesc analyzePrivilegeObject(ASTNode ast) + private SentryHivePrivilegeObjectDesc analyzePrivilegeObject(ASTNode ast) throws SemanticException { - PrivilegeObjectDesc subject = new PrivilegeObjectDesc(); - subject.setObject(BaseSemanticAnalyzer.unescapeIdentifier(ast.getChild(0).getText())); + SentryHivePrivilegeObjectDesc subject = new SentryHivePrivilegeObjectDesc(); + String privilegeObject = BaseSemanticAnalyzer.unescapeIdentifier(ast + .getChild(0).getText()); if (ast.getChildCount() > 1) { - for (int i = 0; i < ast.getChildCount(); i++) { + for (int i = 1; i < ast.getChildCount(); i++) { ASTNode astChild = (ASTNode) ast.getChild(i); if (astChild.getToken().getType() == HiveParser.TOK_PARTSPEC) { throw new SemanticException(SentryHiveConstants.PARTITION_PRIVS_NOT_SUPPORTED); + } else if (astChild.getToken().getType() == HiveParser.TOK_URI) { + privilegeObject = privilegeObject.replaceAll("'", ""); + subject.setUri(true); + } else if (astChild.getToken().getType() == HiveParser.TOK_SERVER) { + subject.setServer(true); } else { - subject.setTable(ast.getChild(0) != null); + subject.setTable(true); } } } + subject.setObject(privilegeObject); return subject; } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/540424d5/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java index 7971ea3..8f0ecfd 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java @@ -724,7 +724,8 @@ public class SentryStore { authorizable.add(KV_JOINER.join(AuthorizableType.URI.name().toLowerCase(), privilege.getURI())); } - if (!Strings.nullToEmpty(privilege.getAction()).isEmpty()) { + if (!Strings.nullToEmpty(privilege.getAction()).isEmpty() + && !privilege.getAction().equalsIgnoreCase(AccessConstants.ALL)) { authorizable.add(KV_JOINER.join(ProviderConstants.PRIVILEGE_NAME.toLowerCase(), privilege.getAction())); } @@ -897,4 +898,3 @@ public class SentryStore { } } - http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/540424d5/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java index 0d8e24f..67b05e6 100644 --- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java @@ -258,7 +258,8 @@ public class TestSentryStore { assertEquals(Sets.newHashSet("server=server1->db=db1->table=tbl1->action=select"), SentryStore.toTrimedLower(sentryStore.listSentryPrivilegesForProvider(Sets.newHashSet(groupName2), new TSentryActiveRoleSet(false, Sets.newHashSet(roleName1))))); - assertEquals(Sets.newHashSet("server=server1"), + assertEquals(Sets.newHashSet( + "server=server1->db=db1->table=tbl1->action=select", "server=server1"), SentryStore.toTrimedLower(sentryStore.listSentryPrivilegesForProvider(Sets.newHashSet(groupName2), new TSentryActiveRoleSet(false, Sets.newHashSet(roleName2))))); // unknown active role @@ -280,7 +281,8 @@ public class TestSentryStore { SentryStore.toTrimedLower(sentryStore.listSentryPrivilegesForProvider(Sets. newHashSet(groupName1, groupName2), new TSentryActiveRoleSet(false, Sets.newHashSet(roleName1))))); - assertEquals(Sets.newHashSet("server=server1"), + assertEquals(Sets.newHashSet( + "server=server1->db=db1->table=tbl1->action=select", "server=server1"), SentryStore.toTrimedLower(sentryStore.listSentryPrivilegesForProvider(Sets. newHashSet(groupName1, groupName2), new TSentryActiveRoleSet(false, Sets.newHashSet(roleName2))))); http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/540424d5/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStoreToAuthorizable.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStoreToAuthorizable.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStoreToAuthorizable.java index 9c851eb..d77786a 100644 --- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStoreToAuthorizable.java +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStoreToAuthorizable.java @@ -35,7 +35,7 @@ public class TestSentryStoreToAuthorizable { SentryStore.toAuthorizable(privilege)); privilege = new MSentryPrivilege(null, null, "server1", null, null, null, AccessConstants.ALL); - assertEquals("server=server1->action=*", + assertEquals("server=server1", SentryStore.toAuthorizable(privilege)); } @@ -54,7 +54,7 @@ public class TestSentryStoreToAuthorizable { SentryStore.toAuthorizable(privilege)); privilege = new MSentryPrivilege(null, null, "server1", "db1", "tbl1", null, AccessConstants.ALL); - assertEquals("server=server1->db=db1->table=tbl1->action=*", + assertEquals("server=server1->db=db1->table=tbl1", SentryStore.toAuthorizable(privilege)); } @@ -65,7 +65,7 @@ public class TestSentryStoreToAuthorizable { SentryStore.toAuthorizable(privilege)); privilege = new MSentryPrivilege(null, null, "server1", "db1", null, null, AccessConstants.ALL); - assertEquals("server=server1->db=db1->action=*", + assertEquals("server=server1->db=db1", SentryStore.toAuthorizable(privilege)); } @@ -80,7 +80,7 @@ public class TestSentryStoreToAuthorizable { SentryStore.toAuthorizable(privilege)); privilege = new MSentryPrivilege(null, null, "server1", null, null, "file:///", AccessConstants.ALL); - assertEquals("server=server1->uri=file:///->action=*", + assertEquals("server=server1->uri=file:///", SentryStore.toAuthorizable(privilege)); } } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/540424d5/sentry-tests/sentry-tests-hive/pom.xml ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/pom.xml b/sentry-tests/sentry-tests-hive/pom.xml index 1d0e169..03802a3 100644 --- a/sentry-tests/sentry-tests-hive/pom.xml +++ b/sentry-tests/sentry-tests-hive/pom.xml @@ -27,8 +27,10 @@ limitations under the License. <name>Sentry Hive Tests</name> <description>end to end tests for sentry-hive integration</description> <properties> - <hadoop-dist></hadoop-dist> + <!-- + <hadoop-dist>.</hadoop-dist> <hive-dist>${hadoop-dist}</hive-dist> + --> <HADOOP_CONF_DIR>${env.HADOOP_CONF_DIR}</HADOOP_CONF_DIR> <HIVE_CONF_DIR>${env.HIVE_CONF_DIR}</HIVE_CONF_DIR> </properties> @@ -237,11 +239,51 @@ limitations under the License. </systemPropertyVariables> </configuration> </plugin> + </plugins> + <pluginManagement> + <plugins> + <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.--> + <plugin> + <groupId>org.eclipse.m2e</groupId> + <artifactId>lifecycle-mapping</artifactId> + <version>1.0.0</version> + <configuration> + <lifecycleMappingMetadata> + <pluginExecutions> + <pluginExecution> + <pluginExecutionFilter> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-antrun-plugin</artifactId> + <versionRange>[1.7,)</versionRange> + <goals> + <goal>run</goal> + </goals> + </pluginExecutionFilter> + <action> + <ignore></ignore> + </action> + </pluginExecution> + </pluginExecutions> + </lifecycleMappingMetadata> + </configuration> + </plugin> + </plugins> + </pluginManagement> + </build> + <profiles> + <profile> + <id>download-hadoop</id> + <activation> + <activeByDefault>false</activeByDefault> + <property><name>!skipTests</name></property> + </activation> + <build> + <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <configuration> - <skipTests>false</skipTests> + <skipTests>true</skipTests> </configuration> <executions> <execution> @@ -282,40 +324,15 @@ limitations under the License. </execution> </executions> </plugin> - </plugins> - <pluginManagement> - <plugins> - <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.--> - <plugin> - <groupId>org.eclipse.m2e</groupId> - <artifactId>lifecycle-mapping</artifactId> - <version>1.0.0</version> - <configuration> - <lifecycleMappingMetadata> - <pluginExecutions> - <pluginExecution> - <pluginExecutionFilter> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-antrun-plugin</artifactId> - <versionRange>[1.7,)</versionRange> - <goals> - <goal>run</goal> - </goals> - </pluginExecutionFilter> - <action> - <ignore></ignore> - </action> - </pluginExecution> - </pluginExecutions> - </lifecycleMappingMetadata> - </configuration> - </plugin> - </plugins> - </pluginManagement> - </build> - <profiles> + </plugins> + </build> + </profile> <profile> <id>link-hadoop</id> + <activation> + <activeByDefault>false</activeByDefault> + <property><name>hadoop-dist</name></property> + </activation> <build> <plugins> <plugin> http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/540424d5/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/AbstractTestWithDbProvider.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/AbstractTestWithDbProvider.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/AbstractTestWithDbProvider.java new file mode 100644 index 0000000..5b655f3 --- /dev/null +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/AbstractTestWithDbProvider.java @@ -0,0 +1,155 @@ +/* + * 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.tests.e2e.dbprovider; + +import java.io.File; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.Map; +import java.util.concurrent.TimeoutException; + +import junit.framework.Assert; + +import org.apache.commons.io.FileUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hive.conf.HiveConf.ConfVars; +import org.apache.sentry.binding.hive.SentryHiveAuthorizationTaskFactoryImpl; +import org.apache.sentry.provider.db.SimpleDBProviderBackend; +import org.apache.sentry.provider.file.PolicyFile; +import org.apache.sentry.service.thrift.SentryService; +import org.apache.sentry.service.thrift.SentryServiceFactory; +import org.apache.sentry.service.thrift.ServiceConstants.ClientConfig; +import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig; +import org.apache.sentry.tests.e2e.hive.AbstractTestWithHiveServer; +import org.apache.sentry.tests.e2e.hive.Context; +import org.apache.sentry.tests.e2e.hive.StaticUserGroup; +import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory; +import org.junit.After; +import org.junit.BeforeClass; + +import com.google.common.collect.Maps; +import com.google.common.io.Files; + +public abstract class AbstractTestWithDbProvider extends AbstractTestWithHiveServer { + + protected static final String SERVER_HOST = "localhost"; + + private Map<String, String> properties; + private File dbDir; + private SentryService sentryServer; + private Configuration conf; + protected PolicyFile policyFile; + + @BeforeClass + public static void setupTest() throws Exception { + } + + public void setupSentryService() throws Exception { + properties = Maps.newHashMap(); + conf = new Configuration(false); + policyFile = new PolicyFile(); + + properties.put(HiveServerFactory.AUTHZ_PROVIDER_BACKEND, SimpleDBProviderBackend.class.getName()); + properties.put(ConfVars.HIVE_AUTHORIZATION_TASK_FACTORY.varname, + SentryHiveAuthorizationTaskFactoryImpl.class.getName()); + properties.put(ServerConfig.SECURITY_MODE, ServerConfig.SECURITY_MODE_NONE); + properties.put(ServerConfig.ADMIN_GROUPS, ADMINGROUP); + properties.put(ServerConfig.RPC_ADDRESS, SERVER_HOST); + properties.put(ServerConfig.RPC_PORT, String.valueOf(0)); + properties.put(ServerConfig.SENTRY_VERIFY_SCHEM_VERSION, "false"); + dbDir = new File(Files.createTempDir(), "sentry_policy_db"); + properties.put(ServerConfig.SENTRY_STORE_JDBC_URL, + "jdbc:derby:;databaseName=" + dbDir.getPath() + ";create=true"); + for (Map.Entry<String, String> entry : properties.entrySet()) { + conf.set(entry.getKey(), entry.getValue()); + } + sentryServer = new SentryServiceFactory().create(conf); + properties.put(ClientConfig.SERVER_RPC_ADDRESS, sentryServer.getAddress().getHostString()); + properties.put(ClientConfig.SERVER_RPC_PORT, + String.valueOf(sentryServer.getAddress().getPort())); + startSentryService(); + } + + @After + public void tearDown() throws Exception { + if (sentryServer != null) { + sentryServer.stop(); + } + if (dbDir != null) { + FileUtils.deleteQuietly(dbDir); + } + } + + public Context createContext() throws Exception { + setupSentryService(); + Context context = createContext(properties); + policyFile + .setUserGroupMapping(StaticUserGroup.getStaticMapping()) + .write(context.getPolicyFile()); + return context; + } + + protected void setupAdmin(Context context) throws Exception { + Connection connection = context.createConnection(ADMIN1); + Statement statement = connection.createStatement(); + statement.execute("CREATE ROLE admin_role"); + statement.execute("GRANT ALL ON SERVER " + + HiveServerFactory.DEFAULT_AUTHZ_SERVER_NAME + " TO ROLE admin_role"); + statement.execute("GRANT ROLE admin_role TO GROUP " + ADMINGROUP); + statement.close(); + connection.close(); + } + + protected void createDb(Connection connection, String...dbs) throws Exception { + Statement statement = connection.createStatement(); + for(String db : dbs) { + statement.execute("CREATE DATABASE " + db); + } + statement.close(); + } + + protected void createTable(Connection connection , String db, File dataFile, String...tables) + throws Exception { + Statement statement = connection.createStatement(); + statement.execute("USE " + db); + for(String table : tables) { + statement.execute("DROP TABLE IF EXISTS " + table); + statement.execute("create table " + table + + " (under_col int comment 'the under column', value string)"); + statement.execute("load data local inpath '" + dataFile.getPath() + + "' into table " + table); + ResultSet res = statement.executeQuery("select * from " + table); + Assert.assertTrue("Table should have data after load", res.next()); + res.close(); + } + statement.close(); + } + + private void startSentryService() throws Exception { + sentryServer.start(); + final long start = System.currentTimeMillis(); + while(!sentryServer.isRunning()) { + Thread.sleep(1000); + if(System.currentTimeMillis() - start > 60000L) { + throw new TimeoutException("Server did not start after 60 seconds"); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/540424d5/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbEndToEnd.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbEndToEnd.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbEndToEnd.java new file mode 100644 index 0000000..eb9f91b --- /dev/null +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbEndToEnd.java @@ -0,0 +1,218 @@ +/* + * 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.tests.e2e.dbprovider; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileOutputStream; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; + +import org.apache.sentry.tests.e2e.hive.Context; +import org.apache.sentry.tests.e2e.hive.StaticUserGroup; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.io.Resources; + +public class TestDbEndToEnd extends AbstractTestWithDbProvider { + private Context context; + private final String SINGLE_TYPE_DATA_FILE_NAME = "kv1.dat"; + private File dataFile; + + @Before + public void setup() throws Exception { + context = createContext(); + dataFile = new File(dataDir, SINGLE_TYPE_DATA_FILE_NAME); + FileOutputStream to = new FileOutputStream(dataFile); + Resources.copy(Resources.getResource(SINGLE_TYPE_DATA_FILE_NAME), to); + to.close(); + setupAdmin(context); + } + + @After + public void tearDown() throws Exception { + if (context != null) { + context.close(); + } + } + + @Test + public void testBasic() throws Exception { + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("CREATE TABLE t1 (c1 string)"); + statement.execute("CREATE ROLE user_role"); + statement.execute("GRANT SELECT ON TABLE t1 TO ROLE user_role"); + statement.execute("GRANT ROLE user_role TO GROUP " + USERGROUP1); + statement.close(); + connection.close(); + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + context.assertSentryServiceAccessDenied(statement, "CREATE ROLE r2"); + // test default of ALL + statement.execute("SELECT * FROM t1"); + // test a specific role + statement.execute("SET ROLE user_role"); + statement.execute("SELECT * FROM t1"); + // test NONE + statement.execute("SET ROLE NONE"); + context.assertAuthzException(statement, "SELECT * FROM t1"); + // test ALL + statement.execute("SET ROLE ALL"); + statement.execute("SELECT * FROM t1"); + statement.close(); + connection.close(); + } + + @Test + public void testUPrivileges() throws Exception { + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("CREATE TABLE t1 (c1 string)"); + statement.execute("CREATE ROLE user_role"); + statement.execute("CREATE ROLE uri_role"); + statement.execute("GRANT SELECT ON URI 'file://" + dataDir.getPath() + + "' TO ROLE uri_role"); + statement.execute("GRANT INSERT ON TABLE t1 TO ROLE user_role"); + + statement.execute("GRANT ROLE user_role TO GROUP " + USERGROUP1); + statement.execute("GRANT ROLE uri_role TO GROUP " + USERGROUP1); + + ResultSet resultSet = statement.executeQuery("SHOW GRANT ROLE uri_role"); + assertTrue(resultSet.next()); + assertEquals("file://" + dataDir.getPath(), resultSet.getString(1)); + resultSet.close(); + + resultSet = statement.executeQuery("SHOW GRANT ROLE user_role"); + assertTrue(resultSet.next()); + assertEquals("default", resultSet.getString(1)); + assertEquals("t1", resultSet.getString(2)); + resultSet.close(); + + statement.close(); + connection.close(); + + } + + /** + * Steps: + * 1. admin create a new experimental database + * 2. admin create a new production database, create table, load data + * 3. admin grant privilege all@'experimental database' to usergroup1 + * 4. user create table, load data in experimental DB + * 5. user create view based on table in experimental DB + * 6. admin create table (same name) in production DB + * 7. admin grant [email protected] to group + * admin grant [email protected] to group + * 8. user load data from experimental table to production table + */ + @Test + public void testEndToEnd1() throws Exception { + policyFile + .setUserGroupMapping(StaticUserGroup.getStaticMapping()) + .write(context.getPolicyFile()); + + String dbName1 = "db_1"; + String dbName2 = "productionDB"; + String tableName1 = "tb_1"; + String tableName2 = "tb_2"; + String viewName1 = "view_1"; + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + // 1 + statement.execute("DROP DATABASE IF EXISTS " + dbName1 + " CASCADE"); + statement.execute("CREATE DATABASE " + dbName1); + // 2 + statement.execute("DROP DATABASE IF EXISTS " + dbName2 + " CASCADE"); + statement.execute("CREATE DATABASE " + dbName2); + statement.execute("USE " + dbName2); + statement.execute("DROP TABLE IF EXISTS " + dbName2 + "." + tableName2); + statement.execute("create table " + dbName2 + "." + tableName2 + + " (under_col int comment 'the under column', value string)"); + statement.execute("load data local inpath '" + dataFile.getPath() + + "' into table " + tableName2); + + // 3 + statement.execute("CREATE ROLE all_db1"); + statement.execute("GRANT ALL ON DATABASE " + dbName1 + " TO ROLE all_db1"); + + statement.execute("CREATE ROLE select_tb1"); + statement.execute("CREATE ROLE insert_tb1"); + statement.execute("CREATE ROLE insert_tb2"); + statement.execute("CREATE ROLE data_uri"); + + statement.execute("USE " + dbName2); + statement.execute("GRANT INSERT ON TABLE " + tableName1 + + " TO ROLE insert_tb1"); + statement.execute("GRANT INSERT ON TABLE " + tableName2 + + " TO ROLE insert_tb2"); + statement.execute("GRANT ALL ON URI 'file://" + dataDir.getPath() + + "' TO ROLE data_uri"); + + statement.execute("USE " + dbName1); + statement.execute("GRANT SELECT ON TABLE " + tableName1 + + " TO ROLE select_tb1"); + + statement + .execute("GRANT ROLE all_db1, select_tb1, insert_tb1, insert_tb2, data_uri TO GROUP " + + USERGROUP1); + + statement.close(); + connection.close(); + + // 4 + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("USE " + dbName1); + statement.execute("DROP TABLE IF EXISTS " + dbName1 + "." + tableName1); + statement.execute("create table " + dbName1 + "." + tableName1 + + " (under_col int comment 'the under column', value string)"); + statement.execute("load data local inpath '" + dataFile.getPath() + + "' into table " + tableName1); + + // 5 + statement.execute("CREATE VIEW " + viewName1 + " (value) AS SELECT value from " + tableName1 + " LIMIT 10"); + statement.close(); + connection.close(); + + // 7 + connection = context.createConnection(ADMIN1); + statement = context.createStatement(connection); + statement.execute("USE " + dbName2); + statement.execute("DROP TABLE IF EXISTS " + dbName1 + "." + tableName1); + statement.execute("create table " + dbName1 + "." + tableName1 + + " (under_col int comment 'the under column', value string)"); + statement.close(); + connection.close(); + + // 8 + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("USE " + dbName2); + statement.execute("INSERT OVERWRITE TABLE " + + dbName2 + "." + tableName2 + " SELECT * FROM " + dbName1 + + "." + tableName1); + statement.close(); + connection.close(); + } +}
