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

dahn pushed a commit to branch 4.20
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 3b987f21afbf02dcdd376a94835e3e277628a4e6
Author: dahn <[email protected]>
AuthorDate: Fri Feb 20 17:28:48 2026 +0100

    [20.3] handle user's canned policy when a bucket is deleted
---
 .../main/java/com/cloud/agent/api/to/BucketTO.java |  7 ++
 .../driver/MinIOObjectStoreDriverImpl.java         | 81 ++++++++++++++--------
 .../driver/MinIOObjectStoreDriverImplTest.java     |  7 +-
 3 files changed, 67 insertions(+), 28 deletions(-)

diff --git a/api/src/main/java/com/cloud/agent/api/to/BucketTO.java 
b/api/src/main/java/com/cloud/agent/api/to/BucketTO.java
index f7e4bfea80f..fd8237998a7 100644
--- a/api/src/main/java/com/cloud/agent/api/to/BucketTO.java
+++ b/api/src/main/java/com/cloud/agent/api/to/BucketTO.java
@@ -26,10 +26,13 @@ public final class BucketTO {
 
     private String secretKey;
 
+    private long accountId;
+
     public BucketTO(Bucket bucket) {
         this.name = bucket.getName();
         this.accessKey = bucket.getAccessKey();
         this.secretKey = bucket.getSecretKey();
+        this.accountId = bucket.getAccountId();
     }
 
     public BucketTO(String name) {
@@ -47,4 +50,8 @@ public final class BucketTO {
     public String getSecretKey() {
         return this.secretKey;
     }
+
+    public long getAccountId() {
+        return this.accountId;
+    }
 }
diff --git 
a/plugins/storage/object/minio/src/main/java/org/apache/cloudstack/storage/datastore/driver/MinIOObjectStoreDriverImpl.java
 
b/plugins/storage/object/minio/src/main/java/org/apache/cloudstack/storage/datastore/driver/MinIOObjectStoreDriverImpl.java
index 9dc4b30414e..28e3b85e1a5 100644
--- 
a/plugins/storage/object/minio/src/main/java/org/apache/cloudstack/storage/datastore/driver/MinIOObjectStoreDriverImpl.java
+++ 
b/plugins/storage/object/minio/src/main/java/org/apache/cloudstack/storage/datastore/driver/MinIOObjectStoreDriverImpl.java
@@ -24,6 +24,8 @@ import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
@@ -98,6 +100,51 @@ public class MinIOObjectStoreDriverImpl extends 
BaseObjectStoreDriverImpl {
         return String.format("%s-%s", ACS_PREFIX, account.getUuid());
     }
 
+    private void updateCannedPolicy(long storeId, Account account, String 
excludeBucket) {
+        List<BucketVO> buckets = 
_bucketDao.listByObjectStoreIdAndAccountId(storeId, account.getId());
+
+        String resources = buckets.stream()
+                .map(BucketVO::getName)
+                .filter(name -> !Objects.equals(name, excludeBucket))
+                .map(name -> "\"arn:aws:s3:::" + name + "/*\"")
+                .collect(Collectors.joining(",\n"));
+        String policy;
+        if (resources.isEmpty()) {
+            // Resource cannot be empty in a canned Policy so deny access to 
all resources if the user has no buckets
+            policy = " {\n" +
+                    "     \"Statement\": [\n" +
+                    "         {\n" +
+                    "             \"Action\": \"s3:*\",\n" +
+                    "             \"Effect\": \"Deny\",\n" +
+                    "             \"Resource\": [\"arn:aws:s3:::*\", 
\"arn:aws:s3:::*/*\"]\n" +
+                    "         }\n" +
+                    "     ],\n" +
+                    "     \"Version\": \"2012-10-17\"\n" +
+                    " }";
+        } else {
+            policy = " {\n" +
+                    "     \"Statement\": [\n" +
+                    "         {\n" +
+                    "             \"Action\": \"s3:*\",\n" +
+                    "             \"Effect\": \"Allow\",\n" +
+                    "             \"Resource\": [" + resources + "]\n" +
+                    "         }\n" +
+                    "     ],\n" +
+                    "     \"Version\": \"2012-10-17\"\n" +
+                    " }";
+        }
+
+        MinioAdminClient minioAdminClient = getMinIOAdminClient(storeId);
+        String policyName = getUserOrAccessKeyForAccount(account) + "-policy";
+        String userName = getUserOrAccessKeyForAccount(account);
+        try {
+            minioAdminClient.addCannedPolicy(policyName, policy);
+            minioAdminClient.setPolicy(userName, false, policyName);
+        } catch (NoSuchAlgorithmException | IOException | InvalidKeyException 
e) {
+            throw new CloudRuntimeException(e);
+        }
+    }
+
     @Override
     public Bucket createBucket(Bucket bucket, boolean objectLock) {
         //ToDo Client pool mgmt
@@ -125,33 +172,8 @@ public class MinIOObjectStoreDriverImpl extends 
BaseObjectStoreDriverImpl {
             throw new CloudRuntimeException(e);
         }
 
-        List<BucketVO> buckets = 
_bucketDao.listByObjectStoreIdAndAccountId(storeId, accountId);
-        StringBuilder resources_builder = new StringBuilder();
-        for(BucketVO exitingBucket : buckets) {
-            
resources_builder.append("\"arn:aws:s3:::"+exitingBucket.getName()+"/*\",\n");
-        }
-        resources_builder.append("\"arn:aws:s3:::"+bucketName+"/*\"\n");
-
-        String policy = " {\n" +
-                "     \"Statement\": [\n" +
-                "         {\n" +
-                "             \"Action\": \"s3:*\",\n" +
-                "             \"Effect\": \"Allow\",\n" +
-                "             \"Principal\": \"*\",\n" +
-                "             \"Resource\": ["+resources_builder+"]" +
-                "         }\n" +
-                "     ],\n" +
-                "     \"Version\": \"2012-10-17\"\n" +
-                " }";
-        MinioAdminClient minioAdminClient = getMinIOAdminClient(storeId);
-        String policyName = getUserOrAccessKeyForAccount(account) + "-policy";
-        String userName = getUserOrAccessKeyForAccount(account);
-        try {
-            minioAdminClient.addCannedPolicy(policyName, policy);
-            minioAdminClient.setPolicy(userName, false, policyName);
-        } catch (Exception e) {
-            throw new CloudRuntimeException(e);
-        }
+        updateCannedPolicy(storeId, account,null);
+
         String accessKey = _accountDetailsDao.findDetail(accountId, 
MINIO_ACCESS_KEY).getValue();
         String secretKey = _accountDetailsDao.findDetail(accountId, 
MINIO_SECRET_KEY).getValue();
         ObjectStoreVO store = _storeDao.findById(storeId);
@@ -183,6 +205,8 @@ public class MinIOObjectStoreDriverImpl extends 
BaseObjectStoreDriverImpl {
     @Override
     public boolean deleteBucket(BucketTO bucket, long storeId) {
         String bucketName = bucket.getName();
+        long accountId = bucket.getAccountId();
+        Account account = _accountDao.findById(accountId);
         MinioClient minioClient = getMinIOClient(storeId);
         try {
             
if(!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()))
 {
@@ -197,6 +221,9 @@ public class MinIOObjectStoreDriverImpl extends 
BaseObjectStoreDriverImpl {
         } catch (Exception e) {
             throw new CloudRuntimeException(e);
         }
+
+        updateCannedPolicy(storeId, account, bucketName);
+
         return true;
     }
 
diff --git 
a/plugins/storage/object/minio/src/test/java/org/apache/cloudstack/storage/datastore/driver/MinIOObjectStoreDriverImplTest.java
 
b/plugins/storage/object/minio/src/test/java/org/apache/cloudstack/storage/datastore/driver/MinIOObjectStoreDriverImplTest.java
index 1a8b3d9663a..d3298a235ca 100644
--- 
a/plugins/storage/object/minio/src/test/java/org/apache/cloudstack/storage/datastore/driver/MinIOObjectStoreDriverImplTest.java
+++ 
b/plugins/storage/object/minio/src/test/java/org/apache/cloudstack/storage/datastore/driver/MinIOObjectStoreDriverImplTest.java
@@ -129,10 +129,15 @@ public class MinIOObjectStoreDriverImplTest {
     @Test
     public void testDeleteBucket() throws Exception {
         String bucketName = "test-bucket";
-        BucketTO bucket = new BucketTO(bucketName);
+        BucketVO bucketVO = new BucketVO(1L, 1L, 1L, bucketName, 1, false, 
false, false, null);
+        BucketTO bucket = new BucketTO(bucketVO);
+        when(accountDao.findById(1L)).thenReturn(account);
+        when(account.getUuid()).thenReturn(UUID.randomUUID().toString());
+        when(bucketDao.listByObjectStoreIdAndAccountId(anyLong(), 
anyLong())).thenReturn(new ArrayList<BucketVO>());
         
doReturn(minioClient).when(minioObjectStoreDriverImpl).getMinIOClient(anyLong());
         
when(minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())).thenReturn(true);
         
doNothing().when(minioClient).removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
+        
doReturn(minioAdminClient).when(minioObjectStoreDriverImpl).getMinIOAdminClient(anyLong());
         boolean success = minioObjectStoreDriverImpl.deleteBucket(bucket, 1L);
         assertTrue(success);
         verify(minioClient, times(1)).bucketExists(any());

Reply via email to