object: Introduce soft ape checks #986

Merged
fyrchik merged 3 commits from aarifullin/frostfs-node:fix/strict_ape_checks into master 2024-02-28 19:05:58 +00:00
6 changed files with 176 additions and 108 deletions
Showing only changes of commit e9363a5094 - Show all commits

View file

@ -104,6 +104,13 @@ func (r RequestInfo) RequestRole() acl.Role {
return r.requestRole
}
// IsSoftAPECheck states if APE should perform soft checks.
// Soft APE check allows a request if CheckAPE returns NoRuleFound for it,
// otherwise it denies the request.
func (r RequestInfo) IsSoftAPECheck() bool {
return r.BasicACL().Bits() != 0

You are always using NOT operator with result of this function and with field StrictAPECheck. How about to replace it with SoftAPECheck?

You are always using NOT operator with result of this function and with field `StrictAPECheck`. How about to replace it with `SoftAPECheck`?

Replaced to SoftAPECheck. Could u check please if I've left mistakes. Also, I fixed commit message

Replaced to `SoftAPECheck`. Could u check please if I've left mistakes. Also, I fixed commit message
}
// MetaWithToken groups session and bearer tokens,
// verification header and raw API request.
type MetaWithToken struct {

View file

@ -116,6 +116,7 @@ func (w *wrappedGetObjectStream) Context() context.Context {
Namespace: w.requestInfo.ContainerNamespace(),
SenderKey: w.requestInfo.SenderKey(),
Role: w.requestInfo.RequestRole(),
SoftAPECheck: w.requestInfo.IsSoftAPECheck(),
})
}
@ -139,6 +140,7 @@ func (w *wrappedRangeStream) Context() context.Context {
Namespace: w.requestInfo.ContainerNamespace(),
SenderKey: w.requestInfo.SenderKey(),
Role: w.requestInfo.RequestRole(),
SoftAPECheck: w.requestInfo.IsSoftAPECheck(),
})
}
@ -162,6 +164,7 @@ func (w *wrappedSearchStream) Context() context.Context {
Namespace: w.requestInfo.ContainerNamespace(),
SenderKey: w.requestInfo.SenderKey(),
Role: w.requestInfo.RequestRole(),
SoftAPECheck: w.requestInfo.IsSoftAPECheck(),
})
}
@ -216,11 +219,13 @@ func (b Service) Get(request *objectV2.GetRequest, stream object.GetObjectStream
reqInfo.obj = obj
if reqInfo.IsSoftAPECheck() {
if !b.checker.CheckBasicACL(reqInfo) {
return basicACLErr(reqInfo)
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
return eACLErr(reqInfo, err)
}
}
return b.next.Get(request, &getStreamBasicChecker{
GetObjectStream: newWrappedGetObjectStreamStream(stream, reqInfo),
@ -283,11 +288,13 @@ func (b Service) Head(
reqInfo.obj = obj
if reqInfo.IsSoftAPECheck() {
if !b.checker.CheckBasicACL(reqInfo) {
return nil, basicACLErr(reqInfo)
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
return nil, eACLErr(reqInfo, err)
}
}
resp, err := b.next.Head(requestContext(ctx, reqInfo), request)
if err == nil {
@ -334,11 +341,13 @@ func (b Service) Search(request *objectV2.SearchRequest, stream object.SearchStr
return err
}
if reqInfo.IsSoftAPECheck() {
if !b.checker.CheckBasicACL(reqInfo) {
return basicACLErr(reqInfo)
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
return eACLErr(reqInfo, err)
}
}
return b.next.Search(request, &searchStreamBasicChecker{
checker: b.checker,
@ -392,11 +401,13 @@ func (b Service) Delete(
reqInfo.obj = obj
if reqInfo.IsSoftAPECheck() {
if !b.checker.CheckBasicACL(reqInfo) {
return nil, basicACLErr(reqInfo)
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
return nil, eACLErr(reqInfo, err)
}
}
return b.next.Delete(requestContext(ctx, reqInfo), request)
}
@ -443,11 +454,13 @@ func (b Service) GetRange(request *objectV2.GetRangeRequest, stream object.GetOb
reqInfo.obj = obj
if reqInfo.IsSoftAPECheck() {
if !b.checker.CheckBasicACL(reqInfo) {
return basicACLErr(reqInfo)
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
return eACLErr(reqInfo, err)
}
}
return b.next.GetRange(request, &rangeStreamBasicChecker{
checker: b.checker,
@ -461,6 +474,7 @@ func requestContext(ctx context.Context, reqInfo RequestInfo) context.Context {
Namespace: reqInfo.ContainerNamespace(),
SenderKey: reqInfo.SenderKey(),
Role: reqInfo.RequestRole(),
SoftAPECheck: reqInfo.IsSoftAPECheck(),
})
}
@ -509,11 +523,13 @@ func (b Service) GetRangeHash(
reqInfo.obj = obj
if reqInfo.IsSoftAPECheck() {
if !b.checker.CheckBasicACL(reqInfo) {
return nil, basicACLErr(reqInfo)
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
return nil, eACLErr(reqInfo, err)
}
}
return b.next.GetRangeHash(requestContext(ctx, reqInfo), request)
}
@ -566,13 +582,14 @@ func (b Service) PutSingle(ctx context.Context, request *objectV2.PutSingleReque
reqInfo.obj = obj
if reqInfo.IsSoftAPECheck() {
if !b.checker.CheckBasicACL(reqInfo) || !b.checker.StickyBitCheck(reqInfo, idOwner) {
return nil, basicACLErr(reqInfo)
}
if err := b.checker.CheckEACL(request, reqInfo); err != nil {
return nil, eACLErr(reqInfo, err)
}
}
return b.next.PutSingle(requestContext(ctx, reqInfo), request)
}
@ -639,9 +656,11 @@ func (p putStreamBasicChecker) Send(ctx context.Context, request *objectV2.PutRe
reqInfo.obj = obj
if reqInfo.IsSoftAPECheck() {
if !p.source.checker.CheckBasicACL(reqInfo) || !p.source.checker.StickyBitCheck(reqInfo, idOwner) {
return basicACLErr(reqInfo)
}
}
ctx = requestContext(ctx, reqInfo)
}

View file

@ -45,6 +45,9 @@ type Prm struct {
// An encoded sender's public key string.
SenderKey string
// If SoftAPECheck is set to true, then NoRuleFound is interpreted as allow.
SoftAPECheck bool
}
var errMissingOID = fmt.Errorf("object ID is not set")
@ -63,9 +66,9 @@ func (c *checkerImpl) CheckAPE(ctx context.Context, prm Prm) error {
return err
}
if !ruleFound || status == apechain.Allow {
if !ruleFound && prm.SoftAPECheck || status == apechain.Allow {
return nil
}
return fmt.Errorf("found denying rule for %s: %s", prm.Method, status)
return fmt.Errorf("method %s: %s", prm.Method, status)
}

View file

@ -165,11 +165,29 @@ func TestAPECheck(t *testing.T) {
container: containerID,
object: stringPtr(objectID),
methods: methodsRequiredOID,
containerRules: []chain.Rule{
{
Status: chain.Allow,
Actions: chain.Actions{Names: methodsRequiredOID},
Resources: chain.Resources{
Names: []string{fmt.Sprintf(nativeschema.ResourceFormatRootContainerObject, containerID, objectID)},
},
},
},
},
{
name: "oid optional requests are allowed",
container: containerID,
methods: methodsOptionalOID,
containerRules: []chain.Rule{
{
Status: chain.Allow,
Actions: chain.Actions{Names: methodsOptionalOID},
Resources: chain.Resources{
Names: []string{fmt.Sprintf(nativeschema.ResourceFormatRootContainerObjects, containerID)},
},
},
},
},
{
name: "oid required requests are denied",

View file

@ -60,9 +60,13 @@ type getStreamBasicChecker struct {
apeChecker Checker
namespace string
senderKey []byte
role string
softAPECheck bool
}
func (g *getStreamBasicChecker) Send(resp *objectV2.GetResponse) error {
@ -73,12 +77,14 @@ func (g *getStreamBasicChecker) Send(resp *objectV2.GetResponse) error {
}
prm := Prm{
Namespace: g.namespace,
Container: cnrID,
Object: objID,
Header: partInit.GetHeader(),
Method: nativeschema.MethodGetObject,
SenderKey: hex.EncodeToString(g.senderKey),
Role: g.role,
SoftAPECheck: g.softAPECheck,
}
if err := g.apeChecker.CheckAPE(g.Context(), prm); err != nil {
@ -118,6 +124,7 @@ func (c *Service) Get(request *objectV2.GetRequest, stream objectSvc.GetObjectSt
Method: nativeschema.MethodGetObject,
Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck,
})
if err != nil {
return toStatusErr(err)
@ -126,6 +133,10 @@ func (c *Service) Get(request *objectV2.GetRequest, stream objectSvc.GetObjectSt
return c.next.Get(request, &getStreamBasicChecker{
GetObjectStream: stream,
apeChecker: c.apeChecker,
namespace: reqCtx.Namespace,
senderKey: reqCtx.SenderKey,
role: nativeSchemaRole(reqCtx.Role),
softAPECheck: reqCtx.SoftAPECheck,
})
}
@ -155,6 +166,7 @@ func (p *putStreamBasicChecker) Send(ctx context.Context, request *objectV2.PutR
Method: nativeschema.MethodPutObject,
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
Role: nativeSchemaRole(reqCtx.Role),
SoftAPECheck: reqCtx.SoftAPECheck,
}
if err := p.apeChecker.CheckAPE(ctx, prm); err != nil {
@ -196,6 +208,7 @@ func (c *Service) Head(ctx context.Context, request *objectV2.HeadRequest) (*obj
Method: nativeschema.MethodHeadObject,
Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck,
})
if err != nil {
return nil, err
@ -233,6 +246,7 @@ func (c *Service) Head(ctx context.Context, request *objectV2.HeadRequest) (*obj
Method: nativeschema.MethodHeadObject,
Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck,
})
if err != nil {
return nil, err
@ -259,6 +273,7 @@ func (c *Service) Search(request *objectV2.SearchRequest, stream objectSvc.Searc
Method: nativeschema.MethodSearchObject,
Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck,
})
if err != nil {
return toStatusErr(err)
@ -285,6 +300,7 @@ func (c *Service) Delete(ctx context.Context, request *objectV2.DeleteRequest) (
Method: nativeschema.MethodDeleteObject,
Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck,
})
if err != nil {
return nil, err
@ -316,6 +332,7 @@ func (c *Service) GetRange(request *objectV2.GetRangeRequest, stream objectSvc.G
Method: nativeschema.MethodRangeObject,
Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck,
})
if err != nil {
return toStatusErr(err)
@ -342,6 +359,7 @@ func (c *Service) GetRangeHash(ctx context.Context, request *objectV2.GetRangeHa
Method: nativeschema.MethodHashObject,
Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck,
}
if err = c.apeChecker.CheckAPE(ctx, prm); err != nil {
@ -378,6 +396,7 @@ func (c *Service) PutSingle(ctx context.Context, request *objectV2.PutSingleRequ
Method: nativeschema.MethodPutObject,
Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck,
}
if err = c.apeChecker.CheckAPE(ctx, prm); err != nil {

View file

@ -13,4 +13,6 @@ type RequestContext struct {
SenderKey []byte
Role acl.Role
SoftAPECheck bool
}