From cb0b55136296d1d949c962e896eabb7024327a83 Mon Sep 17 00:00:00 2001 From: Fabian Morgan Date: Tue, 10 Mar 2026 13:40:29 -0700 Subject: [PATCH] validate LIST permission on the key for ListBucket action instead of READ. --- .../acl/iam/IamSessionPolicyResolver.java | 8 +- .../acl/iam/TestIamSessionPolicyResolver.java | 169 ++++++++++-------- 2 files changed, 103 insertions(+), 74 deletions(-) diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/acl/iam/IamSessionPolicyResolver.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/acl/iam/IamSessionPolicyResolver.java index b8b032f1b358..596fab15729b 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/acl/iam/IamSessionPolicyResolver.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/acl/iam/IamSessionPolicyResolver.java @@ -551,12 +551,12 @@ private static void processBucketResource(String volumeName, Set mappe if (prefixes != null && !prefixes.isEmpty()) { for (String prefix : prefixes) { createObjectResourcesFromConditionPrefix( - volumeName, authorizerType, resourceSpec, prefix, objToAclsMap, EnumSet.of(READ)); + volumeName, authorizerType, resourceSpec, prefix, objToAclsMap, EnumSet.of(LIST)); } } else { - // No condition prefixes, but we need READ access to all objects, so use "*" as the prefix + // No condition prefixes, but we need LIST access to all objects, so use "*" as the prefix createObjectResourcesFromConditionPrefix( - volumeName, authorizerType, resourceSpec, "*", objToAclsMap, EnumSet.of(READ)); + volumeName, authorizerType, resourceSpec, "*", objToAclsMap, EnumSet.of(LIST)); } } } @@ -809,7 +809,7 @@ enum S3Action { GET_BUCKET_LOCATION("s3:GetBucketLocation", ActionKind.BUCKET, EnumSet.of(READ), EnumSet.of(READ), EnumSet.noneOf(ACLType.class)), // Used for HeadBucket, ListObjects and ListObjectsV2 apis - LIST_BUCKET("s3:ListBucket", ActionKind.BUCKET, EnumSet.of(READ), EnumSet.of(READ, LIST), EnumSet.of(READ)), + LIST_BUCKET("s3:ListBucket", ActionKind.BUCKET, EnumSet.of(READ), EnumSet.of(READ, LIST), EnumSet.of(LIST)), // Used for ListMultipartUploads API LIST_BUCKET_MULTIPART_UPLOADS("s3:ListBucketMultipartUploads", ActionKind.BUCKET, EnumSet.of(READ), EnumSet.of(READ, LIST), EnumSet.noneOf(ACLType.class)), diff --git a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/security/acl/iam/TestIamSessionPolicyResolver.java b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/security/acl/iam/TestIamSessionPolicyResolver.java index 41d2fc338f30..120f48d3fed3 100644 --- a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/security/acl/iam/TestIamSessionPolicyResolver.java +++ b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/security/acl/iam/TestIamSessionPolicyResolver.java @@ -713,11 +713,9 @@ public void testCreatePathsAndPermissionsWithResourceAny() { final Map> objToAclsMapRanger = new LinkedHashMap<>(); createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs, emptySet(), objToAclsMapRanger); final Set resultRanger = groupObjectsByAcls(objToAclsMapRanger); - final Set readAndListObjects = objSet(volume(), bucket("*")); // volume, bucket level have READ, LIST - final Set readObject = objSet(key("*", "*")); // key level has READ - assertThat(resultRanger).containsExactlyInAnyOrder( - new OzoneGrant(readAndListObjects, acls(READ, LIST)), - new OzoneGrant(readObject, acls(READ))); + // volume, bucket level, key have READ, LIST + final Set readAndListObjects = objSet(volume(), bucket("*"), key("*", "*")); + assertThat(resultRanger).containsExactlyInAnyOrder(new OzoneGrant(readAndListObjects, acls(READ, LIST))); } @Test @@ -728,18 +726,22 @@ public void testCreatePathsAndPermissionsWithBucketResourceThatIsListBucket() { final Set readAndListObject = objSet(bucket("bucket1")); final Map> objToAclsMapNative = new LinkedHashMap<>(); - final Set nativeReadObjects = objSet(volume(), prefix("bucket1", "")); + final Set nativeListObject = objSet(prefix("bucket1", "")); + final Set nativeReadObject = objSet(volume()); createPathsAndPermissions(VOLUME, NATIVE, actions, resourceSpecs, emptySet(), objToAclsMapNative); final Set resultNative = groupObjectsByAcls(objToAclsMapNative); assertThat(resultNative).containsExactlyInAnyOrder( - new OzoneGrant(readAndListObject, acls(READ, LIST)), new OzoneGrant(nativeReadObjects, acls(READ))); + new OzoneGrant(readAndListObject, acls(READ, LIST)), new OzoneGrant(nativeListObject, acls(LIST)), + new OzoneGrant(nativeReadObject, acls(READ))); final Map> objToAclsMapRanger = new LinkedHashMap<>(); - final Set rangerReadObjects = objSet(volume(), key("bucket1", "*")); + final Set rangerListObject = objSet(key("bucket1", "*")); + final Set rangerReadObject = objSet(volume()); createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs, emptySet(), objToAclsMapRanger); final Set resultRanger = groupObjectsByAcls(objToAclsMapRanger); assertThat(resultRanger).containsExactlyInAnyOrder( - new OzoneGrant(readAndListObject, acls(READ, LIST)), new OzoneGrant(rangerReadObjects, acls(READ))); + new OzoneGrant(readAndListObject, acls(READ, LIST)), new OzoneGrant(rangerListObject, acls(LIST)), + new OzoneGrant(rangerReadObject, acls(READ))); } @Test @@ -801,12 +803,12 @@ public void testCreatePathsAndPermissionsWithBucketsWildcardResourceAll() { createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs, emptySet(), objToAclsMapRanger); // Both the volume and the wildcard bucket should end up with READ + LIST permissions. - // We also need READ access on the keys + // We also need LIST access on the keys final Set resultRanger = groupObjectsByAcls(objToAclsMapRanger); final Set readAndListObjects = objSet(volume(), bucket("*")); - final Set readObjects = objSet(key("*", "*")); + final Set listObjects = objSet(key("*", "*")); assertThat(resultRanger).containsExactlyInAnyOrder( - new OzoneGrant(readAndListObjects, acls(READ, LIST)), new OzoneGrant(readObjects, acls(READ))); + new OzoneGrant(readAndListObjects, acls(READ, LIST)), new OzoneGrant(listObjects, acls(LIST))); } @Test @@ -890,25 +892,29 @@ public void testCreatePathsAndPermissionsWithConditionPrefixesForBucketActionWhe final Set nativeResourceSpecs = Collections.singleton( new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.BUCKET, "bucket1", null, null)); - final Set nativeReadObjects = objSet( - prefix("bucket1", "folder1/"), prefix("bucket1", "folder2/"), volume()); + final Set nativeListObjects = objSet( + prefix("bucket1", "folder1/"), prefix("bucket1", "folder2/")); + final Set nativeReadObject = objSet(volume()); final Set nativeReadAndListObject = objSet(bucket("bucket1")); final Map> objToAclsMapNative = new LinkedHashMap<>(); createPathsAndPermissions(VOLUME, NATIVE, actions, nativeResourceSpecs, prefixes, objToAclsMapNative); final Set resultNative = groupObjectsByAcls(objToAclsMapNative); assertThat(resultNative).containsExactlyInAnyOrder( - new OzoneGrant(nativeReadObjects, acls(READ)), new OzoneGrant(nativeReadAndListObject, acls(READ, LIST))); + new OzoneGrant(nativeListObjects, acls(LIST)), new OzoneGrant(nativeReadAndListObject, acls(READ, LIST)), + new OzoneGrant(nativeReadObject, acls(READ))); final Set rangerResourceSpecs = Collections.singleton( new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.BUCKET, "bucket1", null, null)); - final Set rangerReadObjects = objSet( - key("bucket1", "folder1/"), key("bucket1", "folder2/"), volume()); + final Set rangerListObjects = objSet( + key("bucket1", "folder1/"), key("bucket1", "folder2/")); + final Set rangerReadObject = objSet(volume()); final Set rangerReadAndListObject = objSet(bucket("bucket1")); final Map> objToAclsMapRanger = new LinkedHashMap<>(); createPathsAndPermissions(VOLUME, RANGER, actions, rangerResourceSpecs, prefixes, objToAclsMapRanger); final Set resultRanger = groupObjectsByAcls(objToAclsMapRanger); assertThat(resultRanger).containsExactlyInAnyOrder( - new OzoneGrant(rangerReadObjects, acls(READ)), new OzoneGrant(rangerReadAndListObject, acls(READ, LIST))); + new OzoneGrant(rangerListObjects, acls(LIST)), new OzoneGrant(rangerReadAndListObject, acls(READ, LIST)), + new OzoneGrant(rangerReadObject, acls(READ))); } @Test @@ -1004,19 +1010,23 @@ public void testCreatePathsAndPermissionsWithAllS3ActionsOverridesAnyOtherAction .collect(Collectors.toSet()); final Set allObjects = objSet(key("bucket1", "key.txt"), bucket("bucket2")); - final Set nativeReadObjects = objSet(volume(), bucket("bucket1"), prefix("bucket2", "")); + final Set nativeReadObjects = objSet(volume(), bucket("bucket1")); + final Set nativeListObject = objSet(prefix("bucket2", "")); final Map> objToAclsMapNative = new LinkedHashMap<>(); createPathsAndPermissions(VOLUME, NATIVE, actions, resourceSpecs, emptySet(), objToAclsMapNative); final Set resultNative = groupObjectsByAcls(objToAclsMapNative); assertThat(resultNative).containsExactlyInAnyOrder( - new OzoneGrant(allObjects, acls(ALL)), new OzoneGrant(nativeReadObjects, acls(READ))); + new OzoneGrant(allObjects, acls(ALL)), new OzoneGrant(nativeReadObjects, acls(READ)), + new OzoneGrant(nativeListObject, acls(LIST))); - final Set rangerReadObjects = objSet(volume(), bucket("bucket1"), key("bucket2", "*")); + final Set rangerReadObjects = objSet(volume(), bucket("bucket1")); + final Set rangerListObject = objSet(key("bucket2", "*")); final Map> objToAclsMapRanger = new LinkedHashMap<>(); createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs, emptySet(), objToAclsMapRanger); final Set resultRanger = groupObjectsByAcls(objToAclsMapRanger); assertThat(resultRanger).containsExactlyInAnyOrder( - new OzoneGrant(allObjects, acls(ALL)), new OzoneGrant(rangerReadObjects, acls(READ))); + new OzoneGrant(allObjects, acls(ALL)), new OzoneGrant(rangerReadObjects, acls(READ)), + new OzoneGrant(rangerListObject, acls(LIST))); } @Test @@ -1050,17 +1060,19 @@ public void testDeduplicatesAcrossMultipleStatementsWhenSameStatementsArePresent // Ensure what we got is what we expected final Set expectedResolvedNative = new LinkedHashSet<>(); - // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and prefix "" READ + // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL; volume READ and prefix "" LIST final Set bucketSet = objSet(bucket("my-bucket")); final Set bucketAcls = acls(READ, LIST, READ_ACL, WRITE_ACL); expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls)); - expectedResolvedNative.add(new OzoneGrant(objSet(volume(), prefix("my-bucket", "")), acls(READ))); + expectedResolvedNative.add(new OzoneGrant(objSet(prefix("my-bucket", "")), acls(LIST))); + expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative); final Set expectedResolvedRanger = new LinkedHashSet<>(); - // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and key "*" READ + // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL; volume READ and key "*" LIST expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls)); - expectedResolvedRanger.add(new OzoneGrant(objSet(volume(), key("my-bucket", "*")), acls(READ))); + expectedResolvedRanger.add(new OzoneGrant(objSet(key("my-bucket", "*")), acls(LIST))); + expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); } @@ -1095,19 +1107,21 @@ public void testDeduplicatesAcrossMultipleStatementsForSameActionsButDifferentRe // Ensure what we got is what we expected final Set expectedResolvedNative = new LinkedHashSet<>(); - // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and prefix "" READ + // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL; volume READ and prefix "" LIST final Set bucketSet = objSet(bucket("my-bucket"), bucket("my-bucket2")); final Set bucketAcls = acls(READ, LIST, READ_ACL, WRITE_ACL); expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls)); expectedResolvedNative.add(new OzoneGrant( - objSet(volume(), prefix("my-bucket2", ""), prefix("my-bucket", "")), acls(READ))); + objSet(prefix("my-bucket2", ""), prefix("my-bucket", "")), acls(LIST))); + expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative); final Set expectedResolvedRanger = new LinkedHashSet<>(); - // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and key "*" READ + // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL; volume READ and key "*" LIST expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls)); expectedResolvedRanger.add(new OzoneGrant( - objSet(volume(), key("my-bucket2", "*"), key("my-bucket", "*")), acls(READ))); + objSet(key("my-bucket2", "*"), key("my-bucket", "*")), acls(LIST))); + expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); } @@ -1141,17 +1155,19 @@ public void testDeduplicatesAcrossMultipleStatementsForDifferentActionsButSameRe // Ensure what we got is what we expected final Set expectedResolvedNative = new LinkedHashSet<>(); - // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL, CREATE; volume, prefix "" READ + // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL, CREATE; volume READ, prefix "" LIST final Set bucketSet = objSet(bucket("my-bucket")); final Set bucketAcls = acls(READ, LIST, READ_ACL, WRITE_ACL, CREATE); expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls)); - expectedResolvedNative.add(new OzoneGrant(objSet(volume(), prefix("my-bucket", "")), acls(READ))); + expectedResolvedNative.add(new OzoneGrant(objSet(prefix("my-bucket", "")), acls(LIST))); + expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative); final Set expectedResolvedRanger = new LinkedHashSet<>(); - // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL, CREATE; volume, key "*" READ + // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL, CREATE; volume READ, key "*" LIST expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls)); - expectedResolvedRanger.add(new OzoneGrant(objSet(volume(), key("my-bucket", "*")), acls(READ))); + expectedResolvedRanger.add(new OzoneGrant(objSet(key("my-bucket", "*")), acls(LIST))); + expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); } @@ -1182,17 +1198,19 @@ public void testDeduplicatesAcrossMultipleStatementsWhenAllActionPresent() throw // Ensure what we got is what we expected final Set expectedResolvedNative = new LinkedHashSet<>(); - // Expected for native: bucket ALL (instead of individual actions); volume and prefix "" READ + // Expected for native: bucket ALL (instead of individual actions); volume READ and prefix "" LIST final Set bucketSet = objSet(bucket("my-bucket")); final Set bucketAcls = acls(ALL); expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls)); - expectedResolvedNative.add(new OzoneGrant(objSet(volume(), prefix("my-bucket", "")), acls(READ))); + expectedResolvedNative.add(new OzoneGrant(objSet(prefix("my-bucket", "")), acls(LIST))); + expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative); final Set expectedResolvedRanger = new LinkedHashSet<>(); - // Expected for Ranger: bucket ALL (instead of individual actions); volume and key "*" READ + // Expected for Ranger: bucket ALL (instead of individual actions); volume READ and key "*" LIST expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls)); - expectedResolvedRanger.add(new OzoneGrant(objSet(volume(), key("my-bucket", "*")), acls(READ))); + expectedResolvedRanger.add(new OzoneGrant(objSet(key("my-bucket", "*")), acls(LIST))); + expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); } @@ -1267,16 +1285,18 @@ public void testAllActionsForBucket() throws OMException { // Ensure what we got is what we expected final Set expectedResolvedNative = new LinkedHashSet<>(); - // Expected for native: all Bucket ACLs for bucket; volume, prefix "" READ + // Expected for native: all Bucket ACLs for bucket; volume READ, prefix "" LIST final Set bucketSet = objSet(bucket("my-bucket")); final Set allBucketAcls = acls(ALL); - expectedResolvedNative.add(new OzoneGrant(objSet(volume(), prefix("my-bucket", "")), acls(READ))); + expectedResolvedNative.add(new OzoneGrant(objSet(prefix("my-bucket", "")), acls(LIST))); + expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ))); expectedResolvedNative.add(new OzoneGrant(bucketSet, allBucketAcls)); assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative); - // Expected for Ranger: all Bucket ACLs for bucket; volume, key "*" READ + // Expected for Ranger: all Bucket ACLs for bucket; volume READ, key "*" LIST final Set expectedResolvedRanger = new LinkedHashSet<>(); - expectedResolvedRanger.add(new OzoneGrant(objSet(volume(), key("my-bucket", "*")), acls(READ))); + expectedResolvedRanger.add(new OzoneGrant(objSet(key("my-bucket", "*")), acls(LIST))); + expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ))); expectedResolvedRanger.add(new OzoneGrant(bucketSet, allBucketAcls)); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); } @@ -1457,11 +1477,12 @@ public void testListBucketWithWildcard() throws OMException { final Set resolvedFromRangerAuthorizer = resolve(json, VOLUME, RANGER); // Ensure what we got is what we expected final Set expectedResolvedRanger = new LinkedHashSet<>(); - // Expected for Ranger: bucket READ and LIST on wildcard pattern; volume and key "*" READ + // Expected for Ranger: bucket READ and LIST on wildcard pattern; volume READ; key "*" LIST final Set bucketSet = objSet(bucket("proj-*")); final Set bucketAcls = acls(READ, LIST); expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls)); - expectedResolvedRanger.add(new OzoneGrant(objSet(volume(), key("proj-*", "*")), acls(READ))); + expectedResolvedRanger.add(new OzoneGrant(objSet(key("proj-*", "*")), acls(LIST))); + expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); } @@ -1485,19 +1506,23 @@ public void testListBucketOperationsWithNoPrefixes() throws OMException { // Ensure what we got is what we expected final Set expectedResolvedNative = new LinkedHashSet<>(); - // Expected for native: bucket READ and LIST; volume, prefix "" READ + // Expected for native: bucket READ and LIST; volume, prefix "" LIST final Set bucketSet = objSet(bucket("proj")); final Set bucketAcls = acls(READ, LIST); - final Set nativeReadObjects = objSet(volume(), prefix("proj", "")); + final Set nativeListObject = objSet(prefix("proj", "")); + final Set nativeReadObject = objSet(volume()); expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls)); - expectedResolvedNative.add(new OzoneGrant(nativeReadObjects, acls(READ))); + expectedResolvedNative.add(new OzoneGrant(nativeListObject, acls(LIST))); + expectedResolvedNative.add(new OzoneGrant(nativeReadObject, acls(READ))); assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative); - // Expected for Ranger: bucket READ and LIST; volume, key "*" READ - final Set rangerReadObjects = objSet(volume(), key("proj", "*")); + // Expected for Ranger: bucket READ and LIST; volume READ, key "*" LIST + final Set rangerListObject = objSet(key("proj", "*")); + final Set rangerReadObject = objSet(volume()); final Set expectedResolvedRanger = new LinkedHashSet<>(); expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls)); - expectedResolvedRanger.add(new OzoneGrant(rangerReadObjects, acls(READ))); + expectedResolvedRanger.add(new OzoneGrant(rangerListObject, acls(LIST))); + expectedResolvedRanger.add(new OzoneGrant(rangerReadObject, acls(READ))); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); } @@ -1533,19 +1558,23 @@ public void testIgnoresUnsupportedActionsWhenSupportedActionsAreIncluded() throw // Ensure what we got is what we expected final Set expectedResolvedNative = new LinkedHashSet<>(); - // Expected for native: READ, LIST, READ_ACL bucket acls; volume and prefixes "team/folder", "team/folder/" READ + // Expected for native: READ, LIST, READ_ACL bucket acls; volume READ; + // prefixes "team/folder", "team/folder/" LIST final Set bucketSet = objSet(bucket("bucket1")); final Set bucketAcls = acls(READ, LIST, READ_ACL); expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls)); expectedResolvedNative.add(new OzoneGrant( - objSet(volume(), prefix("bucket1", "team/folder"), prefix("bucket1", "team/folder/")), acls(READ))); + objSet(prefix("bucket1", "team/folder"), prefix("bucket1", "team/folder/")), acls(LIST))); + expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative); final Set expectedResolvedRanger = new LinkedHashSet<>(); - // Expected for Ranger: READ, LIST, READ_ACL bucket acls; volume and keys "team/folder" and "team/folder/*" READ + // Expected for Ranger: READ, LIST, READ_ACL bucket acls; volume READ; + // keys "team/folder" and "team/folder/*" LIST expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls)); expectedResolvedRanger.add(new OzoneGrant( - objSet(volume(), key("bucket1", "team/folder"), key("bucket1", "team/folder/*")), acls(READ))); + objSet(key("bucket1", "team/folder"), key("bucket1", "team/folder/*")), acls(LIST))); + expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ))); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); } @@ -1647,10 +1676,10 @@ public void testBucketActionOnAllResources() throws OMException { final Set resolvedFromRangerAuthorizer = resolve(json, VOLUME, RANGER); // Ensure what we got is what we expected final Set expectedResolvedRanger = new LinkedHashSet<>(); - // Expected for Ranger: READ and LIST on volume and bucket (wildcard), READ on key "*" + // Expected for Ranger: READ and LIST on volume and bucket (wildcard), LIST on key "*" final Set resourceSet = objSet(volume(), bucket("*")); expectedResolvedRanger.add(new OzoneGrant(resourceSet, acls(READ, LIST))); - expectedResolvedRanger.add(new OzoneGrant(objSet(key("*", "*")), acls(READ))); + expectedResolvedRanger.add(new OzoneGrant(objSet(key("*", "*")), acls(LIST))); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); } @@ -1717,11 +1746,12 @@ public void testAllActionsOnAllBucketResources() throws OMException { final Set resolvedFromRangerAuthorizer = resolve(json, VOLUME, RANGER); // Ensure what we got is what we expected final Set expectedResolvedRanger = new LinkedHashSet<>(); - // Expected for Ranger: ALL bucket acls on wildcard pattern, volume READ, key "*" READ + // Expected for Ranger: ALL bucket acls on wildcard pattern, volume READ and LIST (because of ListAllMyBuckets), + // key "*" LIST final Set bucketSet = objSet(bucket("*")); final Set bucketAcls = acls(ALL); expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls)); - expectedResolvedRanger.add(new OzoneGrant(objSet(key("*", "*")), acls(READ))); + expectedResolvedRanger.add(new OzoneGrant(objSet(key("*", "*")), acls(LIST))); expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ, LIST))); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); } @@ -1804,21 +1834,20 @@ public void testWildcardActionGroupListStar() throws OMException { // Ensure what we got is what we expected final Set expectedResolvedNative = new LinkedHashSet<>(); - // Expected for native: READ, LIST bucket acls - final Set bucketSet = objSet(bucket("my-bucket")); - final Set bucketAcls = acls(READ, LIST); - expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls)); - // Expected for native: READ acl on prefix "" under bucket; volume READ - final Set readObjectsNative = objSet(prefix("my-bucket", ""), volume()); - expectedResolvedNative.add(new OzoneGrant(readObjectsNative, acls(READ))); + // Expected for native: READ, LIST bucket acls, READ and LIST acl on prefix "" under bucket; volume READ + final Set readAndListsObjectsNative = objSet(bucket("my-bucket"), prefix("my-bucket", "")); + final Set readObjectNative = objSet(volume()); + expectedResolvedNative.add(new OzoneGrant(readAndListsObjectsNative, acls(READ, LIST))); + expectedResolvedNative.add(new OzoneGrant(readObjectNative, acls(READ))); assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative); final Set expectedResolvedRanger = new LinkedHashSet<>(); - // Expected for Ranger: READ, LIST bucket acls - expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls)); - // Expected for Ranger: READ key acl for resource type KEY with key name "*"; volume READ - final Set readObjectsRanger = objSet(key("my-bucket", "*"), volume()); - expectedResolvedRanger.add(new OzoneGrant(readObjectsRanger, acls(READ))); + // Expected for Ranger: READ, LIST bucket acls; READ and LIST key acl for resource type KEY with key name "*"; + // volume READ + final Set readAndListObjectsRanger = objSet(bucket("my-bucket"), key("my-bucket", "*")); + final Set readObjectRanger = objSet(volume()); + expectedResolvedRanger.add(new OzoneGrant(readAndListObjectsRanger, acls(READ, LIST))); + expectedResolvedRanger.add(new OzoneGrant(readObjectRanger, acls(READ))); assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger); }