forked from TrueCloudLab/frostfs-node
[#1425] services/tree: Remove eACL processing
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
parent
94302235d0
commit
02bb7159a5
4 changed files with 100 additions and 198 deletions
|
@ -9,10 +9,8 @@ import (
|
|||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
core "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
|
||||
|
@ -20,7 +18,6 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type message interface {
|
||||
|
@ -30,16 +27,11 @@ type message interface {
|
|||
SetSignature(*Signature)
|
||||
}
|
||||
|
||||
func basicACLErr(op acl.Op) error {
|
||||
return fmt.Errorf("access to operation %s is denied by basic ACL check", op)
|
||||
}
|
||||
|
||||
func eACLErr(op eacl.Operation, err error) error {
|
||||
return fmt.Errorf("access to operation %s is denied by extended ACL check: %w", op, err)
|
||||
}
|
||||
|
||||
var (
|
||||
errBearerWrongOwner = errors.New("bearer token must be signed by the container owner")
|
||||
errBearerWrongContainer = errors.New("bearer token is created for another container")
|
||||
errBearerSignature = errors.New("invalid bearer token signature")
|
||||
)
|
||||
|
@ -77,56 +69,7 @@ func (s *Service) verifyClient(ctx context.Context, req message, cid cidSDK.ID,
|
|||
return fmt.Errorf("can't get request role: %w", err)
|
||||
}
|
||||
|
||||
basicACL := cnr.Value.BasicACL()
|
||||
// Basic ACL mask can be unset, if a container operations are performed
|
||||
// with strict APE checks only.
|
||||
//
|
||||
// FIXME(@aarifullin): tree service temporiraly performs APE checks on
|
||||
// object verbs, because tree verbs have not been introduced yet.
|
||||
if basicACL == 0x0 {
|
||||
return s.checkAPE(ctx, bt, cnr, cid, op, role, pubKey)
|
||||
}
|
||||
|
||||
if !basicACL.IsOpAllowed(op, role) {
|
||||
return basicACLErr(op)
|
||||
}
|
||||
|
||||
if !basicACL.Extendable() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var useBearer bool
|
||||
if len(rawBearer) != 0 {
|
||||
if !basicACL.AllowedBearerRules(op) {
|
||||
s.log.Debug(logs.TreeBearerPresentedButNotAllowedByACL,
|
||||
zap.String("cid", cid.EncodeToString()),
|
||||
zap.Stringer("op", op),
|
||||
)
|
||||
} else {
|
||||
useBearer = true
|
||||
}
|
||||
}
|
||||
|
||||
var tb eacl.Table
|
||||
signer := req.GetSignature().GetKey()
|
||||
if useBearer && !bt.Impersonate() {
|
||||
if !bearer.ResolveIssuer(*bt).Equals(cnr.Value.Owner()) {
|
||||
return eACLErr(eaclOp, errBearerWrongOwner)
|
||||
}
|
||||
tb = bt.EACLTable()
|
||||
} else {
|
||||
tbCore, err := s.eaclSource.GetEACL(cid)
|
||||
if err != nil {
|
||||
return handleGetEACLError(err)
|
||||
}
|
||||
tb = *tbCore.Value
|
||||
|
||||
if useBearer && bt.Impersonate() {
|
||||
signer = bt.SigningKeyBytes()
|
||||
}
|
||||
}
|
||||
|
||||
return checkEACL(tb, signer, eACLRole(role), eaclOp)
|
||||
return s.checkAPE(ctx, bt, cnr, cid, op, role, pubKey)
|
||||
}
|
||||
|
||||
// Returns true iff the operation is read-only and request was signed
|
||||
|
@ -168,14 +111,6 @@ func parseBearer(rawBearer []byte, cid cidSDK.ID, eaclOp eacl.Operation) (*beare
|
|||
return bt, nil
|
||||
}
|
||||
|
||||
func handleGetEACLError(err error) error {
|
||||
if client.IsErrEACLNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("get eACL table: %w", err)
|
||||
}
|
||||
|
||||
func verifyMessage(m message) error {
|
||||
binBody, err := m.ReadSignedData(nil)
|
||||
if err != nil {
|
||||
|
@ -260,73 +195,3 @@ func eACLOp(op acl.Op) eacl.Operation {
|
|||
panic(fmt.Sprintf("unexpected tree service ACL operation: %s", op))
|
||||
}
|
||||
}
|
||||
|
||||
func eACLRole(role acl.Role) eacl.Role {
|
||||
switch role {
|
||||
case acl.RoleOwner:
|
||||
return eacl.RoleUser
|
||||
case acl.RoleOthers:
|
||||
return eacl.RoleOthers
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected tree service ACL role: %s", role))
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
errDENY = errors.New("DENY eACL rule")
|
||||
errNoAllowRules = errors.New("not found allowing rules for the request")
|
||||
)
|
||||
|
||||
// checkEACL searches for the eACL rules that could be applied to the request
|
||||
// (a tuple of a signer key, his FrostFS 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/frostfs-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, errDENY)
|
||||
default:
|
||||
return eACLErr(op, fmt.Errorf("unexpected action: %s", a))
|
||||
}
|
||||
}
|
||||
|
||||
return eACLErr(op, errNoAllowRules)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue