[#1117] core: Introduce SubjectProvider interface for FrostfsID

* Make tree, object and container services use SubjectProvider interface.
* Fix unit-tests.

Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
Airat Arifullin 2024-05-02 20:26:06 +03:00 committed by Evgenii Stratonikov
parent 45f4e6939d
commit 6c76c9b457
10 changed files with 85 additions and 47 deletions

View file

@ -1,4 +1,4 @@
package ape package request
import ( import (
aperesource "git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource" aperesource "git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource"

View file

@ -0,0 +1,16 @@
package frostfsid
import (
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
"github.com/nspcc-dev/neo-go/pkg/util"
)
const (
SubjectNotFoundErrorMessage = "subject not found"
)
// SubjectProvider interface provides methods to get subject from FrostfsID contract.
type SubjectProvider interface {
GetSubject(util.Uint160) (*client.Subject, error)
GetSubjectExtended(util.Uint160) (*client.SubjectExtended, error)
}

View file

@ -3,6 +3,7 @@ package frostfsid
import ( import (
"fmt" "fmt"
frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
@ -20,6 +21,8 @@ type Client struct {
client *client.StaticClient // static FrostFS ID contract client client *client.StaticClient // static FrostFS ID contract client
} }
var _ frostfsidcore.SubjectProvider = (*Client)(nil)
// NewFromMorph wraps client to work with FrostFS ID contract. // NewFromMorph wraps client to work with FrostFS ID contract.
func NewFromMorph(cli *client.Client, contract util.Uint160, fee fixedn.Fixed8) (*Client, error) { func NewFromMorph(cli *client.Client, contract util.Uint160, fee fixedn.Fixed8) (*Client, error) {
sc, err := client.NewStatic(cli, contract, fee, client.TryNotary(), client.AsAlphabet()) sc, err := client.NewStatic(cli, contract, fee, client.TryNotary(), client.AsAlphabet())

View file

@ -14,9 +14,9 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request" aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request"
containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container" containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-observability/tracing" "git.frostfs.info/TrueCloudLab/frostfs-observability/tracing"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
@ -30,11 +30,6 @@ import (
commonschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/common" commonschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/common"
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native" 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/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util"
)
const (
subjectNotFoundErrorMessage = "subject not found"
) )
var ( var (
@ -59,22 +54,18 @@ type containers interface {
Get(cid.ID) (*containercore.Container, error) Get(cid.ID) (*containercore.Container, error)
} }
type frostfsidSubjectProvider interface {
GetSubject(util.Uint160) (*client.Subject, error)
}
type apeChecker struct { type apeChecker struct {
router policyengine.ChainRouter router policyengine.ChainRouter
reader containers reader containers
ir ir ir ir
nm netmap.Source nm netmap.Source
frostFSIDClient frostfsidSubjectProvider frostFSIDClient frostfsidcore.SubjectProvider
next Server next Server
} }
func NewAPEServer(router policyengine.ChainRouter, reader containers, ir ir, nm netmap.Source, frostFSIDClient frostfsidSubjectProvider, srv Server) Server { func NewAPEServer(router policyengine.ChainRouter, reader containers, ir ir, nm netmap.Source, frostFSIDClient frostfsidcore.SubjectProvider, srv Server) Server {
return &apeChecker{ return &apeChecker{
router: router, router: router,
reader: reader, reader: reader,
@ -574,7 +565,7 @@ func (ac *apeChecker) namespaceByOwner(owner *refs.OwnerID) (string, error) {
if err == nil { if err == nil {
namespace = subject.Namespace namespace = subject.Namespace
} else { } else {
if !strings.Contains(err.Error(), subjectNotFoundErrorMessage) { if !strings.Contains(err.Error(), frostfsidcore.SubjectNotFoundErrorMessage) {
return "", fmt.Errorf("get subject error: %w", err) return "", fmt.Errorf("get subject error: %w", err)
} }
} }
@ -630,7 +621,7 @@ func (ac *apeChecker) fillWithUserClaimTags(reqProps map[string]string, pk *keys
} }
subj, err := ac.frostFSIDClient.GetSubject(pk.GetScriptHash()) subj, err := ac.frostFSIDClient.GetSubject(pk.GetScriptHash())
if err != nil { if err != nil {
if !strings.Contains(err.Error(), subjectNotFoundErrorMessage) { if !strings.Contains(err.Error(), frostfsidcore.SubjectNotFoundErrorMessage) {
return nil, fmt.Errorf("get subject error: %w", err) return nil, fmt.Errorf("get subject error: %w", err)
} }
return reqProps, nil return reqProps, nil

View file

@ -15,6 +15,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client" "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"
frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cnrSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" cnrSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
@ -922,13 +923,22 @@ func (s *netmapStub) Epoch() (uint64, error) {
} }
type frostfsidStub struct { type frostfsidStub struct {
subjects map[util.Uint160]*client.Subject subjects map[util.Uint160]*client.Subject
subjectsExt map[util.Uint160]*client.SubjectExtended
} }
func (f *frostfsidStub) GetSubject(owner util.Uint160) (*client.Subject, error) { func (f *frostfsidStub) GetSubject(owner util.Uint160) (*client.Subject, error) {
s, ok := f.subjects[owner] s, ok := f.subjects[owner]
if !ok { if !ok {
return nil, fmt.Errorf("%s", subjectNotFoundErrorMessage) return nil, fmt.Errorf("%s", frostfsidcore.SubjectNotFoundErrorMessage)
}
return s, nil
}
func (f *frostfsidStub) GetSubjectExtended(owner util.Uint160) (*client.SubjectExtended, error) {
s, ok := f.subjectsExt[owner]
if !ok {
return nil, fmt.Errorf("%s", frostfsidcore.SubjectNotFoundErrorMessage)
} }
return s, nil return s, nil
} }
@ -965,7 +975,8 @@ func newTestAPEServer() testAPEServer {
netmap := &netmapStub{} netmap := &netmapStub{}
frostfsIDSubjectReader := &frostfsidStub{ frostfsIDSubjectReader := &frostfsidStub{
subjects: map[util.Uint160]*client.Subject{}, subjects: map[util.Uint160]*client.Subject{},
subjectsExt: map[util.Uint160]*client.SubjectExtended{},
} }
apeChecker := &apeChecker{ apeChecker := &apeChecker{

View file

@ -6,7 +6,7 @@ import (
"fmt" "fmt"
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client" frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
@ -14,7 +14,6 @@ import (
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine" policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native" 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/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util"
) )
type checkerImpl struct { type checkerImpl struct {
@ -22,14 +21,10 @@ type checkerImpl struct {
headerProvider HeaderProvider headerProvider HeaderProvider
frostFSIDClient frostfsidSubjectProvider frostFSIDClient frostfsidcore.SubjectProvider
} }
type frostfsidSubjectProvider interface { func NewChecker(chainRouter policyengine.ChainRouter, headerProvider HeaderProvider, frostFSIDClient frostfsidcore.SubjectProvider) Checker {
GetSubject(util.Uint160) (*client.Subject, error)
}
func NewChecker(chainRouter policyengine.ChainRouter, headerProvider HeaderProvider, frostFSIDClient frostfsidSubjectProvider) Checker {
return &checkerImpl{ return &checkerImpl{
chainRouter: chainRouter, chainRouter: chainRouter,

View file

@ -7,6 +7,7 @@ import (
"testing" "testing"
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client" "git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
@ -156,14 +157,15 @@ var (
) )
type frostfsIDProviderMock struct { type frostfsIDProviderMock struct {
m map[util.Uint160]*client.Subject subjects map[util.Uint160]*client.Subject
subjectsExtended map[util.Uint160]*client.SubjectExtended
} }
var _ frostfsidSubjectProvider = (*frostfsIDProviderMock)(nil) var _ frostfsidcore.SubjectProvider = (*frostfsIDProviderMock)(nil)
func newFrostfsIDProviderMock(t *testing.T) *frostfsIDProviderMock { func newFrostfsIDProviderMock(t *testing.T) *frostfsIDProviderMock {
return &frostfsIDProviderMock{ return &frostfsIDProviderMock{
m: map[util.Uint160]*client.Subject{ subjects: map[util.Uint160]*client.Subject{
scriptHashFromSenderKey(t, senderKey): { scriptHashFromSenderKey(t, senderKey): {
Namespace: "testnamespace", Namespace: "testnamespace",
Name: "test", Name: "test",
@ -173,6 +175,27 @@ func newFrostfsIDProviderMock(t *testing.T) *frostfsIDProviderMock {
}, },
}, },
}, },
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",
},
},
},
},
},
} }
} }
@ -183,9 +206,17 @@ func scriptHashFromSenderKey(t *testing.T, senderKey string) util.Uint160 {
} }
func (f *frostfsIDProviderMock) GetSubject(key util.Uint160) (*client.Subject, error) { func (f *frostfsIDProviderMock) GetSubject(key util.Uint160) (*client.Subject, error) {
v, ok := f.m[key] v, ok := f.subjects[key]
if !ok { if !ok {
return nil, fmt.Errorf("%s", subjectNotFoundErrorMessage) 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 return v, nil
} }

View file

@ -8,6 +8,7 @@ import (
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request" aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request"
frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
"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"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
@ -18,10 +19,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
) )
const (
subjectNotFoundErrorMessage = "subject not found"
)
var defaultRequest = aperequest.Request{} var defaultRequest = aperequest.Request{}
func nativeSchemaRole(role acl.Role) string { func nativeSchemaRole(role acl.Role) string {
@ -153,7 +150,7 @@ func (c *checkerImpl) fillWithUserClaimTags(reqProps map[string]string, prm Prm)
} }
subj, err := c.frostFSIDClient.GetSubject(pk.GetScriptHash()) subj, err := c.frostFSIDClient.GetSubject(pk.GetScriptHash())
if err != nil { if err != nil {
if !strings.Contains(err.Error(), subjectNotFoundErrorMessage) { if !strings.Contains(err.Error(), frostfsidcore.SubjectNotFoundErrorMessage) {
return nil, fmt.Errorf("get subject error: %w", err) return nil, fmt.Errorf("get subject error: %w", err)
} }
return reqProps, nil return reqProps, nil

View file

@ -8,6 +8,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/converter" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/converter"
aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request" aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request"
core "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container" core "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cnrSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" cnrSDK "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"
@ -19,8 +20,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
) )
var subjectNotFoundErrorMessage = "subject not found"
func (s *Service) checkAPE(container *core.Container, cid cid.ID, operation acl.Op, role acl.Role, publicKey *keys.PublicKey) error { func (s *Service) checkAPE(container *core.Container, cid cid.ID, operation acl.Op, role acl.Role, publicKey *keys.PublicKey) error {
namespace := "" namespace := ""
cntNamespace, hasNamespace := strings.CutSuffix(cnrSDK.ReadDomain(container.Value).Zone(), ".ns") cntNamespace, hasNamespace := strings.CutSuffix(cnrSDK.ReadDomain(container.Value).Zone(), ".ns")
@ -83,7 +82,7 @@ func (s *Service) fillWithUserClaimTags(reqProps map[string]string, publicKey *k
} }
subj, err := s.frostfsidSubjectProvider.GetSubject(publicKey.GetScriptHash()) subj, err := s.frostfsidSubjectProvider.GetSubject(publicKey.GetScriptHash())
if err != nil { if err != nil {
if !strings.Contains(err.Error(), subjectNotFoundErrorMessage) { if !strings.Contains(err.Error(), frostfsidcore.SubjectNotFoundErrorMessage) {
return nil, fmt.Errorf("get subject error: %w", err) return nil, fmt.Errorf("get subject error: %w", err)
} }
return reqProps, nil return reqProps, nil

View file

@ -4,21 +4,16 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"time" "time"
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/pilorama" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/pilorama"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine" policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
"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"
) )
type FrostfsidSubjectProvider interface {
GetSubject(util.Uint160) (*client.Subject, error)
}
type ContainerSource interface { type ContainerSource interface {
container.Source container.Source
@ -36,7 +31,7 @@ type cfg struct {
rawPub []byte rawPub []byte
nmSource netmap.Source nmSource netmap.Source
cnrSource ContainerSource cnrSource ContainerSource
frostfsidSubjectProvider FrostfsidSubjectProvider frostfsidSubjectProvider frostfsidcore.SubjectProvider
eaclSource container.EACLSource eaclSource container.EACLSource
forest pilorama.Forest forest pilorama.Forest
// replication-related parameters // replication-related parameters
@ -62,7 +57,7 @@ func WithContainerSource(src ContainerSource) Option {
} }
} }
func WithFrostfsidSubjectProvider(provider FrostfsidSubjectProvider) Option { func WithFrostfsidSubjectProvider(provider frostfsidcore.SubjectProvider) Option {
return func(c *cfg) { return func(c *cfg) {
c.frostfsidSubjectProvider = provider c.frostfsidSubjectProvider = provider
} }