Repository: incubator-sentry Updated Branches: refs/heads/master 2f4819395 -> 8525fe62e
SENTRY-215: SHOW GRANT ROLE xxx ON [SERVER, DATABASE, TABLE, URI] xxx (Sravya Tirukkovalur via Prasad Mujumdar) Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/8525fe62 Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/8525fe62 Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/8525fe62 Branch: refs/heads/master Commit: 8525fe62eee72a42178b8e8a64e60dffc9953401 Parents: 2f48193 Author: Prasad Mujumdar <[email protected]> Authored: Mon Jun 2 15:20:52 2014 -0700 Committer: Prasad Mujumdar <[email protected]> Committed: Mon Jun 2 15:20:52 2014 -0700 ---------------------------------------------------------------------- .../hive/ql/exec/SentryGrantRevokeTask.java | 73 ++++++-- .../SentryHiveAuthorizationTaskFactoryImpl.java | 21 +-- .../e2e/dbprovider/TestDatabaseProvider.java | 186 +++++++++++++++++-- 3 files changed, 233 insertions(+), 47 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8525fe62/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 1012605..1f56de7 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 @@ -21,6 +21,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -50,7 +51,12 @@ import org.apache.sentry.binding.hive.authz.HiveAuthzBinding; import org.apache.sentry.binding.hive.conf.HiveAuthzConf; import org.apache.sentry.binding.hive.conf.HiveAuthzConf.AuthzConfVars; 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.db.AccessURI; +import org.apache.sentry.core.model.db.Database; +import org.apache.sentry.core.model.db.Server; +import org.apache.sentry.core.model.db.Table; 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; @@ -126,7 +132,7 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable server, work.getRevokeDesc()); } if (work.getShowGrantDesc() != null) { - return processShowGrantDDL(conf, console, sentryClient, subject.getName(), + return processShowGrantDDL(conf, console, sentryClient, subject.getName(), server, work.getShowGrantDesc()); } if (work.getGrantRevokeRoleDDL() != null) { @@ -248,29 +254,61 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable } private int processShowGrantDDL(HiveConf conf, LogHelper console, SentryPolicyServiceClient sentryClient, - String subject, ShowGrantDesc desc) throws SentryUserException{ + String subject, String server, ShowGrantDesc desc) throws SentryUserException{ PrincipalDesc principalDesc = desc.getPrincipalDesc(); PrivilegeObjectDesc hiveObjectDesc = desc.getHiveObj(); String principalName = principalDesc.getName(); - Set<TSentryPrivilege> privileges; try { + if (principalDesc.getType() != PrincipalType.ROLE) { + String msg = SentryHiveConstants.GRANT_REVOKE_NOT_SUPPORTED_FOR_PRINCIPAL + principalDesc.getType(); + throw new HiveException(msg); + } + if (hiveObjectDesc == null) { - privileges = sentryClient.listAllPrivilegesByRoleName(subject, principalName); - writeToFile(writeGrantInfo(privileges, principalName), desc.getResFile()); - return RETURN_CODE_SUCCESS; + privileges = sentryClient.listPrivilegesByRoleName(subject, principalName, null); } else { - throw new AssertionError("TODO: SHOW GRANT role <roleName> on <objectType> <privilegeLevel>"); + SentryHivePrivilegeObjectDesc privSubjectDesc = toSentryHivePrivilegeObjectDesc(hiveObjectDesc); + List<Authorizable> authorizableHeirarchy = toAuthorizable(privSubjectDesc); + privileges = sentryClient.listPrivilegesByRoleName(subject, principalName, authorizableHeirarchy); } + writeToFile(writeGrantInfo(privileges, principalName), desc.getResFile()); + return RETURN_CODE_SUCCESS; } catch (IOException e) { String msg = "IO Error in show grant " + e.getMessage(); LOG.info(msg, e); console.printError(msg); return RETURN_CODE_FAILURE; + } catch (HiveException e) { + String msg = "Error in show grant operation, error message " + e.getMessage(); + LOG.warn(msg, e); + console.printError(msg); + return RETURN_CODE_FAILURE; } + } + private List<Authorizable> toAuthorizable(SentryHivePrivilegeObjectDesc privSubjectDesc) throws HiveException{ + List<Authorizable> authorizableHeirarchy = new ArrayList<Authorizable>(); + authorizableHeirarchy.add(new Server(server)); + String dbName = null; + if (privSubjectDesc.getTable()) { + DatabaseTable dbTable = parseDBTable(privSubjectDesc.getObject()); + dbName = dbTable.getDatabase(); + String tableName = dbTable.getTable(); + authorizableHeirarchy.add(new Table(tableName)); + authorizableHeirarchy.add(new Database(dbName)); + + } else if (privSubjectDesc.getUri()) { + String uriPath = privSubjectDesc.getObject(); + authorizableHeirarchy.add(new AccessURI(uriPath)); + } else { + dbName = privSubjectDesc.getObject(); + authorizableHeirarchy.add(new Database(dbName)); + } + return authorizableHeirarchy; } + private void writeToFile(String data, String file) throws IOException { Path resFile = new Path(file); FileSystem fs = resFile.getFileSystem(conf); @@ -329,6 +367,9 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable if (PrivilegeScope.URI.name().equalsIgnoreCase( privilege.getPrivilegeScope())) { appendNonNull(builder, privilege.getURI(), true); + } else if(PrivilegeScope.SERVER.name().equalsIgnoreCase( + privilege.getPrivilegeScope())) { + appendNonNull(builder, "*", true);//Db column would show * if it is a server level privilege } else { appendNonNull(builder, privilege.getDbName(), true); } @@ -401,7 +442,7 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable private static int processGrantRevokeDDL(LogHelper console, SentryPolicyServiceClient sentryClient, String subject, String server, boolean isGrant, List<PrincipalDesc> principals, - List<PrivilegeDesc> privileges, + List<PrivilegeDesc> privileges, PrivilegeObjectDesc privSubjectObjDesc) throws SentryUserException { if (privileges == null || privileges.size() == 0) { console.printError("No privilege found."); @@ -413,11 +454,7 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable 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; + SentryHivePrivilegeObjectDesc privSubjectDesc = toSentryHivePrivilegeObjectDesc(privSubjectObjDesc); if (privSubjectDesc == null) { throw new HiveException("Privilege subject cannot be null"); @@ -425,7 +462,6 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable if (privSubjectDesc.getPartSpec() != null) { throw new HiveException(SentryHiveConstants.PARTITION_PRIVS_NOT_SUPPORTED); } - // TODO how to grant all on server String obj = privSubjectDesc.getObject(); if (privSubjectDesc.getTable()) { DatabaseTable dbTable = parseDBTable(obj); @@ -484,6 +520,15 @@ public class SentryGrantRevokeTask extends Task<DDLWork> implements Serializable } } + private static SentryHivePrivilegeObjectDesc toSentryHivePrivilegeObjectDesc(PrivilegeObjectDesc privSubjectObjDesc) + throws HiveException{ + if (!(privSubjectObjDesc instanceof SentryHivePrivilegeObjectDesc)) { + throw new HiveException( + "Privilege subject not parsed correctly by Sentry"); + } + return (SentryHivePrivilegeObjectDesc) privSubjectObjDesc; + } + private static DatabaseTable parseDBTable(String obj) throws HiveException { String[] dbTab = Iterables.toArray(DB_TBL_SPLITTER.split(obj), String.class); if (dbTab.length == 2) { http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8525fe62/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 6d89041..9da020c 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 @@ -216,20 +216,9 @@ public class SentryHiveAuthorizationTaskFactoryImpl implements HiveAuthorization if (ast.getChildCount() > 1) { ASTNode child = (ASTNode) ast.getChild(1); if (child.getToken().getType() == HiveParser.TOK_PRIV_OBJECT_COL) { - privHiveObj = new PrivilegeObjectDesc(); - privHiveObj.setObject(BaseSemanticAnalyzer.unescapeIdentifier(child.getChild(0).getText())); - if (child.getChildCount() > 1) { - for (int i = 1; i < child.getChildCount(); i++) { - ASTNode grandChild = (ASTNode) child.getChild(i); - if (grandChild.getToken().getType() == HiveParser.TOK_PARTSPEC) { - throw new SemanticException(SentryHiveConstants.PARTITION_PRIVS_NOT_SUPPORTED); - } else if (grandChild.getToken().getType() == HiveParser.TOK_TABCOLNAME) { - throw new SemanticException(SentryHiveConstants.COLUMN_PRIVS_NOT_SUPPORTED); - } else { - privHiveObj.setTable(child.getChild(i) != null); - } - } - } + privHiveObj = analyzePrivilegeObject(child); + }else { + throw new SemanticException("Unrecognized Token: " + child.getToken().getType()); } } @@ -302,7 +291,9 @@ public class SentryHiveAuthorizationTaskFactoryImpl implements HiveAuthorization 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) { + } else if (astChild.getToken().getType() == HiveParser.TOK_TABCOLNAME) { + throw new SemanticException(SentryHiveConstants.COLUMN_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) { http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8525fe62/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDatabaseProvider.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDatabaseProvider.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDatabaseProvider.java index 50aadb8..05e5218 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDatabaseProvider.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDatabaseProvider.java @@ -17,6 +17,7 @@ package org.apache.sentry.tests.e2e.dbprovider; +import org.apache.sentry.tests.e2e.hive.StaticUserGroup; import static org.hamcrest.Matchers.equalToIgnoringCase; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -36,6 +37,8 @@ import java.util.concurrent.TimeoutException; import org.apache.commons.io.FileUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; +import org.apache.hadoop.hive.ql.metadata.HiveException; +import org.apache.hive.service.cli.HiveSQLException; import org.apache.sentry.binding.hive.SentryHiveAuthorizationTaskFactoryImpl; import org.apache.sentry.provider.db.SimpleDBProviderBackend; import org.apache.sentry.provider.file.PolicyFile; @@ -53,14 +56,6 @@ import com.google.common.collect.Maps; import com.google.common.io.Files; public class TestDatabaseProvider extends AbstractTestWithDbProvider { - protected static final String SERVER_HOST = "localhost"; - - private Map<String, String> properties; - private File dbDir; - private SentryService server; - private Configuration conf; - private PolicyFile policyFile; - private File policyFilePath; @Before public void setup() throws Exception { @@ -211,26 +206,181 @@ public class TestDatabaseProvider extends AbstractTestWithDbProvider { } /** - * SHOW GRANT ROLE roleName ON OBJECT PRIVILEGE not supported yet + * SHOW GRANT ROLE roleName ON TABLE tableName * @throws Exception */ @Test - public void testShowPrivilegesByRoleAndObject() throws Exception { + public void testShowPrivilegesByRoleOnObjectGivenTable() throws Exception { Connection connection = context.createConnection(ADMIN1); Statement statement = context.createStatement(connection); statement.execute("CREATE ROLE role1"); statement.execute("GRANT SELECT ON TABLE t1 TO ROLE role1"); - try { - ResultSet resultSet = statement.executeQuery("SHOW GRANT ROLE role1 ON TABLE tab1"); - assertTrue("Expected an exception", false); - } catch(SQLException e) { - statement.close(); - connection.close(); + //On table - positive + ResultSet resultSet = statement.executeQuery("SHOW GRANT ROLE role1 ON TABLE t1"); + int rowCount = 0 ; + while ( resultSet.next()) { + rowCount++; + assertThat(resultSet.getString(1), equalToIgnoringCase("default")); + assertThat(resultSet.getString(2), equalToIgnoringCase("t1")); + assertThat(resultSet.getString(3), equalToIgnoringCase(""));//partition + assertThat(resultSet.getString(4), equalToIgnoringCase(""));//column + assertThat(resultSet.getString(5), equalToIgnoringCase("role1"));//principalName + assertThat(resultSet.getString(6), equalToIgnoringCase("role"));//principalType + assertThat(resultSet.getString(7), equalToIgnoringCase("select")); + assertThat(resultSet.getBoolean(8), is(new Boolean("False")));//grantOption + //Create time is not tested + //assertThat(resultSet.getLong(9), is(new Long(0))); + assertThat(resultSet.getString(10), equalToIgnoringCase(ADMIN1));//grantor + } + assertThat(rowCount, is(1)); + //On table - negative + resultSet = statement.executeQuery("SHOW GRANT ROLE role1 ON TABLE tab1"); + rowCount = 0 ; + while (resultSet.next()) { + rowCount++; + } + assertThat(rowCount, is(0)); + statement.close(); + connection.close(); + } + + /** + * SHOW GRANT ROLE roleName ON TABLE tableName + * @throws Exception + */ + @Test + public void testShowPrivilegesByRoleOnObjectGivenDatabase() throws Exception { + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("CREATE ROLE role1"); + statement.execute("GRANT ALL ON DATABASE default TO ROLE role1"); + + //On Table - positive + ResultSet resultSet = statement.executeQuery("SHOW GRANT ROLE role1 ON TABLE tab1"); + int rowCount = 0 ; + while ( resultSet.next()) { + rowCount++; + assertThat(resultSet.getString(1), equalToIgnoringCase("default")); + assertThat(resultSet.getString(2), equalToIgnoringCase("")); + assertThat(resultSet.getString(3), equalToIgnoringCase(""));//partition + assertThat(resultSet.getString(4), equalToIgnoringCase(""));//column + assertThat(resultSet.getString(5), equalToIgnoringCase("role1"));//principalName + assertThat(resultSet.getString(6), equalToIgnoringCase("role"));//principalType + assertThat(resultSet.getString(7), equalToIgnoringCase("*")); + assertThat(resultSet.getBoolean(8), is(new Boolean("False")));//grantOption + //Create time is not tested + //assertThat(resultSet.getLong(9), is(new Long(0))); + assertThat(resultSet.getString(10), equalToIgnoringCase(ADMIN1));//grantor + } + + //On Database - positive + resultSet = statement.executeQuery("SHOW GRANT ROLE role1 ON DATABASE default"); + while ( resultSet.next()) { + assertThat(resultSet.getString(1), equalToIgnoringCase("default")); + assertThat(resultSet.getString(2), equalToIgnoringCase(""));//table + assertThat(resultSet.getString(3), equalToIgnoringCase(""));//partition + assertThat(resultSet.getString(4), equalToIgnoringCase(""));//column + assertThat(resultSet.getString(5), equalToIgnoringCase("role1"));//principalName + assertThat(resultSet.getString(6), equalToIgnoringCase("role"));//principalType + assertThat(resultSet.getString(7), equalToIgnoringCase("*")); + assertThat(resultSet.getBoolean(8), is(new Boolean("False")));//grantOption + //Create time is not tested + //assertThat(resultSet.getLong(9), is(new Long(0))); + assertThat(resultSet.getString(10), equalToIgnoringCase(ADMIN1));//grantor + } + + //On Database - negative + resultSet = statement.executeQuery("SHOW GRANT ROLE role1 ON DATABASE db1"); + rowCount = 0 ; + while (resultSet.next()) { + rowCount++; + } + assertThat(rowCount, is(0)); + statement.close(); + connection.close(); + } + + /** + * SHOW GRANT ROLE roleName ON TABLE tableName + * @throws Exception + */ + @Test + public void testShowPrivilegesByRoleObObjectGivenServer() throws Exception { + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("CREATE ROLE role1"); + statement.execute("GRANT ALL ON SERVER server1 TO ROLE role1"); + + //On table - positive + ResultSet resultSet = statement.executeQuery("SHOW GRANT ROLE role1 ON TABLE tab1"); + while ( resultSet.next()) { + assertThat(resultSet.getString(1), equalToIgnoringCase("*")); + assertThat(resultSet.getString(2), equalToIgnoringCase("")); + assertThat(resultSet.getString(3), equalToIgnoringCase(""));//partition + assertThat(resultSet.getString(4), equalToIgnoringCase(""));//column + assertThat(resultSet.getString(5), equalToIgnoringCase("role1"));//principalName + assertThat(resultSet.getString(6), equalToIgnoringCase("role"));//principalType + assertThat(resultSet.getString(7), equalToIgnoringCase("*")); + assertThat(resultSet.getBoolean(8), is(new Boolean("False")));//grantOption + //Create time is not tested + //assertThat(resultSet.getLong(9), is(new Long(0))); + assertThat(resultSet.getString(10), equalToIgnoringCase(ADMIN1));//grantor + } + + //On Database - postive + resultSet = statement.executeQuery("SHOW GRANT ROLE role1 ON DATABASE default"); + while ( resultSet.next()) { + assertThat(resultSet.getString(1), equalToIgnoringCase("*")); + assertThat(resultSet.getString(2), equalToIgnoringCase("")); + assertThat(resultSet.getString(3), equalToIgnoringCase(""));//partition + assertThat(resultSet.getString(4), equalToIgnoringCase(""));//column + assertThat(resultSet.getString(5), equalToIgnoringCase("role1"));//principalName + assertThat(resultSet.getString(6), equalToIgnoringCase("role"));//principalType + assertThat(resultSet.getString(7), equalToIgnoringCase("*")); + assertThat(resultSet.getBoolean(8), is(new Boolean("False")));//grantOption + //Create time is not tested + //assertThat(resultSet.getLong(9), is(new Long(0))); + assertThat(resultSet.getString(10), equalToIgnoringCase(ADMIN1));//grantor + } + + statement.close(); + connection.close(); + } + + /** + * SHOW GRANT ROLE roleName ON DATABASE dbName: Needs Hive patch + * @throws Exception + */ + @Ignore + @Test + public void testShowPrivilegesByRoleOnUri() throws Exception { + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("CREATE ROLE role1"); + statement.execute("GRANT ALL ON URI 'file:///tmp/file.txt' TO ROLE role1"); + + ResultSet resultSet = statement.executeQuery("SHOW GRANT ROLE role1 ON URI 'file:///tmp/file.txt'"); + assertTrue("Expecting SQL Exception", false); + while ( resultSet.next()) { + assertThat(resultSet.getString(1), equalToIgnoringCase("file:///tmp/file.txt")); + assertThat(resultSet.getString(2), equalToIgnoringCase(""));//table + assertThat(resultSet.getString(3), equalToIgnoringCase(""));//partition + assertThat(resultSet.getString(4), equalToIgnoringCase(""));//column + assertThat(resultSet.getString(5), equalToIgnoringCase("role1"));//principalName + assertThat(resultSet.getString(6), equalToIgnoringCase("role"));//principalType + assertThat(resultSet.getString(7), equalToIgnoringCase("*")); + assertThat(resultSet.getBoolean(8), is(new Boolean("False")));//grantOption + //Create time is not tested + //assertThat(resultSet.getLong(9), is(new Long(0))); + assertThat(resultSet.getString(10), equalToIgnoringCase(ADMIN1));//grantor } + statement.close(); + connection.close(); } + /** - * SHOW CURRENT ROLE not supported yet + * SHOW CURRENT ROLE * @throws Exception */ @Test @@ -250,4 +400,4 @@ public class TestDatabaseProvider extends AbstractTestWithDbProvider { statement.close(); connection.close(); } -} \ No newline at end of file +}
