Skip to content

Conversation

HonahX
Copy link
Contributor

@HonahX HonahX commented Oct 7, 2025

In #2697, we introduce fine grained authorizable operations which creates the need to authorize multiple authorizableOperations for one request.

This PR introduce new authorizeOrThrow api to help batch authorize multiple operations, instead of doing so in a for loop in CatalogHandler
Previous

for (PolarisAuthorizableOperation op : ops) {
      authorizer.authorizeOrThrow(
          polarisPrincipal,
          resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
          op,
          target,
          null /* secondary */);
    }

Now:

authorizer.authorizeOrThrow(
        polarisPrincipal,
        resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
        ops,
        target,
        null /* secondary */);

This will be helpful for authorizer backed by external backend, like OpaAuthorizer: #2680, which will send a rest request for every authorizeOrThrow call. Making authorizeOrThrow takes multiple operations allow the implementation to send a batch authorization request to the backend.

cc: @travis-bowen @collado-mike @dimas-b

Comment on lines +45 to +57
void authorizeOrThrow(
@Nonnull PolarisPrincipal polarisPrincipal,
@Nonnull Set<PolarisBaseEntity> activatedEntities,
@Nonnull Set<PolarisAuthorizableOperation> authzOps,
@Nullable PolarisResolvedPathWrapper target,
@Nullable PolarisResolvedPathWrapper secondary);

void authorizeOrThrow(
@Nonnull PolarisPrincipal polarisPrincipal,
@Nonnull Set<PolarisBaseEntity> activatedEntities,
@Nonnull Set<PolarisAuthorizableOperation> authzOps,
@Nullable List<PolarisResolvedPathWrapper> targets,
@Nullable List<PolarisResolvedPathWrapper> secondaries);
Copy link
Contributor

Choose a reason for hiding this comment

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

since this is a public interface, do you wanna may be add some function docs for this ?

Copy link
Contributor

Choose a reason for hiding this comment

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

also do we wanna mark the existing API's deprecated ? since these APIs can superseed them

Copy link
Contributor Author

Choose a reason for hiding this comment

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

do you wanna may be add some function docs for this ?

Sounds great!

also do we wanna mark the existing API's deprecated ? since these APIs can superseed them

I think we should keep the existing ones since they’re widely used across the codebase — they serve as polymorphic helpers.
However, we could provide a default implementation that delegates to the only version requiring an actual implementation. WDYT?

void authorizeOrThrow(
      @Nonnull PolarisPrincipal polarisPrincipal,
      @Nonnull Set<PolarisBaseEntity> activatedEntities,
      @Nonnull Set<PolarisAuthorizableOperation> authzOps,
      @Nullable List<PolarisResolvedPathWrapper> targets,
      @Nullable List<PolarisResolvedPathWrapper> secondaries);

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this probably deserves a mailing list discussion, but I wonder if this API change is really enough to support batching everything together into one call. This API makes the assumption that all operations have the same primary and secondary entities. Is that always going to be the case? or are we fine to kick that can down the road?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good, will start a discussion!

IMHO, batch AuthorizableOperations should mainly be used for fine-grained cases like updateTable, where a single endpoint handles multiple types of updates that each require distinct authorization controls. The original intention behind AuthorizableOperation was that each operation corresponds to one API call, and updateTable is a special exception that needs finer-grained handling.

In the updateTable case, there’s a sort of internal inheritance — for example, a fine-grained operation like TABLE_ADD_SNAPSHOT conceptually extends a broader one such as TABLE_WRITE_PROPERTIES. All these fine-grained operations should share the same set of primary and secondary securable entities; it’s just that this “inheritance” relationship hasn’t been reflected in the code yet.

If two operations involve different sets of securables, they should ideally be authorized through separate API calls, each likely corresponding to its own endpoint.

If in the future the above assumption does not hold, I assume we will need large change anyway and thus a new set of apis will be introduced.

But the above are just my thoughts, let's discuss in dev mailing list to collect thoughts on the new api and see what we want to support : )

Copy link
Contributor

@dimas-b dimas-b left a comment

Choose a reason for hiding this comment

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

LGTM 👍 Just a small code maintenance suggestion.

@Nullable List<PolarisResolvedPathWrapper> targets,
@Nullable List<PolarisResolvedPathWrapper> secondaries);

void authorizeOrThrow(
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be possible to add default (possibly inefficient) implementations to the new methods to simplify transition in downstream projects? This is just a matter of convenience, so optional.

} else if (authzOp == PolarisAuthorizableOperation.RESET_CREDENTIALS) {
if (!isRoot) {
throw new ForbiddenException("Only Root principal(service-admin) can perform %s", authzOp);
for (PolarisAuthorizableOperation authzOp : authzOps) {
Copy link
Contributor

@dimas-b dimas-b Oct 7, 2025

Choose a reason for hiding this comment

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

This loop could be done in a default impl. of the new method (redirecting to old methods). Performance-wise it would be the same, as far as I can tell, but it would have an easier migration path downstream.

@github-project-automation github-project-automation bot moved this from PRs In Progress to Ready to merge in Basic Kanban Board Oct 7, 2025
Copy link
Contributor

@travis-bowen travis-bowen left a comment

Choose a reason for hiding this comment

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

Given the mailing list discussion agrees on the approach, this implementation looks good.

The functional java docs would be useful though.

@Nonnull Set<PolarisAuthorizableOperation> authzOps,
@Nullable PolarisResolvedPathWrapper target,
@Nullable PolarisResolvedPathWrapper secondary) {
authorizeOrThrow(
Copy link
Contributor

Choose a reason for hiding this comment

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

Honestly this and the other authorizeOrThrow (with single op and single target / secondary) would probably be nice to have a default as well to default to calling the option with a list of targets and secondaries.

The Polaris impls end up just delegating these other impls often do as well.

@dimas-b
Copy link
Contributor

dimas-b commented Oct 8, 2025

@travis-bowen :

Given the mailing list discussion agrees on the approach, [...]

Could you link the ML discussion? I might have missed it 😅

@HonahX
Copy link
Contributor Author

HonahX commented Oct 12, 2025

Sorry seems there is some confusion around the dev list discussion. Just to clarify, the discussion for this PR is this thread:
https://lists.apache.org/thread/qgbrd959dyjsncr7wkfd8yz5xq6pl64q (which is still been actively discussed) : ). Thanks everyone who have already chimed in here!

@sungwy
Copy link

sungwy commented Oct 17, 2025

Hi folks, if we are fairly certain on moving forward with this PR, I'll make a change to the OpaPolarisAuthorizer PR to pass a list of actions instead of a single one, in the request payload: #2680

@dimas-b
Copy link
Contributor

dimas-b commented Oct 17, 2025

I'm not sure about making OPA depend on this PR 🤔 E.g. recent discussions in https://lists.apache.org/thread/dqk65wjyqp72po2mcbsvskj8pzygc3dm might require changes to the Authorizer API too... so this might turn into a bigger/longer effort 🤔

If we can make progress on OPA under the current API, let's not wait. If these PRs clash at merge time, it will be unfortunate, but I hope we can deal with that as we collect approvals.

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.

6 participants