[#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 <leonard@nspcc.ru>
This commit is contained in:
parent
bbe700fa37
commit
168dcbdccd
5 changed files with 98 additions and 20 deletions
|
@ -8,10 +8,12 @@ import (
|
||||||
|
|
||||||
acl "github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
acl "github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/container"
|
"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/pkg/owner"
|
||||||
"github.com/nspcc-dev/neofs-api-go/util/signature"
|
"github.com/nspcc-dev/neofs-api-go/util/signature"
|
||||||
bearer "github.com/nspcc-dev/neofs-api-go/v2/acl"
|
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/object"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
|
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
|
||||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||||
|
@ -70,6 +72,8 @@ type (
|
||||||
|
|
||||||
cid *container.ID
|
cid *container.ID
|
||||||
|
|
||||||
|
oid *objectSDK.ID
|
||||||
|
|
||||||
senderKey []byte
|
senderKey []byte
|
||||||
|
|
||||||
bearer *bearer.BearerToken // bearer token of request
|
bearer *bearer.BearerToken // bearer token of request
|
||||||
|
@ -150,6 +154,8 @@ func (b Service) Get(request *object.GetRequest, stream objectSvc.GetObjectStrea
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reqInfo.oid = getObjectIDFromRequestBody(request.GetBody())
|
||||||
|
|
||||||
if !basicACLCheck(reqInfo) {
|
if !basicACLCheck(reqInfo) {
|
||||||
return basicACLErr(reqInfo)
|
return basicACLErr(reqInfo)
|
||||||
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
||||||
|
@ -193,6 +199,8 @@ func (b Service) Head(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reqInfo.oid = getObjectIDFromRequestBody(request.GetBody())
|
||||||
|
|
||||||
if !basicACLCheck(reqInfo) {
|
if !basicACLCheck(reqInfo) {
|
||||||
return nil, basicACLErr(reqInfo)
|
return nil, basicACLErr(reqInfo)
|
||||||
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
||||||
|
@ -228,6 +236,8 @@ func (b Service) Search(request *object.SearchRequest, stream objectSvc.SearchSt
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reqInfo.oid = getObjectIDFromRequestBody(request.GetBody())
|
||||||
|
|
||||||
if !basicACLCheck(reqInfo) {
|
if !basicACLCheck(reqInfo) {
|
||||||
return basicACLErr(reqInfo)
|
return basicACLErr(reqInfo)
|
||||||
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
||||||
|
@ -261,6 +271,8 @@ func (b Service) Delete(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reqInfo.oid = getObjectIDFromRequestBody(request.GetBody())
|
||||||
|
|
||||||
if !basicACLCheck(reqInfo) {
|
if !basicACLCheck(reqInfo) {
|
||||||
return nil, basicACLErr(reqInfo)
|
return nil, basicACLErr(reqInfo)
|
||||||
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
||||||
|
@ -287,6 +299,8 @@ func (b Service) GetRange(request *object.GetRangeRequest, stream objectSvc.GetO
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reqInfo.oid = getObjectIDFromRequestBody(request.GetBody())
|
||||||
|
|
||||||
if !basicACLCheck(reqInfo) {
|
if !basicACLCheck(reqInfo) {
|
||||||
return basicACLErr(reqInfo)
|
return basicACLErr(reqInfo)
|
||||||
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
||||||
|
@ -320,6 +334,8 @@ func (b Service) GetRangeHash(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reqInfo.oid = getObjectIDFromRequestBody(request.GetBody())
|
||||||
|
|
||||||
if !basicACLCheck(reqInfo) {
|
if !basicACLCheck(reqInfo) {
|
||||||
return nil, basicACLErr(reqInfo)
|
return nil, basicACLErr(reqInfo)
|
||||||
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
} else if !eACLCheck(request, reqInfo, b.eACLCfg) {
|
||||||
|
@ -358,6 +374,8 @@ func (p putStreamBasicChecker) Send(request *object.PutRequest) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reqInfo.oid = getObjectIDFromRequestBody(part)
|
||||||
|
|
||||||
if !basicACLCheck(reqInfo) || !stickyBitCheck(reqInfo, ownerID) {
|
if !basicACLCheck(reqInfo) || !stickyBitCheck(reqInfo, ownerID) {
|
||||||
return basicACLErr(reqInfo)
|
return basicACLErr(reqInfo)
|
||||||
} else if !eACLCheck(request, reqInfo, p.eACLCfg) {
|
} 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) {
|
func getObjectOwnerFromMessage(req interface{}) (id *owner.ID, err error) {
|
||||||
switch v := req.(type) {
|
switch v := req.(type) {
|
||||||
case *object.PutRequest:
|
case *object.PutRequest:
|
||||||
|
@ -547,7 +580,12 @@ func eACLCheck(msg interface{}, reqInfo requestInfo, cfg *eACLCfg) bool {
|
||||||
if req, ok := msg.(eaclV2.Request); ok {
|
if req, ok := msg.(eaclV2.Request); ok {
|
||||||
hdrSrcOpts = append(hdrSrcOpts, eaclV2.WithServiceRequest(req))
|
hdrSrcOpts = append(hdrSrcOpts, eaclV2.WithServiceRequest(req))
|
||||||
} else {
|
} 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).
|
action := cfg.eACL.CalculateAction(new(eacl.ValidationUnit).
|
||||||
|
|
|
@ -5,7 +5,9 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg"
|
"github.com/nspcc-dev/neofs-api-go/pkg"
|
||||||
eaclSDK "github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
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"
|
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"
|
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/refs"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
"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:
|
case eaclSDK.HeaderFromRequest:
|
||||||
return requestHeaders(h.msg), true
|
return requestHeaders(h.msg), true
|
||||||
case eaclSDK.HeaderFromObject:
|
case eaclSDK.HeaderFromObject:
|
||||||
return h.objectHeaders()
|
return h.objectHeaders(), true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +80,7 @@ func requestHeaders(msg xHeaderSource) []eacl.Header {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *headerSource) objectHeaders() ([]eacl.Header, bool) {
|
func (h *headerSource) objectHeaders() []eacl.Header {
|
||||||
switch m := h.msg.(type) {
|
switch m := h.msg.(type) {
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unexpected message type %T", h.msg))
|
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.SetObjectID(v.GetObjectID())
|
||||||
oV2.SetHeader(v.GetHeader())
|
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:
|
case *responseXHeaderSource:
|
||||||
switch resp := m.resp.(type) {
|
switch resp := m.resp.(type) {
|
||||||
|
default:
|
||||||
|
return h.localObjectHeaders(m.addr)
|
||||||
case *objectV2.GetResponse:
|
case *objectV2.GetResponse:
|
||||||
if v, ok := resp.GetBody().GetObjectPart().(*objectV2.GetObjectPartInit); ok {
|
if v, ok := resp.GetBody().GetObjectPart().(*objectV2.GetObjectPartInit); ok {
|
||||||
oV2 := new(objectV2.Object)
|
oV2 := new(objectV2.Object)
|
||||||
oV2.SetObjectID(v.GetObjectID())
|
oV2.SetObjectID(v.GetObjectID())
|
||||||
oV2.SetHeader(v.GetHeader())
|
oV2.SetHeader(v.GetHeader())
|
||||||
|
|
||||||
return headersFromObject(object.NewFromV2(oV2)), true
|
return headersFromObject(object.NewFromV2(oV2))
|
||||||
}
|
}
|
||||||
case *objectV2.HeadResponse:
|
case *objectV2.HeadResponse:
|
||||||
oV2 := new(objectV2.Object)
|
oV2 := new(objectV2.Object)
|
||||||
|
@ -122,6 +132,7 @@ func (h *headerSource) objectHeaders() ([]eacl.Header, bool) {
|
||||||
case *objectV2.ShortHeader:
|
case *objectV2.ShortHeader:
|
||||||
hdr = new(objectV2.Header)
|
hdr = new(objectV2.Header)
|
||||||
|
|
||||||
|
hdr.SetContainerID(m.addr.GetContainerID())
|
||||||
hdr.SetVersion(v.GetVersion())
|
hdr.SetVersion(v.GetVersion())
|
||||||
hdr.SetCreationEpoch(v.GetCreationEpoch())
|
hdr.SetCreationEpoch(v.GetCreationEpoch())
|
||||||
hdr.SetOwnerID(v.GetOwnerID())
|
hdr.SetOwnerID(v.GetOwnerID())
|
||||||
|
@ -133,18 +144,48 @@ func (h *headerSource) objectHeaders() ([]eacl.Header, bool) {
|
||||||
|
|
||||||
oV2.SetHeader(hdr)
|
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) {
|
func (h *headerSource) localObjectHeaders(addrV2 *refs.Address) []eacl.Header {
|
||||||
obj, err := h.storage.Head(objectSDK.NewAddressFromV2(addr))
|
addr := objectSDK.NewAddressFromV2(addrV2)
|
||||||
|
|
||||||
|
obj, err := h.storage.Head(addr)
|
||||||
if err == nil {
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,10 +46,7 @@ func headersFromObject(obj *object.Object) []eacl.Header {
|
||||||
for ; obj != nil; obj = obj.GetParent() {
|
for ; obj != nil; obj = obj.GetParent() {
|
||||||
res = append(res,
|
res = append(res,
|
||||||
// container ID
|
// container ID
|
||||||
&sysObjHdr{
|
cidHeader(obj.ContainerID()),
|
||||||
k: acl.FilterObjectContainerID,
|
|
||||||
v: cidValue(obj.ContainerID()),
|
|
||||||
},
|
|
||||||
// owner ID
|
// owner ID
|
||||||
&sysObjHdr{
|
&sysObjHdr{
|
||||||
k: acl.FilterObjectOwnerID,
|
k: acl.FilterObjectOwnerID,
|
||||||
|
@ -65,10 +62,7 @@ func headersFromObject(obj *object.Object) []eacl.Header {
|
||||||
k: acl.FilterObjectPayloadLength,
|
k: acl.FilterObjectPayloadLength,
|
||||||
v: u64Value(obj.PayloadSize()),
|
v: u64Value(obj.PayloadSize()),
|
||||||
},
|
},
|
||||||
&sysObjHdr{
|
oidHeader(obj.ID()),
|
||||||
k: acl.FilterObjectID,
|
|
||||||
v: idValue(obj.ID()),
|
|
||||||
},
|
|
||||||
// TODO: add others fields after neofs-api#84
|
// TODO: add others fields after neofs-api#84
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
|
"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 {
|
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) {
|
return func(c *cfg) {
|
||||||
c.msg = &responseXHeaderSource{
|
c.msg = &responseXHeaderSource{
|
||||||
resp: v,
|
resp: v,
|
||||||
|
addr: addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,6 +15,8 @@ type requestXHeaderSource struct {
|
||||||
|
|
||||||
type responseXHeaderSource struct {
|
type responseXHeaderSource struct {
|
||||||
resp Response
|
resp Response
|
||||||
|
|
||||||
|
addr *refs.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *requestXHeaderSource) GetXHeaders() []*session.XHeader {
|
func (s *requestXHeaderSource) GetXHeaders() []*session.XHeader {
|
||||||
|
|
Loading…
Reference in a new issue