From 168dcbdccd2b4dccb7aacb1fda358336bcb7e1eb Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 14 Dec 2020 15:07:20 +0300 Subject: [PATCH] [#247] object/eacl: Process object address from request In previous implementation eACL validator didn't take into account container and object ID fields of request bodies. Signed-off-by: Leonard Lyubich --- pkg/services/object/acl/acl.go | 40 +++++++++++++- pkg/services/object/acl/eacl/v2/headers.go | 61 ++++++++++++++++++---- pkg/services/object/acl/eacl/v2/object.go | 10 +--- pkg/services/object/acl/eacl/v2/opts.go | 4 +- pkg/services/object/acl/eacl/v2/xheader.go | 3 ++ 5 files changed, 98 insertions(+), 20 deletions(-) diff --git a/pkg/services/object/acl/acl.go b/pkg/services/object/acl/acl.go index 9fe4f73db..0f49502af 100644 --- a/pkg/services/object/acl/acl.go +++ b/pkg/services/object/acl/acl.go @@ -8,10 +8,12 @@ import ( acl "github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl" "github.com/nspcc-dev/neofs-api-go/pkg/container" + objectSDK "github.com/nspcc-dev/neofs-api-go/pkg/object" "github.com/nspcc-dev/neofs-api-go/pkg/owner" "github.com/nspcc-dev/neofs-api-go/util/signature" bearer "github.com/nspcc-dev/neofs-api-go/v2/acl" "github.com/nspcc-dev/neofs-api-go/v2/object" + "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/session" v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature" crypto "github.com/nspcc-dev/neofs-crypto" @@ -70,6 +72,8 @@ type ( cid *container.ID + oid *objectSDK.ID + senderKey []byte bearer *bearer.BearerToken // bearer token of request @@ -150,6 +154,8 @@ func (b Service) Get(request *object.GetRequest, stream objectSvc.GetObjectStrea return err } + reqInfo.oid = getObjectIDFromRequestBody(request.GetBody()) + if !basicACLCheck(reqInfo) { return basicACLErr(reqInfo) } else if !eACLCheck(request, reqInfo, b.eACLCfg) { @@ -193,6 +199,8 @@ func (b Service) Head( return nil, err } + reqInfo.oid = getObjectIDFromRequestBody(request.GetBody()) + if !basicACLCheck(reqInfo) { return nil, basicACLErr(reqInfo) } else if !eACLCheck(request, reqInfo, b.eACLCfg) { @@ -228,6 +236,8 @@ func (b Service) Search(request *object.SearchRequest, stream objectSvc.SearchSt return err } + reqInfo.oid = getObjectIDFromRequestBody(request.GetBody()) + if !basicACLCheck(reqInfo) { return basicACLErr(reqInfo) } else if !eACLCheck(request, reqInfo, b.eACLCfg) { @@ -261,6 +271,8 @@ func (b Service) Delete( return nil, err } + reqInfo.oid = getObjectIDFromRequestBody(request.GetBody()) + if !basicACLCheck(reqInfo) { return nil, basicACLErr(reqInfo) } else if !eACLCheck(request, reqInfo, b.eACLCfg) { @@ -287,6 +299,8 @@ func (b Service) GetRange(request *object.GetRangeRequest, stream objectSvc.GetO return err } + reqInfo.oid = getObjectIDFromRequestBody(request.GetBody()) + if !basicACLCheck(reqInfo) { return basicACLErr(reqInfo) } else if !eACLCheck(request, reqInfo, b.eACLCfg) { @@ -320,6 +334,8 @@ func (b Service) GetRangeHash( return nil, err } + reqInfo.oid = getObjectIDFromRequestBody(request.GetBody()) + if !basicACLCheck(reqInfo) { return nil, basicACLErr(reqInfo) } else if !eACLCheck(request, reqInfo, b.eACLCfg) { @@ -358,6 +374,8 @@ func (p putStreamBasicChecker) Send(request *object.PutRequest) error { return err } + reqInfo.oid = getObjectIDFromRequestBody(part) + if !basicACLCheck(reqInfo) || !stickyBitCheck(reqInfo, ownerID) { return basicACLErr(reqInfo) } else if !eACLCheck(request, reqInfo, p.eACLCfg) { @@ -466,6 +484,21 @@ func getContainerIDFromRequest(req interface{}) (id *container.ID, err error) { } } +func getObjectIDFromRequestBody(body interface{}) *objectSDK.ID { + switch v := body.(type) { + default: + return nil + case interface { + GetObjectID() *refs.ObjectID + }: + return objectSDK.NewIDFromV2(v.GetObjectID()) + case interface { + GetAddress() *refs.Address + }: + return objectSDK.NewIDFromV2(v.GetAddress().GetObjectID()) + } +} + func getObjectOwnerFromMessage(req interface{}) (id *owner.ID, err error) { switch v := req.(type) { case *object.PutRequest: @@ -547,7 +580,12 @@ func eACLCheck(msg interface{}, reqInfo requestInfo, cfg *eACLCfg) bool { if req, ok := msg.(eaclV2.Request); ok { hdrSrcOpts = append(hdrSrcOpts, eaclV2.WithServiceRequest(req)) } else { - hdrSrcOpts = append(hdrSrcOpts, eaclV2.WithServiceResponse(msg.(eaclV2.Response))) + addr := objectSDK.NewAddress() + addr.SetContainerID(reqInfo.cid) + addr.SetObjectID(reqInfo.oid) + + // TODO: Add 'WithAddress' option to config and use address from reqInfo + hdrSrcOpts = append(hdrSrcOpts, eaclV2.WithServiceResponse(msg.(eaclV2.Response), addr.ToV2())) } action := cfg.eACL.CalculateAction(new(eacl.ValidationUnit). diff --git a/pkg/services/object/acl/eacl/v2/headers.go b/pkg/services/object/acl/eacl/v2/headers.go index de81ec2ea..fb6c0896a 100644 --- a/pkg/services/object/acl/eacl/v2/headers.go +++ b/pkg/services/object/acl/eacl/v2/headers.go @@ -5,7 +5,9 @@ import ( "github.com/nspcc-dev/neofs-api-go/pkg" eaclSDK "github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl" + "github.com/nspcc-dev/neofs-api-go/pkg/container" objectSDK "github.com/nspcc-dev/neofs-api-go/pkg/object" + "github.com/nspcc-dev/neofs-api-go/v2/acl" objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object" "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/session" @@ -62,7 +64,7 @@ func (h *headerSource) HeadersOfType(typ eaclSDK.FilterHeaderType) ([]eacl.Heade case eaclSDK.HeaderFromRequest: return requestHeaders(h.msg), true case eaclSDK.HeaderFromObject: - return h.objectHeaders() + return h.objectHeaders(), true } } @@ -78,7 +80,7 @@ func requestHeaders(msg xHeaderSource) []eacl.Header { return res } -func (h *headerSource) objectHeaders() ([]eacl.Header, bool) { +func (h *headerSource) objectHeaders() []eacl.Header { switch m := h.msg.(type) { default: panic(fmt.Sprintf("unexpected message type %T", h.msg)) @@ -100,18 +102,26 @@ func (h *headerSource) objectHeaders() ([]eacl.Header, bool) { oV2.SetObjectID(v.GetObjectID()) oV2.SetHeader(v.GetHeader()) - return headersFromObject(object.NewFromV2(oV2)), true + return headersFromObject(object.NewFromV2(oV2)) + } + case *objectV2.SearchRequest: + return []eacl.Header{cidHeader( + container.NewIDFromV2( + req.GetBody().GetContainerID()), + ), } } case *responseXHeaderSource: switch resp := m.resp.(type) { + default: + return h.localObjectHeaders(m.addr) case *objectV2.GetResponse: if v, ok := resp.GetBody().GetObjectPart().(*objectV2.GetObjectPartInit); ok { oV2 := new(objectV2.Object) oV2.SetObjectID(v.GetObjectID()) oV2.SetHeader(v.GetHeader()) - return headersFromObject(object.NewFromV2(oV2)), true + return headersFromObject(object.NewFromV2(oV2)) } case *objectV2.HeadResponse: oV2 := new(objectV2.Object) @@ -122,6 +132,7 @@ func (h *headerSource) objectHeaders() ([]eacl.Header, bool) { case *objectV2.ShortHeader: hdr = new(objectV2.Header) + hdr.SetContainerID(m.addr.GetContainerID()) hdr.SetVersion(v.GetVersion()) hdr.SetCreationEpoch(v.GetCreationEpoch()) hdr.SetOwnerID(v.GetOwnerID()) @@ -133,18 +144,48 @@ func (h *headerSource) objectHeaders() ([]eacl.Header, bool) { oV2.SetHeader(hdr) - return headersFromObject(object.NewFromV2(oV2)), true + return append( + headersFromObject(object.NewFromV2(oV2)), + oidHeader(objectSDK.NewIDFromV2(m.addr.GetObjectID())), + ) } } - return nil, true + return nil } -func (h *headerSource) localObjectHeaders(addr *refs.Address) ([]eacl.Header, bool) { - obj, err := h.storage.Head(objectSDK.NewAddressFromV2(addr)) +func (h *headerSource) localObjectHeaders(addrV2 *refs.Address) []eacl.Header { + addr := objectSDK.NewAddressFromV2(addrV2) + + obj, err := h.storage.Head(addr) if err == nil { - return headersFromObject(obj), true + return headersFromObject(obj) } - return nil, false + return addressHeaders(addr) +} + +func cidHeader(cid *container.ID) eacl.Header { + return &sysObjHdr{ + k: acl.FilterObjectContainerID, + v: cidValue(cid), + } +} + +func oidHeader(oid *objectSDK.ID) eacl.Header { + return &sysObjHdr{ + k: acl.FilterObjectID, + v: idValue(oid), + } +} + +func addressHeaders(addr *objectSDK.Address) []eacl.Header { + res := make([]eacl.Header, 1, 2) + res[0] = cidHeader(addr.ContainerID()) + + if oid := addr.ObjectID(); oid != nil { + res = append(res, oidHeader(oid)) + } + + return res } diff --git a/pkg/services/object/acl/eacl/v2/object.go b/pkg/services/object/acl/eacl/v2/object.go index f48d8bf45..22d5816a0 100644 --- a/pkg/services/object/acl/eacl/v2/object.go +++ b/pkg/services/object/acl/eacl/v2/object.go @@ -46,10 +46,7 @@ func headersFromObject(obj *object.Object) []eacl.Header { for ; obj != nil; obj = obj.GetParent() { res = append(res, // container ID - &sysObjHdr{ - k: acl.FilterObjectContainerID, - v: cidValue(obj.ContainerID()), - }, + cidHeader(obj.ContainerID()), // owner ID &sysObjHdr{ k: acl.FilterObjectOwnerID, @@ -65,10 +62,7 @@ func headersFromObject(obj *object.Object) []eacl.Header { k: acl.FilterObjectPayloadLength, v: u64Value(obj.PayloadSize()), }, - &sysObjHdr{ - k: acl.FilterObjectID, - v: idValue(obj.ID()), - }, + oidHeader(obj.ID()), // TODO: add others fields after neofs-api#84 ) diff --git a/pkg/services/object/acl/eacl/v2/opts.go b/pkg/services/object/acl/eacl/v2/opts.go index 2a0454819..571744a10 100644 --- a/pkg/services/object/acl/eacl/v2/opts.go +++ b/pkg/services/object/acl/eacl/v2/opts.go @@ -2,6 +2,7 @@ package v2 import ( "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine" + "github.com/nspcc-dev/neofs-api-go/v2/refs" ) func WithObjectStorage(v ObjectStorage) Option { @@ -26,10 +27,11 @@ func WithServiceRequest(v Request) Option { } } -func WithServiceResponse(v Response) Option { +func WithServiceResponse(v Response, addr *refs.Address) Option { return func(c *cfg) { c.msg = &responseXHeaderSource{ resp: v, + addr: addr, } } } diff --git a/pkg/services/object/acl/eacl/v2/xheader.go b/pkg/services/object/acl/eacl/v2/xheader.go index 642c94a76..b01545dd6 100644 --- a/pkg/services/object/acl/eacl/v2/xheader.go +++ b/pkg/services/object/acl/eacl/v2/xheader.go @@ -1,6 +1,7 @@ package v2 import ( + "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/session" ) @@ -14,6 +15,8 @@ type requestXHeaderSource struct { type responseXHeaderSource struct { resp Response + + addr *refs.Address } func (s *requestXHeaderSource) GetXHeaders() []*session.XHeader {