forked from TrueCloudLab/frostfs-node
[#986] object: Introduce soft ape checks
* Soft APE check means that APE should allow request even it gets status NoRuleFound for a request. Otherwise, it is interpreted as Deny. * Soft APE check is performed if basic ACL mask is not set. Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
parent
bc9dbb26ec
commit
7cc368e188
6 changed files with 176 additions and 108 deletions
|
@ -104,6 +104,13 @@ func (r RequestInfo) RequestRole() acl.Role {
|
||||||
return r.requestRole
|
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
|
||||||
|
}
|
||||||
|
|
||||||
// MetaWithToken groups session and bearer tokens,
|
// MetaWithToken groups session and bearer tokens,
|
||||||
// verification header and raw API request.
|
// verification header and raw API request.
|
||||||
type MetaWithToken struct {
|
type MetaWithToken struct {
|
||||||
|
|
|
@ -116,6 +116,7 @@ func (w *wrappedGetObjectStream) Context() context.Context {
|
||||||
Namespace: w.requestInfo.ContainerNamespace(),
|
Namespace: w.requestInfo.ContainerNamespace(),
|
||||||
SenderKey: w.requestInfo.SenderKey(),
|
SenderKey: w.requestInfo.SenderKey(),
|
||||||
Role: w.requestInfo.RequestRole(),
|
Role: w.requestInfo.RequestRole(),
|
||||||
|
SoftAPECheck: w.requestInfo.IsSoftAPECheck(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +140,7 @@ func (w *wrappedRangeStream) Context() context.Context {
|
||||||
Namespace: w.requestInfo.ContainerNamespace(),
|
Namespace: w.requestInfo.ContainerNamespace(),
|
||||||
SenderKey: w.requestInfo.SenderKey(),
|
SenderKey: w.requestInfo.SenderKey(),
|
||||||
Role: w.requestInfo.RequestRole(),
|
Role: w.requestInfo.RequestRole(),
|
||||||
|
SoftAPECheck: w.requestInfo.IsSoftAPECheck(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +164,7 @@ func (w *wrappedSearchStream) Context() context.Context {
|
||||||
Namespace: w.requestInfo.ContainerNamespace(),
|
Namespace: w.requestInfo.ContainerNamespace(),
|
||||||
SenderKey: w.requestInfo.SenderKey(),
|
SenderKey: w.requestInfo.SenderKey(),
|
||||||
Role: w.requestInfo.RequestRole(),
|
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
|
reqInfo.obj = obj
|
||||||
|
|
||||||
|
if reqInfo.IsSoftAPECheck() {
|
||||||
if !b.checker.CheckBasicACL(reqInfo) {
|
if !b.checker.CheckBasicACL(reqInfo) {
|
||||||
return basicACLErr(reqInfo)
|
return basicACLErr(reqInfo)
|
||||||
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
||||||
return eACLErr(reqInfo, err)
|
return eACLErr(reqInfo, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return b.next.Get(request, &getStreamBasicChecker{
|
return b.next.Get(request, &getStreamBasicChecker{
|
||||||
GetObjectStream: newWrappedGetObjectStreamStream(stream, reqInfo),
|
GetObjectStream: newWrappedGetObjectStreamStream(stream, reqInfo),
|
||||||
|
@ -283,11 +288,13 @@ func (b Service) Head(
|
||||||
|
|
||||||
reqInfo.obj = obj
|
reqInfo.obj = obj
|
||||||
|
|
||||||
|
if reqInfo.IsSoftAPECheck() {
|
||||||
if !b.checker.CheckBasicACL(reqInfo) {
|
if !b.checker.CheckBasicACL(reqInfo) {
|
||||||
return nil, basicACLErr(reqInfo)
|
return nil, basicACLErr(reqInfo)
|
||||||
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
||||||
return nil, eACLErr(reqInfo, err)
|
return nil, eACLErr(reqInfo, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := b.next.Head(requestContext(ctx, reqInfo), request)
|
resp, err := b.next.Head(requestContext(ctx, reqInfo), request)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -334,11 +341,13 @@ func (b Service) Search(request *objectV2.SearchRequest, stream object.SearchStr
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if reqInfo.IsSoftAPECheck() {
|
||||||
if !b.checker.CheckBasicACL(reqInfo) {
|
if !b.checker.CheckBasicACL(reqInfo) {
|
||||||
return basicACLErr(reqInfo)
|
return basicACLErr(reqInfo)
|
||||||
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
||||||
return eACLErr(reqInfo, err)
|
return eACLErr(reqInfo, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return b.next.Search(request, &searchStreamBasicChecker{
|
return b.next.Search(request, &searchStreamBasicChecker{
|
||||||
checker: b.checker,
|
checker: b.checker,
|
||||||
|
@ -392,11 +401,13 @@ func (b Service) Delete(
|
||||||
|
|
||||||
reqInfo.obj = obj
|
reqInfo.obj = obj
|
||||||
|
|
||||||
|
if reqInfo.IsSoftAPECheck() {
|
||||||
if !b.checker.CheckBasicACL(reqInfo) {
|
if !b.checker.CheckBasicACL(reqInfo) {
|
||||||
return nil, basicACLErr(reqInfo)
|
return nil, basicACLErr(reqInfo)
|
||||||
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
||||||
return nil, eACLErr(reqInfo, err)
|
return nil, eACLErr(reqInfo, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return b.next.Delete(requestContext(ctx, reqInfo), request)
|
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
|
reqInfo.obj = obj
|
||||||
|
|
||||||
|
if reqInfo.IsSoftAPECheck() {
|
||||||
if !b.checker.CheckBasicACL(reqInfo) {
|
if !b.checker.CheckBasicACL(reqInfo) {
|
||||||
return basicACLErr(reqInfo)
|
return basicACLErr(reqInfo)
|
||||||
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
||||||
return eACLErr(reqInfo, err)
|
return eACLErr(reqInfo, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return b.next.GetRange(request, &rangeStreamBasicChecker{
|
return b.next.GetRange(request, &rangeStreamBasicChecker{
|
||||||
checker: b.checker,
|
checker: b.checker,
|
||||||
|
@ -461,6 +474,7 @@ func requestContext(ctx context.Context, reqInfo RequestInfo) context.Context {
|
||||||
Namespace: reqInfo.ContainerNamespace(),
|
Namespace: reqInfo.ContainerNamespace(),
|
||||||
SenderKey: reqInfo.SenderKey(),
|
SenderKey: reqInfo.SenderKey(),
|
||||||
Role: reqInfo.RequestRole(),
|
Role: reqInfo.RequestRole(),
|
||||||
|
SoftAPECheck: reqInfo.IsSoftAPECheck(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,11 +523,13 @@ func (b Service) GetRangeHash(
|
||||||
|
|
||||||
reqInfo.obj = obj
|
reqInfo.obj = obj
|
||||||
|
|
||||||
|
if reqInfo.IsSoftAPECheck() {
|
||||||
if !b.checker.CheckBasicACL(reqInfo) {
|
if !b.checker.CheckBasicACL(reqInfo) {
|
||||||
return nil, basicACLErr(reqInfo)
|
return nil, basicACLErr(reqInfo)
|
||||||
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
} else if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
||||||
return nil, eACLErr(reqInfo, err)
|
return nil, eACLErr(reqInfo, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return b.next.GetRangeHash(requestContext(ctx, reqInfo), request)
|
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
|
reqInfo.obj = obj
|
||||||
|
|
||||||
|
if reqInfo.IsSoftAPECheck() {
|
||||||
if !b.checker.CheckBasicACL(reqInfo) || !b.checker.StickyBitCheck(reqInfo, idOwner) {
|
if !b.checker.CheckBasicACL(reqInfo) || !b.checker.StickyBitCheck(reqInfo, idOwner) {
|
||||||
return nil, basicACLErr(reqInfo)
|
return nil, basicACLErr(reqInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
if err := b.checker.CheckEACL(request, reqInfo); err != nil {
|
||||||
return nil, eACLErr(reqInfo, err)
|
return nil, eACLErr(reqInfo, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return b.next.PutSingle(requestContext(ctx, reqInfo), request)
|
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
|
reqInfo.obj = obj
|
||||||
|
|
||||||
|
if reqInfo.IsSoftAPECheck() {
|
||||||
if !p.source.checker.CheckBasicACL(reqInfo) || !p.source.checker.StickyBitCheck(reqInfo, idOwner) {
|
if !p.source.checker.CheckBasicACL(reqInfo) || !p.source.checker.StickyBitCheck(reqInfo, idOwner) {
|
||||||
return basicACLErr(reqInfo)
|
return basicACLErr(reqInfo)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx = requestContext(ctx, reqInfo)
|
ctx = requestContext(ctx, reqInfo)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,9 @@ type Prm struct {
|
||||||
|
|
||||||
// An encoded sender's public key string.
|
// An encoded sender's public key string.
|
||||||
SenderKey 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")
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ruleFound || status == apechain.Allow {
|
if !ruleFound && prm.SoftAPECheck || status == apechain.Allow {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("found denying rule for %s: %s", prm.Method, status)
|
return fmt.Errorf("method %s: %s", prm.Method, status)
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,11 +165,29 @@ func TestAPECheck(t *testing.T) {
|
||||||
container: containerID,
|
container: containerID,
|
||||||
object: stringPtr(objectID),
|
object: stringPtr(objectID),
|
||||||
methods: methodsRequiredOID,
|
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",
|
name: "oid optional requests are allowed",
|
||||||
container: containerID,
|
container: containerID,
|
||||||
methods: methodsOptionalOID,
|
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",
|
name: "oid required requests are denied",
|
||||||
|
|
|
@ -60,9 +60,13 @@ type getStreamBasicChecker struct {
|
||||||
|
|
||||||
apeChecker Checker
|
apeChecker Checker
|
||||||
|
|
||||||
|
namespace string
|
||||||
|
|
||||||
senderKey []byte
|
senderKey []byte
|
||||||
|
|
||||||
role string
|
role string
|
||||||
|
|
||||||
|
softAPECheck bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *getStreamBasicChecker) Send(resp *objectV2.GetResponse) error {
|
func (g *getStreamBasicChecker) Send(resp *objectV2.GetResponse) error {
|
||||||
|
@ -73,12 +77,14 @@ func (g *getStreamBasicChecker) Send(resp *objectV2.GetResponse) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
prm := Prm{
|
prm := Prm{
|
||||||
|
Namespace: g.namespace,
|
||||||
Container: cnrID,
|
Container: cnrID,
|
||||||
Object: objID,
|
Object: objID,
|
||||||
Header: partInit.GetHeader(),
|
Header: partInit.GetHeader(),
|
||||||
Method: nativeschema.MethodGetObject,
|
Method: nativeschema.MethodGetObject,
|
||||||
SenderKey: hex.EncodeToString(g.senderKey),
|
SenderKey: hex.EncodeToString(g.senderKey),
|
||||||
Role: g.role,
|
Role: g.role,
|
||||||
|
SoftAPECheck: g.softAPECheck,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := g.apeChecker.CheckAPE(g.Context(), prm); err != nil {
|
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,
|
Method: nativeschema.MethodGetObject,
|
||||||
Role: nativeSchemaRole(reqCtx.Role),
|
Role: nativeSchemaRole(reqCtx.Role),
|
||||||
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
||||||
|
SoftAPECheck: reqCtx.SoftAPECheck,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return toStatusErr(err)
|
return toStatusErr(err)
|
||||||
|
@ -126,6 +133,10 @@ func (c *Service) Get(request *objectV2.GetRequest, stream objectSvc.GetObjectSt
|
||||||
return c.next.Get(request, &getStreamBasicChecker{
|
return c.next.Get(request, &getStreamBasicChecker{
|
||||||
GetObjectStream: stream,
|
GetObjectStream: stream,
|
||||||
apeChecker: c.apeChecker,
|
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,
|
Method: nativeschema.MethodPutObject,
|
||||||
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
||||||
Role: nativeSchemaRole(reqCtx.Role),
|
Role: nativeSchemaRole(reqCtx.Role),
|
||||||
|
SoftAPECheck: reqCtx.SoftAPECheck,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.apeChecker.CheckAPE(ctx, prm); err != nil {
|
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,
|
Method: nativeschema.MethodHeadObject,
|
||||||
Role: nativeSchemaRole(reqCtx.Role),
|
Role: nativeSchemaRole(reqCtx.Role),
|
||||||
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
||||||
|
SoftAPECheck: reqCtx.SoftAPECheck,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -233,6 +246,7 @@ func (c *Service) Head(ctx context.Context, request *objectV2.HeadRequest) (*obj
|
||||||
Method: nativeschema.MethodHeadObject,
|
Method: nativeschema.MethodHeadObject,
|
||||||
Role: nativeSchemaRole(reqCtx.Role),
|
Role: nativeSchemaRole(reqCtx.Role),
|
||||||
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
||||||
|
SoftAPECheck: reqCtx.SoftAPECheck,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -259,6 +273,7 @@ func (c *Service) Search(request *objectV2.SearchRequest, stream objectSvc.Searc
|
||||||
Method: nativeschema.MethodSearchObject,
|
Method: nativeschema.MethodSearchObject,
|
||||||
Role: nativeSchemaRole(reqCtx.Role),
|
Role: nativeSchemaRole(reqCtx.Role),
|
||||||
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
||||||
|
SoftAPECheck: reqCtx.SoftAPECheck,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return toStatusErr(err)
|
return toStatusErr(err)
|
||||||
|
@ -285,6 +300,7 @@ func (c *Service) Delete(ctx context.Context, request *objectV2.DeleteRequest) (
|
||||||
Method: nativeschema.MethodDeleteObject,
|
Method: nativeschema.MethodDeleteObject,
|
||||||
Role: nativeSchemaRole(reqCtx.Role),
|
Role: nativeSchemaRole(reqCtx.Role),
|
||||||
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
||||||
|
SoftAPECheck: reqCtx.SoftAPECheck,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -316,6 +332,7 @@ func (c *Service) GetRange(request *objectV2.GetRangeRequest, stream objectSvc.G
|
||||||
Method: nativeschema.MethodRangeObject,
|
Method: nativeschema.MethodRangeObject,
|
||||||
Role: nativeSchemaRole(reqCtx.Role),
|
Role: nativeSchemaRole(reqCtx.Role),
|
||||||
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
||||||
|
SoftAPECheck: reqCtx.SoftAPECheck,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return toStatusErr(err)
|
return toStatusErr(err)
|
||||||
|
@ -342,6 +359,7 @@ func (c *Service) GetRangeHash(ctx context.Context, request *objectV2.GetRangeHa
|
||||||
Method: nativeschema.MethodHashObject,
|
Method: nativeschema.MethodHashObject,
|
||||||
Role: nativeSchemaRole(reqCtx.Role),
|
Role: nativeSchemaRole(reqCtx.Role),
|
||||||
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
||||||
|
SoftAPECheck: reqCtx.SoftAPECheck,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.apeChecker.CheckAPE(ctx, prm); err != nil {
|
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,
|
Method: nativeschema.MethodPutObject,
|
||||||
Role: nativeSchemaRole(reqCtx.Role),
|
Role: nativeSchemaRole(reqCtx.Role),
|
||||||
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
SenderKey: hex.EncodeToString(reqCtx.SenderKey),
|
||||||
|
SoftAPECheck: reqCtx.SoftAPECheck,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.apeChecker.CheckAPE(ctx, prm); err != nil {
|
if err = c.apeChecker.CheckAPE(ctx, prm); err != nil {
|
||||||
|
|
|
@ -13,4 +13,6 @@ type RequestContext struct {
|
||||||
SenderKey []byte
|
SenderKey []byte
|
||||||
|
|
||||||
Role acl.Role
|
Role acl.Role
|
||||||
|
|
||||||
|
SoftAPECheck bool
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue