Compare commits
2 commits
master
...
fix/tree_r
Author | SHA1 | Date | |
---|---|---|---|
6919c7c17f | |||
37ebd45f3d |
2 changed files with 208 additions and 1 deletions
207
pkg/services/tree/ape_test.go
Normal file
207
pkg/services/tree/ape_test.go
Normal file
|
@ -0,0 +1,207 @@
|
|||
package tree
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||
core "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||
frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
|
||||
checkercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/common/ape"
|
||||
containerSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"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"
|
||||
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
containerID = "73tQMTYyUkTgmvPR1HWib6pndbhSoBovbnMF7Pws8Rcy"
|
||||
|
||||
senderPrivateKey, _ = keys.NewPrivateKey()
|
||||
|
||||
senderKey = hex.EncodeToString(senderPrivateKey.PublicKey().Bytes())
|
||||
|
||||
rootCnr = &core.Container{Value: containerSDK.Container{}}
|
||||
)
|
||||
|
||||
type frostfsIDProviderMock struct {
|
||||
subjects map[util.Uint160]*client.Subject
|
||||
subjectsExtended map[util.Uint160]*client.SubjectExtended
|
||||
}
|
||||
|
||||
func (f *frostfsIDProviderMock) GetSubject(key util.Uint160) (*client.Subject, error) {
|
||||
v, ok := f.subjects[key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s", frostfsidcore.SubjectNotFoundErrorMessage)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (f *frostfsIDProviderMock) GetSubjectExtended(key util.Uint160) (*client.SubjectExtended, error) {
|
||||
v, ok := f.subjectsExtended[key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s", frostfsidcore.SubjectNotFoundErrorMessage)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
var _ frostfsidcore.SubjectProvider = (*frostfsIDProviderMock)(nil)
|
||||
|
||||
func newFrostfsIDProviderMock(t *testing.T) *frostfsIDProviderMock {
|
||||
return &frostfsIDProviderMock{
|
||||
subjects: map[util.Uint160]*client.Subject{
|
||||
scriptHashFromSenderKey(t, senderKey): {
|
||||
Namespace: "testnamespace",
|
||||
Name: "test",
|
||||
KV: map[string]string{
|
||||
"tag-attr1": "value1",
|
||||
"tag-attr2": "value2",
|
||||
},
|
||||
},
|
||||
},
|
||||
subjectsExtended: map[util.Uint160]*client.SubjectExtended{
|
||||
scriptHashFromSenderKey(t, senderKey): {
|
||||
Namespace: "testnamespace",
|
||||
Name: "test",
|
||||
KV: map[string]string{
|
||||
"tag-attr1": "value1",
|
||||
"tag-attr2": "value2",
|
||||
},
|
||||
Groups: []*client.Group{
|
||||
{
|
||||
ID: 1,
|
||||
Name: "test",
|
||||
Namespace: "testnamespace",
|
||||
KV: map[string]string{
|
||||
"attr1": "value1",
|
||||
"attr2": "value2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func scriptHashFromSenderKey(t *testing.T, senderKey string) util.Uint160 {
|
||||
pk, err := keys.NewPublicKeyFromString(senderKey)
|
||||
require.NoError(t, err)
|
||||
return pk.GetScriptHash()
|
||||
}
|
||||
|
||||
type stMock struct{}
|
||||
|
||||
func (m *stMock) CurrentEpoch() uint64 {
|
||||
return 8
|
||||
}
|
||||
|
||||
func TestCheckAPE(t *testing.T) {
|
||||
cid := cid.ID{}
|
||||
_ = cid.DecodeString(containerID)
|
||||
|
||||
t.Run("put non-tombstone rule won't affect tree remove", func(t *testing.T) {
|
||||
los := inmemory.NewInmemoryLocalStorage()
|
||||
mcs := inmemory.NewInmemoryMorphRuleChainStorage()
|
||||
fid := newFrostfsIDProviderMock(t)
|
||||
s := Service{
|
||||
cfg: cfg{
|
||||
frostfsidSubjectProvider: fid,
|
||||
},
|
||||
apeChecker: checkercore.New(los, mcs, fid, &stMock{}),
|
||||
}
|
||||
|
||||
los.AddOverride(chain.Ingress, engine.ContainerTarget(containerID), &chain.Chain{
|
||||
Rules: []chain.Rule{
|
||||
{
|
||||
Status: chain.AccessDenied,
|
||||
Actions: chain.Actions{Names: []string{nativeschema.MethodPutObject}},
|
||||
Resources: chain.Resources{
|
||||
Names: []string{fmt.Sprintf(nativeschema.ResourceFormatRootContainerObjects, containerID)},
|
||||
},
|
||||
Condition: []chain.Condition{
|
||||
{
|
||||
Op: chain.CondStringNotEquals,
|
||||
Kind: chain.KindResource,
|
||||
Key: nativeschema.PropertyKeyObjectType,
|
||||
Value: "TOMBSTONE",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchType: chain.MatchTypeFirstMatch,
|
||||
})
|
||||
|
||||
mcs.AddMorphRuleChain(chain.Ingress, engine.ContainerTarget(containerID), &chain.Chain{
|
||||
Rules: []chain.Rule{
|
||||
{
|
||||
Status: chain.Allow,
|
||||
Actions: chain.Actions{Names: []string{nativeschema.MethodDeleteObject}},
|
||||
Resources: chain.Resources{
|
||||
Names: []string{fmt.Sprintf(nativeschema.ResourceFormatRootContainerObjects, containerID)},
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchType: chain.MatchTypeFirstMatch,
|
||||
})
|
||||
|
||||
err := s.checkAPE(context.Background(), nil, rootCnr, cid, acl.OpObjectDelete, acl.RoleOwner, senderPrivateKey.PublicKey())
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("delete rule won't affect tree add", func(t *testing.T) {
|
||||
los := inmemory.NewInmemoryLocalStorage()
|
||||
mcs := inmemory.NewInmemoryMorphRuleChainStorage()
|
||||
fid := newFrostfsIDProviderMock(t)
|
||||
s := Service{
|
||||
cfg: cfg{
|
||||
frostfsidSubjectProvider: fid,
|
||||
},
|
||||
apeChecker: checkercore.New(los, mcs, fid, &stMock{}),
|
||||
}
|
||||
|
||||
los.AddOverride(chain.Ingress, engine.ContainerTarget(containerID), &chain.Chain{
|
||||
Rules: []chain.Rule{
|
||||
{
|
||||
Status: chain.AccessDenied,
|
||||
Actions: chain.Actions{Names: []string{nativeschema.MethodDeleteObject}},
|
||||
Resources: chain.Resources{
|
||||
Names: []string{fmt.Sprintf(nativeschema.ResourceFormatRootContainerObjects, containerID)},
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchType: chain.MatchTypeFirstMatch,
|
||||
})
|
||||
|
||||
mcs.AddMorphRuleChain(chain.Ingress, engine.ContainerTarget(containerID), &chain.Chain{
|
||||
Rules: []chain.Rule{
|
||||
{
|
||||
Status: chain.Allow,
|
||||
Actions: chain.Actions{Names: []string{nativeschema.MethodPutObject}},
|
||||
Resources: chain.Resources{
|
||||
Names: []string{fmt.Sprintf(nativeschema.ResourceFormatRootContainerObjects, containerID)},
|
||||
},
|
||||
Condition: []chain.Condition{
|
||||
{
|
||||
Op: chain.CondStringNotEquals,
|
||||
Kind: chain.KindResource,
|
||||
Key: nativeschema.PropertyKeyObjectType,
|
||||
Value: "TOMBSTONE",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MatchType: chain.MatchTypeFirstMatch,
|
||||
})
|
||||
|
||||
err := s.checkAPE(context.Background(), nil, rootCnr, cid, acl.OpObjectPut, acl.RoleOwner, senderPrivateKey.PublicKey())
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
|
@ -228,7 +228,7 @@ func (s *Service) Remove(ctx context.Context, req *RemoveRequest) (*RemoveRespon
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err := s.verifyClient(ctx, req, cid, b.GetBearerToken(), acl.OpObjectPut)
|
||||
err := s.verifyClient(ctx, req, cid, b.GetBearerToken(), acl.OpObjectDelete)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue