diff --git a/CHANGELOG.md b/CHANGELOG.md index 43117a02..01e489cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This document outlines major changes between releases. ### Changed - AWS SDK migrated to V2 (#1028) +- Bucket ownership settings moved from EACL to bucket settings meta objects (#1120) ### Fixed @@ -16,6 +17,10 @@ This document outlines major changes between releases. ### Removed +## Upgrading from 0.36.1 +authmate tool "reset-bucket-acl" command was updated to clean redundant EACL records. These settings were moved to +bucket settings object. + ## [0.36.1] - 2025-04-09 ### Fixed diff --git a/api/data/info.go b/api/data/info.go index 07c1a73e..f21ccafd 100644 --- a/api/data/info.go +++ b/api/data/info.go @@ -21,7 +21,21 @@ const ( VersioningSuspended = "Suspended" ) +const ( + // BucketOwnerEnforced is a enforced state. + BucketOwnerEnforced = iota + // BucketOwnerPreferred is a preferred state. + BucketOwnerPreferred + // BucketOwnerPreferredAndRestricted is a preferred state with `bucket-owner-full-control` restriction applied. + BucketOwnerPreferredAndRestricted + // BucketOwnerObjectWriter is a object writer state. + BucketOwnerObjectWriter +) + type ( + // BucketOwner is bucket onwer state. + BucketOwner int + // BucketACLState is bucket ACL state. BucketACLState uint32 @@ -78,6 +92,7 @@ type ( BucketSettings struct { Versioning string `json:"versioning"` LockConfiguration *ObjectLockConfiguration `json:"lock_configuration"` + BucketOwner BucketOwner `json:"bucket_owner"` } // CORSConfiguration stores CORS configuration of a request. diff --git a/api/handler/acl.go b/api/handler/acl.go index 04319a70..afa9e296 100644 --- a/api/handler/acl.go +++ b/api/handler/acl.go @@ -294,13 +294,13 @@ func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) { return } - eacl, err := h.obj.GetBucketACL(r.Context(), bktInfo) + settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) if err != nil { - h.logAndSendError(w, "could not get bucket eacl", reqInfo, err) + h.logAndSendError(w, "could not get bucket settings", reqInfo, err) return } - if IsBucketOwnerForced(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerEnforced { if !isValidOwnerEnforced(r) { h.logAndSendError(w, "access control list not supported", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessControlListNotSupported)) return @@ -425,13 +425,13 @@ func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) { return } - eacl, err := h.obj.GetBucketACL(r.Context(), bktInfo) + settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) if err != nil { - h.logAndSendError(w, "could not get bucket eacl", reqInfo, err) + h.logAndSendError(w, "could not get bucket settings", reqInfo, err) return } - if IsBucketOwnerForced(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerEnforced { if !isValidOwnerEnforced(r) { h.logAndSendError(w, "access control list not supported", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessControlListNotSupported)) return @@ -439,7 +439,7 @@ func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) { r.Header.Set(api.AmzACL, "") } - if IsBucketOwnerPreferredAndRestricted(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerPreferredAndRestricted { if !isValidOwnerPreferred(r) { h.logAndSendError(w, "header x-amz-acl:bucket-owner-full-control must be set", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessDenied)) return @@ -567,6 +567,41 @@ func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) return } + var index = -1 + + // This bucket setting is a part of ACL. It not useful For us inside EACL, therefore we remove it from the table. + for i, res := range astPolicy.Resources { + if res.Version == cannedACLBucketOwnerFullControl && + len(res.Operations) == 1 && + len(res.Operations[0].Users) == 0 && + res.Operations[0].Users[0] == ownerPreferredAndRestrictedUserID { + index = i + break + } + } + + if index >= 0 { + settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) + if err != nil { + h.logAndSendError(w, "could not get bucket settings", reqInfo, err) + return + } + + settings.BucketOwner = data.BucketOwnerPreferredAndRestricted + + p := layer.PutSettingsParams{ + BktInfo: bktInfo, + Settings: settings, + } + + if err = h.obj.PutBucketSettings(r.Context(), &p); err != nil { + h.logAndSendError(w, "couldn't put bucket settings", reqInfo, err) + return + } + + astPolicy.Resources = slices.Delete(astPolicy.Resources, index, index+1) + } + if _, err = h.updateBucketACL(r, astPolicy, bktInfo, token); err != nil { h.logAndSendError(w, "could not update bucket acl", reqInfo, err) return @@ -1024,26 +1059,6 @@ func formRecords(resource *astResource) ([]*eacl.Record, error) { for i := len(resource.Operations) - 1; i >= 0; i-- { astOp := resource.Operations[i] - if len(astOp.Users) == 1 { - var markerRecord *eacl.Record - - switch astOp.Users[0] { - case ownerEnforcedUserID: - markerRecord = BucketOwnerEnforcedRecord() - case ownerPreferredUserID: - markerRecord = BucketOwnerPreferredRecord() - case ownerObjectWriterUserID: - markerRecord = BucketACLObjectWriterRecord() - case ownerPreferredAndRestrictedUserID: - markerRecord = BucketOwnerPreferredAndRestrictedRecord() - } - - if markerRecord != nil { - res = append(res, markerRecord) - return res, nil - } - } - record := eacl.ConstructRecord(astOp.Action, astOp.Op, []eacl.Target{}) if astOp.IsGroupGrantee() { record.SetTargets(eacl.NewTargetByRole(eacl.RoleOthers)) @@ -1696,8 +1711,6 @@ func bucketACLToTable(acp *AccessControlPolicy) (*eacl.Table, error) { records = append(records, *getOthersRecord(op, eacl.ActionDeny)) } - records = append(records, *BucketOwnerEnforcedRecord()) - table := eacl.ConstructTable(records) return &table, nil @@ -1737,20 +1750,6 @@ func getOthersRecord(op eacl.Operation, action eacl.Action) *eacl.Record { return &record } -// BucketOwnerEnforcedRecord generates special marker record for OwnerEnforced policy. -func BucketOwnerEnforcedRecord() *eacl.Record { - var markerRecord = eacl.ConstructRecord(eacl.ActionDeny, eacl.OperationPut, - []eacl.Target{ - eacl.NewTargetByAccounts([]user.ID{ownerEnforcedUserID}), - }, - []eacl.Filter{ - eacl.ConstructFilter(eacl.HeaderFromRequest, amzBucketOwnerField, eacl.MatchStringNotEqual, amzBucketOwnerEnforced), - }..., - ) - - return &markerRecord -} - func isValidOwnerEnforced(r *http.Request) bool { if cannedACL := r.Header.Get(api.AmzACL); cannedACL != "" { switch cannedACL { @@ -1766,120 +1765,12 @@ func isValidOwnerEnforced(r *http.Request) bool { return true } -// BucketACLObjectWriterRecord generates special marker record for OwnerWriter policy. -func BucketACLObjectWriterRecord() *eacl.Record { - var markerRecord = eacl.ConstructRecord(eacl.ActionDeny, eacl.OperationPut, - []eacl.Target{eacl.NewTargetByAccounts([]user.ID{ownerObjectWriterUserID})}, - []eacl.Filter{ - eacl.ConstructFilter(eacl.HeaderFromRequest, amzBucketOwnerField, eacl.MatchStringNotEqual, amzBucketOwnerObjectWriter), - }..., - ) - - return &markerRecord -} - -// IsBucketOwnerForced checks special marker record for OwnerForced policy. -func IsBucketOwnerForced(table *eacl.Table) bool { - if table == nil { - return false - } - - for _, r := range table.Records() { - if r.Action() == eacl.ActionDeny && r.Operation() == eacl.OperationPut { - for _, f := range r.Filters() { - if f.Key() == amzBucketOwnerField && - f.Value() == amzBucketOwnerEnforced && - f.From() == eacl.HeaderFromRequest && - f.Matcher() == eacl.MatchStringNotEqual { - if len(r.Targets()) == 1 && len(r.Targets()[0].Accounts()) == 1 { - return r.Targets()[0].Accounts()[0] == ownerEnforcedUserID - } - } - } - } - } - - return false -} - -// BucketOwnerPreferredRecord generates special marker record for OwnerPreferred policy. -func BucketOwnerPreferredRecord() *eacl.Record { - var markerRecord = eacl.ConstructRecord(eacl.ActionDeny, eacl.OperationPut, - []eacl.Target{eacl.NewTargetByAccounts([]user.ID{ownerPreferredUserID})}, - []eacl.Filter{ - eacl.ConstructFilter(eacl.HeaderFromRequest, amzBucketOwnerField, eacl.MatchStringNotEqual, amzBucketOwnerPreferred), - }..., - ) - - return &markerRecord -} - -// IsBucketOwnerPreferred checks special marker record for OwnerPreferred policy. -func IsBucketOwnerPreferred(table *eacl.Table) bool { - if table == nil { - return false - } - - for _, r := range table.Records() { - if r.Action() == eacl.ActionDeny && r.Operation() == eacl.OperationPut { - for _, f := range r.Filters() { - if f.Key() == amzBucketOwnerField && - f.Value() == amzBucketOwnerPreferred && - f.From() == eacl.HeaderFromRequest && - f.Matcher() == eacl.MatchStringNotEqual { - if len(r.Targets()) == 1 && len(r.Targets()[0].Accounts()) == 1 { - return r.Targets()[0].Accounts()[0] == ownerPreferredUserID - } - } - } - } - } - - return false -} - -// BucketOwnerPreferredRecord generates special marker record for OwnerPreferred policy and sets flag for bucket owner full control acl restriction. -func BucketOwnerPreferredAndRestrictedRecord() *eacl.Record { - var markerRecord = eacl.ConstructRecord(eacl.ActionDeny, eacl.OperationPut, - []eacl.Target{eacl.NewTargetByAccounts([]user.ID{ownerPreferredAndRestrictedUserID})}, - []eacl.Filter{ - eacl.ConstructFilter(eacl.HeaderFromObject, amzBucketOwnerField, eacl.MatchStringEqual, cannedACLBucketOwnerFullControl), - }..., - ) - - return &markerRecord -} - -// IsBucketOwnerPreferredAndRestricted checks special marker record and check ALC bucket owner full control flag for OwnerPreferred policy. -func IsBucketOwnerPreferredAndRestricted(table *eacl.Table) bool { - if table == nil { - return false - } - - for _, r := range table.Records() { - if r.Action() == eacl.ActionDeny && r.Operation() == eacl.OperationPut { - for _, f := range r.Filters() { - if f.Key() == amzBucketOwnerField && - f.Value() == cannedACLBucketOwnerFullControl && - f.From() == eacl.HeaderFromObject && - f.Matcher() == eacl.MatchStringEqual { - if len(r.Targets()) == 1 && len(r.Targets()[0].Accounts()) == 1 { - return r.Targets()[0].Accounts()[0] == ownerPreferredAndRestrictedUserID - } - } - } - } - } - - return false -} - func isValidOwnerPreferred(r *http.Request) bool { cannedACL := r.Header.Get(api.AmzACL) return cannedACL == cannedACLBucketOwnerFullControl } -func updateBucketOwnership(records []eacl.Record, newRecord *eacl.Record) eacl.Table { +func UpdateBucketOwnership(records []eacl.Record, newRecord *eacl.Record) eacl.Table { var ( rowID = -1 ) @@ -1911,26 +1802,3 @@ func updateBucketOwnership(records []eacl.Record, newRecord *eacl.Record) eacl.T return eacl.ConstructTable(records) } - -func isBucketOwnerObjectWriter(table *eacl.Table) bool { - if table == nil { - return false - } - - for _, r := range table.Records() { - if r.Action() == eacl.ActionDeny && r.Operation() == eacl.OperationPut { - for _, f := range r.Filters() { - if f.Key() == amzBucketOwnerField && - f.Value() == amzBucketOwnerObjectWriter && - f.From() == eacl.HeaderFromRequest && - f.Matcher() == eacl.MatchStringNotEqual { - if len(r.Targets()) == 1 && len(r.Targets()[0].Accounts()) == 1 { - return r.Targets()[0].Accounts()[0] == ownerObjectWriterUserID - } - } - } - } - } - - return false -} diff --git a/api/handler/acl_test.go b/api/handler/acl_test.go index 6b4b28e5..9b145df9 100644 --- a/api/handler/acl_test.go +++ b/api/handler/acl_test.go @@ -1182,7 +1182,6 @@ func TestBucketAclToTable(t *testing.T) { for _, op := range fullOps { records = append(records, *getOthersRecord(op, eacl.ActionDeny)) } - records = append(records, *BucketOwnerEnforcedRecord()) actualTable, err := bucketACLToTable(acl) require.NoError(t, err) diff --git a/api/handler/copy.go b/api/handler/copy.go index 86a6d3ac..c0de9953 100644 --- a/api/handler/copy.go +++ b/api/handler/copy.go @@ -123,14 +123,8 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) { return } - eacl, err := h.obj.GetBucketACL(r.Context(), dstBktInfo) - if err != nil { - h.logAndSendError(w, "could not get bucket eacl", reqInfo, err) - return - } - if containsACL { - if IsBucketOwnerForced(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerEnforced { if !isValidOwnerEnforced(r) { h.logAndSendError(w, "access control list not supported", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessControlListNotSupported)) return @@ -144,7 +138,7 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) { } } - if IsBucketOwnerPreferredAndRestricted(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerPreferredAndRestricted { if !isValidOwnerPreferred(r) { h.logAndSendError(w, "header x-amz-acl:bucket-owner-full-control must be set", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessDenied)) return diff --git a/api/handler/multipart_upload.go b/api/handler/multipart_upload.go index 1950b687..2415fae7 100644 --- a/api/handler/multipart_upload.go +++ b/api/handler/multipart_upload.go @@ -112,14 +112,14 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re Data: &layer.UploadData{}, } - eacl, err := h.obj.GetBucketACL(r.Context(), bktInfo) + settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) if err != nil { - h.logAndSendError(w, "could not get bucket eacl", reqInfo, err) + h.logAndSendError(w, "could not get bucket settings", reqInfo, err) return } if containsACLHeaders(r) { - if IsBucketOwnerForced(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerEnforced { if !isValidOwnerEnforced(r) { h.logAndSendError(w, "access control list not supported", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessControlListNotSupported)) return @@ -139,7 +139,7 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re p.Data.ACLHeaders = formACLHeadersForMultipart(r.Header) } - if IsBucketOwnerPreferredAndRestricted(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerPreferredAndRestricted { if !isValidOwnerPreferred(r) { h.logAndSendError(w, "header x-amz-acl:bucket-owner-full-control must be set", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessDenied)) return diff --git a/api/handler/ownership.go b/api/handler/ownership.go index 3541327e..5dcfc989 100644 --- a/api/handler/ownership.go +++ b/api/handler/ownership.go @@ -6,9 +6,9 @@ import ( "net/http" "github.com/nspcc-dev/neofs-s3-gw/api" + "github.com/nspcc-dev/neofs-s3-gw/api/data" "github.com/nspcc-dev/neofs-s3-gw/api/layer" "github.com/nspcc-dev/neofs-s3-gw/api/s3errors" - "github.com/nspcc-dev/neofs-sdk-go/eacl" ) type ( @@ -37,7 +37,6 @@ func (h *handler) PutBucketOwnershipControlsHandler(w http.ResponseWriter, r *ht var ( reqInfo = api.GetReqInfo(r.Context()) params putBucketOwnershipControlsParams - rec *eacl.Record ) defer func() { @@ -54,52 +53,43 @@ func (h *handler) PutBucketOwnershipControlsHandler(w http.ResponseWriter, r *ht return } + bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName) + if err != nil { + h.logAndSendError(w, "could not get bucket objInfo", reqInfo, err) + return + } + + bktSettings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) + if err != nil { + h.logAndSendError(w, "could not get bucket settings", reqInfo, err) + return + } + switch params.Rules[0].ObjectOwnership { case amzBucketOwnerEnforced: - rec = BucketOwnerEnforcedRecord() + bktSettings.BucketOwner = data.BucketOwnerEnforced case amzBucketOwnerPreferred: - rec = BucketOwnerPreferredRecord() + bktSettings.BucketOwner = data.BucketOwnerPreferred case amzBucketOwnerObjectWriter: - rec = BucketACLObjectWriterRecord() + bktSettings.BucketOwner = data.BucketOwnerObjectWriter default: h.logAndSendError(w, "invalid ownership", reqInfo, s3errors.GetAPIError(s3errors.ErrBadRequest)) return } - bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName) - if err != nil { - h.logAndSendError(w, "could not get bucket objInfo", reqInfo, err) - return - } - if expectedBucketOwner := r.Header.Get(xAmzExpectedBucketOwner); expectedBucketOwner != "" { if expectedBucketOwner != bktInfo.Owner.String() { h.logAndSendError(w, "bucket owner mismatch", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessDenied)) } } - token, err := getSessionTokenSetEACL(r.Context()) - if err != nil { - h.logAndSendError(w, "couldn't get eacl token", reqInfo, err) - return - } - - bucketACL, err := h.obj.GetBucketACL(r.Context(), bktInfo) - if err != nil { - h.logAndSendError(w, "could not get bucket eacl", reqInfo, err) - return - } - - newEACL := updateBucketOwnership(bucketACL.EACL.Records(), rec) - - p := layer.PutBucketACLParams{ - BktInfo: bktInfo, - EACL: &newEACL, - SessionToken: token, + sp := &layer.PutSettingsParams{ + BktInfo: bktInfo, + Settings: bktSettings, } - if err = h.obj.PutBucketACL(r.Context(), &p); err != nil { - h.logAndSendError(w, "could not put bucket eacl", reqInfo, err) + if err = h.obj.PutBucketSettings(r.Context(), sp); err != nil { + h.logAndSendError(w, "couldn't put bucket settings", reqInfo, err) return } @@ -124,21 +114,21 @@ func (h *handler) GetBucketOwnershipControlsHandler(w http.ResponseWriter, r *ht } } - bucketACL, err := h.obj.GetBucketACL(r.Context(), bktInfo) + settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) if err != nil { - h.logAndSendError(w, "could not get bucket eacl", reqInfo, err) + h.logAndSendError(w, "could not get bucket settings", reqInfo, err) return } - if IsBucketOwnerForced(bucketACL.EACL) { + if settings.BucketOwner == data.BucketOwnerEnforced { response = &putBucketOwnershipControlsParams{ Rules: []objectOwnershipRules{{ObjectOwnership: amzBucketOwnerEnforced}}, } - } else if IsBucketOwnerPreferred(bucketACL.EACL) { + } else if settings.BucketOwner == data.BucketOwnerPreferred { response = &putBucketOwnershipControlsParams{ Rules: []objectOwnershipRules{{ObjectOwnership: amzBucketOwnerPreferred}}, } - } else if isBucketOwnerObjectWriter(bucketACL.EACL) { + } else if settings.BucketOwner == data.BucketOwnerObjectWriter { response = &putBucketOwnershipControlsParams{ Rules: []objectOwnershipRules{{ObjectOwnership: amzBucketOwnerObjectWriter}}, } @@ -171,28 +161,21 @@ func (h *handler) DeleteBucketOwnershipControlsHandler(w http.ResponseWriter, r } } - token, err := getSessionTokenSetEACL(r.Context()) - if err != nil { - h.logAndSendError(w, "couldn't get eacl token", reqInfo, err) - return - } - - bucketACL, err := h.obj.GetBucketACL(r.Context(), bktInfo) + settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) if err != nil { - h.logAndSendError(w, "could not get bucket eacl", reqInfo, err) + h.logAndSendError(w, "could not get bucket settings", reqInfo, err) return } - newEACL := updateBucketOwnership(bucketACL.EACL.Records(), nil) + settings.BucketOwner = data.BucketOwnerEnforced - p := layer.PutBucketACLParams{ - BktInfo: bktInfo, - EACL: &newEACL, - SessionToken: token, + p := layer.PutSettingsParams{ + BktInfo: bktInfo, + Settings: settings, } - if err = h.obj.PutBucketACL(r.Context(), &p); err != nil { - h.logAndSendError(w, "could not put bucket eacl", reqInfo, err) + if err = h.obj.PutBucketSettings(r.Context(), &p); err != nil { + h.logAndSendError(w, "couldn't put bucket settings", reqInfo, err) return } diff --git a/api/handler/put.go b/api/handler/put.go index 3a7b52b9..79d65b30 100644 --- a/api/handler/put.go +++ b/api/handler/put.go @@ -210,14 +210,14 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) { return } - eacl, err := h.obj.GetBucketACL(r.Context(), bktInfo) + settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) if err != nil { - h.logAndSendError(w, "could not get bucket eacl", reqInfo, err) + h.logAndSendError(w, "could not get bucket settings", reqInfo, err) return } if containsACL { - if IsBucketOwnerForced(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerEnforced { if !isValidOwnerEnforced(r) { h.logAndSendError(w, "access control list not supported", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessControlListNotSupported)) return @@ -226,7 +226,7 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) { } } - if IsBucketOwnerPreferredAndRestricted(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerPreferredAndRestricted { if !isValidOwnerPreferred(r) { h.logAndSendError(w, "header x-amz-acl:bucket-owner-full-control must be set", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessDenied)) return @@ -273,12 +273,6 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) { CopiesNumber: copiesNumber, } - settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) - if err != nil { - h.logAndSendError(w, "could not get bucket settings", reqInfo, err) - return - } - params.Lock, err = formObjectLock(r.Context(), bktInfo, settings.LockConfiguration, r.Header) if err != nil { h.logAndSendError(w, "could not form object lock", reqInfo, err) @@ -478,14 +472,14 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) { return } - eacl, err := h.obj.GetBucketACL(r.Context(), bktInfo) + settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) if err != nil { - h.logAndSendError(w, "could not get bucket eacl", reqInfo, err) + h.logAndSendError(w, "could not get bucket settings", reqInfo, err) return } if containsACL { - if IsBucketOwnerForced(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerEnforced { if !isValidOwnerEnforced(r) { h.logAndSendError(w, "access control list not supported", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessControlListNotSupported)) return @@ -494,7 +488,7 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) { } } - if IsBucketOwnerPreferredAndRestricted(eacl.EACL) { + if settings.BucketOwner == data.BucketOwnerPreferredAndRestricted { if !isValidOwnerPreferred(r) { h.logAndSendError(w, "header x-amz-acl:bucket-owner-full-control must be set", reqInfo, s3errors.GetAPIError(s3errors.ErrAccessDenied)) return diff --git a/cmd/s3-authmate/main.go b/cmd/s3-authmate/main.go index c65868f2..c0a578d2 100644 --- a/cmd/s3-authmate/main.go +++ b/cmd/s3-authmate/main.go @@ -22,7 +22,6 @@ import ( "github.com/nspcc-dev/neofs-s3-gw/internal/wallet" "github.com/nspcc-dev/neofs-sdk-go/client" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" - "github.com/nspcc-dev/neofs-sdk-go/eacl" "github.com/nspcc-dev/neofs-sdk-go/pool" "github.com/nspcc-dev/neofs-sdk-go/user" "github.com/spf13/viper" @@ -735,54 +734,21 @@ func resetBucketEACL() *cli.Command { return cli.Exit(fmt.Sprintf("write resolved CID: %s", err), 5) } - var ( - newEACLTable eacl.Table - targetOwner eacl.Target - records []eacl.Record - ) - - newEACLTable.SetCID(containerID) - targetOwner.SetAccounts([]user.ID{or.BearerToken.Issuer()}) - - for op := eacl.OperationGet; op <= eacl.OperationRangeHash; op++ { - records = append(records, - eacl.ConstructRecord(eacl.ActionAllow, op, []eacl.Target{targetOwner}), - ) - } - - for op := eacl.OperationGet; op <= eacl.OperationRangeHash; op++ { - record := eacl.ConstructRecord(eacl.ActionDeny, op, - []eacl.Target{eacl.NewTargetByRole(eacl.RoleOthers)}, - ) - - records = append(records, record) - } - oldEacl, err := neoFS.ContainerEACL(ctx, containerID) if err != nil { return cli.Exit(fmt.Sprintf("failed to obtain old neofs EACL: %s", err), 1) } - if handler.IsBucketOwnerForced(oldEacl) { - records = append(records, *handler.BucketOwnerEnforcedRecord()) - } - - if handler.IsBucketOwnerPreferred(oldEacl) { - records = append(records, *handler.BucketOwnerPreferredRecord()) - } - - if handler.IsBucketOwnerPreferredAndRestricted(oldEacl) { - records = append(records, *handler.BucketOwnerPreferredAndRestrictedRecord()) - } - - newEACLTable.SetRecords(records) + // remove any bucket ownership record type. + updatedTable := handler.UpdateBucketOwnership(oldEacl.Records(), nil) + oldEacl.SetRecords(updatedTable.Records()) if applyFlag { var tcancel context.CancelFunc ctx, tcancel = context.WithTimeout(ctx, timeoutFlag) defer tcancel() - if err = neoFS.SetContainerEACL(ctx, newEACLTable, or.SessionTokenForSetEACL); err != nil { + if err = neoFS.SetContainerEACL(ctx, *oldEacl, or.SessionTokenForSetEACL); err != nil { return cli.Exit(fmt.Sprintf("failed to setup eacl: %s", err), 1) } } else { @@ -790,7 +756,7 @@ func resetBucketEACL() *cli.Command { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") - if err = enc.Encode(newEACLTable.Records()); err != nil { + if err = enc.Encode(oldEacl.Records()); err != nil { return cli.Exit(fmt.Sprintf("failed to encode new neofs EACL records: %s", err), 1) }