Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.LIST;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.READ;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.READ_ACL;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.WRITE;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.WRITE_ACL;

import com.fasterxml.jackson.databind.JsonNode;
Expand Down Expand Up @@ -868,24 +869,22 @@ enum S3Action {
EnumSet.noneOf(ACLType.class)),
GET_BUCKET_ACL("s3:GetBucketAcl", ActionKind.BUCKET, EnumSet.of(READ), EnumSet.of(READ, READ_ACL),
EnumSet.noneOf(ACLType.class)),
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)),
// Used for ListMultipartUploads API
LIST_BUCKET_MULTIPART_UPLOADS("s3:ListBucketMultipartUploads", ActionKind.BUCKET, EnumSet.of(READ),
EnumSet.of(READ, LIST), EnumSet.noneOf(ACLType.class)),
PUT_BUCKET_ACL("s3:PutBucketAcl", ActionKind.BUCKET, EnumSet.of(READ), EnumSet.of(WRITE_ACL),
PUT_BUCKET_ACL("s3:PutBucketAcl", ActionKind.BUCKET, EnumSet.of(READ), EnumSet.of(READ, READ_ACL, WRITE_ACL),
EnumSet.noneOf(ACLType.class)),

// Object-scope
ABORT_MULTIPART_UPLOAD("s3:AbortMultipartUpload", ActionKind.OBJECT, EnumSet.of(READ), EnumSet.of(READ),
EnumSet.of(DELETE)),
EnumSet.of(WRITE)),
// Used for DeleteObject (when versionId parameter is not supplied),
// DeleteObjects (when versionId parameter is not supplied) APIs
DELETE_OBJECT("s3:DeleteObject", ActionKind.OBJECT, EnumSet.of(READ), EnumSet.of(READ), EnumSet.of(DELETE)),
DELETE_OBJECT_TAGGING("s3:DeleteObjectTagging", ActionKind.OBJECT, EnumSet.of(READ), EnumSet.of(READ),
EnumSet.of(DELETE)),
EnumSet.of(WRITE)),
// Used for HeadObject, CopyObject (for source bucket), GetObject (without versionId parameter) APIs
GET_OBJECT("s3:GetObject", ActionKind.OBJECT, EnumSet.of(READ), EnumSet.of(READ), EnumSet.of(READ)),
GET_OBJECT_TAGGING("s3:GetObjectTagging", ActionKind.OBJECT, EnumSet.of(READ), EnumSet.of(READ), EnumSet.of(READ)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ public void testBuildCaseInsensitiveS3ActionMap() {
// Verify s3:Get* contains Get actions
final Set<S3Action> getActions = caseInsensitiveS3ActionMap.get("s3:get*");
assertThat(getActions).containsOnly(
S3Action.GET_OBJECT, S3Action.GET_BUCKET_ACL, S3Action.GET_BUCKET_LOCATION, S3Action.GET_OBJECT_TAGGING);
S3Action.GET_OBJECT, S3Action.GET_BUCKET_ACL, S3Action.GET_OBJECT_TAGGING);

// Verify s3:Put* contains Put actions
final Set<S3Action> putActions = caseInsensitiveS3ActionMap.get("s3:put*");
Expand Down Expand Up @@ -380,13 +380,11 @@ public void testMapPolicyActionsToS3ActionsWithMultipleActionsMapAllCorrectly()
@Test
public void testMapPolicyActionsToS3ActionsWithWildcardExpansion() {
final Set<S3Action> result = mapPolicyActionsToS3Actions(Collections.singleton("s3:Get*"));
assertThat(result).containsOnly(S3Action.GET_OBJECT, S3Action.GET_BUCKET_ACL, S3Action.GET_BUCKET_LOCATION,
S3Action.GET_OBJECT_TAGGING);
assertThat(result).containsOnly(S3Action.GET_OBJECT, S3Action.GET_BUCKET_ACL, S3Action.GET_OBJECT_TAGGING);

// Ensure it is case-insensitive
final Set<S3Action> resultCi = mapPolicyActionsToS3Actions(Collections.singleton("s3:gET*"));
assertThat(resultCi).containsOnly(S3Action.GET_OBJECT, S3Action.GET_BUCKET_ACL, S3Action.GET_BUCKET_LOCATION,
S3Action.GET_OBJECT_TAGGING);
assertThat(resultCi).containsOnly(S3Action.GET_OBJECT, S3Action.GET_BUCKET_ACL, S3Action.GET_OBJECT_TAGGING);
}

@Test
Expand Down Expand Up @@ -415,15 +413,15 @@ public void testMapPolicyActionsToS3ActionsWithOnlyUnsupportedActionsReturnsEmpt
@Test
public void testMapPolicyActionsToS3ActionsDeduplicatesResults() {
final Set<S3Action> result = mapPolicyActionsToS3Actions(strSet("s3:Get*", "s3:GetObject", "s3:GetBucketAcl"));
assertThat(result).containsOnly(S3Action.GET_OBJECT, S3Action.GET_BUCKET_ACL, S3Action.GET_BUCKET_LOCATION,
S3Action.GET_OBJECT_TAGGING);
assertThat(result).containsOnly(S3Action.GET_OBJECT, S3Action.GET_BUCKET_ACL, S3Action.GET_OBJECT_TAGGING);
}

@Test
public void testMapPolicyActionsToS3ActionsHandlesMultipleWildcards() {
final Set<S3Action> result = mapPolicyActionsToS3Actions(strSet("s3:Get*", "s3:Put*"));
assertThat(result).containsOnly(S3Action.GET_OBJECT, S3Action.GET_BUCKET_ACL, S3Action.GET_BUCKET_LOCATION,
S3Action.GET_OBJECT_TAGGING, S3Action.PUT_OBJECT, S3Action.PUT_OBJECT_TAGGING, S3Action.PUT_BUCKET_ACL);
assertThat(result).containsOnly(
S3Action.GET_OBJECT, S3Action.GET_BUCKET_ACL, S3Action.GET_OBJECT_TAGGING, S3Action.PUT_OBJECT,
S3Action.PUT_OBJECT_TAGGING, S3Action.PUT_BUCKET_ACL);
}

@Test
Expand Down Expand Up @@ -768,7 +766,7 @@ public void testCreatePathsAndPermissionsWithBucketWildcardResource() {
final Set<S3Action> actions = Collections.singleton(IamSessionPolicyResolver.S3Action.PUT_BUCKET_ACL);
final Set<IamSessionPolicyResolver.ResourceSpec> resourceSpecs = Collections.singleton(
new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.BUCKET_WILDCARD, "bucket1*", null, null));
final Set<IOzoneObj> writeAclObject = objSet(bucket("bucket1*"));
final Set<IOzoneObj> readReadAclAndWriteAclObject = objSet(bucket("bucket1*"));
final Set<IOzoneObj> readVolume = objSet(volume());

expectIllegalArgumentException(
Expand All @@ -779,7 +777,8 @@ public void testCreatePathsAndPermissionsWithBucketWildcardResource() {
createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs, null, objToAclsMapRanger);
final Set<OzoneGrant> resultRanger = groupObjectsByAcls(objToAclsMapRanger);
assertThat(resultRanger).containsExactlyInAnyOrder(
new OzoneGrant(writeAclObject, acls(WRITE_ACL)), new OzoneGrant(readVolume, acls(READ)));
new OzoneGrant(readReadAclAndWriteAclObject, acls(READ, READ_ACL, WRITE_ACL)),
new OzoneGrant(readVolume, acls(READ)));
}

