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]