[#1471] eacl: Fix incorrect request denial with incomplete object header

Node shouldn't perform eACL verification during GET/HEAD request
processing until full object header is received. Otherwise, for some
eACL tables request may be falsely rejected.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2022-06-02 17:37:45 +03:00 committed by LeL
parent c89035d544
commit 0e28902b0f

View file

@ -41,6 +41,8 @@ type Response interface {
type headerSource struct { type headerSource struct {
requestHeaders []eaclSDK.Header requestHeaders []eaclSDK.Header
objectHeaders []eaclSDK.Header objectHeaders []eaclSDK.Header
incompleteObjectHeaders bool
} }
func defaultCfg() *cfg { func defaultCfg() *cfg {
@ -60,15 +62,16 @@ func NewMessageHeaderSource(opts ...Option) (eaclSDK.TypedHeaderSource, error) {
return nil, errors.New("message is not provided") return nil, errors.New("message is not provided")
} }
objHdrs, err := cfg.objectHeaders() var res headerSource
err := cfg.readObjectHeaders(&res)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return headerSource{ res.requestHeaders = requestHeaders(cfg.msg)
objectHeaders: objHdrs,
requestHeaders: requestHeaders(cfg.msg), return res, nil
}, nil
} }
func (h headerSource) HeadersOfType(typ eaclSDK.FilterHeaderType) ([]eaclSDK.Header, bool) { func (h headerSource) HeadersOfType(typ eaclSDK.FilterHeaderType) ([]eaclSDK.Header, bool) {
@ -78,7 +81,7 @@ func (h headerSource) HeadersOfType(typ eaclSDK.FilterHeaderType) ([]eaclSDK.Hea
case eaclSDK.HeaderFromRequest: case eaclSDK.HeaderFromRequest:
return h.requestHeaders, true return h.requestHeaders, true
case eaclSDK.HeaderFromObject: case eaclSDK.HeaderFromObject:
return h.objectHeaders, true return h.objectHeaders, !h.incompleteObjectHeaders
} }
} }
@ -98,7 +101,7 @@ func requestHeaders(msg xHeaderSource) []eaclSDK.Header {
var errMissingOID = errors.New("object ID is missing") var errMissingOID = errors.New("object ID is missing")
func (h *cfg) objectHeaders() ([]eaclSDK.Header, error) { func (h *cfg) readObjectHeaders(dst *headerSource) error {
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))
@ -108,26 +111,35 @@ func (h *cfg) objectHeaders() ([]eaclSDK.Header, error) {
*objectV2.GetRequest, *objectV2.GetRequest,
*objectV2.HeadRequest: *objectV2.HeadRequest:
if h.obj == nil { if h.obj == nil {
return nil, errMissingOID return errMissingOID
} }
return h.localObjectHeaders(h.cnr, h.obj) var addr oid.Address
addr.SetContainer(h.cnr)
addr.SetObject(*h.obj)
obj, err := h.storage.Head(addr)
if err == nil {
dst.objectHeaders = headersFromObject(obj, h.cnr, h.obj)
} else {
dst.incompleteObjectHeaders = true
}
case case
*objectV2.GetRangeRequest, *objectV2.GetRangeRequest,
*objectV2.GetRangeHashRequest, *objectV2.GetRangeHashRequest,
*objectV2.DeleteRequest: *objectV2.DeleteRequest:
if h.obj == nil { if h.obj == nil {
return nil, errMissingOID return errMissingOID
} }
return addressHeaders(h.cnr, h.obj), nil dst.objectHeaders = addressHeaders(h.cnr, h.obj)
case *objectV2.PutRequest: case *objectV2.PutRequest:
if v, ok := req.GetBody().GetObjectPart().(*objectV2.PutObjectPartInit); ok { if v, ok := req.GetBody().GetObjectPart().(*objectV2.PutObjectPartInit); 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), h.cnr, h.obj), nil dst.objectHeaders = headersFromObject(object.NewFromV2(oV2), h.cnr, h.obj)
} }
case *objectV2.SearchRequest: case *objectV2.SearchRequest:
cnrV2 := req.GetBody().GetContainerID() cnrV2 := req.GetBody().GetContainerID()
@ -135,11 +147,11 @@ func (h *cfg) objectHeaders() ([]eaclSDK.Header, error) {
if cnrV2 != nil { if cnrV2 != nil {
if err := cnr.ReadFromV2(*cnrV2); err != nil { if err := cnr.ReadFromV2(*cnrV2); err != nil {
return nil, fmt.Errorf("can't parse container ID: %w", err) return fmt.Errorf("can't parse container ID: %w", err)
} }
} }
return []eaclSDK.Header{cidHeader(cnr)}, nil dst.objectHeaders = []eaclSDK.Header{cidHeader(cnr)}
} }
case responseXHeaderSource: case responseXHeaderSource:
switch resp := m.resp.(type) { switch resp := m.resp.(type) {
@ -149,7 +161,7 @@ func (h *cfg) objectHeaders() ([]eaclSDK.Header, error) {
oV2.SetObjectID(v.GetObjectID()) oV2.SetObjectID(v.GetObjectID())
oV2.SetHeader(v.GetHeader()) oV2.SetHeader(v.GetHeader())
return headersFromObject(object.NewFromV2(oV2), h.cnr, h.obj), nil dst.objectHeaders = headersFromObject(object.NewFromV2(oV2), h.cnr, h.obj)
} }
case *objectV2.HeadResponse: case *objectV2.HeadResponse:
oV2 := new(objectV2.Object) oV2 := new(objectV2.Object)
@ -175,27 +187,11 @@ func (h *cfg) objectHeaders() ([]eaclSDK.Header, error) {
oV2.SetHeader(hdr) oV2.SetHeader(hdr)
return headersFromObject(object.NewFromV2(oV2), h.cnr, h.obj), nil dst.objectHeaders = headersFromObject(object.NewFromV2(oV2), h.cnr, h.obj)
} }
} }
return nil, nil return nil
}
func (h *cfg) localObjectHeaders(cnr cid.ID, idObj *oid.ID) ([]eaclSDK.Header, error) {
if idObj != nil {
var addr oid.Address
addr.SetContainer(cnr)
addr.SetObject(*idObj)
obj, err := h.storage.Head(addr)
if err == nil {
return headersFromObject(obj, cnr, idObj), nil
}
}
// Still parse addressHeaders, because the errors is ignored in some places.
return addressHeaders(cnr, idObj), nil
} }
func cidHeader(idCnr cid.ID) sysObjHdr { func cidHeader(idCnr cid.ID) sysObjHdr {