diff --git a/api/handler/acl.go b/api/handler/acl.go index 1ea6d5e9..7befb298 100644 --- a/api/handler/acl.go +++ b/api/handler/acl.go @@ -1190,6 +1190,13 @@ func aclToPolicy(acl *AccessControlPolicy, resInfo *resourceInfo) (*bucketPolicy getAllowStatement(resInfo, acl.Owner.ID, aclFullControl), } + // Expect to have at least 1 full control grant for owner which is set in + // parseACLHeaders(). If there is no other grants, then user sets private + // canned ACL, which is processed in this branch. + if len(acl.AccessControlList) < 2 { + results = append([]statement{getDenyStatement(resInfo, allUsersWildcard, aclFullControl)}, results...) + } + for _, grant := range acl.AccessControlList { if grant.Grantee.Type == acpAmazonCustomerByEmail || (grant.Grantee.Type == acpGroup && grant.Grantee.URI != allUsersGroup) { return nil, stderrors.New("unsupported grantee type") @@ -1227,6 +1234,23 @@ func getAllowStatement(resInfo *resourceInfo, id string, permission AWSACL) stat return state } +func getDenyStatement(resInfo *resourceInfo, id string, permission AWSACL) statement { + state := statement{ + Effect: "Deny", + Principal: principal{ + CanonicalUser: id, + }, + Action: getActions(permission, resInfo.IsBucket()), + Resource: []string{arnAwsPrefix + resInfo.Name()}, + } + + if id == allUsersWildcard { + state.Principal = principal{AWS: allUsersWildcard} + } + + return state +} + func getActions(permission AWSACL, isBucket bool) []string { var res []string switch permission { diff --git a/api/handler/acl_test.go b/api/handler/acl_test.go index f9580c6e..84b2df35 100644 --- a/api/handler/acl_test.go +++ b/api/handler/acl_test.go @@ -862,7 +862,7 @@ func TestObjectWithVersionAclToTable(t *testing.T) { Bucket: "bucketName", Object: "object", } - expectedTable := allowedTableForObject(t, key, resInfoObject) + expectedTable := allowedTableForPrivateObject(t, key, resInfoObject) actualTable := tableFromACL(t, acl, resInfoObject) checkTables(t, expectedTable, actualTable) @@ -871,12 +871,12 @@ func TestObjectWithVersionAclToTable(t *testing.T) { Object: "objectVersion", Version: "Gfrct4Afhio8pCGCCKVNTf1kyexQjMBeaUfvDtQCkAvg", } - expectedTable = allowedTableForObject(t, key, resInfoObjectVersion) + expectedTable = allowedTableForPrivateObject(t, key, resInfoObjectVersion) actualTable = tableFromACL(t, acl, resInfoObjectVersion) checkTables(t, expectedTable, actualTable) } -func allowedTableForObject(t *testing.T, key *keys.PrivateKey, resInfo *resourceInfo) *eacl.Table { +func allowedTableForPrivateObject(t *testing.T, key *keys.PrivateKey, resInfo *resourceInfo) *eacl.Table { var isVersion bool var objID oid.ID if resInfo.Version != "" { @@ -886,7 +886,7 @@ func allowedTableForObject(t *testing.T, key *keys.PrivateKey, resInfo *resource } expectedTable := eacl.NewTable() - serviceRec := &ServiceRecord{Resource: resInfo.Name(), GroupRecordsLength: len(readOps)} + serviceRec := &ServiceRecord{Resource: resInfo.Name(), GroupRecordsLength: len(readOps) * 2} expectedTable.AddRecord(serviceRec.ToEACLRecord()) for i := len(readOps) - 1; i >= 0; i-- { @@ -899,6 +899,16 @@ func allowedTableForObject(t *testing.T, key *keys.PrivateKey, resInfo *resource } expectedTable.AddRecord(record) } + for i := len(readOps) - 1; i >= 0; i-- { + op := readOps[i] + record := getOthersRecord(op, eacl.ActionDeny) + if isVersion { + record.AddObjectIDFilter(eacl.MatchStringEqual, objID) + } else { + record.AddObjectAttributeFilter(eacl.MatchStringEqual, object.AttributeFileName, resInfo.Object) + } + expectedTable.AddRecord(record) + } return expectedTable }