flyrain commented on code in PR #4409: URL: https://github.com/apache/polaris/pull/4409#discussion_r3270508104
########## polaris-core/src/main/java/org/apache/polaris/core/auth/AuthorizationIntent.java: ########## @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.polaris.core.auth; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import org.apache.polaris.core.entity.PolarisEntityType; + +/** Authorization intent describing an operation and its target resource shape. */ +public sealed interface AuthorizationIntent + permits TargetlessAuthorizationIntent, + SingleTargetAuthorizationIntent, + PairwiseTargetAuthorizationIntent { + static AuthorizationIntent of(@Nonnull PolarisAuthorizableOperation operation) { + return new TargetlessAuthorizationIntent(operation); + } + + static AuthorizationIntent of( + @Nonnull PolarisAuthorizableOperation operation, @Nonnull PolarisSecurable target) { + return new SingleTargetAuthorizationIntent(operation, target); + } + + static AuthorizationIntent of( + @Nonnull PolarisAuthorizableOperation operation, + @Nullable PolarisSecurable target, + @Nullable PolarisSecurable secondary) { + return new PairwiseTargetAuthorizationIntent(operation, target, secondary); + } + + @Nonnull + PolarisAuthorizableOperation getOperation(); + + @Nullable + PolarisSecurable getTarget(); Review Comment: Thanks for the change. I think `AuthorizationIntent` as a sealed hierarchy is the right shape for these requests. Want to flag something about the parent interface, because I don't think we're actually getting the benefit of sealing it. The parent exposes `@Nullable getTarget()` and `@Nullable getSecondary()`, plus `hasSecurableType` and `containsType`. Both callers, OPA's `authorize` and `PolarisAuthorizerImpl.authorizeIntent`, just pull the nullable accessors off and null-check at runtime; neither switches on the subtype. And `hasSecurableType` / `containsType` aren't called from anywhere in production code, only by their own tests. So we've ended up with three records, three factory overloads, two nullable parent accessors, and two unused helpers, but the ergonomic at the call site is identical to what `AuthorizationTargetBinding` gave us: a thing with two nullables, check them. What worries me more is what happens next. Say six months from now we add a `TripleTargetAuthorizationIntent(op, t1, t2, t3)`, merge-style ops eventually want something like that. With the current shape we'd either have to bolt `getTertiary()` onto the parent (every existing variant returns `null` for it, every caller grows another nullable branch) or pretend `t3` fits inside one of the accessors we already have. The parent interface ends up accumulating one nullable accessor per shape we've ever supported, and the seal stops paying its way entirely. I think the seal earns its keep if we make the parent thin, just `operation()`, and push typed access onto the subtypes: ```java switch (intent) { case TargetlessAuthorizationIntent t -> ... case SingleTargetAuthorizationIntent s -> ... s.target() ... // @Nonnull case PairwiseTargetAuthorizationIntent p -> ... p.target(), p.secondary() ... } ``` Then `SingleTarget.target()` is non-null by type, so callers stop null-checking what the seal already guarantees. The 3-arg `of(op, target, secondary)` ambiguity quietly dissolves, no nullable parent contract to satisfy, no reason to overload. Adding `TripleTarget` later becomes a compile error at every switch site, which is exactly the property sealed types are there to give you. I'd suggest to push down the subtype switch as much as possible. If some methods are not ready for the change(e.g., the old method `authorizeOrThrow` still takes targets and secondaries, I'm OK to change it as a followup. WDYT? ########## polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizer.java: ########## @@ -44,7 +44,7 @@ void resolveAuthorizationInputs( * Core authorization entry point for the new SPI. * * <p>Implementations should rely on any required state in {@link AuthorizationState} and the - * intent captured by {@link AuthorizationRequest} (principal, operation, and target securables). + * request captured by {@link AuthorizationRequest}. Review Comment: Worth documenting the new batch contract here: intents in one request are AND-combined and evaluation short-circuits on the first deny. Important for downstream `PolarisAuthorizer` authors. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
