[#372] Drop [e]ACL related code
All checks were successful
/ DCO (pull_request) Successful in 2m15s
/ Vulncheck (pull_request) Successful in 2m55s
/ Builds (1.20) (pull_request) Successful in 3m46s
/ Builds (1.21) (pull_request) Successful in 3m48s
/ Lint (pull_request) Successful in 5m26s
/ Tests (1.20) (pull_request) Successful in 3m34s
/ Tests (1.21) (pull_request) Successful in 3m18s
All checks were successful
/ DCO (pull_request) Successful in 2m15s
/ Vulncheck (pull_request) Successful in 2m55s
/ Builds (1.20) (pull_request) Successful in 3m46s
/ Builds (1.21) (pull_request) Successful in 3m48s
/ Lint (pull_request) Successful in 5m26s
/ Tests (1.20) (pull_request) Successful in 3m34s
/ Tests (1.21) (pull_request) Successful in 3m18s
Always consider buckets as APE compatible Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
9241954496
commit
465eaa816a
19 changed files with 43 additions and 3342 deletions
|
@ -31,7 +31,6 @@ type (
|
||||||
LocationConstraint string
|
LocationConstraint string
|
||||||
ObjectLockEnabled bool
|
ObjectLockEnabled bool
|
||||||
HomomorphicHashDisabled bool
|
HomomorphicHashDisabled bool
|
||||||
APEEnabled bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectInfo holds S3 object data.
|
// ObjectInfo holds S3 object data.
|
||||||
|
|
1392
api/handler/acl.go
1392
api/handler/acl.go
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,11 +41,10 @@ func path2BucketObject(path string) (string, string, error) {
|
||||||
|
|
||||||
func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
versionID string
|
versionID string
|
||||||
metadata map[string]string
|
metadata map[string]string
|
||||||
tagSet map[string]string
|
tagSet map[string]string
|
||||||
sessionTokenEACL *session.Container
|
|
||||||
|
|
||||||
ctx = r.Context()
|
ctx = r.Context()
|
||||||
reqInfo = middleware.GetReqInfo(ctx)
|
reqInfo = middleware.GetReqInfo(ctx)
|
||||||
|
@ -93,20 +91,11 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apeEnabled := dstBktInfo.APEEnabled || settings.CannedACL != ""
|
if cannedACLStatus == aclStatusYes {
|
||||||
if apeEnabled && cannedACLStatus == aclStatusYes {
|
|
||||||
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
needUpdateEACLTable := !(apeEnabled || cannedACLStatus == aclStatusNo)
|
|
||||||
if needUpdateEACLTable {
|
|
||||||
if sessionTokenEACL, err = getSessionTokenSetEACL(ctx); err != nil {
|
|
||||||
h.logAndSendError(w, "could not get eacl session token from a box", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extendedSrcObjInfo, err := h.obj.GetExtendedObjectInfo(ctx, srcObjPrm)
|
extendedSrcObjInfo, err := h.obj.GetExtendedObjectInfo(ctx, srcObjPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not find object", reqInfo, err)
|
h.logAndSendError(w, "could not find object", reqInfo, err)
|
||||||
|
@ -239,25 +228,6 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if needUpdateEACLTable {
|
|
||||||
newEaclTable, err := h.getNewEAclTable(r, dstBktInfo, dstObjInfo)
|
|
||||||
if err != nil {
|
|
||||||
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
p := &layer.PutBucketACLParams{
|
|
||||||
BktInfo: dstBktInfo,
|
|
||||||
EACL: newEaclTable,
|
|
||||||
SessionToken: sessionTokenEACL,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = h.obj.PutBucketACL(ctx, p); err != nil {
|
|
||||||
h.logAndSendError(w, "could not put bucket acl", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if tagSet != nil {
|
if tagSet != nil {
|
||||||
tagPrm := &data.PutObjectTaggingParams{
|
tagPrm := &data.PutObjectTaggingParams{
|
||||||
ObjectVersion: &data.ObjectVersion{
|
ObjectVersion: &data.ObjectVersion{
|
||||||
|
|
|
@ -7,12 +7,9 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -84,31 +81,6 @@ func headObject(t *testing.T, tc *handlerContext, bktName, objName string, heade
|
||||||
assertStatus(t, w, status)
|
assertStatus(t, w, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInvalidAccessThroughCache(t *testing.T) {
|
|
||||||
hc := prepareHandlerContext(t)
|
|
||||||
|
|
||||||
bktName, objName := "bucket-for-cache", "obj-for-cache"
|
|
||||||
bktInfo, _ := createBucketAndObject(hc, bktName, objName)
|
|
||||||
setContainerEACL(hc, bktInfo.CID)
|
|
||||||
|
|
||||||
headObject(t, hc, bktName, objName, nil, http.StatusOK)
|
|
||||||
|
|
||||||
w, r := prepareTestRequest(hc, bktName, objName, nil)
|
|
||||||
hc.Handler().HeadObjectHandler(w, r.WithContext(middleware.SetBox(r.Context(), &middleware.Box{AccessBox: newTestAccessBox(t, nil)})))
|
|
||||||
assertStatus(t, w, http.StatusForbidden)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setContainerEACL(hc *handlerContext, cnrID cid.ID) {
|
|
||||||
table := eacl.NewTable()
|
|
||||||
table.SetCID(cnrID)
|
|
||||||
for _, op := range fullOps {
|
|
||||||
table.AddRecord(getOthersRecord(op, eacl.ActionDeny))
|
|
||||||
}
|
|
||||||
|
|
||||||
err := hc.MockedPool().SetContainerEACL(hc.Context(), *table, nil)
|
|
||||||
require.NoError(hc.t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHeadObject(t *testing.T) {
|
func TestHeadObject(t *testing.T) {
|
||||||
hc := prepareHandlerContextWithMinCache(t)
|
hc := prepareHandlerContextWithMinCache(t)
|
||||||
bktName, objName := "bucket", "obj"
|
bktName, objName := "bucket", "obj"
|
||||||
|
@ -155,7 +127,7 @@ func newTestAccessBox(t *testing.T, key *keys.PrivateKey) *accessbox.Box {
|
||||||
}
|
}
|
||||||
|
|
||||||
var btoken bearer.Token
|
var btoken bearer.Token
|
||||||
btoken.SetEACLTable(*eacl.NewTable())
|
btoken.SetImpersonate(true)
|
||||||
err = btoken.Sign(key.PrivateKey)
|
err = btoken.Sign(key.PrivateKey)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|
|
@ -112,14 +112,7 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo)
|
if cannedACLStatus == aclStatusYes {
|
||||||
if err != nil {
|
|
||||||
h.logAndSendError(w, "couldn't get bucket settings", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
apeEnabled := bktInfo.APEEnabled || settings.CannedACL != ""
|
|
||||||
if apeEnabled && cannedACLStatus == aclStatusYes {
|
|
||||||
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -133,20 +126,6 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re
|
||||||
Data: &layer.UploadData{},
|
Data: &layer.UploadData{},
|
||||||
}
|
}
|
||||||
|
|
||||||
needUpdateEACLTable := !(apeEnabled || cannedACLStatus == aclStatusNo)
|
|
||||||
if needUpdateEACLTable {
|
|
||||||
key, err := h.bearerTokenIssuerKey(r.Context())
|
|
||||||
if err != nil {
|
|
||||||
h.logAndSendError(w, "couldn't get gate key", reqInfo, err, additional...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err = parseACLHeaders(r.Header, key); err != nil {
|
|
||||||
h.logAndSendError(w, "could not parse acl", reqInfo, err, additional...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.Data.ACLHeaders = formACLHeadersForMultipart(r.Header)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(r.Header.Get(api.AmzTagging)) > 0 {
|
if len(r.Header.Get(api.AmzTagging)) > 0 {
|
||||||
p.Data.TagSet, err = parseTaggingHeader(r.Header)
|
p.Data.TagSet, err = parseTaggingHeader(r.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -196,25 +175,6 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func formACLHeadersForMultipart(header http.Header) map[string]string {
|
|
||||||
result := make(map[string]string)
|
|
||||||
|
|
||||||
if value := header.Get(api.AmzACL); value != "" {
|
|
||||||
result[api.AmzACL] = value
|
|
||||||
}
|
|
||||||
if value := header.Get(api.AmzGrantRead); value != "" {
|
|
||||||
result[api.AmzGrantRead] = value
|
|
||||||
}
|
|
||||||
if value := header.Get(api.AmzGrantFullControl); value != "" {
|
|
||||||
result[api.AmzGrantFullControl] = value
|
|
||||||
}
|
|
||||||
if value := header.Get(api.AmzGrantWrite); value != "" {
|
|
||||||
result[api.AmzGrantWrite] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *handler) UploadPartHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) UploadPartHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
reqInfo := middleware.GetReqInfo(r.Context())
|
reqInfo := middleware.GetReqInfo(r.Context())
|
||||||
|
|
||||||
|
@ -500,33 +460,6 @@ func (h *handler) completeMultipartUpload(r *http.Request, c *layer.CompleteMult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(uploadData.ACLHeaders) != 0 {
|
|
||||||
sessionTokenSetEACL, err := getSessionTokenSetEACL(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("couldn't get eacl token: %w", err)
|
|
||||||
}
|
|
||||||
key, err := h.bearerTokenIssuerKey(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("couldn't get gate key: %w", err)
|
|
||||||
}
|
|
||||||
acl, err := parseACLHeaders(r.Header, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not parse acl: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resInfo := &resourceInfo{
|
|
||||||
Bucket: objInfo.Bucket,
|
|
||||||
Object: objInfo.Name,
|
|
||||||
}
|
|
||||||
astObject, err := aclToAst(acl, resInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not translate acl of completed multipart upload to ast: %w", err)
|
|
||||||
}
|
|
||||||
if _, err = h.updateBucketACL(r, astObject, bktInfo, sessionTokenSetEACL); err != nil {
|
|
||||||
return nil, fmt.Errorf("could not update bucket acl while completing multipart upload: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return objInfo, nil
|
return objInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/retryer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/retryer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/s3"
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/s3"
|
||||||
|
@ -173,10 +171,9 @@ func (p *policyCondition) UnmarshalJSON(data []byte) error {
|
||||||
|
|
||||||
// keywords of predefined basic ACL values.
|
// keywords of predefined basic ACL values.
|
||||||
const (
|
const (
|
||||||
basicACLPrivate = "private"
|
basicACLPrivate = "private"
|
||||||
basicACLReadOnly = "public-read"
|
basicACLReadOnly = "public-read"
|
||||||
basicACLPublic = "public-read-write"
|
basicACLPublic = "public-read-write"
|
||||||
cannedACLAuthRead = "authenticated-read"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type createBucketParams struct {
|
type createBucketParams struct {
|
||||||
|
@ -186,12 +183,10 @@ type createBucketParams struct {
|
||||||
|
|
||||||
func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
newEaclTable *eacl.Table
|
cannedACLStatus = aclHeadersStatus(r)
|
||||||
sessionTokenEACL *session.Container
|
ctx = r.Context()
|
||||||
cannedACLStatus = aclHeadersStatus(r)
|
reqInfo = middleware.GetReqInfo(ctx)
|
||||||
ctx = r.Context()
|
|
||||||
reqInfo = middleware.GetReqInfo(ctx)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
||||||
|
@ -206,20 +201,11 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apeEnabled := bktInfo.APEEnabled || settings.CannedACL != ""
|
if cannedACLStatus == aclStatusYes {
|
||||||
if apeEnabled && cannedACLStatus == aclStatusYes {
|
|
||||||
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
needUpdateEACLTable := !(apeEnabled || cannedACLStatus == aclStatusNo)
|
|
||||||
if needUpdateEACLTable {
|
|
||||||
if sessionTokenEACL, err = getSessionTokenSetEACL(r.Context()); err != nil {
|
|
||||||
h.logAndSendError(w, "could not get eacl session token from a box", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tagSet, err := parseTaggingHeader(r.Header)
|
tagSet, err := parseTaggingHeader(r.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not parse tagging header", reqInfo, err)
|
h.logAndSendError(w, "could not parse tagging header", reqInfo, err)
|
||||||
|
@ -292,13 +278,6 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
objInfo := extendedObjInfo.ObjectInfo
|
objInfo := extendedObjInfo.ObjectInfo
|
||||||
|
|
||||||
if needUpdateEACLTable {
|
|
||||||
if newEaclTable, err = h.getNewEAclTable(r, bktInfo, objInfo); err != nil {
|
|
||||||
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if tagSet != nil {
|
if tagSet != nil {
|
||||||
tagPrm := &data.PutObjectTaggingParams{
|
tagPrm := &data.PutObjectTaggingParams{
|
||||||
ObjectVersion: &data.ObjectVersion{
|
ObjectVersion: &data.ObjectVersion{
|
||||||
|
@ -315,19 +294,6 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if newEaclTable != nil {
|
|
||||||
p := &layer.PutBucketACLParams{
|
|
||||||
BktInfo: bktInfo,
|
|
||||||
EACL: newEaclTable,
|
|
||||||
SessionToken: sessionTokenEACL,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = h.obj.PutBucketACL(r.Context(), p); err != nil {
|
|
||||||
h.logAndSendError(w, "could not put bucket acl", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.VersioningEnabled() {
|
if settings.VersioningEnabled() {
|
||||||
w.Header().Set(api.AmzVersionID, objInfo.VersionID())
|
w.Header().Set(api.AmzVersionID, objInfo.VersionID())
|
||||||
}
|
}
|
||||||
|
@ -459,13 +425,10 @@ func formEncryptionParamsBase(r *http.Request, isCopySource bool) (enc encryptio
|
||||||
|
|
||||||
func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
newEaclTable *eacl.Table
|
tagSet map[string]string
|
||||||
tagSet map[string]string
|
ctx = r.Context()
|
||||||
sessionTokenEACL *session.Container
|
reqInfo = middleware.GetReqInfo(ctx)
|
||||||
ctx = r.Context()
|
metadata = make(map[string]string)
|
||||||
reqInfo = middleware.GetReqInfo(ctx)
|
|
||||||
metadata = make(map[string]string)
|
|
||||||
cannedACLStatus = aclHeadersStatus(r)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
policy, err := checkPostPolicy(r, reqInfo, metadata)
|
policy, err := checkPostPolicy(r, reqInfo, metadata)
|
||||||
|
@ -501,20 +464,11 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apeEnabled := bktInfo.APEEnabled || settings.CannedACL != ""
|
if acl := auth.MultipartFormValue(r, "acl"); acl != "" && acl != basicACLPrivate {
|
||||||
if apeEnabled && cannedACLStatus == aclStatusYes {
|
|
||||||
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
needUpdateEACLTable := !(apeEnabled || cannedACLStatus == aclStatusNo)
|
|
||||||
if needUpdateEACLTable {
|
|
||||||
if sessionTokenEACL, err = getSessionTokenSetEACL(ctx); err != nil {
|
|
||||||
h.logAndSendError(w, "could not get eacl session token from a box", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var contentReader io.Reader
|
var contentReader io.Reader
|
||||||
var size uint64
|
var size uint64
|
||||||
if content, ok := r.MultipartForm.Value["file"]; ok {
|
if content, ok := r.MultipartForm.Value["file"]; ok {
|
||||||
|
@ -550,18 +504,6 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
objInfo := extendedObjInfo.ObjectInfo
|
objInfo := extendedObjInfo.ObjectInfo
|
||||||
|
|
||||||
if acl := auth.MultipartFormValue(r, "acl"); acl != "" {
|
|
||||||
r.Header.Set(api.AmzACL, acl)
|
|
||||||
r.Header.Set(api.AmzGrantFullControl, "")
|
|
||||||
r.Header.Set(api.AmzGrantWrite, "")
|
|
||||||
r.Header.Set(api.AmzGrantRead, "")
|
|
||||||
|
|
||||||
if newEaclTable, err = h.getNewEAclTable(r, bktInfo, objInfo); err != nil {
|
|
||||||
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if tagSet != nil {
|
if tagSet != nil {
|
||||||
tagPrm := &data.PutObjectTaggingParams{
|
tagPrm := &data.PutObjectTaggingParams{
|
||||||
ObjectVersion: &data.ObjectVersion{
|
ObjectVersion: &data.ObjectVersion{
|
||||||
|
@ -578,19 +520,6 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if newEaclTable != nil {
|
|
||||||
p := &layer.PutBucketACLParams{
|
|
||||||
BktInfo: bktInfo,
|
|
||||||
EACL: newEaclTable,
|
|
||||||
SessionToken: sessionTokenEACL,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = h.obj.PutBucketACL(ctx, p); err != nil {
|
|
||||||
h.logAndSendError(w, "could not put bucket acl", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.VersioningEnabled() {
|
if settings.VersioningEnabled() {
|
||||||
w.Header().Set(api.AmzVersionID, objInfo.VersionID())
|
w.Header().Set(api.AmzVersionID, objInfo.VersionID())
|
||||||
}
|
}
|
||||||
|
@ -716,56 +645,6 @@ func aclHeadersStatus(r *http.Request) aclStatus {
|
||||||
return aclStatusNo
|
return aclStatusNo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) getNewEAclTable(r *http.Request, bktInfo *data.BucketInfo, objInfo *data.ObjectInfo) (*eacl.Table, error) {
|
|
||||||
var newEaclTable *eacl.Table
|
|
||||||
key, err := h.bearerTokenIssuerKey(r.Context())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("get bearer token issuer: %w", err)
|
|
||||||
}
|
|
||||||
objectACL, err := parseACLHeaders(r.Header, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not parse object acl: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resInfo := &resourceInfo{
|
|
||||||
Bucket: objInfo.Bucket,
|
|
||||||
Object: objInfo.Name,
|
|
||||||
Version: objInfo.VersionID(),
|
|
||||||
}
|
|
||||||
|
|
||||||
bktPolicy, err := aclToPolicy(objectACL, resInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not translate object acl to bucket policy: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
astChild, err := policyToAst(bktPolicy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not translate policy to ast: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
bacl, err := h.obj.GetBucketACL(r.Context(), bktInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not get bucket eacl: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
parentAst := tableToAst(bacl.EACL, objInfo.Bucket)
|
|
||||||
strCID := bacl.Info.CID.EncodeToString()
|
|
||||||
|
|
||||||
for _, resource := range parentAst.Resources {
|
|
||||||
if resource.Bucket == strCID {
|
|
||||||
resource.Bucket = objInfo.Bucket
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if resAst, updated := mergeAst(parentAst, astChild); updated {
|
|
||||||
if newEaclTable, err = astToTable(resAst); err != nil {
|
|
||||||
return nil, fmt.Errorf("could not translate ast to table: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newEaclTable, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseTaggingHeader(header http.Header) (map[string]string, error) {
|
func parseTaggingHeader(header http.Header) (map[string]string, error) {
|
||||||
var tagSet map[string]string
|
var tagSet map[string]string
|
||||||
if tagging := header.Get(api.AmzTagging); len(tagging) > 0 {
|
if tagging := header.Get(api.AmzTagging); len(tagging) > 0 {
|
||||||
|
@ -805,8 +684,7 @@ func parseCannedACL(header http.Header) (string, error) {
|
||||||
return basicACLPrivate, nil
|
return basicACLPrivate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if acl == basicACLPrivate || acl == basicACLPublic ||
|
if acl == basicACLPrivate || acl == basicACLPublic || acl == basicACLReadOnly {
|
||||||
acl == cannedACLAuthRead || acl == basicACLReadOnly {
|
|
||||||
return acl, nil
|
return acl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,7 +751,6 @@ func (h *handler) createBucketHandlerPolicy(w http.ResponseWriter, r *http.Reque
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p.APEEnabled = true
|
|
||||||
bktInfo, err := h.obj.CreateBucket(ctx, p)
|
bktInfo, err := h.obj.CreateBucket(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not create bucket", reqInfo, err)
|
h.logAndSendError(w, "could not create bucket", reqInfo, err)
|
||||||
|
@ -990,8 +867,6 @@ func bucketCannedACLToAPERules(cannedACL string, reqInfo *middleware.ReqInfo, cn
|
||||||
|
|
||||||
switch cannedACL {
|
switch cannedACL {
|
||||||
case basicACLPrivate:
|
case basicACLPrivate:
|
||||||
case cannedACLAuthRead:
|
|
||||||
fallthrough
|
|
||||||
case basicACLReadOnly:
|
case basicACLReadOnly:
|
||||||
chains[0].Rules = append(chains[0].Rules, chain.Rule{
|
chains[0].Rules = append(chains[0].Rules, chain.Rule{
|
||||||
Status: chain.Allow,
|
Status: chain.Allow,
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
frosterrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
frosterrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -142,16 +141,3 @@ func parseRange(s string) (*layer.RangeParams, error) {
|
||||||
End: values[1],
|
End: values[1],
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSessionTokenSetEACL(ctx context.Context) (*session.Container, error) {
|
|
||||||
boxData, err := middleware.GetBoxData(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
sessionToken := boxData.Gate.SessionTokenForSetEACL()
|
|
||||||
if sessionToken == nil {
|
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrAccessDenied)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sessionToken, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,21 +12,9 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// BucketACL extends BucketInfo by eacl.Table.
|
|
||||||
BucketACL struct {
|
|
||||||
Info *data.BucketInfo
|
|
||||||
EACL *eacl.Table
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
attributeLocationConstraint = ".s3-location-constraint"
|
attributeLocationConstraint = ".s3-location-constraint"
|
||||||
AttributeLockEnabled = "LockEnabled"
|
AttributeLockEnabled = "LockEnabled"
|
||||||
|
@ -64,7 +52,6 @@ func (n *Layer) containerInfo(ctx context.Context, prm PrmContainer) (*data.Buck
|
||||||
info.Created = container.CreatedAt(cnr)
|
info.Created = container.CreatedAt(cnr)
|
||||||
info.LocationConstraint = cnr.Attribute(attributeLocationConstraint)
|
info.LocationConstraint = cnr.Attribute(attributeLocationConstraint)
|
||||||
info.HomomorphicHashDisabled = container.IsHomomorphicHashingDisabled(cnr)
|
info.HomomorphicHashDisabled = container.IsHomomorphicHashingDisabled(cnr)
|
||||||
info.APEEnabled = cnr.BasicACL().Bits() == 0
|
|
||||||
|
|
||||||
attrLockEnabled := cnr.Attribute(AttributeLockEnabled)
|
attrLockEnabled := cnr.Attribute(AttributeLockEnabled)
|
||||||
if len(attrLockEnabled) > 0 {
|
if len(attrLockEnabled) > 0 {
|
||||||
|
@ -133,7 +120,6 @@ func (n *Layer) createContainer(ctx context.Context, p *CreateBucketParams) (*da
|
||||||
Created: TimeNow(ctx),
|
Created: TimeNow(ctx),
|
||||||
LocationConstraint: p.LocationConstraint,
|
LocationConstraint: p.LocationConstraint,
|
||||||
ObjectLockEnabled: p.ObjectLockEnabled,
|
ObjectLockEnabled: p.ObjectLockEnabled,
|
||||||
APEEnabled: p.APEEnabled,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes := [][2]string{
|
attributes := [][2]string{
|
||||||
|
@ -146,11 +132,6 @@ func (n *Layer) createContainer(ctx context.Context, p *CreateBucketParams) (*da
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
basicACL := acl.PublicRWExtended
|
|
||||||
if p.APEEnabled {
|
|
||||||
basicACL = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := n.frostFS.CreateContainer(ctx, PrmContainerCreate{
|
res, err := n.frostFS.CreateContainer(ctx, PrmContainerCreate{
|
||||||
Creator: bktInfo.Owner,
|
Creator: bktInfo.Owner,
|
||||||
Policy: p.Policy,
|
Policy: p.Policy,
|
||||||
|
@ -159,7 +140,7 @@ func (n *Layer) createContainer(ctx context.Context, p *CreateBucketParams) (*da
|
||||||
SessionToken: p.SessionContainerCreation,
|
SessionToken: p.SessionContainerCreation,
|
||||||
CreationTime: bktInfo.Created,
|
CreationTime: bktInfo.Created,
|
||||||
AdditionalAttributes: attributes,
|
AdditionalAttributes: attributes,
|
||||||
BasicACL: basicACL,
|
BasicACL: 0, // means APE
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create container: %w", err)
|
return nil, fmt.Errorf("create container: %w", err)
|
||||||
|
@ -172,17 +153,3 @@ func (n *Layer) createContainer(ctx context.Context, p *CreateBucketParams) (*da
|
||||||
|
|
||||||
return bktInfo, nil
|
return bktInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Layer) setContainerEACLTable(ctx context.Context, idCnr cid.ID, table *eacl.Table, sessionToken *session.Container) error {
|
|
||||||
table.SetCID(idCnr)
|
|
||||||
|
|
||||||
return n.frostFS.SetContainerEACL(ctx, *table, sessionToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Layer) GetContainerEACL(ctx context.Context, cnrID cid.ID) (*eacl.Table, error) {
|
|
||||||
prm := PrmContainerEACL{
|
|
||||||
ContainerID: cnrID,
|
|
||||||
SessionToken: n.SessionTokenForRead(ctx),
|
|
||||||
}
|
|
||||||
return n.frostFS.ContainerEACL(ctx, prm)
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
|
@ -64,15 +63,6 @@ type PrmUserContainers struct {
|
||||||
SessionToken *session.Container
|
SessionToken *session.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrmContainerEACL groups parameters of FrostFS.ContainerEACL operation.
|
|
||||||
type PrmContainerEACL struct {
|
|
||||||
// Container identifier.
|
|
||||||
ContainerID cid.ID
|
|
||||||
|
|
||||||
// Token of the container's creation session. Nil means session absence.
|
|
||||||
SessionToken *session.Container
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerCreateResult is a result parameter of FrostFS.CreateContainer operation.
|
// ContainerCreateResult is a result parameter of FrostFS.CreateContainer operation.
|
||||||
type ContainerCreateResult struct {
|
type ContainerCreateResult struct {
|
||||||
ContainerID cid.ID
|
ContainerID cid.ID
|
||||||
|
@ -216,18 +206,6 @@ type FrostFS interface {
|
||||||
// prevented the containers from being listed.
|
// prevented the containers from being listed.
|
||||||
UserContainers(context.Context, PrmUserContainers) ([]cid.ID, error)
|
UserContainers(context.Context, PrmUserContainers) ([]cid.ID, error)
|
||||||
|
|
||||||
// SetContainerEACL saves the eACL table of the container in FrostFS. The
|
|
||||||
// extended ACL is modified within session if session token is not nil.
|
|
||||||
//
|
|
||||||
// It returns any error encountered which prevented the eACL from being saved.
|
|
||||||
SetContainerEACL(context.Context, eacl.Table, *session.Container) error
|
|
||||||
|
|
||||||
// ContainerEACL reads the container eACL from FrostFS by the container ID.
|
|
||||||
//
|
|
||||||
// It returns exactly one non-nil value. It returns any error encountered which
|
|
||||||
// prevented the eACL from being read.
|
|
||||||
ContainerEACL(context.Context, PrmContainerEACL) (*eacl.Table, error)
|
|
||||||
|
|
||||||
// DeleteContainer marks the container to be removed from FrostFS by ID.
|
// DeleteContainer marks the container to be removed from FrostFS by ID.
|
||||||
// Request is sent within session if the session token is specified.
|
// Request is sent within session if the session token is specified.
|
||||||
// Successful return does not guarantee actual removal.
|
// Successful return does not guarantee actual removal.
|
||||||
|
|
|
@ -5,13 +5,11 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
|
||||||
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
|
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
|
||||||
objectv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
objectv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
|
@ -20,7 +18,6 @@ import (
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||||
|
@ -68,7 +65,6 @@ type TestFrostFS struct {
|
||||||
objectErrors map[string]error
|
objectErrors map[string]error
|
||||||
objectPutErrors map[string]error
|
objectPutErrors map[string]error
|
||||||
containers map[string]*container.Container
|
containers map[string]*container.Container
|
||||||
eaclTables map[string]*eacl.Table
|
|
||||||
currentEpoch uint64
|
currentEpoch uint64
|
||||||
key *keys.PrivateKey
|
key *keys.PrivateKey
|
||||||
}
|
}
|
||||||
|
@ -79,7 +75,6 @@ func NewTestFrostFS(key *keys.PrivateKey) *TestFrostFS {
|
||||||
objectErrors: make(map[string]error),
|
objectErrors: make(map[string]error),
|
||||||
objectPutErrors: make(map[string]error),
|
objectPutErrors: make(map[string]error),
|
||||||
containers: make(map[string]*container.Container),
|
containers: make(map[string]*container.Container),
|
||||||
eaclTables: make(map[string]*eacl.Table),
|
|
||||||
key: key,
|
key: key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,7 +217,7 @@ func (t *TestFrostFS) ReadObject(ctx context.Context, prm PrmObjectRead) (*Objec
|
||||||
|
|
||||||
if obj, ok := t.objects[sAddr]; ok {
|
if obj, ok := t.objects[sAddr]; ok {
|
||||||
owner := getBearerOwner(ctx)
|
owner := getBearerOwner(ctx)
|
||||||
if !t.checkAccess(prm.Container, owner, eacl.OperationGet, obj) {
|
if !t.checkAccess(prm.Container, owner) {
|
||||||
return nil, ErrAccessDenied
|
return nil, ErrAccessDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,9 +319,9 @@ func (t *TestFrostFS) DeleteObject(ctx context.Context, prm PrmObjectDelete) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj, ok := t.objects[addr.EncodeToString()]; ok {
|
if _, ok := t.objects[addr.EncodeToString()]; ok {
|
||||||
owner := getBearerOwner(ctx)
|
owner := getBearerOwner(ctx)
|
||||||
if !t.checkAccess(prm.Container, owner, eacl.OperationDelete, obj) {
|
if !t.checkAccess(prm.Container, owner) {
|
||||||
return ErrAccessDenied
|
return ErrAccessDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,30 +349,6 @@ func (t *TestFrostFS) AllObjects(cnrID cid.ID) []oid.ID {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TestFrostFS) SetContainerEACL(_ context.Context, table eacl.Table, _ *session.Container) error {
|
|
||||||
cnrID, ok := table.CID()
|
|
||||||
if !ok {
|
|
||||||
return errors.New("invalid cid")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok = t.containers[cnrID.EncodeToString()]; !ok {
|
|
||||||
return errors.New("not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
t.eaclTables[cnrID.EncodeToString()] = &table
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TestFrostFS) ContainerEACL(_ context.Context, prm PrmContainerEACL) (*eacl.Table, error) {
|
|
||||||
table, ok := t.eaclTables[prm.ContainerID.EncodeToString()]
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return table, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TestFrostFS) SearchObjects(_ context.Context, prm PrmObjectSearch) ([]oid.ID, error) {
|
func (t *TestFrostFS) SearchObjects(_ context.Context, prm PrmObjectSearch) ([]oid.ID, error) {
|
||||||
filters := object.NewSearchFilters()
|
filters := object.NewSearchFilters()
|
||||||
filters.AddRootFilter()
|
filters.AddRootFilter()
|
||||||
|
@ -415,7 +386,7 @@ func (t *TestFrostFS) SearchObjects(_ context.Context, prm PrmObjectSearch) ([]o
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TestFrostFS) checkAccess(cnrID cid.ID, owner user.ID, op eacl.Operation, obj *object.Object) bool {
|
func (t *TestFrostFS) checkAccess(cnrID cid.ID, owner user.ID) bool {
|
||||||
cnr, ok := t.containers[cnrID.EncodeToString()]
|
cnr, ok := t.containers[cnrID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
|
@ -425,57 +396,6 @@ func (t *TestFrostFS) checkAccess(cnrID cid.ID, owner user.ID, op eacl.Operation
|
||||||
return cnr.Owner().Equals(owner)
|
return cnr.Owner().Equals(owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
table, ok := t.eaclTables[cnrID.EncodeToString()]
|
|
||||||
if !ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rec := range table.Records() {
|
|
||||||
if rec.Operation() != op {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !matchTarget(rec, owner) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if matchFilter(rec.Filters(), obj) {
|
|
||||||
return rec.Action() == eacl.ActionAllow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchTarget(rec eacl.Record, owner user.ID) bool {
|
|
||||||
for _, trgt := range rec.Targets() {
|
|
||||||
if trgt.Role() == eacl.RoleOthers {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
var targetOwner user.ID
|
|
||||||
for _, pk := range eacl.TargetECDSAKeys(&trgt) {
|
|
||||||
user.IDFromKey(&targetOwner, *pk)
|
|
||||||
if targetOwner.Equals(owner) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchFilter(filters []eacl.Filter, obj *object.Object) bool {
|
|
||||||
objID, _ := obj.ID()
|
|
||||||
for _, f := range filters {
|
|
||||||
fv2 := f.ToV2()
|
|
||||||
if fv2.GetMatchType() != acl.MatchTypeStringEqual ||
|
|
||||||
fv2.GetHeaderType() != acl.HeaderTypeObject ||
|
|
||||||
fv2.GetKey() != acl.FilterObjectID ||
|
|
||||||
fv2.GetValue() != objID.EncodeToString() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||||
|
@ -159,13 +158,6 @@ type (
|
||||||
SessionContainerCreation *session.Container
|
SessionContainerCreation *session.Container
|
||||||
LocationConstraint string
|
LocationConstraint string
|
||||||
ObjectLockEnabled bool
|
ObjectLockEnabled bool
|
||||||
APEEnabled bool
|
|
||||||
}
|
|
||||||
// PutBucketACLParams stores put bucket acl request parameters.
|
|
||||||
PutBucketACLParams struct {
|
|
||||||
BktInfo *data.BucketInfo
|
|
||||||
EACL *eacl.Table
|
|
||||||
SessionToken *session.Container
|
|
||||||
}
|
}
|
||||||
// DeleteBucketParams stores delete bucket request parameters.
|
// DeleteBucketParams stores delete bucket request parameters.
|
||||||
DeleteBucketParams struct {
|
DeleteBucketParams struct {
|
||||||
|
@ -350,24 +342,6 @@ func (n *Layer) ResolveCID(ctx context.Context, name string) (cid.ID, error) {
|
||||||
return n.ResolveBucket(ctx, name)
|
return n.ResolveBucket(ctx, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBucketACL returns bucket acl info by name.
|
|
||||||
func (n *Layer) GetBucketACL(ctx context.Context, bktInfo *data.BucketInfo) (*BucketACL, error) {
|
|
||||||
eACL, err := n.GetContainerEACL(ctx, bktInfo.CID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("get container eacl: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &BucketACL{
|
|
||||||
Info: bktInfo,
|
|
||||||
EACL: eACL,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PutBucketACL puts bucket acl by name.
|
|
||||||
func (n *Layer) PutBucketACL(ctx context.Context, param *PutBucketACLParams) error {
|
|
||||||
return n.setContainerEACLTable(ctx, param.BktInfo.CID, param.EACL, param.SessionToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListBuckets returns all user containers. The name of the bucket is a container
|
// ListBuckets returns all user containers. The name of the bucket is a container
|
||||||
// id. Timestamp is omitted since it is not saved in frostfs container.
|
// id. Timestamp is omitted since it is not saved in frostfs container.
|
||||||
func (n *Layer) ListBuckets(ctx context.Context) ([]*data.BucketInfo, error) {
|
func (n *Layer) ListBuckets(ctx context.Context) ([]*data.BucketInfo, error) {
|
||||||
|
|
|
@ -36,7 +36,6 @@ const (
|
||||||
MultipartObjectSize = "S3-Multipart-Object-Size"
|
MultipartObjectSize = "S3-Multipart-Object-Size"
|
||||||
|
|
||||||
metaPrefix = "meta-"
|
metaPrefix = "meta-"
|
||||||
aclPrefix = "acl-"
|
|
||||||
|
|
||||||
MaxSizeUploadsList = 1000
|
MaxSizeUploadsList = 1000
|
||||||
MaxSizePartsList = 1000
|
MaxSizePartsList = 1000
|
||||||
|
@ -62,8 +61,7 @@ type (
|
||||||
}
|
}
|
||||||
|
|
||||||
UploadData struct {
|
UploadData struct {
|
||||||
TagSet map[string]string
|
TagSet map[string]string
|
||||||
ACLHeaders map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UploadPartParams struct {
|
UploadPartParams struct {
|
||||||
|
@ -149,7 +147,6 @@ type (
|
||||||
func (n *Layer) CreateMultipartUpload(ctx context.Context, p *CreateMultipartParams) error {
|
func (n *Layer) CreateMultipartUpload(ctx context.Context, p *CreateMultipartParams) error {
|
||||||
metaSize := len(p.Header)
|
metaSize := len(p.Header)
|
||||||
if p.Data != nil {
|
if p.Data != nil {
|
||||||
metaSize += len(p.Data.ACLHeaders)
|
|
||||||
metaSize += len(p.Data.TagSet)
|
metaSize += len(p.Data.TagSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,10 +164,6 @@ func (n *Layer) CreateMultipartUpload(ctx context.Context, p *CreateMultipartPar
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Data != nil {
|
if p.Data != nil {
|
||||||
for key, val := range p.Data.ACLHeaders {
|
|
||||||
info.Meta[aclPrefix+key] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, val := range p.Data.TagSet {
|
for key, val := range p.Data.TagSet {
|
||||||
info.Meta[tagPrefix+key] = val
|
info.Meta[tagPrefix+key] = val
|
||||||
}
|
}
|
||||||
|
@ -432,16 +425,13 @@ func (n *Layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipar
|
||||||
initMetadata[MultipartObjectSize] = strconv.FormatUint(multipartObjetSize, 10)
|
initMetadata[MultipartObjectSize] = strconv.FormatUint(multipartObjetSize, 10)
|
||||||
|
|
||||||
uploadData := &UploadData{
|
uploadData := &UploadData{
|
||||||
TagSet: make(map[string]string),
|
TagSet: make(map[string]string),
|
||||||
ACLHeaders: make(map[string]string),
|
|
||||||
}
|
}
|
||||||
for key, val := range multipartInfo.Meta {
|
for key, val := range multipartInfo.Meta {
|
||||||
if strings.HasPrefix(key, metaPrefix) {
|
if strings.HasPrefix(key, metaPrefix) {
|
||||||
initMetadata[strings.TrimPrefix(key, metaPrefix)] = val
|
initMetadata[strings.TrimPrefix(key, metaPrefix)] = val
|
||||||
} else if strings.HasPrefix(key, tagPrefix) {
|
} else if strings.HasPrefix(key, tagPrefix) {
|
||||||
uploadData.TagSet[strings.TrimPrefix(key, tagPrefix)] = val
|
uploadData.TagSet[strings.TrimPrefix(key, tagPrefix)] = val
|
||||||
} else if strings.HasPrefix(key, aclPrefix) {
|
|
||||||
uploadData.ACLHeaders[strings.TrimPrefix(key, aclPrefix)] = val
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,12 +149,7 @@ func policyCheck(r *http.Request, cfg PolicyConfig) error {
|
||||||
return apiErr.GetAPIErrorWithError(apiErr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
|
return apiErr.GetAPIErrorWithError(apiErr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
isAPE := true
|
if cfg.Settings.PolicyDenyByDefault() {
|
||||||
if bktInfo != nil {
|
|
||||||
isAPE = bktInfo.APEEnabled
|
|
||||||
}
|
|
||||||
|
|
||||||
if isAPE && cfg.Settings.PolicyDenyByDefault() {
|
|
||||||
return apiErr.GetAPIErrorWithError(apiErr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
|
return apiErr.GetAPIErrorWithError(apiErr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -424,8 +424,7 @@ func (h *handlerMock) CreateBucketHandler(w http.ResponseWriter, r *http.Request
|
||||||
reqInfo := middleware.GetReqInfo(r.Context())
|
reqInfo := middleware.GetReqInfo(r.Context())
|
||||||
|
|
||||||
h.buckets[reqInfo.Namespace+reqInfo.BucketName] = &data.BucketInfo{
|
h.buckets[reqInfo.Namespace+reqInfo.BucketName] = &data.BucketInfo{
|
||||||
Name: reqInfo.BucketName,
|
Name: reqInfo.BucketName,
|
||||||
APEEnabled: true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &handlerResult{
|
res := &handlerResult{
|
||||||
|
|
|
@ -17,9 +17,7 @@ import (
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
s3middleware "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
s3middleware "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
|
||||||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
|
|
||||||
engineiam "git.frostfs.info/TrueCloudLab/policy-engine/iam"
|
engineiam "git.frostfs.info/TrueCloudLab/policy-engine/iam"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
|
@ -305,58 +303,6 @@ func TestDefaultPolicyCheckerWithUserTags(t *testing.T) {
|
||||||
createBucket(router, ns, bktName)
|
createBucket(router, ns, bktName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestACLAPE(t *testing.T) {
|
|
||||||
t.Run("acl disabled, ape deny by default", func(t *testing.T) {
|
|
||||||
router := prepareRouter(t)
|
|
||||||
|
|
||||||
ns, bktName, objName := "", "bucket", "object"
|
|
||||||
bktNameOld, bktNameNew := "old-bucket", "new-bucket"
|
|
||||||
createOldBucket(router, bktNameOld)
|
|
||||||
createNewBucket(router, bktNameNew)
|
|
||||||
|
|
||||||
router.middlewareSettings.denyByDefault = true
|
|
||||||
|
|
||||||
// Allow because of using old bucket
|
|
||||||
putObject(router, ns, bktNameOld, objName, nil)
|
|
||||||
// Deny because of deny by default
|
|
||||||
putObjectErr(router, ns, bktNameNew, objName, nil, apiErrors.ErrAccessDenied)
|
|
||||||
|
|
||||||
// Deny because of deny by default
|
|
||||||
createBucketErr(router, ns, bktName, nil, apiErrors.ErrAccessDenied)
|
|
||||||
listBucketsErr(router, ns, apiErrors.ErrAccessDenied)
|
|
||||||
|
|
||||||
// Allow operations and check
|
|
||||||
allowOperations(router, ns, []string{"s3:CreateBucket", "s3:ListAllMyBuckets"}, nil)
|
|
||||||
createBucket(router, ns, bktName)
|
|
||||||
listBuckets(router, ns)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("acl disabled, ape allow by default", func(t *testing.T) {
|
|
||||||
router := prepareRouter(t)
|
|
||||||
|
|
||||||
ns, bktName, objName := "", "bucket", "object"
|
|
||||||
bktNameOld, bktNameNew := "old-bucket", "new-bucket"
|
|
||||||
createOldBucket(router, bktNameOld)
|
|
||||||
createNewBucket(router, bktNameNew)
|
|
||||||
|
|
||||||
router.middlewareSettings.denyByDefault = false
|
|
||||||
|
|
||||||
// Allow because of using old bucket
|
|
||||||
putObject(router, ns, bktNameOld, objName, nil)
|
|
||||||
// Allow because of allow by default
|
|
||||||
putObject(router, ns, bktNameNew, objName, nil)
|
|
||||||
|
|
||||||
// Allow because of deny by default
|
|
||||||
createBucket(router, ns, bktName)
|
|
||||||
listBuckets(router, ns)
|
|
||||||
|
|
||||||
// Deny operations and check
|
|
||||||
denyOperations(router, ns, []string{"s3:CreateBucket", "s3:ListAllMyBuckets"}, nil)
|
|
||||||
createBucketErr(router, ns, bktName, nil, apiErrors.ErrAccessDenied)
|
|
||||||
listBucketsErr(router, ns, apiErrors.ErrAccessDenied)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRequestParametersCheck(t *testing.T) {
|
func TestRequestParametersCheck(t *testing.T) {
|
||||||
t.Run("prefix parameter, allow specific value", func(t *testing.T) {
|
t.Run("prefix parameter, allow specific value", func(t *testing.T) {
|
||||||
router := prepareRouter(t)
|
router := prepareRouter(t)
|
||||||
|
@ -679,28 +625,6 @@ func addPolicy(router *routerMock, ns string, id string, effect engineiam.Effect
|
||||||
require.NoError(router.t, err)
|
require.NoError(router.t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createOldBucket(router *routerMock, bktName string) {
|
|
||||||
createSpecificBucket(router, bktName, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createNewBucket(router *routerMock, bktName string) {
|
|
||||||
createSpecificBucket(router, bktName, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSpecificBucket(router *routerMock, bktName string, old bool) {
|
|
||||||
router.handler.buckets[bktName] = &data.BucketInfo{
|
|
||||||
Name: bktName,
|
|
||||||
Zone: "container",
|
|
||||||
CID: cidtest.ID(),
|
|
||||||
Owner: usertest.ID(),
|
|
||||||
Created: time.Now(),
|
|
||||||
LocationConstraint: "default",
|
|
||||||
ObjectLockEnabled: false,
|
|
||||||
HomomorphicHashDisabled: false,
|
|
||||||
APEEnabled: !old,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createBucket(router *routerMock, namespace, bktName string) {
|
func createBucket(router *routerMock, namespace, bktName string) {
|
||||||
w := createBucketBase(router, namespace, bktName, nil)
|
w := createBucketBase(router, namespace, bktName, nil)
|
||||||
resp := readResponse(router.t, w)
|
resp := readResponse(router.t, w)
|
||||||
|
@ -723,24 +647,6 @@ func createBucketBase(router *routerMock, namespace, bktName string, header http
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func listBuckets(router *routerMock, namespace string) {
|
|
||||||
w := listBucketsBase(router, namespace)
|
|
||||||
resp := readResponse(router.t, w)
|
|
||||||
require.Equal(router.t, s3middleware.ListBucketsOperation, resp.Method)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listBucketsErr(router *routerMock, namespace string, errCode apiErrors.ErrorCode) {
|
|
||||||
w := listBucketsBase(router, namespace)
|
|
||||||
assertAPIError(router.t, w, errCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listBucketsBase(router *routerMock, namespace string) *httptest.ResponseRecorder {
|
|
||||||
w, r := httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/", nil)
|
|
||||||
r.Header.Set(FrostfsNamespaceHeader, namespace)
|
|
||||||
router.ServeHTTP(w, r)
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBucketErr(router *routerMock, namespace, bktName string, errCode apiErrors.ErrorCode) {
|
func getBucketErr(router *routerMock, namespace, bktName string, errCode apiErrors.ErrorCode) {
|
||||||
w := getBucketBase(router, namespace, bktName)
|
w := getBucketBase(router, namespace, bktName)
|
||||||
assertAPIError(router.t, w, errCode)
|
assertAPIError(router.t, w, errCode)
|
||||||
|
|
|
@ -54,11 +54,6 @@ func (g *GateData) SessionTokenForDelete() *session.Container {
|
||||||
return g.containerSessionToken(session.VerbContainerDelete)
|
return g.containerSessionToken(session.VerbContainerDelete)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionTokenForSetEACL returns the first suitable container session context for SetEACL operation.
|
|
||||||
func (g *GateData) SessionTokenForSetEACL() *session.Container {
|
|
||||||
return g.containerSessionToken(session.VerbContainerSetEACL)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SessionToken returns the first container session context.
|
// SessionToken returns the first container session context.
|
||||||
func (g *GateData) SessionToken() *session.Container {
|
func (g *GateData) SessionToken() *session.Container {
|
||||||
if len(g.SessionTokens) != 0 {
|
if len(g.SessionTokens) != 0 {
|
||||||
|
@ -78,7 +73,7 @@ func (g *GateData) containerSessionToken(verb session.ContainerVerb) *session.Co
|
||||||
|
|
||||||
func isAppropriateContainerContext(tok *session.Container, verb session.ContainerVerb) bool {
|
func isAppropriateContainerContext(tok *session.Container, verb session.ContainerVerb) bool {
|
||||||
switch verb {
|
switch verb {
|
||||||
case session.VerbContainerSetEACL, session.VerbContainerDelete, session.VerbContainerPut:
|
case session.VerbContainerDelete, session.VerbContainerPut:
|
||||||
return tok.AssertVerb(verb)
|
return tok.AssertVerb(verb)
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -205,18 +205,6 @@ func TestGateDataSessionToken(t *testing.T) {
|
||||||
require.Equal(t, sessionTknDelete, sessionTkn)
|
require.Equal(t, sessionTknDelete, sessionTkn)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("session token for set eACL", func(t *testing.T) {
|
|
||||||
gate.SessionTokens = []*session.Container{}
|
|
||||||
sessionTkn := gate.SessionTokenForSetEACL()
|
|
||||||
require.Nil(t, sessionTkn)
|
|
||||||
|
|
||||||
sessionTknSetEACL := new(session.Container)
|
|
||||||
sessionTknSetEACL.ForVerb(session.VerbContainerSetEACL)
|
|
||||||
gate.SessionTokens = []*session.Container{sessionTknSetEACL}
|
|
||||||
sessionTkn = gate.SessionTokenForSetEACL()
|
|
||||||
require.Equal(t, sessionTknSetEACL, sessionTkn)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("session token", func(t *testing.T) {
|
t.Run("session token", func(t *testing.T) {
|
||||||
gate.SessionTokens = []*session.Container{}
|
gate.SessionTokens = []*session.Container{}
|
||||||
sessionTkn := gate.SessionToken()
|
sessionTkn := gate.SessionToken()
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
||||||
|
@ -162,29 +161,6 @@ func (x *FrostFS) UserContainers(ctx context.Context, layerPrm layer.PrmUserCont
|
||||||
return r, handleObjectError("list user containers via connection pool", err)
|
return r, handleObjectError("list user containers via connection pool", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetContainerEACL implements frostfs.FrostFS interface method.
|
|
||||||
func (x *FrostFS) SetContainerEACL(ctx context.Context, table eacl.Table, sessionToken *session.Container) error {
|
|
||||||
prm := pool.PrmContainerSetEACL{Table: table, Session: sessionToken, WaitParams: &x.await}
|
|
||||||
|
|
||||||
err := x.pool.SetEACL(ctx, prm)
|
|
||||||
return handleObjectError("save eACL via connection pool", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerEACL implements frostfs.FrostFS interface method.
|
|
||||||
func (x *FrostFS) ContainerEACL(ctx context.Context, layerPrm layer.PrmContainerEACL) (*eacl.Table, error) {
|
|
||||||
prm := pool.PrmContainerEACL{
|
|
||||||
ContainerID: layerPrm.ContainerID,
|
|
||||||
Session: layerPrm.SessionToken,
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := x.pool.GetEACL(ctx, prm)
|
|
||||||
if err != nil {
|
|
||||||
return nil, handleObjectError("read eACL via connection pool", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteContainer implements frostfs.FrostFS interface method.
|
// DeleteContainer implements frostfs.FrostFS interface method.
|
||||||
func (x *FrostFS) DeleteContainer(ctx context.Context, id cid.ID, token *session.Container) error {
|
func (x *FrostFS) DeleteContainer(ctx context.Context, id cid.ID, token *session.Container) error {
|
||||||
prm := pool.PrmContainerDelete{ContainerID: id, Session: token, WaitParams: &x.await}
|
prm := pool.PrmContainerDelete{ContainerID: id, Session: token, WaitParams: &x.await}
|
||||||
|
|
Loading…
Reference in a new issue