Skip to content

[#12560] feat(lance): Add table read and list authorization for Lance REST - #12694

Merged
yuqi1129 merged 1 commit into
apache:mainfrom
yuqi1129:feat/12560-lance-table-read-authz
Sep 2, 2026
Merged

[#12560] feat(lance): Add table read and list authorization for Lance REST#12694
yuqi1129 merged 1 commit into
apache:mainfrom
yuqi1129:feat/12560-lance-table-read-authz

Conversation

@yuqi1129

Copy link
Copy Markdown
Contributor

Draft: depends on #12693 (#12559). This branch is stacked on it, so the diff shown here includes that PR's commit until it merges. Rebase onto main after #12693 lands.

What changes were proposed in this pull request?

Authorizes the read-only Lance REST table operations.

  • describe-table requires the standard load-table privileges. table-exists additionally accepts CREATE_TABLE, because clients probe for a table immediately before creating it; describe-table deliberately does not, so a probe privilege never exposes a table's schema, properties, or storage options.
  • list-tables is authorized on the addressed schema, and the tables the caller may not see are removed before the page is cut, so pagination stays consistent with what the caller is allowed to see. This adds a filterTables hook to LanceMetadataFilter, implemented against FILTER_TABLE_AUTHORIZATION_EXPRESSION — which carries the parent-scope short-circuit and deny precedence used by the rest of Gravitino.
  • A Lance identifier carries its depth rather than its kind, so the interceptor now resolves a three-level identifier to a table, and every table expression is guarded on the addressed entity type. An identifier of the wrong depth for an operation matches no branch and is denied, rather than being silently authorized against another entity.

Credential vending stays out of scope.

Fix: #12560

Why are the changes needed?

The Lance REST table surface was still unauthorized after #12558 and #12559 covered the namespace surface.

Does this PR introduce any user-facing change?

Yes. With authorization enabled, describe-table and table-exists are now authorized and return 403 when denied, and list-tables returns only the tables the caller may see. A table the caller may not read is reported as forbidden whether or not it exists, so the endpoints cannot be used to probe for existence.

How was this patch tested?

  • TestLanceMetadataAuthorizationMethodInterceptor: new tests for SELECT_TABLE/MODIFY_TABLE reads, the CREATE_TABLE probe that must not read, deny precedence, and identifiers of the wrong depth.
  • TestGravitinoLanceNamespaceListFiltering: a new test proving tables are filtered before pagination, using a hidden table that sorts first.
  • New LanceTableAuthorizationIT: four tests covering table read privileges, the probe-but-not-read distinction, indistinguishable inaccessible and missing tables, and filtered pagination.
  • ./gradlew :lance:lance-rest-server:build :lance:lance-common:build — 180 tests, all passing.

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

Code Coverage Report

Overall Project 68.53% -0.08% 🟢
Files changed 58.37% 🔴

Module Coverage
aliyun 19.74% 🔴
api 52.09% 🟢
authorization-common 85.96% 🟢
authorization-ranger 4.38% 🔴
aws 53.54% 🟢
azure 32.1% 🔴
catalog-common 9.9% 🔴
catalog-fileset 80.3% 🟢
catalog-glue 69.24% 🟢
catalog-hive 82.96% 🟢
catalog-jdbc-common 45.69% 🟢
catalog-jdbc-doris 82.44% 🟢
catalog-jdbc-mysql 79.33% 🟢
catalog-jdbc-postgresql 83.39% 🟢
catalog-jdbc-starrocks 79.16% 🟢
catalog-kafka 76.99% 🟢
catalog-lakehouse-generic 60.55% 🟢
catalog-lakehouse-hudi 79.1% 🟢
catalog-lakehouse-iceberg 85.86% 🟢
catalog-lakehouse-paimon 84.26% 🟢
catalog-model 77.99% 🟢
cli 44.48% 🟢
client-java 77.44% 🟢
common 55.5% 🟢
core 83.58% 🟢
filesystem-hadoop3 76.45% 🟢
flink 0.0% 🔴
flink-common 50.29% 🟢
flink-runtime 0.0% 🔴
gcp 32.2% 🔴
hadoop-auth 68.0% 🟢
hadoop-common 17.84% 🔴
hive-metastore-common 53.4% 🟢
iceberg-aliyun-bundle 0.0% 🔴
iceberg-common 64.75% 🟢
iceberg-rest-server 75.89% 🟢
idp-basic 85.98% 🟢
integration-test-common 0.0% 🔴
jobs 62.92% 🟢
lance-common 32.52% -8.13% 🔴
lance-rest-server 65.69% +23.58% 🟢
lineage 53.02% 🟢
optimizer 83.24% 🟢
optimizer-api 21.95% 🔴
server 88.15% 🟢
server-common 80.5% 🟢
spark 28.57% 🔴
spark-common 48.92% 🟢
tencent 69.84% 🟢
trino-connector 47.44% +2.11% 🟢
Files
Module File Coverage
lance-common LanceMetadataFilter.java 25.0% 🔴
GravitinoLanceNameSpaceOperations.java 1.33% 🔴
lance-rest-server LanceMetadataAuthorizationMethodInterceptor.java 97.62% 🟢
LanceTableOperations.java 97.37% 🟢
LanceNamespaceOperations.java 88.37% 🟢
LanceAuthorizationExpressions.java 0.0% 🔴
LanceAuthorizationMetadataFilter.java 0.0% 🔴
LanceRESTAuthInterceptionService.java 0.0% 🔴
trino-connector GravitinoConfig.java 85.71% 🟢
GravitinoConnectorFactory.java 67.74% 🟢

@yuqi1129
yuqi1129 force-pushed the feat/12560-lance-table-read-authz branch from a58ab7b to eb31a03 Compare August 30, 2026 12:28
… Lance REST

Authorize describe-table and table-exists, and filter list-table results
before the page is cut so pagination stays consistent with what the
caller may see.

A Lance identifier carries its depth rather than its kind, so the
interceptor now resolves a three-level identifier to a table and every
table expression is guarded on the addressed entity type: an identifier
of the wrong depth matches no branch and is denied instead of being
authorized against another entity. The accepted depth is bounded per
resource rather than globally, because a namespace operation stops at a
schema: a table identifier sent to one is not a namespace at all, so it
is rejected before any expression sees it. Bounding it globally would
have let CAN_ACCESS_METADATA, which expands to a branch per entity type,
authorize such a request against the table it names.

Table-exists additionally accepts PROBE_TABLE_LIKE, the privilege that
means exactly this, and CREATE_TABLE, because clients probe for a table
immediately before creating it. The endpoint answers with an empty 200
or a 404, so existence is the only thing either privilege reveals.
Describe stays restricted to read privileges, so a probe never exposes
table properties.

Claude-Session: https://claude.ai/code/session_01EPJduJLZAREBg1bKxybe1e
@yuqi1129
yuqi1129 force-pushed the feat/12560-lance-table-read-authz branch from eb31a03 to 6a9ce71 Compare August 30, 2026 12:31
@yuqi1129 yuqi1129 self-assigned this Aug 30, 2026
@yuqi1129
yuqi1129 marked this pull request as ready for review August 30, 2026 12:32
Copilot AI lite review requested due to automatic review settings August 30, 2026 12:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@yuqi1129
yuqi1129 requested a review from roryqi August 31, 2026 02:41
@yuqi1129

yuqi1129 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

@roryqi
Can you help me to review this one?

@yuqi1129
yuqi1129 merged commit d0c656a into apache:main Sep 2, 2026
40 of 41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Subtask] Add table read and list authorization for Lance REST

3 participants