|
40 | 40 | import org.apache.hc.core5.http.io.entity.StringEntity; |
41 | 41 | import org.apache.iceberg.exceptions.ForbiddenException; |
42 | 42 | import org.apache.polaris.core.auth.AuthorizationDecision; |
| 43 | +import org.apache.polaris.core.auth.AuthorizationIntent; |
43 | 44 | import org.apache.polaris.core.auth.AuthorizationRequest; |
44 | 45 | import org.apache.polaris.core.auth.AuthorizationState; |
45 | 46 | import org.apache.polaris.core.auth.PathSegment; |
46 | 47 | import org.apache.polaris.core.auth.PolarisAuthorizableOperation; |
47 | 48 | import org.apache.polaris.core.auth.PolarisAuthorizer; |
48 | 49 | import org.apache.polaris.core.auth.PolarisPrincipal; |
49 | 50 | import org.apache.polaris.core.auth.PolarisSecurable; |
| 51 | +import org.apache.polaris.core.auth.PolicyAttachmentAuthorizationIntent; |
| 52 | +import org.apache.polaris.core.auth.PrivilegeGrantAuthorizationIntent; |
| 53 | +import org.apache.polaris.core.auth.RenameAuthorizationIntent; |
| 54 | +import org.apache.polaris.core.auth.RoleAssignmentAuthorizationIntent; |
| 55 | +import org.apache.polaris.core.auth.RootPrivilegeGrantAuthorizationIntent; |
| 56 | +import org.apache.polaris.core.auth.SingleTargetAuthorizationIntent; |
| 57 | +import org.apache.polaris.core.auth.TargetlessAuthorizationIntent; |
50 | 58 | import org.apache.polaris.core.entity.PolarisBaseEntity; |
51 | 59 | import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper; |
52 | 60 | import org.apache.polaris.core.persistence.ResolvedPolarisEntity; |
@@ -117,17 +125,52 @@ public void resolveAuthorizationInputs( |
117 | 125 | @NonNull |
118 | 126 | public AuthorizationDecision authorize( |
119 | 127 | @NonNull AuthorizationState authzState, @NonNull AuthorizationRequest request) { |
120 | | - boolean allowed = |
121 | | - queryOpa( |
122 | | - buildOpaAuthorizationInput( |
123 | | - request.getPrincipal(), |
124 | | - request.getOperation(), |
125 | | - toResourceEntitiesFromSecurables(request.getTargets()), |
126 | | - toResourceEntitiesFromSecurables(request.getSecondaries()))); |
127 | | - return allowed |
128 | | - ? AuthorizationDecision.allow() |
129 | | - : AuthorizationDecision.deny( |
130 | | - "OPA denied authorization for " + request.formatForAuthorizationMessage()); |
| 128 | + for (AuthorizationIntent intent : request.intents()) { |
| 129 | + PolarisAuthorizableOperation operation = intent.getOperation(); |
| 130 | + List<ResourceEntity> targets; |
| 131 | + List<ResourceEntity> secondaries; |
| 132 | + switch (intent) { |
| 133 | + case TargetlessAuthorizationIntent ignored -> { |
| 134 | + targets = List.of(); |
| 135 | + secondaries = List.of(); |
| 136 | + } |
| 137 | + case SingleTargetAuthorizationIntent singleTargetIntent -> { |
| 138 | + targets = toResourceEntitiesFromSecurable(singleTargetIntent.target()); |
| 139 | + secondaries = List.of(); |
| 140 | + } |
| 141 | + case RenameAuthorizationIntent renameIntent -> { |
| 142 | + targets = toResourceEntitiesFromSecurable(renameIntent.from()); |
| 143 | + secondaries = toResourceEntitiesFromSecurable(renameIntent.to()); |
| 144 | + } |
| 145 | + case PolicyAttachmentAuthorizationIntent policyAttachmentIntent -> { |
| 146 | + targets = toResourceEntitiesFromSecurable(policyAttachmentIntent.policy()); |
| 147 | + secondaries = toResourceEntitiesFromSecurable(policyAttachmentIntent.attachedTo()); |
| 148 | + } |
| 149 | + case RoleAssignmentAuthorizationIntent roleAssignmentIntent -> { |
| 150 | + targets = toResourceEntitiesFromSecurable(roleAssignmentIntent.role()); |
| 151 | + secondaries = toResourceEntitiesFromSecurable(roleAssignmentIntent.assignee()); |
| 152 | + } |
| 153 | + case PrivilegeGrantAuthorizationIntent privilegeGrantIntent -> { |
| 154 | + targets = toResourceEntitiesFromSecurable(privilegeGrantIntent.grantTarget()); |
| 155 | + secondaries = toResourceEntitiesFromSecurable(privilegeGrantIntent.grantee()); |
| 156 | + } |
| 157 | + case RootPrivilegeGrantAuthorizationIntent rootPrivilegeGrantIntent -> { |
| 158 | + targets = List.of(); |
| 159 | + secondaries = toResourceEntitiesFromSecurable(rootPrivilegeGrantIntent.grantee()); |
| 160 | + } |
| 161 | + } |
| 162 | + boolean allowed = |
| 163 | + queryOpa( |
| 164 | + buildOpaAuthorizationInput(request.principal(), operation, targets, secondaries)); |
| 165 | + if (!allowed) { |
| 166 | + return AuthorizationDecision.deny( |
| 167 | + "OPA denied authorization for principal=" |
| 168 | + + request.principal().getName() |
| 169 | + + " operation=" |
| 170 | + + operation); |
| 171 | + } |
| 172 | + } |
| 173 | + return AuthorizationDecision.allow(); |
131 | 174 | } |
132 | 175 |
|
133 | 176 | /** |
@@ -296,9 +339,9 @@ private ImmutableContext buildContext() { |
296 | 339 |
|
297 | 340 | private ImmutableResource buildResource( |
298 | 341 | List<ResourceEntity> targets, List<ResourceEntity> secondaries) { |
299 | | - // Backward compatibility: keep the existing OPA input shape with separate target and |
300 | | - // secondary lists. Future work can align this with AuthorizationTargetBinding semantics |
301 | | - // using binding tuples like [(target, secondary), ...]. |
| 342 | + // Keep the existing OPA input shape by always emitting target and secondary lists, using |
| 343 | + // empty lists when an intent does not carry that slot. Future work can revisit the payload |
| 344 | + // shape if OPA starts consuming intent subtype distinctions directly. |
302 | 345 | return ImmutableResource.builder().targets(targets).secondaries(secondaries).build(); |
303 | 346 | } |
304 | 347 |
|
@@ -361,17 +404,8 @@ private List<ResourceEntity> toResourceEntitiesFromResolvedPaths( |
361 | 404 | return entities; |
362 | 405 | } |
363 | 406 |
|
364 | | - @NonNull |
365 | | - private List<ResourceEntity> toResourceEntitiesFromSecurables( |
366 | | - @Nullable List<PolarisSecurable> securables) { |
367 | | - if (securables == null || securables.isEmpty()) { |
368 | | - return List.of(); |
369 | | - } |
370 | | - |
371 | | - List<ResourceEntity> entities = new ArrayList<>(); |
372 | | - for (PolarisSecurable securable : securables) { |
373 | | - entities.add(buildResourceEntity(securable)); |
374 | | - } |
375 | | - return entities; |
| 407 | + private List<ResourceEntity> toResourceEntitiesFromSecurable( |
| 408 | + @Nullable PolarisSecurable securable) { |
| 409 | + return securable == null ? List.of() : List.of(buildResourceEntity(securable)); |
376 | 410 | } |
377 | 411 | } |
0 commit comments