@ -3,6 +3,7 @@ package s3acl
import (
"encoding/json"
"encoding/xml"
"fmt"
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/seaweedfs/seaweedfs/weed/filer"
@ -16,6 +17,8 @@ import (
"strings"
)
var customAclHeaders = [ ] string { s3_constants . AmzAclFullControl , s3_constants . AmzAclRead , s3_constants . AmzAclReadAcp , s3_constants . AmzAclWrite , s3_constants . AmzAclWriteAcp }
// GetAccountId get AccountId from request headers, AccountAnonymousId will be return if not presen
func GetAccountId ( r * http . Request ) string {
id := r . Header . Get ( s3_constants . AmzAccountId )
@ -26,11 +29,36 @@ func GetAccountId(r *http.Request) string {
}
}
// ExtractAcl extracts the acl from the request body, or from the header if request body is empty
func ExtractAcl ( r * http . Request , accountManager * s3account . AccountManager , ownership , bucketOwnerId , ownerId , accountId string ) ( grants [ ] * s3 . Grant , errCode s3err . ErrorCode ) {
if r . Body != nil && r . Body != http . NoBody {
defer util . CloseRequest ( r )
// ValidateAccount validate weather request account id is allowed to access
func ValidateAccount ( requestAccountId string , allowedAccounts ... string ) bool {
for _ , allowedAccount := range allowedAccounts {
if requestAccountId == allowedAccount {
return true
}
}
return false
}
// ExtractBucketAcl extracts the acl from the request body, or from the header if request body is empty
func ExtractBucketAcl ( r * http . Request , accountManager * s3account . AccountManager , objectOwnership , bucketOwnerId , requestAccountId string , createBucket bool ) ( grants [ ] * s3 . Grant , errCode s3err . ErrorCode ) {
cannedAclPresent := false
if r . Header . Get ( s3_constants . AmzCannedAcl ) != "" {
cannedAclPresent = true
}
customAclPresent := false
for _ , customAclHeader := range customAclHeaders {
if r . Header . Get ( customAclHeader ) != "" {
customAclPresent = true
break
}
}
// AccessControlList body is not support when create object/bucket
if ! createBucket && r . Body != nil && r . Body != http . NoBody {
defer util . CloseRequest ( r )
if cannedAclPresent || customAclPresent {
return nil , s3err . ErrUnexpectedContent
}
var acp s3 . AccessControlPolicy
err := xmlutil . UnmarshalXML ( & acp , xml . NewDecoder ( r . Body ) , "" )
if err != nil || acp . Owner == nil || acp . Owner . ID == nil {
@ -38,101 +66,113 @@ func ExtractAcl(r *http.Request, accountManager *s3account.AccountManager, owner
}
//owner should present && owner is immutable
if * acp . Owner . ID != o wnerId {
glog . V ( 3 ) . Infof ( "set acl denied! owner account is not consistent, request account id: %s, expect account id: %s" , accountId , o wnerId)
if * acp . Owner . ID == "" || * acp . Owner . ID != bucketO wnerId {
glog . V ( 3 ) . Infof ( "set acl denied! owner account is not consistent, request account id: %s, expect account id: %s" , * acp . Owner . ID , bucketO wnerId)
return nil , s3err . ErrAccessDenied
}
return ValidateAndTransferGrants ( accountManager , acp . Grants )
grants = acp . Grants
} else {
_ , grants , errCode = ParseAndValidateAclHeadersOrElseDefault ( r , accountManager , ownership , bucketOwnerId , accountId , true )
return grants , errCode
if cannedAclPresent && customAclPresent {
return nil , s3err . ErrInvalidRequest
}
if cannedAclPresent {
grants , errCode = ExtractBucketCannedAcl ( r , requestAccountId )
} else if customAclPresent {
grants , errCode = ExtractCustomAcl ( r )
}
// ParseAndValidateAclHeadersOrElseDefault will callParseAndValidateAclHeaders to get Grants, if empty, it will return Grant that grant `accountId` with `FullControl` permission
func ParseAndValidateAclHeadersOrElseDefault ( r * http . Request , accountManager * s3account . AccountManager , ownership , bucketOwnerId , accountId string , putAcl bool ) ( ownerId string , grants [ ] * s3 . Grant , errCode s3err . ErrorCode ) {
ownerId , grants , errCode = ParseAndValidateAclHeaders ( r , accountManager , ownership , bucketOwnerId , accountId , putAcl )
if errCode != s3err . ErrNone {
return
return nil , errCode
}
if len ( grants ) == 0 {
//if no acl(both customAcl and cannedAcl) specified, grant accountId(object writer) with full control permission
grants = append ( grants , & s3 . Grant {
Grantee : & s3 . Grantee {
Type : & s3_constants . GrantTypeCanonicalUser ,
ID : & accountId ,
} ,
Permission : & s3_constants . PermissionFullControl ,
} )
}
return
}
// ParseAndValidateAclHeaders parse and validate acl from header
func ParseAndValidateAclHeaders ( r * http . Request , accountManager * s3account . AccountManager , ownership , bucketOwnerId , accountId string , putAcl bool ) ( ownerId string , grants [ ] * s3 . Grant , errCode s3err . ErrorCode ) {
ownerId , grants , errCode = ParseAclHeaders ( r , ownership , bucketOwnerId , accountId , putAcl )
errCode = ValidateObjectOwnershipAndGrants ( objectOwnership , bucketOwnerId , grants )
if errCode != s3err . ErrNone {
return
return nil , errCode
}
if len ( grants ) > 0 {
grants , errCode = ValidateAndTransferGrants ( accountManager , grants )
if errCode != s3err . ErrNone {
return nil , errCode
}
return
return grants , s3err . ErrNone
}
// ParseAclHeaders parse acl headers
// When `putAcl` is true, only `CannedAcl` is parsed, such as `PutBucketAcl` or `PutObjectAcl`
// is requested, `CustomAcl` is parsed from the request body not from headers, and only if the
// request body is empty, `CannedAcl` is parsed from the header, and will not parse `CustomAcl` from the header
//
// Since `CustomAcl` has higher priority, it will be parsed first; if `CustomAcl` does not exist, `CannedAcl` will be parsed
func ParseAclHeaders ( r * http . Request , ownership , bucketOwnerId , accountId string , putAcl bool ) ( ownerId string , grants [ ] * s3 . Grant , errCode s3err . ErrorCode ) {
if ! putAcl {
errCode = ParseCustomAclHeaders ( r , & grants )
if errCode != s3err . ErrNone {
return "" , nil , errCode
// ExtractObjectAcl extracts the acl from the request body, or from the header if request body is empty
func ExtractObjectAcl ( r * http . Request , accountManager * s3account . AccountManager , objectOwnership , bucketOwnerId , requestAccountId string , createObject bool ) ( ownerId string , grants [ ] * s3 . Grant , errCode s3err . ErrorCode ) {
cannedAclPresent := false
if r . Header . Get ( s3_constants . AmzCannedAcl ) != "" {
cannedAclPresent = true
}
customAclPresent := false
for _ , customAclHeader := range customAclHeaders {
if r . Header . Get ( customAclHeader ) != "" {
customAclPresent = true
break
}
if len ( grants ) > 0 {
return accountId , grants , s3err . ErrNone
}
cannedAcl := r . Header . Get ( s3_constants . AmzCannedAcl )
if len ( cannedAcl ) == 0 {
return accountId , grants , s3err . ErrNone
// AccessControlList body is not support when create object/bucket
if ! createObject && r . Body != nil && r . Body != http . NoBody {
defer util . CloseRequest ( r )
if cannedAclPresent || customAclPresent {
return "" , nil , s3err . ErrUnexpectedContent
}
var acp s3 . AccessControlPolicy
err := xmlutil . UnmarshalXML ( & acp , xml . NewDecoder ( r . Body ) , "" )
if err != nil || acp . Owner == nil || acp . Owner . ID == nil {
return "" , nil , s3err . ErrInvalidRequest
}
//if canned acl specified, parse cannedAcl (lower priority to custom acl)
ownerId , grants , errCode = ParseCannedAclHeader ( ownership , bucketOwnerId , accountId , cannedAcl , putAcl )
//owner should present && owner is immutable
if * acp . Owner . ID == "" {
glog . V ( 1 ) . Infof ( "Access denied! The owner id is required when specifying grants using AccessControlList" )
return "" , nil , s3err . ErrAccessDenied
}
ownerId = * acp . Owner . ID
grants = acp . Grants
} else {
if cannedAclPresent && customAclPresent {
return "" , nil , s3err . ErrInvalidRequest
}
if cannedAclPresent {
ownerId , grants , errCode = ExtractObjectCannedAcl ( r , objectOwnership , bucketOwnerId , requestAccountId , createObject )
} else {
grants , errCode = ExtractCustomAcl ( r )
}
if errCode != s3err . ErrNone {
return "" , nil , errCode
}
}
errCode = ValidateObjectOwnershipAndGrants ( objectOwnership , bucketOwnerId , grants )
if errCode != s3err . ErrNone {
return "" , nil , errCode
}
grants , errCode = ValidateAndTransferGrants ( accountManager , grants )
return ownerId , grants , errCode
}
func ParseCustomAclHeaders ( r * http . Request , grants * [ ] * s3 . Grant ) s3err . ErrorCode {
customAclHeaders := [ ] string { s3_constants . AmzAclFullControl , s3_constants . AmzAclRead , s3_constants . AmzAclReadAcp , s3_constants . AmzAclWrite , s3_constants . AmzAclWriteAcp }
func ExtractCustomAcl ( r * http . Request ) ( [ ] * s3 . Grant , s3err . ErrorCode ) {
var errCode s3err . ErrorCode
var grants [ ] * s3 . Grant
for _ , customAclHeader := range customAclHeaders {
headerValue := r . Header . Get ( customAclHeader )
switch customAclHeader {
case s3_constants . AmzAclRead :
errCode = ParseCustomAclHeader ( headerValue , s3_constants . PermissionRead , grants )
errCode = ParseCustomAclHeader ( headerValue , s3_constants . PermissionRead , & grants )
case s3_constants . AmzAclWrite :
errCode = ParseCustomAclHeader ( headerValue , s3_constants . PermissionWrite , grants )
errCode = ParseCustomAclHeader ( headerValue , s3_constants . PermissionWrite , & grants )
case s3_constants . AmzAclReadAcp :
errCode = ParseCustomAclHeader ( headerValue , s3_constants . PermissionReadAcp , grants )
errCode = ParseCustomAclHeader ( headerValue , s3_constants . PermissionReadAcp , & grants )
case s3_constants . AmzAclWriteAcp :
errCode = ParseCustomAclHeader ( headerValue , s3_constants . PermissionWriteAcp , grants )
errCode = ParseCustomAclHeader ( headerValue , s3_constants . PermissionWriteAcp , & grants )
case s3_constants . AmzAclFullControl :
errCode = ParseCustomAclHeader ( headerValue , s3_constants . PermissionFullControl , grants )
errCode = ParseCustomAclHeader ( headerValue , s3_constants . PermissionFullControl , & grants )
default :
errCode = s3err . ErrInvalidAclArgument
}
if errCode != s3err . ErrNone {
return errCode
return nil , errCode
}
}
return s3err . ErrNone
return grants , s3err . ErrNone
}
func ParseCustomAclHeader ( headerValue , permission string , grants * [ ] * s3 . Grant ) s3err . ErrorCode {
@ -144,10 +184,9 @@ func ParseCustomAclHeader(headerValue, permission string, grants *[]*s3.Grant) s
return s3err . ErrInvalidRequest
}
switch kv [ 0 ] {
switch strings . TrimSpace ( kv [ 0 ] ) {
case "id" :
var accountId string
_ = json . Unmarshal ( [ ] byte ( kv [ 1 ] ) , & accountId )
accountId := decodeGranteeValue ( kv [ 1 ] )
* grants = append ( * grants , & s3 . Grant {
Grantee : & s3 . Grantee {
Type : & s3_constants . GrantTypeCanonicalUser ,
@ -156,8 +195,7 @@ func ParseCustomAclHeader(headerValue, permission string, grants *[]*s3.Grant) s
Permission : & permission ,
} )
case "emailAddress" :
var emailAddress string
_ = json . Unmarshal ( [ ] byte ( kv [ 1 ] ) , & emailAddress )
emailAddress := decodeGranteeValue ( kv [ 1 ] )
* grants = append ( * grants , & s3 . Grant {
Grantee : & s3 . Grantee {
Type : & s3_constants . GrantTypeAmazonCustomerByEmail ,
@ -167,7 +205,7 @@ func ParseCustomAclHeader(headerValue, permission string, grants *[]*s3.Grant) s
} )
case "uri" :
var groupName string
_ = json . Unmarshal ( [ ] byt e( kv [ 1 ] ) , & groupName )
groupName = decodeGranteeValu e( kv [ 1 ] )
* grants = append ( * grants , & s3 . Grant {
Grantee : & s3 . Grantee {
Type : & s3_constants . GrantTypeGroup ,
@ -179,17 +217,66 @@ func ParseCustomAclHeader(headerValue, permission string, grants *[]*s3.Grant) s
}
}
return s3err . ErrNone
}
func decodeGranteeValue ( value string ) ( result string ) {
if ! strings . HasPrefix ( value , "\"" ) {
return value
}
_ = json . Unmarshal ( [ ] byte ( value ) , & result )
if result == "" {
result = value
}
return result
}
func ParseCannedAclHeader ( bucketOwnership , bucketOwnerId , accountId , cannedAcl string , putAcl bool ) ( ownerId string , grants [ ] * s3 . Grant , err s3err . ErrorCode ) {
// ExtractBucketCannedAcl parse bucket canned acl, includes: 'private'|'public-read'|'public-read-write'|'authenticated-read'
func ExtractBucketCannedAcl ( request * http . Request , requestAccountId string ) ( grants [ ] * s3 . Grant , err s3err . ErrorCode ) {
cannedAcl := request . Header . Get ( s3_constants . AmzCannedAcl )
if cannedAcl == "" {
return grants , s3err . ErrNone
}
err = s3err . ErrNone
ownerId = accountId
objectWriterFullControl := & s3 . Grant {
Grantee : & s3 . Grantee {
ID : & requestAccountId ,
Type : & s3_constants . GrantTypeCanonicalUser ,
} ,
Permission : & s3_constants . PermissionFullControl ,
}
switch cannedAcl {
case s3_constants . CannedAclPrivate :
grants = append ( grants , objectWriterFullControl )
case s3_constants . CannedAclPublicRead :
grants = append ( grants , objectWriterFullControl )
grants = append ( grants , s3_constants . PublicRead ... )
case s3_constants . CannedAclPublicReadWrite :
grants = append ( grants , objectWriterFullControl )
grants = append ( grants , s3_constants . PublicReadWrite ... )
case s3_constants . CannedAclAuthenticatedRead :
grants = append ( grants , objectWriterFullControl )
grants = append ( grants , s3_constants . AuthenticatedRead ... )
default :
err = s3err . ErrInvalidAclArgument
}
return
}
// ExtractObjectCannedAcl parse object canned acl, includes: 'private'|'public-read'|'public-read-write'|'authenticated-read'|'aws-exec-read'|'bucket-owner-read'|'bucket-owner-full-control'
func ExtractObjectCannedAcl ( request * http . Request , objectOwnership , bucketOwnerId , requestAccountId string , createObject bool ) ( ownerId string , grants [ ] * s3 . Grant , errCode s3err . ErrorCode ) {
if createObject {
ownerId = requestAccountId
}
cannedAcl := request . Header . Get ( s3_constants . AmzCannedAcl )
if cannedAcl == "" {
return ownerId , grants , s3err . ErrNone
}
//objectWrite automatically has full control on current object
errCode = s3err . ErrNone
objectWriterFullControl := & s3 . Grant {
Grantee : & s3 . Grantee {
ID : & accountId ,
ID : & requestA ccountId,
Type : & s3_constants . GrantTypeCanonicalUser ,
} ,
Permission : & s3_constants . PermissionFullControl ,
@ -212,7 +299,7 @@ func ParseCannedAclHeader(bucketOwnership, bucketOwnerId, accountId, cannedAcl s
grants = append ( grants , s3_constants . LogDeliveryWrite ... )
case s3_constants . CannedAclBucketOwnerRead :
grants = append ( grants , objectWriterFullControl )
if bucketOwnerId != "" && bucketOwnerId != account Id {
if requestAccountId != bucketOwner Id {
grants = append ( grants ,
& s3 . Grant {
Grantee : & s3 . Grantee {
@ -225,7 +312,7 @@ func ParseCannedAclHeader(bucketOwnership, bucketOwnerId, accountId, cannedAcl s
case s3_constants . CannedAclBucketOwnerFullControl :
if bucketOwnerId != "" {
// if set ownership to 'BucketOwnerPreferred' when upload object, the bucket owner will be the object owner
if ! putAcl && bucke tOwnership == s3_constants . OwnershipBucketOwnerPreferred {
if createObject && objec tOwnership == s3_constants . OwnershipBucketOwnerPreferred {
ownerId = bucketOwnerId
grants = append ( grants ,
& s3 . Grant {
@ -237,7 +324,7 @@ func ParseCannedAclHeader(bucketOwnership, bucketOwnerId, accountId, cannedAcl s
} )
} else {
grants = append ( grants , objectWriterFullControl )
if a ccountId != bucketOwnerId {
if requestA ccountId != bucketOwnerId {
grants = append ( grants ,
& s3 . Grant {
Grantee : & s3 . Grantee {
@ -249,15 +336,13 @@ func ParseCannedAclHeader(bucketOwnership, bucketOwnerId, accountId, cannedAcl s
}
}
}
case s3_constants . CannedAclAwsExecRead :
err = s3err . ErrNotImplemented
default :
err = s3err . ErrInvalidReques t
errCode = s3err . ErrInvalidAclArgument
}
return
}
// ValidateAndTransferGrants validate grant & transfer Email-Grant to Id-Grant
// ValidateAndTransferGrants validate grant entity exists and transfer Email-Grant to Id-Grant
func ValidateAndTransferGrants ( accountManager * s3account . AccountManager , grants [ ] * s3 . Grant ) ( [ ] * s3 . Grant , s3err . ErrorCode ) {
var result [ ] * s3 . Grant
for _ , grant := range grants {
@ -314,15 +399,43 @@ func ValidateAndTransferGrants(accountManager *s3account.AccountManager, grants
return result , s3err . ErrNone
}
// DetermineReqGrants generates the grant set (Grants) according to accountId and reqPermission.
func DetermineReqGrants ( accountId , aclAction string ) ( grants [ ] * s3 . Grant ) {
// ValidateObjectOwnershipAndGrants validate if grants equals OwnerFullControl when 'ObjectOwnership' is 'BucketOwnerEnforced'
func ValidateObjectOwnershipAndGrants ( objectOwnership , bucketOwnerId string , grants [ ] * s3 . Grant ) s3err . ErrorCode {
if len ( grants ) == 0 {
return s3err . ErrNone
}
if objectOwnership == "" {
objectOwnership = s3_constants . DefaultObjectOwnership
}
if objectOwnership != s3_constants . OwnershipBucketOwnerEnforced {
return s3err . ErrNone
}
if len ( grants ) > 1 {
return s3err . AccessControlListNotSupported
}
bucketOwnerFullControlGrant := & s3 . Grant {
Permission : & s3_constants . PermissionFullControl ,
Grantee : & s3 . Grantee {
Type : & s3_constants . GrantTypeCanonicalUser ,
ID : & bucketOwnerId ,
} ,
}
if GrantEquals ( bucketOwnerFullControlGrant , grants [ 0 ] ) {
return s3err . ErrNone
}
return s3err . AccessControlListNotSupported
}
// DetermineRequiredGrants generates the grant set (Grants) according to accountId and reqPermission.
func DetermineRequiredGrants ( accountId , permission string ) ( grants [ ] * s3 . Grant ) {
// group grantee (AllUsers)
grants = append ( grants , & s3 . Grant {
Grantee : & s3 . Grantee {
Type : & s3_constants . GrantTypeGroup ,
URI : & s3_constants . GranteeGroupAllUsers ,
} ,
Permission : & aclAction ,
Permission : & permiss ion,
} )
grants = append ( grants , & s3 . Grant {
Grantee : & s3 . Grantee {
@ -338,7 +451,7 @@ func DetermineReqGrants(accountId, aclAction string) (grants []*s3.Grant) {
Type : & s3_constants . GrantTypeCanonicalUser ,
ID : & accountId ,
} ,
Permission : & aclAct ion,
Permission : & permiss ion,
} )
grants = append ( grants , & s3 . Grant {
Grantee : & s3 . Grantee {
@ -355,7 +468,7 @@ func DetermineReqGrants(accountId, aclAction string) (grants []*s3.Grant) {
Type : & s3_constants . GrantTypeGroup ,
URI : & s3_constants . GranteeGroupAuthenticatedUsers ,
} ,
Permission : & aclAct ion,
Permission : & permiss ion,
} )
grants = append ( grants , & s3 . Grant {
Grantee : & s3 . Grantee {
@ -392,7 +505,7 @@ func SetAcpGrantsHeader(r *http.Request, acpGrants []*s3.Grant) {
}
// GetAcpGrants return grants parsed from entry
func GetAcpGrants ( entryExtended map [ string ] [ ] byte ) [ ] * s3 . Grant {
func GetAcpGrants ( ownerId * string , entryExtended map [ string ] [ ] byte ) [ ] * s3 . Grant {
acpBytes , ok := entryExtended [ s3_constants . ExtAmzAclKey ]
if ok && len ( acpBytes ) > 0 {
var grants [ ] * s3 . Grant
@ -400,31 +513,43 @@ func GetAcpGrants(entryExtended map[string][]byte) []*s3.Grant {
if err == nil {
return grants
}
glog . Warning ( "grants Unmarshal error" , err )
}
if ownerId == nil {
return nil
}
return [ ] * s3 . Grant {
{
Grantee : & s3 . Grantee {
Type : & s3_constants . GrantTypeCanonicalUser ,
ID : ownerId ,
} ,
Permission : & s3_constants . PermissionFullControl ,
} ,
}
}
// AssembleEntryWithAcp fill entry with owner and grants
func AssembleEntryWithAcp ( objectEntry * filer_pb . Entry , objectOwner string , grants [ ] * s3 . Grant ) s3err . ErrorCode {
if objectEntry . Extended == nil {
objectEntry . Extended = make ( map [ string ] [ ] byte )
func AssembleEntryWithAcp ( filer Entry * filer_pb . Entry , ownerId string , grants [ ] * s3 . Grant ) s3err . ErrorCode {
if filer Entry. Extended == nil {
filer Entry. Extended = make ( map [ string ] [ ] byte )
}
if len ( objectOwner ) > 0 {
objectEntry . Extended [ s3_constants . ExtAmzOwnerKey ] = [ ] byte ( objectOwner )
if len ( ownerId ) > 0 {
filer Entry. Extended [ s3_constants . ExtAmzOwnerKey ] = [ ] byte ( ownerId )
} else {
delete ( object Entry. Extended , s3_constants . ExtAmzOwnerKey )
delete ( filer Entry. Extended , s3_constants . ExtAmzOwnerKey )
}
if len ( grants ) > 0 {
if grants != nil {
grantsBytes , err := json . Marshal ( grants )
if err != nil {
glog . Warning ( "assemble acp to entry:" , err )
return s3err . ErrInvalidRequest
}
object Entry. Extended [ s3_constants . ExtAmzAclKey ] = grantsBytes
filer Entry. Extended [ s3_constants . ExtAmzAclKey ] = grantsBytes
} else {
delete ( object Entry. Extended , s3_constants . ExtAmzAclKey )
delete ( filer Entry. Extended , s3_constants . ExtAmzAclKey )
}
return s3err . ErrNone
@ -509,6 +634,46 @@ func GrantEquals(a, b *s3.Grant) bool {
return true
}
func MarshalGrantsToJson ( grants [ ] * s3 . Grant ) ( [ ] byte , error ) {
if len ( grants ) == 0 {
return nil , nil
}
var GrantsToMap [ ] map [ string ] any
for _ , grant := range grants {
grantee := grant . Grantee
switch * grantee . Type {
case s3_constants . GrantTypeGroup :
GrantsToMap = append ( GrantsToMap , map [ string ] any {
"Permission" : grant . Permission ,
"Grantee" : map [ string ] any {
"Type" : grantee . Type ,
"URI" : grantee . URI ,
} ,
} )
case s3_constants . GrantTypeCanonicalUser :
GrantsToMap = append ( GrantsToMap , map [ string ] any {
"Permission" : grant . Permission ,
"Grantee" : map [ string ] any {
"Type" : grantee . Type ,
"ID" : grantee . ID ,
} ,
} )
case s3_constants . GrantTypeAmazonCustomerByEmail :
GrantsToMap = append ( GrantsToMap , map [ string ] any {
"Permission" : grant . Permission ,
"Grantee" : map [ string ] any {
"Type" : grantee . Type ,
"EmailAddress" : grantee . EmailAddress ,
} ,
} )
default :
return nil , fmt . Errorf ( "grantee type[%s] is not valid" , * grantee . Type )
}
}
return json . Marshal ( GrantsToMap )
}
func GrantWithFullControl ( accountId string ) * s3 . Grant {
return & s3 . Grant {
Permission : & s3_constants . PermissionFullControl ,
@ -524,22 +689,22 @@ func CheckObjectAccessForReadObject(r *http.Request, w http.ResponseWriter, entr
return http . StatusOK , true
}
a ccountId := GetAccountId ( r )
if len ( a ccountId) == 0 {
requestA ccountId := GetAccountId ( r )
if len ( requestA ccountId) == 0 {
glog . Warning ( "#checkObjectAccessForReadObject header[accountId] not exists!" )
return http . StatusForbidden , false
}
//owner access
objectOwner := GetAcpOwner ( entry . Extended , bucketOwnerId )
if accountId == objectOwner {
if ValidateAccount ( requestAccountId , objectOwner ) {
return http . StatusOK , true
}
//find in Grants
acpGrants := GetAcpGrants ( entry . Extended )
acpGrants := GetAcpGrants ( nil , entry . Extended )
if acpGrants != nil {
reqGrants := DetermineReqGrants ( a ccountId, s3_constants . PermissionRead )
reqGrants := DetermineRequired Grants ( requestA ccountId, s3_constants . PermissionRead )
for _ , requiredGrant := range reqGrants {
for _ , grant := range acpGrants {
if GrantEquals ( requiredGrant , grant ) {
@ -549,6 +714,6 @@ func CheckObjectAccessForReadObject(r *http.Request, w http.ResponseWriter, entr
}
}
glog . V ( 3 ) . Infof ( "acl denied! request account id: %s" , a ccountId)
glog . V ( 3 ) . Infof ( "acl denied! request account id: %s" , requestA ccountId)
return http . StatusForbidden , false
}