This is an automated email from the ASF dual-hosted git repository.

weichiu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new 716c69751fa HDDS-13864. Move ACL check to preExecute in 
OMTenantCreateRequest and OMTenantDeleteRequest (#9279)
716c69751fa is described below

commit 716c69751fa9350dba5674ec34eb445a2c9ca5bb
Author: ChenChen Lai <[email protected]>
AuthorDate: Tue Jan 13 03:10:25 2026 +0800

    HDDS-13864. Move ACL check to preExecute in OMTenantCreateRequest and 
OMTenantDeleteRequest (#9279)
    
    Co-authored-by: Wei-Chiu Chuang <[email protected]>
---
 .../request/s3/tenant/OMTenantCreateRequest.java   |  23 +++-
 .../request/s3/tenant/OMTenantDeleteRequest.java   |  40 +++++-
 .../s3/tenant}/TestOMTenantCreateRequest.java      |  40 +++++-
 .../s3/tenant/TestOMTenantDeleteRequest.java       | 149 +++++++++++++++++++++
 4 files changed, 236 insertions(+), 16 deletions(-)

diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
index 0a9977ff785..ecb5a19f343 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
@@ -142,6 +142,22 @@ public OMRequest preExecute(OzoneManager ozoneManager) 
throws IOException {
     final String dbVolumeKey = ozoneManager.getMetadataManager()
         .getVolumeKey(volumeName);
 
+    // ACL check during preExecute (align with other create requests)
+    if (ozoneManager.getAclsEnabled()) {
+      try {
+        checkAcls(ozoneManager, OzoneObj.ResourceType.VOLUME,
+            OzoneObj.StoreType.OZONE, IAccessAuthorizer.ACLType.CREATE,
+            volumeName, null, null);
+      } catch (IOException ex) {
+        // Ensure audit log captures preExecute failures
+        markForAudit(ozoneManager.getAuditLogger(),
+            buildAuditMessage(OMAction.CREATE_TENANT,
+                buildVolumeAuditMap(volumeName), ex,
+                omRequest.getUserInfo()));
+        throw ex;
+      }
+    }
+
     // Backwards compatibility with older Ozone clients that don't have this
     // field. Defaults to false.
     boolean forceCreationWhenVolumeExists =
@@ -244,13 +260,6 @@ public OMClientResponse 
validateAndUpdateCache(OzoneManager ozoneManager, Execut
     Exception exception = null;
 
     try {
-      // Check ACL: requires volume CREATE permission.
-      if (ozoneManager.getAclsEnabled()) {
-        checkAcls(ozoneManager, OzoneObj.ResourceType.VOLUME,
-            OzoneObj.StoreType.OZONE, IAccessAuthorizer.ACLType.CREATE,
-            tenantId, null, null);
-      }
-
       mergeOmLockDetails(omMetadataManager.getLock().acquireWriteLock(
           VOLUME_LOCK, volumeName));
       acquiredVolumeLock = getOmLockDetails().isLockAcquired();
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
index 28b3dc71f22..c49525271a7 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
@@ -17,6 +17,7 @@
 
 package org.apache.hadoop.ozone.om.request.s3.tenant;
 
+import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_REQUEST;
 import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TENANT_NOT_EMPTY;
 import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TENANT_NOT_FOUND;
 import static 
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.LeveledResource.VOLUME_LOCK;
@@ -96,6 +97,38 @@ public OMRequest preExecute(OzoneManager ozoneManager) 
throws IOException {
     // Get tenant object by tenant name
     final Tenant tenantObj = multiTenantManager.getTenantFromDBById(tenantId);
 
+    final OMMetadataManager omMetadataManager = 
ozoneManager.getMetadataManager();
+    final OmDBTenantState dbTenantState =
+        omMetadataManager.getTenantStateTable().get(tenantId);
+    if (dbTenantState == null) {
+      LOG.debug("tenant: '{}' does not exist", tenantId);
+      throw new OMException("Tenant '" + tenantId + "' does not exist",
+          TENANT_NOT_FOUND);
+    }
+    final String volumeName = dbTenantState.getBucketNamespaceName();
+    Objects.requireNonNull(volumeName);
+    if (volumeName.isEmpty()) {
+      throw new OMException("Tenant '" + tenantId + "' has empty volume name",
+          INVALID_REQUEST);
+    }
+
+    // Perform ACL check during preExecute (WRITE_ACL on volume if applicable)
+    if (ozoneManager.getAclsEnabled()) {
+      try {
+        checkAcls(ozoneManager, OzoneObj.ResourceType.VOLUME,
+            OzoneObj.StoreType.OZONE, IAccessAuthorizer.ACLType.WRITE_ACL,
+            volumeName, null, null);
+      } catch (IOException ex) {
+        // Ensure audit log captures preExecute failures
+        Map<String, String> auditMap = new HashMap<>();
+        auditMap.put(OzoneConsts.TENANT, tenantId);
+        markForAudit(ozoneManager.getAuditLogger(),
+            buildAuditMessage(OMAction.DELETE_TENANT, auditMap, ex,
+                omRequest.getUserInfo()));
+        throw ex;
+      }
+    }
+
     // Acquire write lock to authorizer (Ranger)
     multiTenantManager.getAuthorizerLock().tryWriteLockInOMRequest();
     try {
@@ -167,13 +200,6 @@ public OMClientResponse 
validateAndUpdateCache(OzoneManager ozoneManager, Execut
 
       // Decrement volume refCount
       if (decVolumeRefCount) {
-        // Check Acl
-        if (ozoneManager.getAclsEnabled()) {
-          checkAcls(ozoneManager, OzoneObj.ResourceType.VOLUME,
-              OzoneObj.StoreType.OZONE, IAccessAuthorizer.ACLType.WRITE_ACL,
-              volumeName, null, null);
-        }
-
         omVolumeArgs = getVolumeInfo(omMetadataManager, volumeName)
             .toBuilder()
             .decRefCount()
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMTenantCreateRequest.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tenant/TestOMTenantCreateRequest.java
similarity index 87%
rename from 
hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMTenantCreateRequest.java
rename to 
hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tenant/TestOMTenantCreateRequest.java
index f5dc694f695..36529d01064 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMTenantCreateRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tenant/TestOMTenantCreateRequest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.hadoop.ozone.om;
+package org.apache.hadoop.ozone.om.request.s3.tenant;
 
 import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.VOLUME_ALREADY_EXISTS;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -36,16 +36,24 @@
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
 import org.apache.hadoop.ozone.audit.AuditLogger;
 import org.apache.hadoop.ozone.audit.AuditMessage;
+import org.apache.hadoop.ozone.om.OMConfigKeys;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OMMetrics;
+import org.apache.hadoop.ozone.om.OMMultiTenantManager;
+import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
+import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.TenantOp;
 import org.apache.hadoop.ozone.om.exceptions.OMException;
 import org.apache.hadoop.ozone.om.multitenant.AuthorizerLock;
 import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
-import org.apache.hadoop.ozone.om.request.s3.tenant.OMTenantCreateRequest;
 import org.apache.hadoop.ozone.om.response.OMClientResponse;
 import org.apache.hadoop.ozone.om.upgrade.OMLayoutVersionManager;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateTenantRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status;
+import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
+import org.apache.hadoop.ozone.security.acl.OzoneObj;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -266,4 +274,32 @@ private void doPreExecute(String tenantId) throws 
Exception {
     omTenantCreateRequest.preExecute(ozoneManager);
   }
 
+  @Test
+  public void preExecutePermissionDeniedWhenAclEnabled() throws Exception {
+    when(ozoneManager.getAclsEnabled()).thenReturn(true);
+
+    final String tenantId = UUID.randomUUID().toString();
+    OMRequest originalRequest =
+        OMRequestTestUtils.createTenantRequest(tenantId, false);
+
+    OMTenantCreateRequest omTenantCreateRequest =
+        spy(new OMTenantCreateRequest(originalRequest) {
+          @Override
+          public void checkAcls(OzoneManager om,
+              OzoneObj.ResourceType resType, OzoneObj.StoreType storeType,
+              IAccessAuthorizer.ACLType aclType, String volume, String bucket,
+              String key) throws IOException {
+            throw new OMException("denied",
+                OMException.ResultCodes.PERMISSION_DENIED);
+          }
+        });
+    doReturn("username").when(omTenantCreateRequest).getUserName();
+
+    OMException exception = assertThrows(OMException.class,
+        () -> omTenantCreateRequest.preExecute(ozoneManager));
+    assertEquals(OMException.ResultCodes.PERMISSION_DENIED,
+        exception.getResult());
+  }
+
 }
+
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tenant/TestOMTenantDeleteRequest.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tenant/TestOMTenantDeleteRequest.java
new file mode 100644
index 00000000000..6de4f1d8446
--- /dev/null
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tenant/TestOMTenantDeleteRequest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.hadoop.ozone.om.request.s3.tenant;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.framework;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.UUID;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.audit.AuditLogger;
+import org.apache.hadoop.ozone.audit.AuditMessage;
+import org.apache.hadoop.ozone.om.OMConfigKeys;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OMMetrics;
+import org.apache.hadoop.ozone.om.OMMultiTenantManager;
+import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
+import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.TenantOp;
+import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.OmDBTenantState;
+import org.apache.hadoop.ozone.om.multitenant.AuthorizerLock;
+import org.apache.hadoop.ozone.om.multitenant.OzoneTenant;
+import org.apache.hadoop.ozone.om.multitenant.Tenant;
+import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
+import org.apache.hadoop.ozone.om.upgrade.OMLayoutVersionManager;
+import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
+import org.apache.hadoop.ozone.security.acl.OzoneObj;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+/**
+ * Tests delete tenant request.
+ */
+public class TestOMTenantDeleteRequest {
+
+  @TempDir
+  private Path folder;
+  private OzoneManager ozoneManager;
+  private OMMetadataManager omMetadataManager;
+  private OMMetrics omMetrics;
+  private OMMultiTenantManager multiTenantManager;
+
+  @BeforeEach
+  public void setup() throws Exception {
+    ozoneManager = mock(OzoneManager.class);
+    omMetrics = OMMetrics.create();
+    OzoneConfiguration ozoneConfiguration = new OzoneConfiguration();
+    ozoneConfiguration.set(OMConfigKeys.OZONE_OM_DB_DIRS,
+        folder.toAbsolutePath().toString());
+    omMetadataManager = new OmMetadataManagerImpl(ozoneConfiguration,
+        ozoneManager);
+    when(ozoneManager.getMetrics()).thenReturn(omMetrics);
+    when(ozoneManager.getMetadataManager()).thenReturn(omMetadataManager);
+
+    OMLayoutVersionManager lvm = mock(OMLayoutVersionManager.class);
+    when(lvm.getMetadataLayoutVersion()).thenReturn(0);
+    when(lvm.isAllowed(anyString())).thenReturn(true);
+    when(ozoneManager.getVersionManager()).thenReturn(lvm);
+
+    AuditLogger auditLogger = mock(AuditLogger.class);
+    when(ozoneManager.getAuditLogger()).thenReturn(auditLogger);
+    doNothing().when(auditLogger).logWrite(any(AuditMessage.class));
+
+    multiTenantManager = mock(OMMultiTenantManager.class);
+    doNothing().when(multiTenantManager).checkAdmin();
+    when(multiTenantManager.isTenantEmpty(anyString())).thenReturn(true);
+    when(multiTenantManager.getTenantFromDBById(anyString())).thenAnswer(
+        invocation -> new OzoneTenant(invocation.getArgument(0, 
String.class)));
+    AuthorizerLock authorizerLock = mock(AuthorizerLock.class);
+    doNothing().when(authorizerLock).tryWriteLockInOMRequest();
+    doNothing().when(authorizerLock).unlockWriteInOMRequest();
+    when(multiTenantManager.getAuthorizerLock()).thenReturn(authorizerLock);
+
+    TenantOp tenantOp = mock(TenantOp.class);
+    doNothing().when(tenantOp).deleteTenant(any(Tenant.class));
+    when(multiTenantManager.getAuthorizerOp()).thenReturn(tenantOp);
+    when(multiTenantManager.getCacheOp()).thenReturn(tenantOp);
+
+    when(ozoneManager.getMultiTenantManager()).thenReturn(multiTenantManager);
+  }
+
+  @AfterEach
+  public void tearDown() {
+    omMetrics.unRegister();
+    framework().clearInlineMocks();
+  }
+
+  @Test
+  public void preExecutePermissionDeniedWhenAclEnabled() throws Exception {
+    when(ozoneManager.getAclsEnabled()).thenReturn(true);
+
+    final String tenantId = UUID.randomUUID().toString();
+    final String volumeName = tenantId;
+    when(multiTenantManager.isTenantEmpty(tenantId)).thenReturn(true);
+    when(multiTenantManager.getTenantFromDBById(tenantId)).thenReturn(
+        new OzoneTenant(tenantId));
+
+    OmDBTenantState tenantState =
+        new OmDBTenantState(tenantId, volumeName, "userRole", "adminRole",
+            "bucketNamespacePolicy", "bucketPolicy");
+    omMetadataManager.getTenantStateTable().put(tenantId, tenantState);
+
+    OMRequest deleteRequest = OMRequestTestUtils.deleteTenantRequest(tenantId);
+
+    OMTenantDeleteRequest omTenantDeleteRequest =
+        new OMTenantDeleteRequest(deleteRequest) {
+          @Override
+          public void checkAcls(OzoneManager om,
+              OzoneObj.ResourceType resType, OzoneObj.StoreType storeType,
+              IAccessAuthorizer.ACLType aclType, String volume, String bucket,
+              String key) throws IOException {
+            throw new OMException("denied",
+                OMException.ResultCodes.PERMISSION_DENIED);
+          }
+        };
+
+    OMException exception = assertThrows(OMException.class,
+        () -> omTenantDeleteRequest.preExecute(ozoneManager));
+    assertEquals(OMException.ResultCodes.PERMISSION_DENIED,
+        exception.getResult());
+  }
+}
+


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to