Copilot commented on code in PR #4409:
URL: https://github.com/apache/polaris/pull/4409#discussion_r3234197233


##########
extensions/auth/opa/impl/src/main/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizer.java:
##########
@@ -109,25 +110,55 @@ public OpaPolarisAuthorizer(
    */
   @Override
   public void resolveAuthorizationInputs(
-      @Nonnull AuthorizationState authzState, @Nonnull AuthorizationRequest 
request) {
+      @Nonnull AuthorizationState authzState,
+      @Nonnull PolarisPrincipal polarisPrincipal,
+      @Nonnull AuthorizationRequest request) {
+    authzState.getResolutionManifest().resolveAll();
+  }
+
+  @Override
+  public void resolveAuthorizationInputs(
+      @Nonnull AuthorizationState authzState,
+      @Nonnull PolarisPrincipal polarisPrincipal,
+      @Nonnull List<AuthorizationRequest> requests) {
+    Preconditions.checkArgument(
+        !requests.isEmpty(), "Authorization request batch must contain at 
least one request");
     authzState.getResolutionManifest().resolveAll();
   }
 
   @Override
   @Nonnull
   public AuthorizationDecision authorize(
-      @Nonnull AuthorizationState authzState, @Nonnull AuthorizationRequest 
request) {
+      @Nonnull AuthorizationState authzState,
+      @Nonnull PolarisPrincipal polarisPrincipal,
+      @Nonnull AuthorizationRequest request) {
     boolean allowed =
         queryOpa(
             buildOpaAuthorizationInput(
-                request.getPrincipal(),
+                polarisPrincipal,
                 request.getOperation(),
                 toResourceEntitiesFromSecurables(request.getTargets()),
                 toResourceEntitiesFromSecurables(request.getSecondaries())));
     return allowed
         ? AuthorizationDecision.allow()
         : AuthorizationDecision.deny(
-            "OPA denied authorization for " + 
request.formatForAuthorizationMessage());
+            "OPA denied authorization for principal="
+                + polarisPrincipal.getName()
+                + " operation="
+                + request.getOperation());

Review Comment:
   The deny message here drops request context (targets/secondaries) that was 
previously included, which will make authorization failures significantly 
harder to debug. Since the method still has access to 
request.getTargets()/getSecondaries(), consider including their formatted 
securables (or a stable request summary) in the message while keeping the 
principal passed explicitly.



##########
extensions/auth/opa/impl/src/test/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerTest.java:
##########
@@ -934,14 +930,136 @@ <T> T httpClientExecute(
         .isEqualTo(expectedDestination);
   }
 
+  @Test
+  void authorizeSingleOperationBatchEvaluatesSequentially() throws Exception {
+    final List<String> capturedRequestBodies = new ArrayList<>();
+    HttpEntity mockEntity = 
HttpEntities.create("{\"result\":{\"allow\":true}}");
+    @SuppressWarnings("resource")
+    ClassicHttpResponse mockResponse = new BasicClassicHttpResponse(200);
+    mockResponse.setEntity(mockEntity);
+
+    PolarisResolutionManifest resolutionManifest = 
mock(PolarisResolutionManifest.class);
+    AuthorizationState authzState = new AuthorizationState();
+    authzState.setResolutionManifest(resolutionManifest);
+    PolarisPrincipal principal = PolarisPrincipal.of("alice", Map.of(), 
Set.of("role-1"));
+
+    OpaPolarisAuthorizer authorizer =
+        new OpaPolarisAuthorizer(
+            URI.create("http://opa.example.com:8181/v1/data/polaris/allow";),
+            mock(CloseableHttpClient.class),
+            JsonMapper.builder().build(),
+            null) {
+          @Override
+          <T> T httpClientExecute(
+              ClassicHttpRequest request, HttpClientResponseHandler<? extends 
T> responseHandler)
+              throws HttpException, IOException {
+            capturedRequestBodies.add(
+                new String(
+                    request.getEntity().getContent().readAllBytes(), 
StandardCharsets.UTF_8));
+            return responseHandler.handleResponse(mockResponse);
+          }
+        };
+
+    AuthorizationDecision decision =
+        authorizer.authorize(
+            authzState,
+            principal,
+            List.of(
+                AuthorizationRequest.of(
+                    PolarisAuthorizableOperation.GET_CATALOG,
+                    PolarisSecurable.of(new 
PathSegment(PolarisEntityType.CATALOG, "catalog-1"))),
+                AuthorizationRequest.of(
+                    PolarisAuthorizableOperation.GET_CATALOG,
+                    PolarisSecurable.of(new 
PathSegment(PolarisEntityType.CATALOG, "catalog-2")))));
+
+    ObjectMapper mapper = JsonMapper.builder().build();
+    JsonNode firstRoot = mapper.readTree(capturedRequestBodies.get(0));
+    JsonNode secondRoot = mapper.readTree(capturedRequestBodies.get(1));
+
+    assertThat(decision.isAllowed()).isTrue();
+    assertThat(capturedRequestBodies).hasSize(2);

Review Comment:
   This test reads capturedRequestBodies.get(0)/(1) before asserting that two 
requests were captured, so a regression in batch execution would fail with 
IndexOutOfBoundsException instead of a clear assertion. Assert 
capturedRequestBodies has size 2 before indexing into it (or use 
containsExactly/first/last assertions).
   



-- 
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]

Reply via email to