fmorg-git commented on code in PR #9315:
URL: https://github.com/apache/ozone/pull/9315#discussion_r2597143462
##########
hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/security/acl/iam/TestIamSessionPolicyResolver.java:
##########
@@ -903,22 +914,1013 @@ public void
testCreatePathsAndPermissionsWithConditionPrefixesForBucketActionWhe
final Set<IamSessionPolicyResolver.ResourceSpec> nativeResourceSpecs =
Collections.singleton(
new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.BUCKET,
"bucket1", null, null));
- final Set<AssumeRoleRequest.OzoneGrant> resultNative =
createPathsAndPermissions(
- VOLUME, NATIVE, actions, nativeResourceSpecs, prefixes);
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, NATIVE, actions, nativeResourceSpecs,
prefixes, objToAclsMapNative);
+ final Set<OzoneGrant> resultNative =
groupObjectsByAcls(objToAclsMapNative);
assertThat(resultNative).containsExactlyInAnyOrder(
- new AssumeRoleRequest.OzoneGrant(readObject, acls(READ)),
- new AssumeRoleRequest.OzoneGrant(readAndReadAclObject, acls(READ,
READ_ACL)));
+ new OzoneGrant(readObject, acls(READ)), new
OzoneGrant(readAndReadAclObject, acls(READ, READ_ACL)));
final Set<IamSessionPolicyResolver.ResourceSpec> rangerResourceSpecs =
Collections.singleton(
new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.BUCKET,
"bucket1", null, null));
- final Set<AssumeRoleRequest.OzoneGrant> resultRanger =
createPathsAndPermissions(
- VOLUME, RANGER, actions, rangerResourceSpecs, prefixes);
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, RANGER, actions, rangerResourceSpecs,
prefixes, objToAclsMapRanger);
+ final Set<OzoneGrant> resultRanger =
groupObjectsByAcls(objToAclsMapRanger);
+ assertThat(resultRanger).containsExactlyInAnyOrder(
+ new OzoneGrant(readObject, acls(READ)), new
OzoneGrant(readAndReadAclObject, acls(READ, READ_ACL)));
+ }
+
+ @Test
+ public void testCreatePathsAndPermissionsWithNoMappedActions() {
+ final Set<S3Action> actions = emptySet();
+
+ final Set<IamSessionPolicyResolver.ResourceSpec> nativeResourceSpecs =
Collections.singleton(
+ new
IamSessionPolicyResolver.ResourceSpec(S3ResourceType.OBJECT_PREFIX, "bucket1",
null, null));
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, NATIVE, actions, nativeResourceSpecs,
emptySet(), objToAclsMapNative);
+ final Set<OzoneGrant> resultNative =
groupObjectsByAcls(objToAclsMapNative);
+ assertThat(resultNative).isEmpty();
+
+ final Set<IamSessionPolicyResolver.ResourceSpec> rangerResourceSpecs =
Collections.singleton(
+ new
IamSessionPolicyResolver.ResourceSpec(S3ResourceType.OBJECT_PREFIX_WILDCARD,
"bucket1", null, null));
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, RANGER, actions, rangerResourceSpecs,
emptySet(), objToAclsMapRanger);
+ final Set<OzoneGrant> resultRanger =
groupObjectsByAcls(objToAclsMapRanger);
+ assertThat(resultRanger).isEmpty();
+ }
+
+ @Test
+ public void testCreatePathsAndPermissionsWithNoMappedResources() {
+ final Set<S3Action> actions = Collections.singleton(S3Action.GET_OBJECT);
+ final Set<IamSessionPolicyResolver.ResourceSpec> resourceSpecs =
emptySet();
+
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, NATIVE, actions, resourceSpecs,
emptySet(), objToAclsMapNative);
+ final Set<OzoneGrant> resultNative =
groupObjectsByAcls(objToAclsMapNative);
+ assertThat(resultNative).isEmpty();
+
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs,
emptySet(), objToAclsMapRanger);
+ final Set<OzoneGrant> resultRanger =
groupObjectsByAcls(objToAclsMapRanger);
+ assertThat(resultRanger).isEmpty();
+ }
+
+ @Test
+ public void
testCreatePathsAndPermissionsDeduplicatesAcrossSameResourceTypes() {
+ final Set<S3Action> actions = Stream.of(
+ S3Action.GET_OBJECT, S3Action.GET_OBJECT_TAGGING,
S3Action.DELETE_OBJECT, S3Action.DELETE_OBJECT_TAGGING)
+ .collect(Collectors.toSet());
+ final Set<IamSessionPolicyResolver.ResourceSpec> resourceSpecs =
Collections.singleton(
+ new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.OBJECT_EXACT,
"bucket1", null, "key.txt"));
+ final Set<IOzoneObj> readAndDeleteObject = objSet(key("bucket1",
"key.txt"));
+ final Set<IOzoneObj> readObjects = objSet(bucket("bucket1"), volume());
+
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, NATIVE, actions, resourceSpecs,
emptySet(), objToAclsMapNative);
+ final Set<OzoneGrant> resultNative =
groupObjectsByAcls(objToAclsMapNative);
+ assertThat(resultNative).containsExactlyInAnyOrder(
+ new OzoneGrant(readAndDeleteObject, acls(READ, DELETE)), new
OzoneGrant(readObjects, acls(READ)));
+
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs,
emptySet(), objToAclsMapRanger);
+ final Set<OzoneGrant> resultRanger =
groupObjectsByAcls(objToAclsMapRanger);
assertThat(resultRanger).containsExactlyInAnyOrder(
- new AssumeRoleRequest.OzoneGrant(readObject, acls(READ)),
- new AssumeRoleRequest.OzoneGrant(readAndReadAclObject, acls(READ,
READ_ACL)));
+ new OzoneGrant(readAndDeleteObject, acls(READ, DELETE)), new
OzoneGrant(readObjects, acls(READ)));
+ }
+
+ @Test
+ public void
testCreatePathsAndPermissionsWithAllS3ActionsOverridesAnyOtherAction() {
+ final Set<S3Action> actions = Stream.of(
+ S3Action.ALL_S3, S3Action.GET_OBJECT, S3Action.DELETE_OBJECT,
S3Action.LIST_BUCKET)
+ .collect(Collectors.toSet());
+ final Set<IamSessionPolicyResolver.ResourceSpec> resourceSpecs = Stream.of(
+ new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.OBJECT_EXACT,
"bucket1", null, "key.txt"),
+ new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.BUCKET,
"bucket2", null, null))
+ .collect(Collectors.toSet());
+ final Set<IOzoneObj> allObjects = objSet(key("bucket1", "key.txt"),
bucket("bucket2"));
+
+ final Set<IOzoneObj> nativeReadObjects = objSet(volume(),
bucket("bucket1"), prefix("bucket2", ""));
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, NATIVE, actions, resourceSpecs,
emptySet(), objToAclsMapNative);
+ final Set<OzoneGrant> resultNative =
groupObjectsByAcls(objToAclsMapNative);
+ assertThat(resultNative).containsExactlyInAnyOrder(
+ new OzoneGrant(allObjects, acls(ALL)), new
OzoneGrant(nativeReadObjects, acls(READ)));
+
+ final Set<IOzoneObj> rangerReadObjects = objSet(volume(),
bucket("bucket1"), key("bucket2", "*"));
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs,
emptySet(), objToAclsMapRanger);
+ final Set<OzoneGrant> resultRanger =
groupObjectsByAcls(objToAclsMapRanger);
+ assertThat(resultRanger).containsExactlyInAnyOrder(
+ new OzoneGrant(allObjects, acls(ALL)), new
OzoneGrant(rangerReadObjects, acls(READ)));
+ }
+
+ @Test
+ public void
testDeduplicatesAcrossMultipleStatementsWhenSameStatementsArePresent() throws
OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and
prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> 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)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and
key "*" READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
key("my-bucket", "*")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void
testDeduplicatesAcrossMultipleStatementsForSameActionsButDifferentResource()
throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket2\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and
prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"),
bucket("my-bucket2"));
+ final Set<ACLType> 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)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and
key "*" READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(
+ objSet(volume(), key("my-bucket2", "*"), key("my-bucket", "*")),
acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void
testDeduplicatesAcrossMultipleStatementsForDifferentActionsButSameResource()
throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:CreateBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL, CREATE;
volume, prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> 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)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL, CREATE;
volume, key "*" READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
key("my-bucket", "*")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testDeduplicatesAcrossMultipleStatementsWhenAllActionPresent()
throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket ALL (instead of individual actions); volume
and prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> bucketAcls = acls(ALL);
+ expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume(),
prefix("my-bucket", "")), acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket ALL (instead of individual actions); volume
and key "*" READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
key("my-bucket", "*")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testAllowGetPutOnKey() throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\"s3:GetObject\", \"s3:PutObject\"],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket/folder/file.txt\"\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedFromBothAuthorizers = new
LinkedHashSet<>();
+ // Expected: READ, CREATE, WRITE on key; bucket READ; volume READ
+ final Set<IOzoneObj> keySet = objSet(key("my-bucket", "folder/file.txt"));
+ final Set<ACLType> keyAcls = acls(READ, CREATE, WRITE);
+ expectedResolvedFromBothAuthorizers.add(new OzoneGrant(objSet(volume(),
bucket("my-bucket")), acls(READ)));
+ expectedResolvedFromBothAuthorizers.add(new OzoneGrant(keySet, keyAcls));
+
+
assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedFromBothAuthorizers);
+
assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedFromBothAuthorizers);
+ }
+
+ @Test
+ public void testAllActionsForKey() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket/*\"\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: all key ACLs on prefix "" under bucket; bucket
READ, volume READ
+ final Set<IOzoneObj> keyPrefixSet = objSet(prefix("my-bucket", ""));
+ final Set<ACLType> allKeyAcls = acls(ALL);
+ expectedResolvedNative.add(new OzoneGrant(keyPrefixSet, allKeyAcls));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume(),
bucket("my-bucket")), acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ // Expected for Ranger: all key acls for resource type KEY with key name
"*"
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ final Set<IOzoneObj> rangerKeySet = objSet(key("my-bucket", "*"));
+ expectedResolvedRanger.add(new OzoneGrant(rangerKeySet, allKeyAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
bucket("my-bucket")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testAllActionsForBucket() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: all Bucket ACLs for bucket; volume, prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> allBucketAcls = acls(ALL);
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume(),
prefix("my-bucket", "")), acls(READ)));
+ expectedResolvedNative.add(new OzoneGrant(bucketSet, allBucketAcls));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ // Expected for Ranger: all Bucket ACLs for bucket; volume, key "*" READ
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
key("my-bucket", "*")), acls(READ)));
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, allBucketAcls));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testMultipleResourcesInSeparateStatements() throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket/*\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL; volume READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> bucketAcls = acls(READ, LIST, READ_ACL, WRITE_ACL);
+ expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ // Expected for native: all key ACLs on prefix "" under bucket
+ final Set<IOzoneObj> keyPrefixSet = objSet(prefix("my-bucket", ""));
+ final Set<ACLType> keyAllAcls = acls(ALL);
+ expectedResolvedNative.add(new OzoneGrant(keyPrefixSet, keyAllAcls));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL; volume READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ // Expected for Ranger: all key acls for resource type KEY with key name
"*"
+ final Set<IOzoneObj> rangerKeySet = objSet(key("my-bucket", "*"));
+ expectedResolvedRanger.add(new OzoneGrant(rangerKeySet, keyAllAcls));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testMultipleResourcesInOneStatement() throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:*\"\n" +
+ " ],\n" +
+ " \"Resource\": [\n" +
+ " \"arn:aws:s3:::my-bucket\",\n" +
+ " \"arn:aws:s3:::my-bucket/*\"\n" +
+ " ]\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: all for bucket and key acls; volume READ
+ final Set<IOzoneObj> resourceSetNative = objSet(bucket("my-bucket"),
prefix("my-bucket", ""));
+ expectedResolvedNative.add(new OzoneGrant(resourceSetNative, acls(ALL)));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: all for bucket and key acls; volume READ
+ final Set<IOzoneObj> resourceSetRanger = objSet(bucket("my-bucket"),
key("my-bucket", "*"));
+ expectedResolvedRanger.add(new OzoneGrant(resourceSetRanger, acls(ALL)));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void
testMultipleResourcesWithDifferentBucketsAndDeepPathsInOneStatement() throws
OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:*\"\n" +
+ " ],\n" +
+ " \"Resource\": [\n" +
+ " \"arn:aws:s3:::my-bucket/team/folder1/security/*\",\n" +
+ " \"arn:aws:s3:::my-bucket2/team/folder2/misc/*\"\n" +
+ " ]\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: all key ACLs on prefix "team/folder1/security/"
under
+ // my-bucket and all key ACLs on prefix "team/folder2/misc/" under
my-bucket2; bucket READ; volume READ
+ final Set<IOzoneObj> keyPrefixSet = objSet(
+ prefix("my-bucket", "team/folder1/security/"), prefix("my-bucket2",
"team/folder2/misc/"));
+ final Set<ACLType> keyAllAcls = acls(ALL);
+ expectedResolvedNative.add(new OzoneGrant(keyPrefixSet, keyAllAcls));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume(),
bucket("my-bucket"), bucket("my-bucket2")), acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: all key acls for resource type KEY with key name
+ // "team/folder1/security/*" under my-bucket and "team/folder2/misc/*"
under my-bucket2; bucket READ; volume READ
+ final Set<IOzoneObj> rangerKeySet = objSet(
+ key("my-bucket", "team/folder1/security/*"), key("my-bucket2",
"team/folder2/misc/*"));
+ expectedResolvedRanger.add(new OzoneGrant(rangerKeySet, keyAllAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
bucket("my-bucket"), bucket("my-bucket2")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testUnsupportedActionIgnoredWhenItIsTheOnlyAction() throws
OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:ReplicateObject\",\n" + // unsupported
action
+ " \"Resource\": \"*\"\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ assertThat(resolvedFromNativeAuthorizer.isEmpty());
+ assertThat(resolvedFromRangerAuthorizer.isEmpty());
Review Comment:
updated
##########
hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/security/acl/iam/TestIamSessionPolicyResolver.java:
##########
@@ -903,22 +914,1013 @@ public void
testCreatePathsAndPermissionsWithConditionPrefixesForBucketActionWhe
final Set<IamSessionPolicyResolver.ResourceSpec> nativeResourceSpecs =
Collections.singleton(
new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.BUCKET,
"bucket1", null, null));
- final Set<AssumeRoleRequest.OzoneGrant> resultNative =
createPathsAndPermissions(
- VOLUME, NATIVE, actions, nativeResourceSpecs, prefixes);
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, NATIVE, actions, nativeResourceSpecs,
prefixes, objToAclsMapNative);
+ final Set<OzoneGrant> resultNative =
groupObjectsByAcls(objToAclsMapNative);
assertThat(resultNative).containsExactlyInAnyOrder(
- new AssumeRoleRequest.OzoneGrant(readObject, acls(READ)),
- new AssumeRoleRequest.OzoneGrant(readAndReadAclObject, acls(READ,
READ_ACL)));
+ new OzoneGrant(readObject, acls(READ)), new
OzoneGrant(readAndReadAclObject, acls(READ, READ_ACL)));
final Set<IamSessionPolicyResolver.ResourceSpec> rangerResourceSpecs =
Collections.singleton(
new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.BUCKET,
"bucket1", null, null));
- final Set<AssumeRoleRequest.OzoneGrant> resultRanger =
createPathsAndPermissions(
- VOLUME, RANGER, actions, rangerResourceSpecs, prefixes);
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, RANGER, actions, rangerResourceSpecs,
prefixes, objToAclsMapRanger);
+ final Set<OzoneGrant> resultRanger =
groupObjectsByAcls(objToAclsMapRanger);
+ assertThat(resultRanger).containsExactlyInAnyOrder(
+ new OzoneGrant(readObject, acls(READ)), new
OzoneGrant(readAndReadAclObject, acls(READ, READ_ACL)));
+ }
+
+ @Test
+ public void testCreatePathsAndPermissionsWithNoMappedActions() {
+ final Set<S3Action> actions = emptySet();
+
+ final Set<IamSessionPolicyResolver.ResourceSpec> nativeResourceSpecs =
Collections.singleton(
+ new
IamSessionPolicyResolver.ResourceSpec(S3ResourceType.OBJECT_PREFIX, "bucket1",
null, null));
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, NATIVE, actions, nativeResourceSpecs,
emptySet(), objToAclsMapNative);
+ final Set<OzoneGrant> resultNative =
groupObjectsByAcls(objToAclsMapNative);
+ assertThat(resultNative).isEmpty();
+
+ final Set<IamSessionPolicyResolver.ResourceSpec> rangerResourceSpecs =
Collections.singleton(
+ new
IamSessionPolicyResolver.ResourceSpec(S3ResourceType.OBJECT_PREFIX_WILDCARD,
"bucket1", null, null));
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, RANGER, actions, rangerResourceSpecs,
emptySet(), objToAclsMapRanger);
+ final Set<OzoneGrant> resultRanger =
groupObjectsByAcls(objToAclsMapRanger);
+ assertThat(resultRanger).isEmpty();
+ }
+
+ @Test
+ public void testCreatePathsAndPermissionsWithNoMappedResources() {
+ final Set<S3Action> actions = Collections.singleton(S3Action.GET_OBJECT);
+ final Set<IamSessionPolicyResolver.ResourceSpec> resourceSpecs =
emptySet();
+
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, NATIVE, actions, resourceSpecs,
emptySet(), objToAclsMapNative);
+ final Set<OzoneGrant> resultNative =
groupObjectsByAcls(objToAclsMapNative);
+ assertThat(resultNative).isEmpty();
+
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs,
emptySet(), objToAclsMapRanger);
+ final Set<OzoneGrant> resultRanger =
groupObjectsByAcls(objToAclsMapRanger);
+ assertThat(resultRanger).isEmpty();
+ }
+
+ @Test
+ public void
testCreatePathsAndPermissionsDeduplicatesAcrossSameResourceTypes() {
+ final Set<S3Action> actions = Stream.of(
+ S3Action.GET_OBJECT, S3Action.GET_OBJECT_TAGGING,
S3Action.DELETE_OBJECT, S3Action.DELETE_OBJECT_TAGGING)
+ .collect(Collectors.toSet());
+ final Set<IamSessionPolicyResolver.ResourceSpec> resourceSpecs =
Collections.singleton(
+ new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.OBJECT_EXACT,
"bucket1", null, "key.txt"));
+ final Set<IOzoneObj> readAndDeleteObject = objSet(key("bucket1",
"key.txt"));
+ final Set<IOzoneObj> readObjects = objSet(bucket("bucket1"), volume());
+
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, NATIVE, actions, resourceSpecs,
emptySet(), objToAclsMapNative);
+ final Set<OzoneGrant> resultNative =
groupObjectsByAcls(objToAclsMapNative);
+ assertThat(resultNative).containsExactlyInAnyOrder(
+ new OzoneGrant(readAndDeleteObject, acls(READ, DELETE)), new
OzoneGrant(readObjects, acls(READ)));
+
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs,
emptySet(), objToAclsMapRanger);
+ final Set<OzoneGrant> resultRanger =
groupObjectsByAcls(objToAclsMapRanger);
assertThat(resultRanger).containsExactlyInAnyOrder(
- new AssumeRoleRequest.OzoneGrant(readObject, acls(READ)),
- new AssumeRoleRequest.OzoneGrant(readAndReadAclObject, acls(READ,
READ_ACL)));
+ new OzoneGrant(readAndDeleteObject, acls(READ, DELETE)), new
OzoneGrant(readObjects, acls(READ)));
+ }
+
+ @Test
+ public void
testCreatePathsAndPermissionsWithAllS3ActionsOverridesAnyOtherAction() {
+ final Set<S3Action> actions = Stream.of(
+ S3Action.ALL_S3, S3Action.GET_OBJECT, S3Action.DELETE_OBJECT,
S3Action.LIST_BUCKET)
+ .collect(Collectors.toSet());
+ final Set<IamSessionPolicyResolver.ResourceSpec> resourceSpecs = Stream.of(
+ new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.OBJECT_EXACT,
"bucket1", null, "key.txt"),
+ new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.BUCKET,
"bucket2", null, null))
+ .collect(Collectors.toSet());
+ final Set<IOzoneObj> allObjects = objSet(key("bucket1", "key.txt"),
bucket("bucket2"));
+
+ final Set<IOzoneObj> nativeReadObjects = objSet(volume(),
bucket("bucket1"), prefix("bucket2", ""));
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, NATIVE, actions, resourceSpecs,
emptySet(), objToAclsMapNative);
+ final Set<OzoneGrant> resultNative =
groupObjectsByAcls(objToAclsMapNative);
+ assertThat(resultNative).containsExactlyInAnyOrder(
+ new OzoneGrant(allObjects, acls(ALL)), new
OzoneGrant(nativeReadObjects, acls(READ)));
+
+ final Set<IOzoneObj> rangerReadObjects = objSet(volume(),
bucket("bucket1"), key("bucket2", "*"));
+ final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new
LinkedHashMap<>();
+ createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs,
emptySet(), objToAclsMapRanger);
+ final Set<OzoneGrant> resultRanger =
groupObjectsByAcls(objToAclsMapRanger);
+ assertThat(resultRanger).containsExactlyInAnyOrder(
+ new OzoneGrant(allObjects, acls(ALL)), new
OzoneGrant(rangerReadObjects, acls(READ)));
+ }
+
+ @Test
+ public void
testDeduplicatesAcrossMultipleStatementsWhenSameStatementsArePresent() throws
OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and
prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> 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)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and
key "*" READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
key("my-bucket", "*")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void
testDeduplicatesAcrossMultipleStatementsForSameActionsButDifferentResource()
throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket2\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and
prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"),
bucket("my-bucket2"));
+ final Set<ACLType> 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)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL; volume and
key "*" READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(
+ objSet(volume(), key("my-bucket2", "*"), key("my-bucket", "*")),
acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void
testDeduplicatesAcrossMultipleStatementsForDifferentActionsButSameResource()
throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:CreateBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL, CREATE;
volume, prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> 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)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL, CREATE;
volume, key "*" READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
key("my-bucket", "*")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testDeduplicatesAcrossMultipleStatementsWhenAllActionPresent()
throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket ALL (instead of individual actions); volume
and prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> bucketAcls = acls(ALL);
+ expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume(),
prefix("my-bucket", "")), acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket ALL (instead of individual actions); volume
and key "*" READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
key("my-bucket", "*")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testAllowGetPutOnKey() throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\"s3:GetObject\", \"s3:PutObject\"],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket/folder/file.txt\"\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedFromBothAuthorizers = new
LinkedHashSet<>();
+ // Expected: READ, CREATE, WRITE on key; bucket READ; volume READ
+ final Set<IOzoneObj> keySet = objSet(key("my-bucket", "folder/file.txt"));
+ final Set<ACLType> keyAcls = acls(READ, CREATE, WRITE);
+ expectedResolvedFromBothAuthorizers.add(new OzoneGrant(objSet(volume(),
bucket("my-bucket")), acls(READ)));
+ expectedResolvedFromBothAuthorizers.add(new OzoneGrant(keySet, keyAcls));
+
+
assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedFromBothAuthorizers);
+
assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedFromBothAuthorizers);
+ }
+
+ @Test
+ public void testAllActionsForKey() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket/*\"\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: all key ACLs on prefix "" under bucket; bucket
READ, volume READ
+ final Set<IOzoneObj> keyPrefixSet = objSet(prefix("my-bucket", ""));
+ final Set<ACLType> allKeyAcls = acls(ALL);
+ expectedResolvedNative.add(new OzoneGrant(keyPrefixSet, allKeyAcls));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume(),
bucket("my-bucket")), acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ // Expected for Ranger: all key acls for resource type KEY with key name
"*"
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ final Set<IOzoneObj> rangerKeySet = objSet(key("my-bucket", "*"));
+ expectedResolvedRanger.add(new OzoneGrant(rangerKeySet, allKeyAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
bucket("my-bucket")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testAllActionsForBucket() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: all Bucket ACLs for bucket; volume, prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> allBucketAcls = acls(ALL);
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume(),
prefix("my-bucket", "")), acls(READ)));
+ expectedResolvedNative.add(new OzoneGrant(bucketSet, allBucketAcls));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ // Expected for Ranger: all Bucket ACLs for bucket; volume, key "*" READ
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
key("my-bucket", "*")), acls(READ)));
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, allBucketAcls));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testMultipleResourcesInSeparateStatements() throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:PutBucketAcl\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"arn:aws:s3:::my-bucket/*\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ, LIST, READ_ACL, WRITE_ACL; volume READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> bucketAcls = acls(READ, LIST, READ_ACL, WRITE_ACL);
+ expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ // Expected for native: all key ACLs on prefix "" under bucket
+ final Set<IOzoneObj> keyPrefixSet = objSet(prefix("my-bucket", ""));
+ final Set<ACLType> keyAllAcls = acls(ALL);
+ expectedResolvedNative.add(new OzoneGrant(keyPrefixSet, keyAllAcls));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ, LIST, READ_ACL, WRITE_ACL; volume READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ // Expected for Ranger: all key acls for resource type KEY with key name
"*"
+ final Set<IOzoneObj> rangerKeySet = objSet(key("my-bucket", "*"));
+ expectedResolvedRanger.add(new OzoneGrant(rangerKeySet, keyAllAcls));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testMultipleResourcesInOneStatement() throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:*\"\n" +
+ " ],\n" +
+ " \"Resource\": [\n" +
+ " \"arn:aws:s3:::my-bucket\",\n" +
+ " \"arn:aws:s3:::my-bucket/*\"\n" +
+ " ]\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: all for bucket and key acls; volume READ
+ final Set<IOzoneObj> resourceSetNative = objSet(bucket("my-bucket"),
prefix("my-bucket", ""));
+ expectedResolvedNative.add(new OzoneGrant(resourceSetNative, acls(ALL)));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: all for bucket and key acls; volume READ
+ final Set<IOzoneObj> resourceSetRanger = objSet(bucket("my-bucket"),
key("my-bucket", "*"));
+ expectedResolvedRanger.add(new OzoneGrant(resourceSetRanger, acls(ALL)));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void
testMultipleResourcesWithDifferentBucketsAndDeepPathsInOneStatement() throws
OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:*\"\n" +
+ " ],\n" +
+ " \"Resource\": [\n" +
+ " \"arn:aws:s3:::my-bucket/team/folder1/security/*\",\n" +
+ " \"arn:aws:s3:::my-bucket2/team/folder2/misc/*\"\n" +
+ " ]\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: all key ACLs on prefix "team/folder1/security/"
under
+ // my-bucket and all key ACLs on prefix "team/folder2/misc/" under
my-bucket2; bucket READ; volume READ
+ final Set<IOzoneObj> keyPrefixSet = objSet(
+ prefix("my-bucket", "team/folder1/security/"), prefix("my-bucket2",
"team/folder2/misc/"));
+ final Set<ACLType> keyAllAcls = acls(ALL);
+ expectedResolvedNative.add(new OzoneGrant(keyPrefixSet, keyAllAcls));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume(),
bucket("my-bucket"), bucket("my-bucket2")), acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: all key acls for resource type KEY with key name
+ // "team/folder1/security/*" under my-bucket and "team/folder2/misc/*"
under my-bucket2; bucket READ; volume READ
+ final Set<IOzoneObj> rangerKeySet = objSet(
+ key("my-bucket", "team/folder1/security/*"), key("my-bucket2",
"team/folder2/misc/*"));
+ expectedResolvedRanger.add(new OzoneGrant(rangerKeySet, keyAllAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(),
bucket("my-bucket"), bucket("my-bucket2")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testUnsupportedActionIgnoredWhenItIsTheOnlyAction() throws
OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:ReplicateObject\",\n" + // unsupported
action
+ " \"Resource\": \"*\"\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ assertThat(resolvedFromNativeAuthorizer.isEmpty());
+ assertThat(resolvedFromRangerAuthorizer.isEmpty());
+ }
+
+ @Test
+ public void testUnsupportedResourceArnThrows() {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:ListBucket\",\n" +
+ " \"Resource\":
\"arn:aws:dynamodb:us-east-2:123456789012:table/example-table\"\n" +
+ " }]\n" +
+ "}";
+
+ expectResolveThrowsForBothAuthorizers(
+ json, "Unsupported Resource Arn - " +
+ "arn:aws:dynamodb:us-east-2:123456789012:table/example-table",
NOT_SUPPORTED_OPERATION);
+ }
+
+ @Test
+ public void testListBucketWithWildcard() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:ListBucket\",\n" +
+ " \"Resource\": \"arn:aws:s3:::proj-*\"\n" +
+ " }]\n" +
+ "}";
+
+ // Wildcards on bucket are not supported for Native authorizer
+ expectBucketWildcardUnsupportedExceptionForNativeAuthorizer(json);
+
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ and LIST on wildcard pattern; volume
and key "*" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("proj-*"));
+ final Set<ACLType> bucketAcls = acls(READ, LIST);
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(), key("proj-*",
"*")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testListBucketOperationsWithNoPrefixes() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:ListBucket\",\n" +
+ " \"s3:ListBucketMultipartUploads\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::proj\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ and LIST; volume, prefix "" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("proj"));
+ final Set<ACLType> bucketAcls = acls(READ, LIST);
+ final Set<IOzoneObj> nativeReadObjects = objSet(volume(), prefix("proj",
""));
+ expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedNative.add(new OzoneGrant(nativeReadObjects, acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ // Expected for Ranger: bucket READ and LIST; volume, key "*" READ
+ final Set<IOzoneObj> rangerReadObjects = objSet(volume(), key("proj",
"*"));
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(rangerReadObjects, acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testIgnoresUnsupportedActionsWhenSupportedActionsAreIncluded()
throws OMException {
+ final String json = "{\n" +
+ " \"Version\": \"2012-10-17\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Sid\": \"AllowListingOfDataLakeFolder\",\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:GetAccelerateConfiguration\",\n" + // unsupported
action
+ " \"s3:GetBucketAcl\",\n" +
+ " \"s3:GetObject\",\n" + // object-level
action not applied for bucket
+ " \"s3:GetObjectAcl\",\n" + // unsupported
action
+ " \"s3:ListBucket\",\n" +
+ " \"s3:ListBucketMultipartUploads\"\n" +
+ " ],\n" +
+ " \"Resource\": \"arn:aws:s3:::bucket1\",\n" +
+ " \"Condition\": {\n" +
+ " \"StringEquals\": {\n" +
+ " \"s3:prefix\": [ \"team/folder\", \"team/folder/*\" ]\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+
+ // Expected for native: READ, LIST, READ_ACL bucket acls; volume and
prefixes "team/folder", "team/folder/" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("bucket1"));
+ final Set<ACLType> 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)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: READ, LIST, READ_ACL bucket acls; volume and keys
"team/folder" and "team/folder/*" READ
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(
+ objSet(volume(), key("bucket1", "team/folder"), key("bucket1",
"team/folder/*")), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testMultiplePrefixesWithWildcards() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:GetObject\",\n" +
+ " \"Resource\": \"arn:aws:s3:::logs/*\",\n" +
+ " \"Condition\": { \"StringEquals\": { \"s3:prefix\": [\"a/*\",
\"b/*\"] } }\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: READ acl on prefix "" (condition prefixes are
ignored); bucket READ; volume READ;
+ final Set<IOzoneObj> readObjectsNative = objSet(prefix("logs", ""),
bucket("logs"), volume());
+ expectedResolvedNative.add(new OzoneGrant(readObjectsNative, acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: READ acl on key "*" (condition prefixes are
ignored)
+ final Set<IOzoneObj> keySet = objSet(key("logs", "*"), bucket("logs"),
volume());
+ expectedResolvedRanger.add(new OzoneGrant(keySet, acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testObjectResourceWithWildcardInMiddle() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:GetObject\",\n" +
+ " \"Resource\": \"arn:aws:s3:::logs/file*.log\"\n" +
+ " }]\n" +
+ "}";
+
+ // Wildcards in middle of object resource are not supported for Native
authorizer
+ expectResolveThrows(
+ json, NATIVE, "Wildcard prefix patterns are not supported for Ozone
native " +
+ "authorizer if wildcard is not at the end", NOT_SUPPORTED_OPERATION);
+
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: READ acl on key "file*.log", bucket READ, volume
READ
+ final Set<IOzoneObj> readObjectsRanger = objSet(key("logs", "file*.log"),
bucket("logs"), volume());
+ expectedResolvedRanger.add(new OzoneGrant(readObjectsRanger, acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testObjectResourceWithPrefixWildcard() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:GetObject\",\n" +
+ " \"Resource\": \"arn:aws:s3:::myBucket/file*\"\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: READ acl on prefix "file" under bucket, bucket
READ, volume READ
+ final Set<IOzoneObj> readObjectsNative = objSet(prefix("myBucket",
"file"), bucket("myBucket"), volume());
+ expectedResolvedNative.add(new OzoneGrant(readObjectsNative, acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: READ acl on key "file*", bucket READ, volume READ
+ final Set<IOzoneObj> readObjectsRanger = objSet(key("myBucket", "file*"),
bucket("myBucket"), volume());
+ expectedResolvedRanger.add(new OzoneGrant(readObjectsRanger, acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testBucketActionOnAllResources() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": [\n" +
+ " \"s3:ListAllMyBuckets\",\n" +
+ " \"s3:ListBucket\"\n" +
+ " ],\n" +
+ " \"Resource\": \"*\"\n" +
+ " }]\n" +
+ "}";
+
+ // Wildcards on bucket are not supported for Native authorizer
+ expectBucketWildcardUnsupportedExceptionForNativeAuthorizer(json);
+
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: READ and LIST on volume and bucket (wildcard),
READ on key "*"
+ final Set<IOzoneObj> resourceSet = objSet(volume(), bucket("*"));
+ expectedResolvedRanger.add(new OzoneGrant(resourceSet, acls(READ, LIST)));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(key("*", "*")),
acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testObjectActionOnAllResources() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:PutObject\",\n" +
+ " \"Resource\": \"*\"\n" +
+ " }]\n" +
+ "}";
+
+ // Wildcards on bucket are not supported for Native authorizer
+ expectBucketWildcardUnsupportedExceptionForNativeAuthorizer(json);
+
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: CREATE and WRITE key acls on wildcard pattern,
bucket READ, volume READ
+ final Set<IOzoneObj> keySet = objSet(key("*", "*"));
+ final Set<ACLType> keyAcls = acls(CREATE, WRITE);
+ expectedResolvedRanger.add(new OzoneGrant(keySet, keyAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(), bucket("*")),
acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testAllActionsOnAllResources() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"*\"\n" +
+ " }]\n" +
+ "}";
+
+ // Wildcards on bucket are not supported for Native authorizer
+ expectBucketWildcardUnsupportedExceptionForNativeAuthorizer(json);
+
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: READ, LIST acl on volume, ALL acl bucket
(wildcard) and key (wildcard)
+ final Set<IOzoneObj> resourceSet = objSet(bucket("*"), key("*", "*"));
+ expectedResolvedRanger.add(new OzoneGrant(resourceSet, acls(ALL)));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ,
LIST)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testAllActionsOnAllBucketResources() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"arn:aws:s3:::*\"\n" +
+ " }]\n" +
+ "}";
+
+ // Wildcards on bucket are not supported for Native authorizer
+ expectBucketWildcardUnsupportedExceptionForNativeAuthorizer(json);
+
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: ALL bucket acls on wildcard pattern, volume READ,
key "*" READ
+ final Set<IOzoneObj> bucketSet = objSet(bucket("*"));
+ final Set<ACLType> bucketAcls = acls(ALL);
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(), key("*", "*")),
acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testAllActionsOnAllObjectResources() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:*\",\n" +
+ " \"Resource\": \"arn:aws:s3:::*/*\"\n" +
+ " }]\n" +
+ "}";
+
+ // Wildcards on bucket are not supported for Native authorizer
+ expectBucketWildcardUnsupportedExceptionForNativeAuthorizer(json);
+
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: ALL key acls on wildcard pattern; bucket READ;
volume READ
+ final Set<IOzoneObj> keySet = objSet(key("*", "*"));
+ final Set<ACLType> keyAcls = acls(ALL);
+ expectedResolvedRanger.add(new OzoneGrant(keySet, keyAcls));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume(), bucket("*")),
acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testWildcardActionGroupGetStar() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:Get*\",\n" +
+ " \"Resource\": [\n" +
+ " \"arn:aws:s3:::my-bucket\",\n" +
+ " \"arn:aws:s3:::my-bucket/*\"\n" +
+ " ]\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ, READ_ACL acls
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> bucketAcls = acls(READ, READ_ACL);
+ expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls));
+ // Expected for native: READ acl on prefix "" under bucket; volume READ
+ final Set<IOzoneObj> readObjectsNative = objSet(prefix("my-bucket", ""),
volume());
+ expectedResolvedNative.add(new OzoneGrant(readObjectsNative, acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ, READ_ACL acls
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcls));
+ // Expected for Ranger: READ key acl for resource type KEY with key name
"*"; volume READ
+ final Set<IOzoneObj> readObjectsRanger = objSet(key("my-bucket", "*"),
volume());
+ expectedResolvedRanger.add(new OzoneGrant(readObjectsRanger, acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testWildcardActionGroupListStar() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:List*\",\n" +
+ " \"Resource\": [\n" +
+ " \"arn:aws:s3:::my-bucket\",\n" +
+ " \"arn:aws:s3:::my-bucket/*\"\n" + //
ListMultipartUploadParts has READ effect on file/object resources
+ " ]\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: READ, LIST bucket acls
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> bucketAcls = acls(READ, LIST);
+ expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcls));
+ // Expected for native: READ acl on prefix "" under bucket; volume READ
+ final Set<IOzoneObj> readObjectsNative = objSet(prefix("my-bucket", ""),
volume());
+ expectedResolvedNative.add(new OzoneGrant(readObjectsNative, acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> 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<IOzoneObj> readObjectsRanger = objSet(key("my-bucket", "*"),
volume());
+ expectedResolvedRanger.add(new OzoneGrant(readObjectsRanger, acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testWildcardActionGroupPutStar() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:Put*\",\n" +
+ " \"Resource\": [\n" +
+ " \"arn:aws:s3:::my-bucket\",\n" +
+ " \"arn:aws:s3:::my-bucket/*\"\n" +
+ " ]\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: bucket READ, WRITE_ACL acl
+ final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
+ final Set<ACLType> bucketAcl = acls(READ, WRITE_ACL);
+ expectedResolvedNative.add(new OzoneGrant(bucketSet, bucketAcl));
+ // Expected for native: CREATE, WRITE acls on prefix "" under bucket
+ final Set<IOzoneObj> keyPrefixSet = objSet(prefix("my-bucket", ""));
+ final Set<ACLType> keyAcls = acls(CREATE, WRITE);
+ expectedResolvedNative.add(new OzoneGrant(keyPrefixSet, keyAcls));
+ // Expected for native: volume READ
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: bucket READ, WRITE_ACL acl
+ expectedResolvedRanger.add(new OzoneGrant(bucketSet, bucketAcl));
+ // Expected for Ranger: CREATE, WRITE key acls for resource type KEY with
key name "*"
+ final Set<IOzoneObj> rangerKeySet = objSet(key("my-bucket", "*"));
+ expectedResolvedRanger.add(new OzoneGrant(rangerKeySet, keyAcls));
+ // Expected for Ranger: volume READ
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
}
- // TODO sts - add more createPathsAndPermissions tests in the next PR
+ @Test
+ public void testWildcardActionGroupDeleteStar() throws OMException {
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:Delete*\",\n" +
+ " \"Resource\": [\n" +
+ " \"arn:aws:s3:::my-bucket\",\n" +
+ " \"arn:aws:s3:::my-bucket/*\"\n" +
+ " ]\n" +
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
+ // Expected for native: DELETE on prefix "" under bucket; bucket READ,
DELETE; volume READ
+ final Set<IOzoneObj> resourceSetNative = objSet(prefix("my-bucket", ""));
+ expectedResolvedNative.add(new OzoneGrant(resourceSetNative,
acls(DELETE)));
+ expectedResolvedNative.add(new OzoneGrant(objSet(bucket("my-bucket")),
acls(READ, DELETE)));
+ expectedResolvedNative.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);
+
+ final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
+ // Expected for Ranger: DELETE on resource type KEY with key name "*";
bucket READ, DELETE; volume READ
+ final Set<IOzoneObj> resourceSetRanger = objSet(key("my-bucket", "*"));
+ expectedResolvedRanger.add(new OzoneGrant(resourceSetRanger,
acls(DELETE)));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(bucket("my-bucket")),
acls(READ, DELETE)));
+ expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ)));
+ assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
+ }
+
+ @Test
+ public void testMismatchedActionAndResourceReturnsEmpty() throws OMException
{
+ final String json = "{\n" +
+ " \"Statement\": [{\n" +
+ " \"Effect\": \"Allow\",\n" +
+ " \"Action\": \"s3:GetObject\",\n" + // object-level
action
+ " \"Resource\": \"arn:aws:s3:::my-bucket\"\n" + // bucket-level
resource
+ " }]\n" +
+ "}";
+
+ final Set<OzoneGrant> resolvedFromNativeAuthorizer = resolve(json, VOLUME,
NATIVE);
+ final Set<OzoneGrant> resolvedFromRangerAuthorizer = resolve(json, VOLUME,
RANGER);
+
+ // Ensure what we got is what we expected
+ assertThat(resolvedFromNativeAuthorizer.isEmpty());
+ assertThat(resolvedFromRangerAuthorizer.isEmpty());
Review Comment:
updated
--
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]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]