From a0a04a73bdf2932730ff07b11c01de5ba4842ef7 Mon Sep 17 00:00:00 2001 From: Angira Kekteeva Date: Mon, 18 Apr 2022 19:35:25 +0400 Subject: [PATCH] [#347] Add setEACL session token checks Signed-off-by: Angira Kekteeva --- api/handler/acl.go | 29 +++++++++++-- api/handler/multipart_upload.go | 74 +++++++++++++++++++-------------- api/handler/put.go | 51 +++++++++++++++++++---- api/handler/util.go | 18 +++++++- 4 files changed, 127 insertions(+), 45 deletions(-) diff --git a/api/handler/acl.go b/api/handler/acl.go index b099a0856..b4be5efec 100644 --- a/api/handler/acl.go +++ b/api/handler/acl.go @@ -20,6 +20,7 @@ import ( "github.com/nspcc-dev/neofs-sdk-go/eacl" "github.com/nspcc-dev/neofs-sdk-go/object" oid "github.com/nspcc-dev/neofs-sdk-go/object/id" + "github.com/nspcc-dev/neofs-sdk-go/session" ) var ( @@ -168,6 +169,12 @@ func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) { return } + token, err := getSessionTokenSetEACL(r.Context()) + if err != nil { + h.logAndSendError(w, "couldn't get eacl token", reqInfo, err) + return + } + list := &AccessControlPolicy{} if r.ContentLength == 0 { list, err = parseACLHeaders(r.Header, key) @@ -193,14 +200,14 @@ func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) { return } - if err = h.updateBucketACL(r, astBucket, bktInfo); err != nil { + if err = h.updateBucketACL(r, astBucket, bktInfo, token); err != nil { h.logAndSendError(w, "could not update bucket acl", reqInfo, err) return } w.WriteHeader(http.StatusOK) } -func (h *handler) updateBucketACL(r *http.Request, astChild *ast, bktInfo *data.BucketInfo) error { +func (h *handler) updateBucketACL(r *http.Request, astChild *ast, bktInfo *data.BucketInfo, sessionToken *session.Token) error { bucketACL, err := h.obj.GetBucketACL(r.Context(), bktInfo) if err != nil { return fmt.Errorf("could not get bucket eacl: %w", err) @@ -223,6 +230,8 @@ func (h *handler) updateBucketACL(r *http.Request, astChild *ast, bktInfo *data. return fmt.Errorf("could not translate ast to table: %w", err) } + table.SetSessionToken(sessionToken) + p := &layer.PutBucketACLParams{ BktInfo: bktInfo, EACL: table, @@ -264,6 +273,12 @@ func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) { return } + token, err := getSessionTokenSetEACL(r.Context()) + if err != nil { + h.logAndSendError(w, "couldn't get eacl token", reqInfo, err) + return + } + list := &AccessControlPolicy{} if r.ContentLength == 0 { list, err = parseACLHeaders(r.Header, key) @@ -305,7 +320,7 @@ func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) { return } - if err = h.updateBucketACL(r, astObject, bktInfo); err != nil { + if err = h.updateBucketACL(r, astObject, bktInfo, token); err != nil { h.logAndSendError(w, "could not update bucket acl", reqInfo, err) return } @@ -359,6 +374,12 @@ func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) return } + token, err := getSessionTokenSetEACL(r.Context()) + if err == nil { + h.logAndSendError(w, "couldn't get eacl token", reqInfo, err) + return + } + bktPolicy := &bucketPolicy{Bucket: reqInfo.BucketName} if err := json.NewDecoder(r.Body).Decode(bktPolicy); err != nil { h.logAndSendError(w, "could not parse bucket policy", reqInfo, err) @@ -371,7 +392,7 @@ func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) return } - if err = h.updateBucketACL(r, astPolicy, bktInfo); err != nil { + if err = h.updateBucketACL(r, astPolicy, bktInfo, token); err != nil { h.logAndSendError(w, "could not update bucket acl", reqInfo, err) return } diff --git a/api/handler/multipart_upload.go b/api/handler/multipart_upload.go index 089f4f043..d61e09753 100644 --- a/api/handler/multipart_upload.go +++ b/api/handler/multipart_upload.go @@ -14,6 +14,7 @@ import ( "github.com/nspcc-dev/neofs-s3-gw/api/data" "github.com/nspcc-dev/neofs-s3-gw/api/errors" "github.com/nspcc-dev/neofs-s3-gw/api/layer" + "github.com/nspcc-dev/neofs-sdk-go/session" "go.uber.org/zap" ) @@ -345,6 +346,8 @@ func (h *handler) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http. } var ( + sessionTokenSetEACL *session.Token + uploadID = r.URL.Query().Get(uploadIDHeaderName) uploadInfo = &layer.UploadInfoParams{ UploadID: uploadID, @@ -352,6 +355,7 @@ func (h *handler) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http. Key: reqInfo.ObjectName, } additional = []zap.Field{zap.String("uploadID", uploadID), zap.String("Key", reqInfo.ObjectName)} + uploadData = &UploadData{} ) reqBody := new(CompleteMultipartUpload) @@ -371,16 +375,6 @@ func (h *handler) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http. return } - c := &layer.CompleteMultipartParams{ - Info: uploadInfo, - Parts: reqBody.Parts, - } - objInfo, err := h.obj.CompleteMultipartUpload(r.Context(), c) - if err != nil { - h.logAndSendError(w, "could not complete multipart upload", reqInfo, err, additional...) - return - } - if initPart.Size > 0 { initPartPayload := bytes.NewBuffer(make([]byte, 0, initPart.Size)) p := &layer.GetObjectParams{ @@ -392,37 +386,53 @@ func (h *handler) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http. return } - uploadData := &UploadData{} if err = json.Unmarshal(initPartPayload.Bytes(), uploadData); err != nil { h.logAndSendError(w, "could not unmarshal multipart upload acl and/or tagging", reqInfo, err, additional...) return } - if len(uploadData.TagSet) != 0 { - t := &layer.PutTaggingParams{ - ObjectInfo: objInfo, - TagSet: uploadData.TagSet, - } - if err = h.obj.PutObjectTagging(r.Context(), t); err != nil { - h.logAndSendError(w, "could not put tagging file of completed multipart upload", reqInfo, err, additional...) + if uploadData.ACL != nil { + if sessionTokenSetEACL, err = getSessionTokenSetEACL(r.Context()); err != nil { + h.logAndSendError(w, "couldn't get eacl token", reqInfo, err) return } } + } - if uploadData.ACL != nil { - resInfo := &resourceInfo{ - Bucket: objInfo.Bucket, - Object: objInfo.Name, - } - astObject, err := aclToAst(uploadData.ACL, resInfo) - if err != nil { - h.logAndSendError(w, "could not translate acl of completed multipart upload to ast", reqInfo, err, additional...) - return - } - if err = h.updateBucketACL(r, astObject, bktInfo); err != nil { - h.logAndSendError(w, "could not update bucket acl while completing multipart upload", reqInfo, err, additional...) - return - } + c := &layer.CompleteMultipartParams{ + Info: uploadInfo, + Parts: reqBody.Parts, + } + objInfo, err := h.obj.CompleteMultipartUpload(r.Context(), c) + if err != nil { + h.logAndSendError(w, "could not complete multipart upload", reqInfo, err, additional...) + return + } + + if len(uploadData.TagSet) != 0 { + t := &layer.PutTaggingParams{ + ObjectInfo: objInfo, + TagSet: uploadData.TagSet, + } + if err = h.obj.PutObjectTagging(r.Context(), t); err != nil { + h.logAndSendError(w, "could not put tagging file of completed multipart upload", reqInfo, err, additional...) + return + } + } + + if uploadData.ACL != nil { + resInfo := &resourceInfo{ + Bucket: objInfo.Bucket, + Object: objInfo.Name, + } + astObject, err := aclToAst(uploadData.ACL, resInfo) + if err != nil { + h.logAndSendError(w, "could not translate acl of completed multipart upload to ast", reqInfo, err, additional...) + return + } + if err = h.updateBucketACL(r, astObject, bktInfo, sessionTokenSetEACL); err != nil { + h.logAndSendError(w, "could not update bucket acl while completing multipart upload", reqInfo, err, additional...) + return } } diff --git a/api/handler/put.go b/api/handler/put.go index 5c8de2f4d..24c115d8e 100644 --- a/api/handler/put.go +++ b/api/handler/put.go @@ -21,6 +21,7 @@ import ( "github.com/nspcc-dev/neofs-s3-gw/api/layer" "github.com/nspcc-dev/neofs-s3-gw/creds/accessbox" "github.com/nspcc-dev/neofs-sdk-go/eacl" + "github.com/nspcc-dev/neofs-sdk-go/session" "go.uber.org/zap" ) @@ -172,8 +173,21 @@ type createBucketParams struct { } func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) { - var newEaclTable *eacl.Table - reqInfo := api.GetReqInfo(r.Context()) + var ( + err error + newEaclTable *eacl.Table + sessionTokenEACL *session.Token + containsACL = containsACLHeaders(r) + reqInfo = api.GetReqInfo(r.Context()) + ) + + if containsACL { + 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) if err != nil { h.logAndSendError(w, "could not parse tagging header", reqInfo, err) @@ -233,11 +247,12 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) { h.log.Error("couldn't send notification: %w", zap.Error(err)) } - if containsACLHeaders(r) { + if containsACL { if newEaclTable, err = h.getNewEAclTable(r, bktInfo, info); err != nil { h.logAndSendError(w, "could not get new eacl table", reqInfo, err) return } + newEaclTable.SetSessionToken(sessionTokenEACL) } if tagSet != nil { @@ -269,10 +284,12 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) { func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) { var ( - newEaclTable *eacl.Table - tagSet map[string]string - reqInfo = api.GetReqInfo(r.Context()) - metadata = make(map[string]string) + newEaclTable *eacl.Table + tagSet map[string]string + sessionTokenEACL *session.Token + reqInfo = api.GetReqInfo(r.Context()) + metadata = make(map[string]string) + containsACL = containsACLHeaders(r) ) policy, err := checkPostPolicy(r, reqInfo, metadata) @@ -290,6 +307,13 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) { } } + if containsACL { + if sessionTokenEACL, err = getSessionTokenSetEACL(r.Context()); err != nil { + h.logAndSendError(w, "could not get eacl session token from a box", reqInfo, err) + return + } + } + var contentReader io.Reader var size int64 if content, ok := r.MultipartForm.Value["file"]; ok { @@ -360,6 +384,8 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) { } if newEaclTable != nil { + newEaclTable.SetSessionToken(sessionTokenEACL) + p := &layer.PutBucketACLParams{ BktInfo: bktInfo, EACL: newEaclTable, @@ -582,6 +608,17 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) { if err == nil { policies = boxData.Policies p.SessionToken = boxData.Gate.SessionTokenForPut() + p.EACL.SetSessionToken(boxData.Gate.SessionTokenForSetEACL()) + } + + if p.SessionToken == nil { + h.logAndSendError(w, "couldn't find session token for put", reqInfo, errors.GetAPIError(errors.ErrAccessDenied)) + return + } + + if p.EACL.SessionToken() == nil { + h.logAndSendError(w, "couldn't find session token for setEACL", reqInfo, errors.GetAPIError(errors.ErrAccessDenied)) + return } if createParams.LocationConstraint != "" { diff --git a/api/handler/util.go b/api/handler/util.go index e7cbc3afa..52a39d545 100644 --- a/api/handler/util.go +++ b/api/handler/util.go @@ -1,15 +1,16 @@ package handler import ( + "context" "net/http" "strconv" "strings" - "github.com/nspcc-dev/neofs-s3-gw/api/data" - "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/errors" "github.com/nspcc-dev/neofs-s3-gw/api/layer" + "github.com/nspcc-dev/neofs-sdk-go/session" "go.uber.org/zap" ) @@ -80,3 +81,16 @@ func parseRange(s string) (*layer.RangeParams, error) { End: values[1], }, nil } + +func getSessionTokenSetEACL(ctx context.Context) (*session.Token, error) { + boxData, err := layer.GetBoxData(ctx) + if err != nil { + return nil, err + } + sessionToken := boxData.Gate.SessionTokenForSetEACL() + if sessionToken == nil { + return nil, errors.GetAPIError(errors.ErrAccessDenied) + } + + return sessionToken, nil +}