[#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
|
@ -54,7 +54,6 @@ func initTreeService(c *cfg) {
|
||||||
cli: c.shared.cnrClient,
|
cli: c.shared.cnrClient,
|
||||||
}),
|
}),
|
||||||
tree.WithFrostfsidSubjectProvider(c.shared.frostfsidClient),
|
tree.WithFrostfsidSubjectProvider(c.shared.frostfsidClient),
|
||||||
tree.WithEACLSource(c.cfgObject.eaclSource),
|
|
||||||
tree.WithNetmapSource(c.netMapSource),
|
tree.WithNetmapSource(c.netMapSource),
|
||||||
tree.WithPrivateKey(&c.key.PrivateKey),
|
tree.WithPrivateKey(&c.key.PrivateKey),
|
||||||
tree.WithLogger(c.log),
|
tree.WithLogger(c.log),
|
||||||
|
|
|
@ -33,7 +33,6 @@ type cfg struct {
|
||||||
nmSource netmap.Source
|
nmSource netmap.Source
|
||||||
cnrSource ContainerSource
|
cnrSource ContainerSource
|
||||||
frostfsidSubjectProvider frostfsidcore.SubjectProvider
|
frostfsidSubjectProvider frostfsidcore.SubjectProvider
|
||||||
eaclSource container.EACLSource
|
|
||||||
forest pilorama.Forest
|
forest pilorama.Forest
|
||||||
// replication-related parameters
|
// replication-related parameters
|
||||||
replicatorChannelCapacity int
|
replicatorChannelCapacity int
|
||||||
|
@ -65,14 +64,6 @@ func WithFrostfsidSubjectProvider(provider frostfsidcore.SubjectProvider) Option
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithEACLSource sets a eACL table source for a tree service.
|
|
||||||
// This option is required.
|
|
||||||
func WithEACLSource(src container.EACLSource) Option {
|
|
||||||
return func(c *cfg) {
|
|
||||||
c.eaclSource = src
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithNetmapSource sets a netmap source for a tree service.
|
// WithNetmapSource sets a netmap source for a tree service.
|
||||||
// This option is required.
|
// This option is required.
|
||||||
func WithNetmapSource(src netmap.Source) Option {
|
func WithNetmapSource(src netmap.Source) Option {
|
||||||
|
|
|
@ -9,10 +9,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
"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"
|
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/bearer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||||
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
|
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/eacl"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type message interface {
|
type message interface {
|
||||||
|
@ -30,16 +27,11 @@ type message interface {
|
||||||
SetSignature(*Signature)
|
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 {
|
func eACLErr(op eacl.Operation, err error) error {
|
||||||
return fmt.Errorf("access to operation %s is denied by extended ACL check: %w", op, err)
|
return fmt.Errorf("access to operation %s is denied by extended ACL check: %w", op, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errBearerWrongOwner = errors.New("bearer token must be signed by the container owner")
|
|
||||||
errBearerWrongContainer = errors.New("bearer token is created for another container")
|
errBearerWrongContainer = errors.New("bearer token is created for another container")
|
||||||
errBearerSignature = errors.New("invalid bearer token signature")
|
errBearerSignature = errors.New("invalid bearer token signature")
|
||||||
)
|
)
|
||||||
|
@ -77,58 +69,9 @@ func (s *Service) verifyClient(ctx context.Context, req message, cid cidSDK.ID,
|
||||||
return fmt.Errorf("can't get request role: %w", err)
|
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)
|
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true iff the operation is read-only and request was signed
|
// Returns true iff the operation is read-only and request was signed
|
||||||
// with one of the authorized keys.
|
// with one of the authorized keys.
|
||||||
func (s *Service) isAuthorized(req message, op acl.Op) (bool, error) {
|
func (s *Service) isAuthorized(req message, op acl.Op) (bool, error) {
|
||||||
|
@ -168,14 +111,6 @@ func parseBearer(rawBearer []byte, cid cidSDK.ID, eaclOp eacl.Operation) (*beare
|
||||||
return bt, nil
|
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 {
|
func verifyMessage(m message) error {
|
||||||
binBody, err := m.ReadSignedData(nil)
|
binBody, err := m.ReadSignedData(nil)
|
||||||
if err != 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))
|
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,22 +4,30 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
aclV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
aclV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||||
containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
||||||
|
checkercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/common/ape"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
||||||
eaclSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
|
||||||
netmapSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
netmapSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine/inmemory"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,6 +35,34 @@ type dummyNetmapSource struct {
|
||||||
netmap.Source
|
netmap.Source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type dummySubjectProvider struct {
|
||||||
|
subjects map[util.Uint160]client.SubjectExtended
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s dummySubjectProvider) GetSubject(addr util.Uint160) (*client.Subject, error) {
|
||||||
|
res := s.subjects[addr]
|
||||||
|
return &client.Subject{
|
||||||
|
PrimaryKey: res.PrimaryKey,
|
||||||
|
AdditionalKeys: res.AdditionalKeys,
|
||||||
|
Namespace: res.Namespace,
|
||||||
|
Name: res.Name,
|
||||||
|
KV: res.KV,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s dummySubjectProvider) GetSubjectExtended(addr util.Uint160) (*client.SubjectExtended, error) {
|
||||||
|
res := s.subjects[addr]
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type dummyEpochSource struct {
|
||||||
|
epoch uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s dummyEpochSource) CurrentEpoch() uint64 {
|
||||||
|
return s.epoch
|
||||||
|
}
|
||||||
|
|
||||||
type dummyContainerSource map[string]*containercore.Container
|
type dummyContainerSource map[string]*containercore.Container
|
||||||
|
|
||||||
func (s dummyContainerSource) List() ([]cid.ID, error) {
|
func (s dummyContainerSource) List() ([]cid.ID, error) {
|
||||||
|
@ -57,16 +93,6 @@ func (s dummyContainerSource) DeletionInfo(id cid.ID) (*containercore.DelInfo, e
|
||||||
return &containercore.DelInfo{}, nil
|
return &containercore.DelInfo{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type dummyEACLSource map[string]*containercore.EACL
|
|
||||||
|
|
||||||
func (s dummyEACLSource) GetEACL(id cid.ID) (*containercore.EACL, error) {
|
|
||||||
cntEACL, ok := s[id.String()]
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("container not found")
|
|
||||||
}
|
|
||||||
return cntEACL, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func testContainer(owner user.ID) container.Container {
|
func testContainer(owner user.ID) container.Container {
|
||||||
var r netmapSDK.ReplicaDescriptor
|
var r netmapSDK.ReplicaDescriptor
|
||||||
r.SetNumberOfObjects(1)
|
r.SetNumberOfObjects(1)
|
||||||
|
@ -81,6 +107,8 @@ func testContainer(owner user.ID) container.Container {
|
||||||
return cnt
|
return cnt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentEpoch = 123
|
||||||
|
|
||||||
func TestMessageSign(t *testing.T) {
|
func TestMessageSign(t *testing.T) {
|
||||||
privs := make([]*keys.PrivateKey, 4)
|
privs := make([]*keys.PrivateKey, 4)
|
||||||
for i := range privs {
|
for i := range privs {
|
||||||
|
@ -99,6 +127,15 @@ func TestMessageSign(t *testing.T) {
|
||||||
Value: testContainer(ownerID),
|
Value: testContainer(ownerID),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e := inmemory.NewInMemoryLocalOverrides()
|
||||||
|
e.MorphRuleChainStorage().AddMorphRuleChain(chain.Ingress, engine.Target{
|
||||||
|
Type: engine.Container,
|
||||||
|
Name: cid1.EncodeToString(),
|
||||||
|
}, testChain(privs[0].PublicKey(), privs[1].PublicKey()))
|
||||||
|
frostfsidProvider := dummySubjectProvider{
|
||||||
|
subjects: make(map[util.Uint160]client.SubjectExtended),
|
||||||
|
}
|
||||||
|
|
||||||
s := &Service{
|
s := &Service{
|
||||||
cfg: cfg{
|
cfg: cfg{
|
||||||
log: test.NewLogger(t),
|
log: test.NewLogger(t),
|
||||||
|
@ -107,12 +144,10 @@ func TestMessageSign(t *testing.T) {
|
||||||
cnrSource: dummyContainerSource{
|
cnrSource: dummyContainerSource{
|
||||||
cid1.String(): cnr,
|
cid1.String(): cnr,
|
||||||
},
|
},
|
||||||
eaclSource: dummyEACLSource{
|
frostfsidSubjectProvider: frostfsidProvider,
|
||||||
cid1.String(): &containercore.EACL{
|
state: dummyEpochSource{epoch: currentEpoch},
|
||||||
Value: testTable(cid1, privs[0].PublicKey(), privs[1].PublicKey()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
apeChecker: checkercore.New(e.LocalStorage(), e.MorphRuleChainStorage(), frostfsidProvider, dummyEpochSource{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
rawCID1 := make([]byte, sha256.Size)
|
rawCID1 := make([]byte, sha256.Size)
|
||||||
|
@ -235,46 +270,58 @@ func TestMessageSign(t *testing.T) {
|
||||||
|
|
||||||
func testBearerToken(cid cid.ID, forPutGet, forGet *keys.PublicKey) bearer.Token {
|
func testBearerToken(cid cid.ID, forPutGet, forGet *keys.PublicKey) bearer.Token {
|
||||||
var b bearer.Token
|
var b bearer.Token
|
||||||
b.SetEACLTable(*testTable(cid, forPutGet, forGet))
|
b.SetExp(currentEpoch + 1)
|
||||||
|
b.SetAPEOverride(bearer.APEOverride{
|
||||||
|
Target: ape.ChainTarget{
|
||||||
|
TargetType: ape.TargetTypeContainer,
|
||||||
|
Name: cid.EncodeToString(),
|
||||||
|
},
|
||||||
|
Chains: []ape.Chain{{Raw: testChain(forPutGet, forGet).Bytes()}},
|
||||||
|
})
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func testTable(cid cid.ID, forPutGet, forGet *keys.PublicKey) *eaclSDK.Table {
|
func testChain(forPutGet, forGet *keys.PublicKey) *chain.Chain {
|
||||||
tgtGet := eaclSDK.NewTarget()
|
ruleGet := chain.Rule{
|
||||||
tgtGet.SetRole(eaclSDK.RoleUnknown)
|
Status: chain.Allow,
|
||||||
tgtGet.SetBinaryKeys([][]byte{forPutGet.Bytes(), forGet.Bytes()})
|
Resources: chain.Resources{Names: []string{native.ResourceFormatAllObjects}},
|
||||||
|
Actions: chain.Actions{Names: []string{native.MethodGetObject}},
|
||||||
rGet := eaclSDK.NewRecord()
|
Any: true,
|
||||||
rGet.SetAction(eaclSDK.ActionAllow)
|
Condition: []chain.Condition{
|
||||||
rGet.SetOperation(eaclSDK.OperationGet)
|
{
|
||||||
rGet.SetTargets(*tgtGet)
|
Op: chain.CondStringEquals,
|
||||||
|
Kind: chain.KindRequest,
|
||||||
tgtPut := eaclSDK.NewTarget()
|
Key: native.PropertyKeyActorPublicKey,
|
||||||
tgtPut.SetRole(eaclSDK.RoleUnknown)
|
Value: hex.EncodeToString(forPutGet.Bytes()),
|
||||||
tgtPut.SetBinaryKeys([][]byte{forPutGet.Bytes()})
|
},
|
||||||
|
{
|
||||||
rPut := eaclSDK.NewRecord()
|
Op: chain.CondStringEquals,
|
||||||
rPut.SetAction(eaclSDK.ActionAllow)
|
Kind: chain.KindRequest,
|
||||||
rPut.SetOperation(eaclSDK.OperationPut)
|
Key: native.PropertyKeyActorPublicKey,
|
||||||
rPut.SetTargets(*tgtPut)
|
Value: hex.EncodeToString(forGet.Bytes()),
|
||||||
|
},
|
||||||
tb := eaclSDK.NewTable()
|
},
|
||||||
tb.AddRecord(rGet)
|
}
|
||||||
tb.AddRecord(rPut)
|
rulePut := chain.Rule{
|
||||||
|
Status: chain.Allow,
|
||||||
tgt := eaclSDK.NewTarget()
|
Resources: chain.Resources{Names: []string{native.ResourceFormatAllObjects}},
|
||||||
tgt.SetRole(eaclSDK.RoleOthers)
|
Actions: chain.Actions{Names: []string{native.MethodPutObject}},
|
||||||
|
Any: true,
|
||||||
for _, op := range []eaclSDK.Operation{eaclSDK.OperationGet, eaclSDK.OperationPut} {
|
Condition: []chain.Condition{
|
||||||
r := eaclSDK.NewRecord()
|
{
|
||||||
r.SetAction(eaclSDK.ActionDeny)
|
Op: chain.CondStringEquals,
|
||||||
r.SetTargets(*tgt)
|
Kind: chain.KindRequest,
|
||||||
r.SetOperation(op)
|
Key: native.PropertyKeyActorPublicKey,
|
||||||
tb.AddRecord(r)
|
Value: hex.EncodeToString(forPutGet.Bytes()),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
tb.SetCID(cid)
|
return &chain.Chain{
|
||||||
|
Rules: []chain.Rule{
|
||||||
return tb
|
ruleGet,
|
||||||
|
rulePut,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue