Skip to content

Commit

Permalink
HIVE-8611: grant/revoke syntax should support additional objects for …
Browse files Browse the repository at this point in the history
…authorization plugins (Prasad Mujumdar, reviewed by Brock Noland)

git-svn-id: https://svn.apache.org/repos/asf/hive/trunk@1638001 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
pmujumdar committed Nov 11, 2014
1 parent d3dff34 commit aa394b9
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 3 deletions.
3 changes: 3 additions & 0 deletions common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,9 @@ public static enum ConfVars {
"An example like \"select,drop\" will grant select and drop privilege to the owner\n" +
"of the table. Note that the default gives the creator of a table no access to the\n" +
"table (but see HIVE-8067)."),
HIVE_AUTHORIZATION_TASK_FACTORY("hive.security.authorization.task.factory",
"org.apache.hadoop.hive.ql.parse.authorization.HiveAuthorizationTaskFactoryImpl",
"Authorization DDL task factory implementation"),

// if this is not set default value is set during config initialization
// Default value can't be set in this constructor as it would refer names in other ConfVars
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import static org.apache.hadoop.hive.ql.parse.HiveParser.TOK_DATABASEPROPERTIES;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
Expand Down Expand Up @@ -229,7 +231,7 @@ public DDLSemanticAnalyzer(HiveConf conf, Hive db) throws SemanticException {
reservedPartitionValues.add(HiveConf.getVar(conf, ConfVars.METASTORE_INT_ORIGINAL));
reservedPartitionValues.add(HiveConf.getVar(conf, ConfVars.METASTORE_INT_ARCHIVED));
reservedPartitionValues.add(HiveConf.getVar(conf, ConfVars.METASTORE_INT_EXTRACTED));
hiveAuthorizationTaskFactory = new HiveAuthorizationTaskFactoryImpl(conf, db);
hiveAuthorizationTaskFactory = createAuthorizationTaskFactory(conf, db);
}

@Override
Expand Down Expand Up @@ -3419,4 +3421,30 @@ private void validateSkewedLocationString(String newLocation) throws SemanticExc
throw new SemanticException(e);
}
}

private HiveAuthorizationTaskFactory createAuthorizationTaskFactory(HiveConf conf, Hive db) {
Class<? extends HiveAuthorizationTaskFactory> authProviderClass = conf.
getClass(HiveConf.ConfVars.HIVE_AUTHORIZATION_TASK_FACTORY.varname,
HiveAuthorizationTaskFactoryImpl.class,
HiveAuthorizationTaskFactory.class);
String msg = "Unable to create instance of " + authProviderClass.getName() + ": ";
try {
Constructor<? extends HiveAuthorizationTaskFactory> constructor =
authProviderClass.getConstructor(HiveConf.class, Hive.class);
return constructor.newInstance(conf, db);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(msg + e.getMessage(), e);
} catch (SecurityException e) {
throw new IllegalStateException(msg + e.getMessage(), e);
} catch (InstantiationException e) {
throw new IllegalStateException(msg + e.getMessage(), e);
} catch (IllegalAccessException e) {
throw new IllegalStateException(msg + e.getMessage(), e);
} catch (IllegalArgumentException e) {
throw new IllegalStateException(msg + e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new IllegalStateException(msg + e.getMessage(), e);
}
}

}
2 changes: 2 additions & 0 deletions ql/src/java/org/apache/hadoop/hive/ql/parse/HiveLexer.g
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ KW_ROLE: 'ROLE';
KW_ROLES: 'ROLES';
KW_INNER: 'INNER';
KW_EXCHANGE: 'EXCHANGE';
KW_URI: 'URI';
KW_SERVER : 'SERVER';
KW_ADMIN: 'ADMIN';
KW_OWNER: 'OWNER';
KW_PRINCIPALS: 'PRINCIPALS';
Expand Down
6 changes: 6 additions & 0 deletions ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ TOK_VIRTUAL_TABLE;
TOK_VIRTUAL_TABREF;
TOK_ANONYMOUS;
TOK_COL_NAME;
TOK_URI_TYPE;
TOK_SERVER_TYPE;
}