@Test
Expand Down Expand Up @@ -827,6 +826,48 @@ public void testCreatePathsAndPermissionsWithObjectExactResource() {
assertThat(resultRanger).containsExactly(new OzoneGrant(readObjects, acls(READ)));
}

@Test
public void testCreatePathsAndPermissionsWithDeleteObjectGrantsDeleteOnKey() {
final Set<S3Action> actions = Collections.singleton(S3Action.DELETE_OBJECT);
final Set<IamSessionPolicyResolver.ResourceSpec> resourceSpecs = Collections.singleton(
new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.OBJECT_EXACT, "bucket1", null, "key.txt"));
final Set<IOzoneObj> readVolumeAndBucket = objSet(volume(), bucket("bucket1"));
final Set<IOzoneObj> deleteKey = objSet(key("bucket1", "key.txt"));

final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new LinkedHashMap<>();
createPathsAndPermissions(VOLUME, NATIVE, actions, resourceSpecs, null, objToAclsMapNative);
final Set<OzoneGrant> resultNative = groupObjectsByAcls(objToAclsMapNative);
assertThat(resultNative).containsExactlyInAnyOrder(
new OzoneGrant(readVolumeAndBucket, acls(READ)), new OzoneGrant(deleteKey, acls(DELETE)));

final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new LinkedHashMap<>();
createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs, null, objToAclsMapRanger);
final Set<OzoneGrant> resultRanger = groupObjectsByAcls(objToAclsMapRanger);
assertThat(resultRanger).containsExactlyInAnyOrder(
new OzoneGrant(readVolumeAndBucket, acls(READ)), new OzoneGrant(deleteKey, acls(DELETE)));
}

@Test
public void testCreatePathsAndPermissionsWithAbortMultipartUploadGrantsWriteOnKey() {
final Set<S3Action> actions = Collections.singleton(S3Action.ABORT_MULTIPART_UPLOAD);
final Set<IamSessionPolicyResolver.ResourceSpec> resourceSpecs = Collections.singleton(
new IamSessionPolicyResolver.ResourceSpec(S3ResourceType.OBJECT_EXACT, "bucket1", null, "key.txt"));
final Set<IOzoneObj> readVolumeAndBucket = objSet(volume(), bucket("bucket1"));
final Set<IOzoneObj> writeKey = objSet(key("bucket1", "key.txt"));

final Map<IOzoneObj, Set<ACLType>> objToAclsMapNative = new LinkedHashMap<>();
createPathsAndPermissions(VOLUME, NATIVE, actions, resourceSpecs, null, objToAclsMapNative);
final Set<OzoneGrant> resultNative = groupObjectsByAcls(objToAclsMapNative);
assertThat(resultNative).containsExactlyInAnyOrder(
new OzoneGrant(readVolumeAndBucket, acls(READ)), new OzoneGrant(writeKey, acls(WRITE)));

final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new LinkedHashMap<>();
createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs, null, objToAclsMapRanger);
final Set<OzoneGrant> resultRanger = groupObjectsByAcls(objToAclsMapRanger);
assertThat(resultRanger).containsExactlyInAnyOrder(
new OzoneGrant(readVolumeAndBucket, acls(READ)), new OzoneGrant(writeKey, acls(WRITE)));
}

@Test
public void testCreatePathsAndPermissionsWithObjectPrefixResource() {
final Set<S3Action> actions = Collections.singleton(S3Action.GET_OBJECT);
Expand Down Expand Up @@ -983,20 +1024,22 @@ public void testCreatePathsAndPermissionsDeduplicatesAcrossSameResourceTypes() {
.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> readAndDeleteAndWriteObject = 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, null, objToAclsMapNative);
final Set<OzoneGrant> resultNative = groupObjectsByAcls(objToAclsMapNative);
assertThat(resultNative).containsExactlyInAnyOrder(
new OzoneGrant(readAndDeleteObject, acls(READ, DELETE)), new OzoneGrant(readObjects, acls(READ)));
new OzoneGrant(readAndDeleteAndWriteObject, acls(READ, DELETE, WRITE)),
new OzoneGrant(readObjects, acls(READ)));

final Map<IOzoneObj, Set<ACLType>> objToAclsMapRanger = new LinkedHashMap<>();
createPathsAndPermissions(VOLUME, RANGER, actions, resourceSpecs, null, objToAclsMapRanger);
final Set<OzoneGrant> resultRanger = groupObjectsByAcls(objToAclsMapRanger);
assertThat(resultRanger).containsExactlyInAnyOrder(
new OzoneGrant(readAndDeleteObject, acls(READ, DELETE)), new OzoneGrant(readObjects, acls(READ)));
new OzoneGrant(readAndDeleteAndWriteObject, acls(READ, DELETE, WRITE)),
new OzoneGrant(readObjects, acls(READ)));
}

@Test
Expand Down Expand Up @@ -1976,9 +2019,9 @@ public void testWildcardActionGroupPutStar() throws OMException {

// Ensure what we got is what we expected
final Set<OzoneGrant> expectedResolvedNative = new LinkedHashSet<>();
// Expected for native: bucket READ, WRITE_ACL acl
// Expected for native: bucket READ, READ_ACL, WRITE_ACL acl
final Set<IOzoneObj> bucketSet = objSet(bucket("my-bucket"));
final Set<ACLType> bucketAcl = acls(READ, WRITE_ACL);
final Set<ACLType> bucketAcl = acls(READ, READ_ACL, 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", ""));
Expand All @@ -1989,7 +2032,7 @@ public void testWildcardActionGroupPutStar() throws OMException {
assertThat(resolvedFromNativeAuthorizer).isEqualTo(expectedResolvedNative);

final Set<OzoneGrant> expectedResolvedRanger = new LinkedHashSet<>();
// Expected for Ranger: bucket READ, WRITE_ACL acl
// Expected for Ranger: bucket READ, READ_ACL, 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", "*"));
Expand Down Expand Up @@ -2017,17 +2060,17 @@ public void testWildcardActionGroupDeleteStar() throws OMException {

// 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
// Expected for native: DELETE and WRITE 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(resourceSetNative, acls(DELETE, WRITE)));
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
// Expected for Ranger: DELETE and WRITE 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(resourceSetRanger, acls(DELETE, WRITE)));
expectedResolvedRanger.add(new OzoneGrant(objSet(bucket("my-bucket")), acls(READ, DELETE)));
expectedResolvedRanger.add(new OzoneGrant(objSet(volume()), acls(READ)));
assertThat(resolvedFromRangerAuthorizer).isEqualTo(expectedResolvedRanger);
Expand Down