This is an automated email from the ASF dual-hosted git repository.
peter-toth pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new c79692e43ac0 [SPARK-57882][SQL] Enforce AuthV2 metadata authorization
on GetPrimaryKeys and GetCrossReference operations
c79692e43ac0 is described below
commit c79692e43ac07aaf80955f2aa43bf4ae8e9b7d9d
Author: Peter Toth <[email protected]>
AuthorDate: Fri Jul 3 18:11:54 2026 +0200
[SPARK-57882][SQL] Enforce AuthV2 metadata authorization on GetPrimaryKeys
and GetCrossReference operations
### What changes were proposed in this pull request?
Add the `isAuthV2Enabled()/authorizeMetaGets()` authorization gate to
`GetPrimaryKeysOperation.runInternal()` and
`GetCrossReferenceOperation.runInternal()` in the Hive Thrift server, mirroring
the pattern already used by the sibling `MetadataOperation` subclasses
(`GetTablesOperation`, `GetColumnsOperation`, etc.). The check uses
table-scoped `TABLE_OR_VIEW` privilege objects for the referenced table(s);
`GetCrossReferenceOperation` handles the `getImportedKeys`/`getExportedKeys`
cas [...]
### Why are the changes needed?
When Hive AuthV2 authorization is configured
(`hive.security.authorization.manager` set to a `HiveAuthorizerFactory` with
authorization enabled), metadata operations gate metastore access through
`authorizeMetaGets`. Every sibling `MetadataOperation` subclass does this, and
Spark's own `SparkGet*Operation` classes do too. `GetPrimaryKeysOperation` and
`GetCrossReferenceOperation` are the only metadata operations that omit the
gate, and `SparkSQLOperationManager` does not override them [...]
### Does this PR introduce _any_ user-facing change?
Only when Hive AuthV2 authorization is enabled:
`DatabaseMetaData.getPrimaryKeys`/`getImportedKeys`/`getExportedKeys`/`getCrossReference`
now perform the same authorization check as the other metadata calls, and
access to unauthorized tables' key metadata is rejected. With authorization
disabled (the default), behavior is unchanged.
### How was this patch tested?
Compiled `hive-thriftserver` and ran the existing
`SparkMetadataOperationSuite` (15 tests, all passing). The gate is a no-op when
authorization is disabled, which is the path the suite exercises, so behavior
is unchanged there.
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 4.8)
Closes #56962 from peter-toth/SPARK-57882-authv2-metadata-gate-pk-fk.
Authored-by: Peter Toth <[email protected]>
Signed-off-by: Peter Toth <[email protected]>
---
.../cli/operation/GetCrossReferenceOperation.java | 25 ++++++++++++++++++++++
.../cli/operation/GetPrimaryKeysOperation.java | 16 ++++++++++++++
2 files changed, 41 insertions(+)
diff --git
a/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/operation/GetCrossReferenceOperation.java
b/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/operation/GetCrossReferenceOperation.java
index 3a29859a2074..04a6d50ad649 100644
---
a/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/operation/GetCrossReferenceOperation.java
+++
b/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/operation/GetCrossReferenceOperation.java
@@ -20,12 +20,16 @@ package org.apache.hive.service.cli.operation;
import org.apache.hadoop.hive.metastore.IMetaStoreClient;
import org.apache.hadoop.hive.metastore.api.ForeignKeysRequest;
import org.apache.hadoop.hive.metastore.api.SQLForeignKey;
+import
org.apache.hadoop.hive.ql.security.authorization.plugin.HiveOperationType;
+import
org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject;
+import
org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject.HivePrivilegeObjectType;
import org.apache.hadoop.hive.serde2.thrift.Type;
import org.apache.hive.service.cli.*;
import org.apache.hive.service.cli.session.HiveSession;
import org.apache.hive.service.rpc.thrift.TRowSet;
import org.apache.hive.service.rpc.thrift.TTableSchema;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -117,6 +121,27 @@ public class GetCrossReferenceOperation extends
MetadataOperation {
setState(OperationState.RUNNING);
try {
IMetaStoreClient metastoreClient =
getParentSession().getMetaStoreClient();
+ if (isAuthV2Enabled()) {
+ List<HivePrivilegeObject> privObjs = new ArrayList<>();
+ if (parentTableName != null) {
+ privObjs.add(new HivePrivilegeObject(
+ HivePrivilegeObjectType.TABLE_OR_VIEW, parentSchemaName,
parentTableName));
+ }
+ if (foreignTableName != null) {
+ privObjs.add(new HivePrivilegeObject(
+ HivePrivilegeObjectType.TABLE_OR_VIEW, foreignSchemaName,
foreignTableName));
+ }
+ String cmdStr = "catalog : " + parentCatalogName
+ + ", parentSchema : " + parentSchemaName + ", parentTable : " +
parentTableName
+ + ", foreignSchema : " + foreignSchemaName + ", foreignTable : " +
foreignTableName;
+ if (privObjs.isEmpty()) {
+ // Neither table is specified, so the request cannot be scoped to
any privilege object;
+ // reject it instead of skipping the authorization check.
+ throw new HiveSQLException(
+ "Access denied: neither parent nor foreign table specified. " +
cmdStr);
+ }
+ authorizeMetaGets(HiveOperationType.GET_COLUMNS, privObjs, cmdStr);
+ }
ForeignKeysRequest fkReq = new ForeignKeysRequest(parentSchemaName,
parentTableName, foreignSchemaName, foreignTableName);
List<SQLForeignKey> fks = metastoreClient.getForeignKeys(fkReq);
if (fks == null) {
diff --git
a/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/operation/GetPrimaryKeysOperation.java
b/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/operation/GetPrimaryKeysOperation.java
index 927328342974..c7dd29e7305c 100644
---
a/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/operation/GetPrimaryKeysOperation.java
+++
b/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/operation/GetPrimaryKeysOperation.java
@@ -20,12 +20,16 @@ package org.apache.hive.service.cli.operation;
import org.apache.hadoop.hive.metastore.IMetaStoreClient;
import org.apache.hadoop.hive.metastore.api.PrimaryKeysRequest;
import org.apache.hadoop.hive.metastore.api.SQLPrimaryKey;
+import
org.apache.hadoop.hive.ql.security.authorization.plugin.HiveOperationType;
+import
org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject;
+import
org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject.HivePrivilegeObjectType;
import org.apache.hadoop.hive.serde2.thrift.Type;
import org.apache.hive.service.cli.*;
import org.apache.hive.service.cli.session.HiveSession;
import org.apache.hive.service.rpc.thrift.TRowSet;
import org.apache.hive.service.rpc.thrift.TTableSchema;
+import java.util.Collections;
import java.util.List;
/**
@@ -75,6 +79,18 @@ public class GetPrimaryKeysOperation extends
MetadataOperation {
setState(OperationState.RUNNING);
try {
IMetaStoreClient metastoreClient =
getParentSession().getMetaStoreClient();
+ if (isAuthV2Enabled()) {
+ String cmdStr = "catalog : " + catalogName + ", schema : " + schemaName
+ + ", table : " + tableName;
+ if (tableName == null) {
+ // The request cannot be scoped to a privilege object without a
table name; reject it
+ // instead of skipping the authorization check.
+ throw new HiveSQLException("Access denied: no table specified. " +
cmdStr);
+ }
+ List<HivePrivilegeObject> privObjs = Collections.singletonList(
+ new HivePrivilegeObject(HivePrivilegeObjectType.TABLE_OR_VIEW,
schemaName, tableName));
+ authorizeMetaGets(HiveOperationType.GET_COLUMNS, privObjs, cmdStr);
+ }
PrimaryKeysRequest sqlReq = new PrimaryKeysRequest(schemaName,
tableName);
List<SQLPrimaryKey> pks = metastoreClient.getPrimaryKeys(sqlReq);
if (pks == null) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]