[#214] Add condition to update eacl

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2021-08-19 17:14:19 +03:00 committed by Angira Kekteeva
parent a0f59bb348
commit 76fc241bc1

View file

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
"github.com/nspcc-dev/neofs-node/pkg/policy" "github.com/nspcc-dev/neofs-node/pkg/policy"
"github.com/nspcc-dev/neofs-s3-gw/api" "github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/errors" "github.com/nspcc-dev/neofs-s3-gw/api/errors"
@ -30,56 +31,60 @@ 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 newEaclTable *eacl.Table
err error reqInfo := api.GetReqInfo(r.Context())
info *layer.ObjectInfo
reqInfo = api.GetReqInfo(r.Context())
)
objectACL, err := parseACLHeaders(r) if containsACLHeaders(r) {
if err != nil { objectACL, err := parseACLHeaders(r)
h.logAndSendError(w, "could not parse object acl", reqInfo, err) if err != nil {
return h.logAndSendError(w, "could not parse object acl", reqInfo, err)
} return
objectACL.Resource = reqInfo.BucketName + "/" + reqInfo.ObjectName }
objectACL.Resource = reqInfo.BucketName + "/" + reqInfo.ObjectName
bktPolicy, err := aclToPolicy(objectACL) bktPolicy, err := aclToPolicy(objectACL)
if err != nil { if err != nil {
h.logAndSendError(w, "could not translate object acl to bucket policy", reqInfo, err) h.logAndSendError(w, "could not translate object acl to bucket policy", reqInfo, err)
return return
}
astChild, err := policyToAst(bktPolicy)
if err != nil {
h.logAndSendError(w, "could not translate policy to ast", reqInfo, err)
return
}
bacl, err := h.obj.GetBucketACL(r.Context(), reqInfo.BucketName)
if err != nil {
h.logAndSendError(w, "could not get bucket eacl", reqInfo, err)
return
}
parentAst := tableToAst(bacl.EACL, reqInfo.BucketName)
for _, resource := range parentAst.Resources {
if resource.Name == bacl.Info.CID.String() {
resource.Name = reqInfo.BucketName
}
}
if resAst, updated := mergeAst(parentAst, astChild); updated {
if newEaclTable, err = astToTable(resAst, reqInfo.BucketName); err != nil {
h.logAndSendError(w, "could not translate ast to table", reqInfo, err)
return
}
}
} }
astChild, err := policyToAst(bktPolicy) bktInfo, err := h.obj.GetBucketInfo(r.Context(), reqInfo.BucketName)
if err != nil {
h.logAndSendError(w, "could not translate policy to ast", reqInfo, err)
return
}
bacl, err := h.obj.GetBucketACL(r.Context(), reqInfo.BucketName)
if err != nil { if err != nil {
h.logAndSendError(w, "could not get bucket eacl", reqInfo, err) h.logAndSendError(w, "could not get bucket eacl", reqInfo, err)
return return
} }
if err = checkOwner(bktInfo, r.Header.Get(api.AmzExpectedBucketOwner)); err != nil {
if err = checkOwner(bacl.Info, r.Header.Get(api.AmzExpectedBucketOwner)); err != nil {
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err) h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
return return
} }
parentAst := tableToAst(bacl.EACL, reqInfo.BucketName)
for _, resource := range parentAst.Resources {
if resource.Name == bacl.Info.CID.String() {
resource.Name = reqInfo.BucketName
}
}
resAst, updated := mergeAst(parentAst, astChild)
table, err := astToTable(resAst, reqInfo.BucketName)
if err != nil {
h.logAndSendError(w, "could not translate ast to table", reqInfo, err)
return
}
metadata := parseMetadata(r) metadata := parseMetadata(r)
if contentType := r.Header.Get(api.ContentType); len(contentType) > 0 { if contentType := r.Header.Get(api.ContentType); len(contentType) > 0 {
metadata[api.ContentType] = contentType metadata[api.ContentType] = contentType
@ -93,15 +98,16 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
Header: metadata, Header: metadata,
} }
if info, err = h.obj.PutObject(r.Context(), params); err != nil { info, err := h.obj.PutObject(r.Context(), params)
if err != nil {
h.logAndSendError(w, "could not upload object", reqInfo, err) h.logAndSendError(w, "could not upload object", reqInfo, err)
return return
} }
if updated { if newEaclTable != nil {
p := &layer.PutBucketACLParams{ p := &layer.PutBucketACLParams{
Name: reqInfo.BucketName, Name: reqInfo.BucketName,
EACL: table, EACL: newEaclTable,
} }
if err = h.obj.PutBucketACL(r.Context(), p); err != nil { if err = h.obj.PutBucketACL(r.Context(), p); err != nil {
@ -114,6 +120,11 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
api.WriteSuccessResponseHeadersOnly(w) api.WriteSuccessResponseHeadersOnly(w)
} }
func containsACLHeaders(r *http.Request) bool {
return r.Header.Get(api.AmzACL) != "" || r.Header.Get(api.AmzGrantRead) != "" ||
r.Header.Get(api.AmzGrantFullControl) != "" || r.Header.Get(api.AmzGrantWrite) != ""
}
func parseMetadata(r *http.Request) map[string]string { func parseMetadata(r *http.Request) map[string]string {
res := make(map[string]string) res := make(map[string]string)
for k, v := range r.Header { for k, v := range r.Header {