Expand Down Expand Up @@ -1485,11 +1487,15 @@ privilegeObject
privObject
: (KW_DATABASE|KW_SCHEMA) identifier -> ^(TOK_DB_TYPE identifier)
| KW_TABLE? tableName partitionSpec? -> ^(TOK_TABLE_TYPE tableName partitionSpec?)
| KW_URI (path=StringLiteral) -> ^(TOK_URI_TYPE $path)
| KW_SERVER identifier -> ^(TOK_SERVER_TYPE identifier)
;
privObjectCols
: (KW_DATABASE|KW_SCHEMA) identifier -> ^(TOK_DB_TYPE identifier)
| KW_TABLE? tableName (LPAREN cols=columnNameList RPAREN)? partitionSpec? -> ^(TOK_TABLE_TYPE tableName $cols? partitionSpec?)
| KW_URI (path=StringLiteral) -> ^(TOK_URI_TYPE $path)
| KW_SERVER identifier -> ^(TOK_SERVER_TYPE identifier)
;
privilegeList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -545,5 +545,5 @@ principalIdentifier

nonReserved
:
KW_TRUE | KW_FALSE | KW_LIKE | KW_EXISTS | KW_ASC | KW_DESC | KW_ORDER | KW_GROUP | KW_BY | KW_AS | KW_INSERT | KW_OVERWRITE | KW_OUTER | KW_LEFT | KW_RIGHT | KW_FULL | KW_PARTITION | KW_PARTITIONS | KW_TABLE | KW_TABLES | KW_COLUMNS | KW_INDEX | KW_INDEXES | KW_REBUILD | KW_FUNCTIONS | KW_SHOW | KW_MSCK | KW_REPAIR | KW_DIRECTORY | KW_LOCAL | KW_USING | KW_CLUSTER | KW_DISTRIBUTE | KW_SORT | KW_UNION | KW_LOAD | KW_EXPORT | KW_IMPORT | KW_DATA | KW_INPATH | KW_IS | KW_NULL | KW_CREATE | KW_EXTERNAL | KW_ALTER | KW_CHANGE | KW_FIRST | KW_AFTER | KW_DESCRIBE | KW_DROP | KW_RENAME | KW_IGNORE | KW_PROTECTION | KW_TO | KW_COMMENT | KW_BOOLEAN | KW_TINYINT | KW_SMALLINT | KW_INT | KW_BIGINT | KW_FLOAT | KW_DOUBLE | KW_DATE | KW_DATETIME | KW_TIMESTAMP | KW_DECIMAL | KW_STRING | KW_ARRAY | KW_STRUCT | KW_UNIONTYPE | KW_PARTITIONED | KW_CLUSTERED | KW_SORTED | KW_INTO | KW_BUCKETS | KW_ROW | KW_ROWS | KW_FORMAT | KW_DELIMITED | KW_FIELDS | KW_TERMINATED | KW_ESCAPED | KW_COLLECTION | KW_ITEMS | KW_KEYS | KW_KEY_TYPE | KW_LINES | KW_STORED | KW_FILEFORMAT | KW_INPUTFORMAT | KW_OUTPUTFORMAT | KW_INPUTDRIVER | KW_OUTPUTDRIVER | KW_OFFLINE | KW_ENABLE | KW_DISABLE | KW_READONLY | KW_NO_DROP | KW_LOCATION | KW_BUCKET | KW_OUT | KW_OF | KW_PERCENT | KW_ADD | KW_REPLACE | KW_RLIKE | KW_REGEXP | KW_TEMPORARY | KW_EXPLAIN | KW_FORMATTED | KW_PRETTY | KW_DEPENDENCY | KW_LOGICAL | KW_SERDE | KW_WITH | KW_DEFERRED | KW_SERDEPROPERTIES | KW_DBPROPERTIES | KW_LIMIT | KW_SET | KW_UNSET | KW_TBLPROPERTIES | KW_IDXPROPERTIES | KW_VALUE_TYPE | KW_ELEM_TYPE | KW_MAPJOIN | KW_STREAMTABLE | KW_HOLD_DDLTIME | KW_CLUSTERSTATUS | KW_UTC | KW_UTCTIMESTAMP | KW_LONG | KW_DELETE | KW_PLUS | KW_MINUS | KW_FETCH | KW_INTERSECT | KW_VIEW | KW_IN | KW_DATABASES | KW_MATERIALIZED | KW_SCHEMA | KW_SCHEMAS | KW_GRANT | KW_REVOKE | KW_SSL | KW_UNDO | KW_LOCK | KW_LOCKS | KW_UNLOCK | KW_SHARED | KW_EXCLUSIVE | KW_PROCEDURE | KW_UNSIGNED | KW_WHILE | KW_READ | KW_READS | KW_PURGE | KW_RANGE | KW_ANALYZE | KW_BEFORE | KW_BETWEEN | KW_BOTH | KW_BINARY | KW_CONTINUE | KW_CURSOR | KW_TRIGGER | KW_RECORDREADER | KW_RECORDWRITER | KW_SEMI | KW_LATERAL | KW_TOUCH | KW_ARCHIVE | KW_UNARCHIVE | KW_COMPUTE | KW_STATISTICS | KW_USE | KW_OPTION | KW_CONCATENATE | KW_SHOW_DATABASE | KW_UPDATE | KW_RESTRICT | KW_CASCADE | KW_SKEWED | KW_ROLLUP | KW_CUBE | KW_DIRECTORIES | KW_FOR | KW_GROUPING | KW_SETS | KW_TRUNCATE | KW_NOSCAN | KW_USER | KW_ROLE | KW_ROLES | KW_INNER | KW_DEFINED | KW_ADMIN | KW_JAR | KW_FILE | KW_OWNER | KW_PRINCIPALS | KW_ALL | KW_DEFAULT | KW_NONE | KW_COMPACT | KW_COMPACTIONS | KW_TRANSACTIONS | KW_REWRITE | KW_AUTHORIZATION | KW_VALUES
KW_TRUE | KW_FALSE | KW_LIKE | KW_EXISTS | KW_ASC | KW_DESC | KW_ORDER | KW_GROUP | KW_BY | KW_AS | KW_INSERT | KW_OVERWRITE | KW_OUTER | KW_LEFT | KW_RIGHT | KW_FULL | KW_PARTITION | KW_PARTITIONS | KW_TABLE | KW_TABLES | KW_COLUMNS | KW_INDEX | KW_INDEXES | KW_REBUILD | KW_FUNCTIONS | KW_SHOW | KW_MSCK | KW_REPAIR | KW_DIRECTORY | KW_LOCAL | KW_USING | KW_CLUSTER | KW_DISTRIBUTE | KW_SORT | KW_UNION | KW_LOAD | KW_EXPORT | KW_IMPORT | KW_DATA | KW_INPATH | KW_IS | KW_NULL | KW_CREATE | KW_EXTERNAL | KW_ALTER | KW_CHANGE | KW_FIRST | KW_AFTER | KW_DESCRIBE | KW_DROP | KW_RENAME | KW_IGNORE | KW_PROTECTION | KW_TO | KW_COMMENT | KW_BOOLEAN | KW_TINYINT | KW_SMALLINT | KW_INT | KW_BIGINT | KW_FLOAT | KW_DOUBLE | KW_DATE | KW_DATETIME | KW_TIMESTAMP | KW_DECIMAL | KW_STRING | KW_ARRAY | KW_STRUCT | KW_UNIONTYPE | KW_PARTITIONED | KW_CLUSTERED | KW_SORTED | KW_INTO | KW_BUCKETS | KW_ROW | KW_ROWS | KW_FORMAT | KW_DELIMITED | KW_FIELDS | KW_TERMINATED | KW_ESCAPED | KW_COLLECTION | KW_ITEMS | KW_KEYS | KW_KEY_TYPE | KW_LINES | KW_STORED | KW_FILEFORMAT | KW_INPUTFORMAT | KW_OUTPUTFORMAT | KW_INPUTDRIVER | KW_OUTPUTDRIVER | KW_OFFLINE | KW_ENABLE | KW_DISABLE | KW_READONLY | KW_NO_DROP | KW_LOCATION | KW_BUCKET | KW_OUT | KW_OF | KW_PERCENT | KW_ADD | KW_REPLACE | KW_RLIKE | KW_REGEXP | KW_TEMPORARY | KW_EXPLAIN | KW_FORMATTED | KW_PRETTY | KW_DEPENDENCY | KW_LOGICAL | KW_SERDE | KW_WITH | KW_DEFERRED | KW_SERDEPROPERTIES | KW_DBPROPERTIES | KW_LIMIT | KW_SET | KW_UNSET | KW_TBLPROPERTIES | KW_IDXPROPERTIES | KW_VALUE_TYPE | KW_ELEM_TYPE | KW_MAPJOIN | KW_STREAMTABLE | KW_HOLD_DDLTIME | KW_CLUSTERSTATUS | KW_UTC | KW_UTCTIMESTAMP | KW_LONG | KW_DELETE | KW_PLUS | KW_MINUS | KW_FETCH | KW_INTERSECT | KW_VIEW | KW_IN | KW_DATABASES | KW_MATERIALIZED | KW_SCHEMA | KW_SCHEMAS | KW_GRANT | KW_REVOKE | KW_SSL | KW_UNDO | KW_LOCK | KW_LOCKS | KW_UNLOCK | KW_SHARED | KW_EXCLUSIVE | KW_PROCEDURE | KW_UNSIGNED | KW_WHILE | KW_READ | KW_READS | KW_PURGE | KW_RANGE | KW_ANALYZE | KW_BEFORE | KW_BETWEEN | KW_BOTH | KW_BINARY | KW_CONTINUE | KW_CURSOR | KW_TRIGGER | KW_RECORDREADER | KW_RECORDWRITER | KW_SEMI | KW_LATERAL | KW_TOUCH | KW_ARCHIVE | KW_UNARCHIVE | KW_COMPUTE | KW_STATISTICS | KW_USE | KW_OPTION | KW_CONCATENATE | KW_SHOW_DATABASE | KW_UPDATE | KW_RESTRICT | KW_CASCADE | KW_SKEWED | KW_ROLLUP | KW_CUBE | KW_DIRECTORIES | KW_FOR | KW_GROUPING | KW_SETS | KW_TRUNCATE | KW_NOSCAN | KW_USER | KW_ROLE | KW_ROLES | KW_INNER | KW_DEFINED | KW_ADMIN | KW_JAR | KW_FILE | KW_OWNER | KW_PRINCIPALS | KW_ALL | KW_DEFAULT | KW_NONE | KW_COMPACT | KW_COMPACTIONS | KW_TRANSACTIONS | KW_REWRITE | KW_AUTHORIZATION | KW_VALUES | KW_URI | KW_SERVER
;
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.HashSet;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hive.common.classification.InterfaceAudience.LimitedPrivate;
import org.apache.hadoop.hive.common.classification.InterfaceStability.Evolving;
import org.apache.hadoop.hive.ql.exec.Task;
import org.apache.hadoop.hive.ql.hooks.ReadEntity;
import org.apache.hadoop.hive.ql.hooks.WriteEntity;
Expand All @@ -32,6 +34,8 @@
* tasks. Every method in this class may return null, indicating no task
* needs to be executed or can throw a SemanticException.
*/
@LimitedPrivate(value = { "Apache Hive, Apache Sentry (incubating)" })
@Evolving
public interface HiveAuthorizationTaskFactory {
public Task<? extends Serializable> createCreateRoleTask(ASTNode node, HashSet<ReadEntity> inputs,
HashSet<WriteEntity> outputs) throws SemanticException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,16 @@ private PrivilegeObjectDesc analyzePrivilegeObject(ASTNode ast,
return subject;
}

private PrivilegeObjectDesc parsePrivObject(ASTNode ast) throws SemanticException {
protected PrivilegeObjectDesc parsePrivObject(ASTNode ast) throws SemanticException {
PrivilegeObjectDesc subject = new PrivilegeObjectDesc();
ASTNode child = (ASTNode) ast.getChild(0);
ASTNode gchild = (ASTNode)child.getChild(0);
if (child.getType() == HiveParser.TOK_TABLE_TYPE) {
subject.setTable(true);
String[] qualified = BaseSemanticAnalyzer.getQualifiedTableName(gchild);
subject.setObject(BaseSemanticAnalyzer.getDotName(qualified));
} else if (child.getType() == HiveParser.TOK_URI_TYPE || child.getType() == HiveParser.TOK_SERVER_TYPE) {
throw new SemanticException("Hive authorization does not support the URI or SERVER objects");
} else {
subject.setTable(false);
subject.setObject(BaseSemanticAnalyzer.unescapeIdentifier(gchild.getText()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,23 @@
import junit.framework.Assert;

import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
import org.apache.hadoop.hive.metastore.api.PrincipalType;
import org.apache.hadoop.hive.ql.Context;
import org.apache.hadoop.hive.ql.metadata.Hive;
import org.apache.hadoop.hive.ql.metadata.Partition;
import org.apache.hadoop.hive.ql.metadata.Table;
import org.apache.hadoop.hive.ql.parse.ASTNode;
import org.apache.hadoop.hive.ql.parse.DDLSemanticAnalyzer;
import org.apache.hadoop.hive.ql.parse.HiveParser;
import org.apache.hadoop.hive.ql.parse.ParseDriver;
import org.apache.hadoop.hive.ql.parse.SemanticException;
import org.apache.hadoop.hive.ql.plan.DDLWork;
import org.apache.hadoop.hive.ql.plan.GrantDesc;
import org.apache.hadoop.hive.ql.plan.GrantRevokeRoleDDL;
import org.apache.hadoop.hive.ql.plan.PrincipalDesc;
import org.apache.hadoop.hive.ql.plan.PrivilegeDesc;
import org.apache.hadoop.hive.ql.plan.PrivilegeObjectDesc;
import org.apache.hadoop.hive.ql.plan.RevokeDesc;
import org.apache.hadoop.hive.ql.plan.RoleDDLDesc;
import org.apache.hadoop.hive.ql.plan.RoleDDLDesc.RoleOperation;
Expand All @@ -47,6 +52,33 @@

public class TestHiveAuthorizationTaskFactory {

public static class DummyHiveAuthorizationTaskFactoryImpl extends HiveAuthorizationTaskFactoryImpl {

static String uriPath = "";
static String serverName = "";

public DummyHiveAuthorizationTaskFactoryImpl(HiveConf conf, Hive db) {
super(conf, db);
}

@Override
protected PrivilegeObjectDesc parsePrivObject(ASTNode ast) throws SemanticException {
ASTNode child = (ASTNode) ast.getChild(0);
ASTNode gchild = (ASTNode)child.getChild(0);
if (child.getType() == HiveParser.TOK_URI_TYPE) {
uriPath = gchild.getText().replaceAll("'", "").replaceAll("\"", "");
} else if (child.getType() == HiveParser.TOK_SERVER_TYPE) {
serverName = gchild.getText();
}
return super.parsePrivObject(ast);
}

public static void reset() {
uriPath = "";
serverName = "";
}
}

private static final String SELECT = "SELECT";
private static final String DB = "default";
private static final String TABLE = "table1";
Expand All @@ -67,6 +99,8 @@ public class TestHiveAuthorizationTaskFactory {
@Before
public void setup() throws Exception {
conf = new HiveConf();
conf.setVar(ConfVars.HIVE_AUTHORIZATION_TASK_FACTORY,
TestHiveAuthorizationTaskFactory.DummyHiveAuthorizationTaskFactoryImpl.class.getName());
db = Mockito.mock(Hive.class);
table = new Table(DB, TABLE);
partition = new Partition(table);
Expand All @@ -81,6 +115,7 @@ public void setup() throws Exception {
HadoopDefaultAuthenticator auth = new HadoopDefaultAuthenticator();
auth.setConf(conf);
currentUser = auth.getUserName();
DummyHiveAuthorizationTaskFactoryImpl.reset();

}
/**
Expand Down Expand Up @@ -414,6 +449,34 @@ public void testShowGrantGroupOnTable() throws Exception {
Assert.assertTrue("Expected table", grantDesc.getHiveObj().getTable());
}

/**
* GRANT ALL ON URI
*/
@Test
public void testGrantUri() throws Exception {
String uriPath = "/tmp";
try {
analyze("GRANT ALL ON URI '" + uriPath + "' TO USER user2");
Assert.fail("Grant on URI should fail");
} catch (SemanticException e) {
Assert.assertEquals(uriPath, DummyHiveAuthorizationTaskFactoryImpl.uriPath);
}
}

/**
* GRANT ALL ON SERVER
*/
@Test
public void testGrantServer() throws Exception {
String serverName = "foo";
try {
analyze("GRANT ALL ON SERVER " + serverName + " TO USER user2");
Assert.fail("Grant on Server should fail");
} catch (SemanticException e) {
Assert.assertEquals(serverName, DummyHiveAuthorizationTaskFactoryImpl.serverName);
}
}

private DDLWork analyze(String command) throws Exception {
return AuthorizationTestUtil.analyze(command, conf, db);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
set hive.test.authz.sstd.hs2.mode=true;
set hive.security.authorization.manager=org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactoryForTest;
set hive.security.authenticator.manager=org.apache.hadoop.hive.ql.security.SessionStateConfigUserAuthenticator;

set user.name=user1;

-- grant insert on group should fail
GRANT ALL ON SERVER foo TO user user2;
9 changes: 9 additions & 0 deletions ql/src/test/queries/clientnegative/authorization_grant_uri.q
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
set hive.test.authz.sstd.hs2.mode=true;
set hive.security.authorization.manager=org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactoryForTest;
set hive.security.authenticator.manager=org.apache.hadoop.hive.ql.security.SessionStateConfigUserAuthenticator;

set user.name=user1;
-- current user has been set (comment line before the set cmd is resulting in parse error!!)

-- grant insert on group should fail
GRANT ALL ON URI '/tmp' TO user user2;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FAILED: SemanticException Hive authorization does not support the URI or SERVER objects
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FAILED: SemanticException Hive authorization does not support the URI or SERVER objects

0 comments on commit aa394b9

Please sign in to comment.