From 8d0906c6ab5a049be0034d4f6106e4ddb7f10ccd Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Fri, 9 Sep 2022 12:09:38 +0300 Subject: [PATCH] [#1628] tree: Skip eACL filters for tree requests Do not call `CalculateAction` for the eACL checks since it requires object headers that are meaningless in the tree context. Signed-off-by: Pavel Karpy --- pkg/services/tree/signature.go | 70 +++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/pkg/services/tree/signature.go b/pkg/services/tree/signature.go index 3500d1b9..2bbf75fe 100644 --- a/pkg/services/tree/signature.go +++ b/pkg/services/tree/signature.go @@ -1,6 +1,7 @@ package tree import ( + "bytes" "crypto/ecdsa" "crypto/elliptic" "errors" @@ -97,20 +98,7 @@ func (s *Service) verifyClient(req message, cid cidSDK.ID, rawBearer []byte, op tb = *tbCore.Value } - // The default action should be DENY. - action, found := eacl.NewValidator().CalculateAction(new(eacl.ValidationUnit). - WithEACLTable(&tb). - WithContainerID(&cid). - WithRole(eACLRole(role)). - WithSenderKey(req.GetSignature().GetKey()). - WithOperation(eaclOp)) - if !found { - return eACLErr(eaclOp, errors.New("not found allowing rules for the request")) - } else if action != eacl.ActionAllow { - return eACLErr(eaclOp, errors.New("DENY eACL rule")) - } - - return nil + return checkEACL(tb, req.GetSignature().GetKey(), eACLRole(role), eaclOp) } func verifyMessage(m message) error { @@ -200,3 +188,57 @@ func eACLRole(role acl.Role) eacl.Role { panic(fmt.Sprintf("unexpected tree service ACL role: %s", role)) } } + +// checkEACL searches for the eACL rules that could be applied to the request +// (a tuple of a signer key, his NeoFS role and a request operation). +// It does not filter the request by the filters of the eACL table since tree +// requests do not contain any "object" information that could be filtered and, +// therefore, filtering leads to unexpected results. +// The code was copied with the minor updates from the SDK repo: +// https://github.com/nspcc-dev/neofs-sdk-go/blob/43a57d42dd50dc60465bfd3482f7f12bcfcf3411/eacl/validator.go#L28. +func checkEACL(tb eacl.Table, signer []byte, role eacl.Role, op eacl.Operation) error { + for _, record := range tb.Records() { + // check type of operation + if record.Operation() != op { + continue + } + + // check target + if !targetMatches(record, role, signer) { + continue + } + + switch a := record.Action(); a { + case eacl.ActionAllow: + return nil + case eacl.ActionDeny: + return eACLErr(op, errors.New("DENY eACL rule")) + default: + return eACLErr(op, fmt.Errorf("unexpected action: %s", a)) + } + } + + return eACLErr(op, errors.New("not found allowing rules for the request")) +} + +func targetMatches(rec eacl.Record, role eacl.Role, signer []byte) bool { + for _, target := range rec.Targets() { + // check public key match + if pubs := target.BinaryKeys(); len(pubs) != 0 { + for _, key := range pubs { + if bytes.Equal(key, signer) { + return true + } + } + + continue + } + + // check target group match + if role == target.Role() { + return true + } + } + + return false +}