Skip to content

Update CatalogHandler and PolarisAdminServier to authorize using AuthorizationIntent - #5194

Merged
sungwy merged 14 commits into
apache:mainfrom
sungwy:auth-refactor-phase-5
Sep 8, 2026
Merged

sungwy merged 14 commits into
apache:mainfrom
sungwy:auth-refactor-phase-5

Conversation

@sungwy

@sungwy sungwy commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

Update the handler call sites to use the new authorize method using AuthorizationIntent.

This will allow each PolarisAuthorizer implementations to decide which PolarisEntity needs to be resolved for its authorization decision, allowing them to ignore RBAC resolution by choice.

Checklist

  • 🛡️ Don't disclose security issues! (contact security@apache.org)
  • 🔗 Clearly explained why the changes are needed, or linked related issues: Fixes #
  • 🧪 Added/updated tests with good coverage, or manually tested (and explained how)
  • 💡 Added comments for complex logic
  • 🧾 Updated CHANGELOG.md (if needed)
  • 📚 Updated documentation in site/content/in-dev/unreleased (if needed)

@github-project-automation github-project-automation Bot moved this to PRs In Progress in Basic Kanban Board Jul 30, 2026
@sungwy
sungwy marked this pull request as ready for review August 11, 2026 18:28
Copilot AI lite review requested due to automatic review settings August 11, 2026 18:28

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.

Pull request overview

This draft PR migrates service handlers and authorizer implementations from the legacy authorizeOrThrow(...) APIs to the newer intent-based authorize(AuthorizationState, AuthorizationRequest) SPI, so each PolarisAuthorizer can decide what it needs to resolve for an authorization decision.

Changes:

  • Updates handler authorization call sites (catalog/admin/policy) to build AuthorizationRequest objects with AuthorizationIntent and use AuthorizationDecision results.
  • Extends core auth primitives: deprecates legacy authorizeOrThrow overloads and adds AuthorizationDecision.throwIfDenied().
  • Implements/updates intent-based authorization behavior in extension authorizers (notably Ranger) and adjusts unit tests accordingly.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java Updates test fixture stubbing for the new authorize(...) return type.
runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerTest.java Refactors mocks/assertions to validate intent-based AuthorizationRequest calls.
runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAdminServiceTest.java Updates admin service tests to stub authorize(...) decisions.
runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandler.java Migrates policy authorization flow to intent-based requests and decisions.
runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java Migrates Iceberg catalog authorization paths to the new SPI.
runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java Centralizes intent-based authorization helpers for common catalog operations.
runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java Updates admin authorization helpers to use AuthorizationRequest + AuthorizationDecision.
polaris-core/src/test/java/org/apache/polaris/core/auth/PolarisAuthorizerImplTest.java Updates core authorizer tests for intent-based flows and updated internals.
polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java Routes intent-based authorization through RBAC logic; deprecates legacy overloads.
polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizer.java Deprecates legacy entry points in favor of intent-based authorize(...).
polaris-core/src/main/java/org/apache/polaris/core/auth/AuthorizationDecision.java Adds throwIfDenied() helper for decision-to-exception conversion.
extensions/auth/ranger/src/test/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizerTest.java Adds/updates tests for Ranger intent-based authorization behavior.
extensions/auth/ranger/src/main/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizer.java Implements intent-based authorize(...) by resolving targets from intents.
extensions/auth/opa/src/test/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerTest.java Updates tests to drive OPA authorization through intent-based requests.
extensions/auth/opa/src/main/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizer.java Deprecates legacy overloads and clarifies legacy path serialization comments.
Suppressed comments (3)

runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java:304

  • authorizeResolvedRegisterTableOverwriteOrThrow calls authorize() for overwriteRequest/fallbackRequest without ensuring resolveAuthorizationInputs has been invoked for those specific requests. With the intent-based SPI, an authorizer may populate AuthorizationState based on the request, so each request passed to authorize() should be resolved first.
    if (tableTarget != null) {
      authorizer().authorize(authorizationState, overwriteRequest).throwIfDenied();
    } else {

runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java:369

  • authorizeResolvedBasicTableLikeOperationOrThrow constructs a new AuthorizationRequest for authorize() but never resolves it. This can break authorizer implementations that rely on resolveAuthorizationInputs to populate AuthorizationState based on the request/intents.
    authorizer()
        .authorize(
            authorizationState,
            new AuthorizationRequest(

runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java:406

  • authorizeBasicTableLikeOperationsOrThrow loops over ops and calls authorize() on per-op AuthorizationRequests without resolving them. To keep the resolve/authorize contract intact and avoid redundant per-op calls, build a single AuthorizationRequest with one intent per operation, resolve it once, then authorize once (intents are AND-combined per PolarisAuthorizer contract).
    for (PolarisAuthorizableOperation op : ops) {
      AuthorizationRequest authorizationRequest =
          new AuthorizationRequest(
              polarisPrincipal(),
              List.of(

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

op,
target,
null /* secondary */);
authorizer().authorize(authorizationState, authorizationRequest).throwIfDenied();
@dimas-b

dimas-b commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

@sungwy : Is this still a draft PR (title / description)?

dimas-b
dimas-b previously approved these changes Aug 11, 2026
Comment thread polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizer.java Outdated
Comment thread polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizer.java Outdated
@github-project-automation github-project-automation Bot moved this from PRs In Progress to Ready to merge in Basic Kanban Board Aug 11, 2026
@sungwy

sungwy commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

@sungwy : Is this still a draft PR (title / description)?

I toggling the state while trying to figure out how to unblock the CI that seems to be stuck on this PR 😅

But thank you for the early review @dimas-b . This will help move it closer to the finishline

@dimas-b

dimas-b commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

@sungwy : as for CI, a rebase or simple force push should help

dimas-b
dimas-b previously approved these changes Aug 13, 2026
sungwy added 6 commits August 14, 2026 19:14
# Conflicts:
#	polaris-core/src/test/java/org/apache/polaris/core/auth/PolarisAuthorizerImplTest.java
#	runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAdminServiceTest.java
dimas-b
dimas-b previously approved these changes Aug 17, 2026
@sungwy

sungwy commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed reviews @dimas-b

@flyrain and @gracechen09 - could I ask for your reviews on this PR?

@flyrain

flyrain commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Thanks for the detailed reviews @dimas-b

@flyrain and @gracechen09 - could I ask for your reviews on this PR?

@sungwy , just back from the vacation. Sorry for the delay. Will take a look soon.

flyrain
flyrain previously approved these changes Aug 18, 2026

@flyrain flyrain 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.

+1 Thanks @sungwy !

@flyingImer flyingImer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm aligned with moving handlers to the intent-based SPI, but I don't think this is merge-ready. Details inline.

@sungwy
sungwy requested a review from flyrain September 2, 2026 18:45
@sungwy
sungwy requested review from dimas-b and flyingImer September 3, 2026 01:37
dimas-b
dimas-b previously approved these changes Sep 3, 2026
// Reuse the already-resolved table view for the read-delegation fallback.
authorizeResolvedBasicTableLikeOperationOrThrow(
read, PolarisEntitySubType.ICEBERG_TABLE, tableIdentifier);
authorizationState, read, PolarisEntitySubType.ICEBERG_TABLE, tableIdentifier);

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.

We authorize "read" here but the resolution was done on a "write" request. Practically, this is not significant, since only entity references matter for resolution, but it would be nice to make it explicit in the AuthZ SPI.... meaning that resolution should not have the operation itself as a formal parameter.

This is just a point for follow-up thinking / PR. Not a blocker 🙂

@sungwy sungwy Sep 3, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes, that's right and I think unlike the AuthorizationRequest, it's important that we share the AuthorizationState, since we want to read or write on the same resolved PolarisSecurable.

@sungwy sungwy added this to the 1.8.0 milestone Sep 3, 2026
@sungwy

sungwy commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

sorry to ask for your approval again @dimas-b - there was a merge conflict on CHANGELOG.md. I'll merge it now once the CI turns green given that this PR has been open for a while with a number of approvals.

dimas-b
dimas-b previously approved these changes Sep 8, 2026

@dimas-b dimas-b 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.

LGTM 👍

@sungwy
sungwy enabled auto-merge (squash) September 8, 2026 16:09

@flyingImer flyingImer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No blocking concerns from my side. Good to merge once CI is green.

@sungwy
sungwy merged commit 0858f79 into apache:main Sep 8, 2026
24 checks passed
@github-project-automation github-project-automation Bot moved this from Ready to merge to Done in Basic Kanban Board Sep 8, 2026
obelix74 pushed a commit to obelix74/polaris that referenced this pull request Sep 9, 2026
…splayName tweak (post-merge)

Merging upstream/main pulled in apache#5194 (Update CatalogHandler and
PolarisAdminServier to authorize using AuthorizationIntent), which removed
PolarisAuthorizer.authorizeOrThrow entirely. Migrate
MetricsReportsService.resolveAndAuthorizeTableMetrics to build one
AuthorizationRequest of SingleTargetAuthorizationIntent(LIST_TABLE_METRICS,
...) per table, call resolveAuthorizationInputs once, do the existing
not-found checks against the manifest, then authorize(...).throwIfDenied()
once for the whole batch (AND-combined, short-circuits on first deny) --
mirroring CatalogHandler.authorizeBatchTableLikeOperationOrThrow. Update
MetricsReportsServiceTest's mocks to the authorize()/AuthorizationDecision
style used elsewhere post-migration.

Also revert the dev_polaris.json/polaris-ranger-servicedef.json
"Polaris (draft)" -> "Apache Polaris" displayName tweak from the prior
commit: unrelated to metrics, flagged in review
(apache#4115 (comment)).

spotlessApply also reflowed the TABLE_READ_METRICS javadoc comment in
PolarisPrivilege.java by a couple of characters (newer google-java-format
line-wrap width); included since it touches PR1's own new javadoc.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@sungwy

sungwy commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Awesome. thanks for the reviews @dimas-b @flyingImer and @flyrain

@flyrain

flyrain commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Thanks a lot for the changes, @sungwy !

gracechen09 added a commit to gracechen09/polaris that referenced this pull request Sep 13, 2026
Resolves the conflict introduced by apache#5194, which removed the three
authorizeOrThrow methods from PolarisAuthorizer. Kept this branch's batch
authorize(AuthorizationState, List<AuthorizationRequest>) and dropped the
removed methods.

apache#5194 also required fixes that git auto-merged cleanly but which do not
compile, all caused by overload ambiguity between the single-request and
batch authorize:

- PolarisAuthorizerTest: dropped the two now-obsolete authorizeOrThrow
  stubs from RecordingAuthorizer, plus three unused imports.
- TestServices, PolarisAdminServiceTest, IcebergCatalogHandlerTest,
  SemanticModelCatalogHandlerAuthzTest, AbstractSemanticModelCatalogHandlerTest:
  disambiguated Mockito matchers -- any() -> any(AuthorizationRequest.class),
  and typed the argThat lambdas.

apache#5194 did not touch the list methods, so entity-level filtering is
unaffected. Verified: all affected modules compile, spotless clean, and
IcebergCatalogHandlerAuthzTest (6929) plus IcebergCatalogHandlerTest (20)
pass with all 8 filtering tests intact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
obelix74 pushed a commit to obelix74/polaris that referenced this pull request Sep 16, 2026
…splayName tweak (post-merge)

Merging upstream/main pulled in apache#5194 (Update CatalogHandler and
PolarisAdminServier to authorize using AuthorizationIntent), which removed
PolarisAuthorizer.authorizeOrThrow entirely. Migrate
MetricsReportsService.resolveAndAuthorizeTableMetrics to build one
AuthorizationRequest of SingleTargetAuthorizationIntent(LIST_TABLE_METRICS,
...) per table, call resolveAuthorizationInputs once, do the existing
not-found checks against the manifest, then authorize(...).throwIfDenied()
once for the whole batch (AND-combined, short-circuits on first deny) --
mirroring CatalogHandler.authorizeBatchTableLikeOperationOrThrow. Update
MetricsReportsServiceTest's mocks to the authorize()/AuthorizationDecision
style used elsewhere post-migration.

Also revert the dev_polaris.json/polaris-ranger-servicedef.json
"Polaris (draft)" -> "Apache Polaris" displayName tweak from the prior
commit: unrelated to metrics, flagged in review
(apache#4115 (comment)).

spotlessApply also reflowed the TABLE_READ_METRICS javadoc comment in
PolarisPrivilege.java by a couple of characters (newer google-java-format
line-wrap width); included since it touches PR1's own new javadoc.
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.

5 participants