diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/FunctionSemanticAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/FunctionSemanticAnalyzer.java index 68a25e0..dd6f552 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/FunctionSemanticAnalyzer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/FunctionSemanticAnalyzer.java @@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; +import org.apache.hadoop.hive.metastore.MetaStoreUtils; import org.apache.hadoop.hive.metastore.api.Database; import org.apache.hadoop.hive.metastore.api.ResourceType; import org.apache.hadoop.hive.metastore.api.ResourceUri; @@ -31,6 +32,7 @@ import org.apache.hadoop.hive.ql.exec.FunctionRegistry; import org.apache.hadoop.hive.ql.exec.FunctionUtils; import org.apache.hadoop.hive.ql.exec.TaskFactory; +import org.apache.hadoop.hive.ql.hooks.WriteEntity; import org.apache.hadoop.hive.ql.metadata.Hive; import org.apache.hadoop.hive.ql.metadata.HiveException; import org.apache.hadoop.hive.ql.plan.CreateFunctionDesc; @@ -80,6 +82,8 @@ private void analyzeCreateFunction(ASTNode ast) throws SemanticException { CreateFunctionDesc desc = new CreateFunctionDesc(functionName, isTemporaryFunction, className, resources); rootTasks.add(TaskFactory.get(new FunctionWork(desc), conf)); + + addEntities(functionName, isTemporaryFunction); } private void analyzeDropFunction(ASTNode ast) throws SemanticException { @@ -103,6 +107,8 @@ private void analyzeDropFunction(ASTNode ast) throws SemanticException { boolean isTemporaryFunction = (ast.getFirstChildWithType(HiveParser.TOK_TEMPORARY) != null); DropFunctionDesc desc = new DropFunctionDesc(functionName, isTemporaryFunction); rootTasks.add(TaskFactory.get(new FunctionWork(desc), conf)); + + addEntities(functionName, isTemporaryFunction); } private ResourceType getResourceType(ASTNode token) throws SemanticException { @@ -144,4 +150,28 @@ private ResourceType getResourceType(ASTNode token) throws SemanticException { return resources; } + + /** + * Add write entities to the semantic analyzer to restrict function creation to priviliged users. + */ + private void addEntities(String functionName, boolean isTemporaryFunction) + throws SemanticException { + Database database = null; + if (isTemporaryFunction) { + // This means temp function creation is also restricted. + database = getDatabase(MetaStoreUtils.DEFAULT_DATABASE_NAME); + } else { + try { + String[] qualifiedNameParts = FunctionUtils.getQualifiedFunctionNameParts(functionName); + String dbName = qualifiedNameParts[0]; + database = getDatabase(dbName); + } catch (HiveException e) { + LOG.error(e); + throw new SemanticException(e); + } + } + if (database != null) { + outputs.add(new WriteEntity(database)); + } + } } diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/MacroSemanticAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/MacroSemanticAnalyzer.java index 0ae07e3..4678d74 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/MacroSemanticAnalyzer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/MacroSemanticAnalyzer.java @@ -31,6 +31,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; +import org.apache.hadoop.hive.metastore.MetaStoreUtils; import org.apache.hadoop.hive.metastore.api.Database; import org.apache.hadoop.hive.metastore.api.FieldSchema; import org.apache.hadoop.hive.ql.ErrorMsg; @@ -38,6 +39,7 @@ import org.apache.hadoop.hive.ql.exec.FunctionRegistry; import org.apache.hadoop.hive.ql.exec.FunctionUtils; import org.apache.hadoop.hive.ql.exec.TaskFactory; +import org.apache.hadoop.hive.ql.hooks.WriteEntity; import org.apache.hadoop.hive.ql.lib.Dispatcher; import org.apache.hadoop.hive.ql.lib.Node; import org.apache.hadoop.hive.ql.lib.PreOrderWalker; @@ -138,6 +140,8 @@ public Object dispatch(Node nd, Stack stack, Object... nodeOutputs) } CreateMacroDesc desc = new CreateMacroDesc(functionName, macroColNames, macroColTypes, body); rootTasks.add(TaskFactory.get(new FunctionWork(desc), conf)); + + addEntities(); } @SuppressWarnings("unchecked") @@ -160,5 +164,13 @@ private void analyzeDropMacro(ASTNode ast) throws SemanticException { DropMacroDesc desc = new DropMacroDesc(functionName); rootTasks.add(TaskFactory.get(new FunctionWork(desc), conf)); + + addEntities(); + } + + private void addEntities() throws SemanticException { + Database database = getDatabase(MetaStoreUtils.DEFAULT_DATABASE_NAME); + // This restricts macro creation to privileged users. + outputs.add(new WriteEntity(database)); } } diff --git a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/Operation2Privilege.java b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/Operation2Privilege.java index fae6844..baa5143 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/Operation2Privilege.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/Operation2Privilege.java @@ -160,10 +160,10 @@ op2Priv.put(HiveOperationType.SHOWINDEXES, new InOutPrivs(null, null)); op2Priv.put(HiveOperationType.SHOWPARTITIONS, new InOutPrivs(null, null)); op2Priv.put(HiveOperationType.SHOWLOCKS, new InOutPrivs(null, null)); - op2Priv.put(HiveOperationType.CREATEFUNCTION, new InOutPrivs(null, null)); - op2Priv.put(HiveOperationType.DROPFUNCTION, new InOutPrivs(null, null)); - op2Priv.put(HiveOperationType.CREATEMACRO, new InOutPrivs(null, null)); - op2Priv.put(HiveOperationType.DROPMACRO, new InOutPrivs(null, null)); + op2Priv.put(HiveOperationType.CREATEFUNCTION, new InOutPrivs(null, ADMIN_PRIV_AR)); + op2Priv.put(HiveOperationType.DROPFUNCTION, new InOutPrivs(null, ADMIN_PRIV_AR)); + op2Priv.put(HiveOperationType.CREATEMACRO, new InOutPrivs(null, ADMIN_PRIV_AR)); + op2Priv.put(HiveOperationType.DROPMACRO, new InOutPrivs(null, ADMIN_PRIV_AR)); op2Priv.put(HiveOperationType.LOCKTABLE, new InOutPrivs(null, null)); op2Priv.put(HiveOperationType.UNLOCKTABLE, new InOutPrivs(null, null)); diff --git a/ql/src/test/queries/clientnegative/authorization_create_func1.q b/ql/src/test/queries/clientnegative/authorization_create_func1.q new file mode 100644 index 0000000..1a974ca --- /dev/null +++ b/ql/src/test/queries/clientnegative/authorization_create_func1.q @@ -0,0 +1,7 @@ +set hive.security.authorization.manager=org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory; +set hive.security.authenticator.manager=org.apache.hadoop.hive.ql.security.SessionStateConfigUserAuthenticator; +set hive.security.authorization.enabled=true; +set user.name=hive_test_user; + +-- permanent function creation should fail for non-admin roles +create function perm_fn as 'org.apache.hadoop.hive.ql.udf.UDFAscii'; diff --git a/ql/src/test/queries/clientnegative/authorization_create_func2.q b/ql/src/test/queries/clientnegative/authorization_create_func2.q new file mode 100644 index 0000000..936bf2d --- /dev/null +++ b/ql/src/test/queries/clientnegative/authorization_create_func2.q @@ -0,0 +1,8 @@ +set hive.security.authorization.manager=org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory; +set hive.security.authenticator.manager=org.apache.hadoop.hive.ql.security.SessionStateConfigUserAuthenticator; +set hive.security.authorization.enabled=true; +set user.name=hive_test_user; + +-- temp function creation should fail for non-admin roles +create temporary function temp_fn as 'org.apache.hadoop.hive.ql.udf.UDFAscii'; + diff --git a/ql/src/test/queries/clientnegative/authorization_create_macro1.q b/ql/src/test/queries/clientnegative/authorization_create_macro1.q new file mode 100644 index 0000000..a8d1d3d --- /dev/null +++ b/ql/src/test/queries/clientnegative/authorization_create_macro1.q @@ -0,0 +1,8 @@ +set hive.security.authorization.manager=org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory; +set hive.security.authenticator.manager=org.apache.hadoop.hive.ql.security.SessionStateConfigUserAuthenticator; +set hive.security.authorization.enabled=true; +set user.name=hive_test_user; + +-- temp macro creation should fail for non-admin roles +create temporary macro mymacro1(x double) x * x; + diff --git a/ql/src/test/queries/clientpositive/authorization_create_func1.q b/ql/src/test/queries/clientpositive/authorization_create_func1.q new file mode 100644 index 0000000..47ec439 --- /dev/null +++ b/ql/src/test/queries/clientpositive/authorization_create_func1.q @@ -0,0 +1,14 @@ +set hive.users.in.admin.role=hive_admin_user; +set hive.security.authorization.manager=org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory; +set hive.security.authenticator.manager=org.apache.hadoop.hive.ql.security.SessionStateConfigUserAuthenticator; +set hive.security.authorization.enabled=true; +set user.name=hive_admin_user; + +-- admin required for create function +set role ADMIN; + +create temporary function temp_fn as 'org.apache.hadoop.hive.ql.udf.UDFAscii'; +create function perm_fn as 'org.apache.hadoop.hive.ql.udf.UDFAscii'; + +drop temporary function temp_fn; +drop function perm_fn; diff --git a/ql/src/test/queries/clientpositive/authorization_create_macro1.q b/ql/src/test/queries/clientpositive/authorization_create_macro1.q new file mode 100644 index 0000000..e1fd0fa --- /dev/null +++ b/ql/src/test/queries/clientpositive/authorization_create_macro1.q @@ -0,0 +1,12 @@ +set hive.users.in.admin.role=hive_admin_user; +set hive.security.authorization.manager=org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory; +set hive.security.authenticator.manager=org.apache.hadoop.hive.ql.security.SessionStateConfigUserAuthenticator; +set hive.security.authorization.enabled=true; +set user.name=hive_admin_user; + +-- admin required for create macro +set role ADMIN; + +create temporary macro mymacro1(x double) x * x; + +drop temporary macro mymacro1; diff --git a/ql/src/test/results/clientnegative/authorization_create_func1.q.out b/ql/src/test/results/clientnegative/authorization_create_func1.q.out new file mode 100644 index 0000000..7c72092 --- /dev/null +++ b/ql/src/test/results/clientnegative/authorization_create_func1.q.out @@ -0,0 +1 @@ +FAILED: HiveAccessControlException Permission denied. Principal [name=hive_test_user, type=USER] does not have following privileges on Object [type=DATABASE, name=default] : [ADMIN PRIVILEGE] diff --git a/ql/src/test/results/clientnegative/authorization_create_func2.q.out b/ql/src/test/results/clientnegative/authorization_create_func2.q.out new file mode 100644 index 0000000..7c72092 --- /dev/null +++ b/ql/src/test/results/clientnegative/authorization_create_func2.q.out @@ -0,0 +1 @@ +FAILED: HiveAccessControlException Permission denied. Principal [name=hive_test_user, type=USER] does not have following privileges on Object [type=DATABASE, name=default] : [ADMIN PRIVILEGE] diff --git a/ql/src/test/results/clientnegative/authorization_create_macro1.q.out b/ql/src/test/results/clientnegative/authorization_create_macro1.q.out new file mode 100644 index 0000000..7c72092 --- /dev/null +++ b/ql/src/test/results/clientnegative/authorization_create_macro1.q.out @@ -0,0 +1 @@ +FAILED: HiveAccessControlException Permission denied. Principal [name=hive_test_user, type=USER] does not have following privileges on Object [type=DATABASE, name=default] : [ADMIN PRIVILEGE] diff --git a/ql/src/test/results/clientpositive/authorization_create_func1.q.out b/ql/src/test/results/clientpositive/authorization_create_func1.q.out new file mode 100644 index 0000000..45f93ba --- /dev/null +++ b/ql/src/test/results/clientpositive/authorization_create_func1.q.out @@ -0,0 +1,30 @@ +PREHOOK: query: -- admin required for create function +set role ADMIN +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: -- admin required for create function +set role ADMIN +POSTHOOK: type: SHOW_ROLES +PREHOOK: query: create temporary function temp_fn as 'org.apache.hadoop.hive.ql.udf.UDFAscii' +PREHOOK: type: CREATEFUNCTION +PREHOOK: Output: database:default +POSTHOOK: query: create temporary function temp_fn as 'org.apache.hadoop.hive.ql.udf.UDFAscii' +POSTHOOK: type: CREATEFUNCTION +POSTHOOK: Output: database:default +PREHOOK: query: create function perm_fn as 'org.apache.hadoop.hive.ql.udf.UDFAscii' +PREHOOK: type: CREATEFUNCTION +PREHOOK: Output: database:default +POSTHOOK: query: create function perm_fn as 'org.apache.hadoop.hive.ql.udf.UDFAscii' +POSTHOOK: type: CREATEFUNCTION +POSTHOOK: Output: database:default +PREHOOK: query: drop temporary function temp_fn +PREHOOK: type: DROPFUNCTION +PREHOOK: Output: database:default +POSTHOOK: query: drop temporary function temp_fn +POSTHOOK: type: DROPFUNCTION +POSTHOOK: Output: database:default +PREHOOK: query: drop function perm_fn +PREHOOK: type: DROPFUNCTION +PREHOOK: Output: database:default +POSTHOOK: query: drop function perm_fn +POSTHOOK: type: DROPFUNCTION +POSTHOOK: Output: database:default diff --git a/ql/src/test/results/clientpositive/authorization_create_macro1.q.out b/ql/src/test/results/clientpositive/authorization_create_macro1.q.out new file mode 100644 index 0000000..9932cdd --- /dev/null +++ b/ql/src/test/results/clientpositive/authorization_create_macro1.q.out @@ -0,0 +1,18 @@ +PREHOOK: query: -- admin required for create macro +set role ADMIN +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: -- admin required for create macro +set role ADMIN +POSTHOOK: type: SHOW_ROLES +PREHOOK: query: create temporary macro mymacro1(x double) x * x +PREHOOK: type: CREATEMACRO +PREHOOK: Output: database:default +POSTHOOK: query: create temporary macro mymacro1(x double) x * x +POSTHOOK: type: CREATEMACRO +POSTHOOK: Output: database:default +PREHOOK: query: drop temporary macro mymacro1 +PREHOOK: type: DROPMACRO +PREHOOK: Output: database:default +POSTHOOK: query: drop temporary macro mymacro1 +POSTHOOK: type: DROPMACRO +POSTHOOK: Output: database:default