forked from TrueCloudLab/frostfs-node
[#1096] object: Make ape middleware fill request with user claim tags
Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
parent
6772976657
commit
c21d72ac23
7 changed files with 105 additions and 10 deletions
|
@ -46,6 +46,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||||
containerClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
containerClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||||
|
frostfsidClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
netmap2 "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
netmap2 "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
||||||
|
@ -415,6 +416,8 @@ type shared struct {
|
||||||
|
|
||||||
cnrClient *containerClient.Client
|
cnrClient *containerClient.Client
|
||||||
|
|
||||||
|
frostfsidClient *frostfsidClient.Client
|
||||||
|
|
||||||
respSvc *response.Service
|
respSvc *response.Service
|
||||||
|
|
||||||
replicator *replicator.Replicator
|
replicator *replicator.Replicator
|
||||||
|
|
|
@ -35,12 +35,13 @@ func initContainerService(_ context.Context, c *cfg) {
|
||||||
|
|
||||||
frostFSIDClient, err := frostfsid.NewFromMorph(c.cfgMorph.client, c.cfgFrostfsID.scriptHash, 0)
|
frostFSIDClient, err := frostfsid.NewFromMorph(c.cfgMorph.client, c.cfgFrostfsID.scriptHash, 0)
|
||||||
fatalOnErr(err)
|
fatalOnErr(err)
|
||||||
|
c.shared.frostfsidClient = frostFSIDClient
|
||||||
|
|
||||||
server := containerTransportGRPC.New(
|
server := containerTransportGRPC.New(
|
||||||
containerService.NewSignService(
|
containerService.NewSignService(
|
||||||
&c.key.PrivateKey,
|
&c.key.PrivateKey,
|
||||||
containerService.NewAPEServer(c.cfgObject.cfgAccessPolicyEngine.accessPolicyEngine, cnrRdr,
|
containerService.NewAPEServer(c.cfgObject.cfgAccessPolicyEngine.accessPolicyEngine, cnrRdr,
|
||||||
newCachedIRFetcher(createInnerRingFetcher(c)), c.netMapSource, frostFSIDClient,
|
newCachedIRFetcher(createInnerRingFetcher(c)), c.netMapSource, c.shared.frostfsidClient,
|
||||||
containerService.NewExecutionService(containerMorph.NewExecutor(cnrRdr, cnrWrt), c.respSvc),
|
containerService.NewExecutionService(containerMorph.NewExecutor(cnrRdr, cnrWrt), c.respSvc),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -444,6 +444,7 @@ func createAPEService(c *cfg, splitSvc *objectService.TransportSplitter) *object
|
||||||
objectAPE.NewChecker(
|
objectAPE.NewChecker(
|
||||||
c.cfgObject.cfgAccessPolicyEngine.accessPolicyEngine.chainRouter,
|
c.cfgObject.cfgAccessPolicyEngine.accessPolicyEngine.chainRouter,
|
||||||
objectAPE.NewStorageEngineHeaderProvider(c.cfgObject.cfgLocalStorage.localStorage),
|
objectAPE.NewStorageEngineHeaderProvider(c.cfgObject.cfgLocalStorage.localStorage),
|
||||||
|
c.shared.frostfsidClient,
|
||||||
),
|
),
|
||||||
splitSvc,
|
splitSvc,
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,6 +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"
|
||||||
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"
|
||||||
|
@ -13,19 +14,28 @@ 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 {
|
||||||
chainRouter policyengine.ChainRouter
|
chainRouter policyengine.ChainRouter
|
||||||
|
|
||||||
headerProvider HeaderProvider
|
headerProvider HeaderProvider
|
||||||
|
|
||||||
|
frostFSIDClient frostfsidSubjectProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChecker(chainRouter policyengine.ChainRouter, headerProvider HeaderProvider) Checker {
|
type frostfsidSubjectProvider interface {
|
||||||
|
GetSubject(util.Uint160) (*client.Subject, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChecker(chainRouter policyengine.ChainRouter, headerProvider HeaderProvider, frostFSIDClient frostfsidSubjectProvider) Checker {
|
||||||
return &checkerImpl{
|
return &checkerImpl{
|
||||||
chainRouter: chainRouter,
|
chainRouter: chainRouter,
|
||||||
|
|
||||||
headerProvider: headerProvider,
|
headerProvider: headerProvider,
|
||||||
|
|
||||||
|
frostFSIDClient: frostFSIDClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||||
"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"
|
||||||
|
@ -17,6 +18,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine/inmemory"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine/inmemory"
|
||||||
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"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -153,6 +155,41 @@ var (
|
||||||
senderKey = hex.EncodeToString(senderPrivateKey.PublicKey().Bytes())
|
senderKey = hex.EncodeToString(senderPrivateKey.PublicKey().Bytes())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type frostfsIDProviderMock struct {
|
||||||
|
m map[util.Uint160]*client.Subject
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ frostfsidSubjectProvider = (*frostfsIDProviderMock)(nil)
|
||||||
|
|
||||||
|
func newFrostfsIDProviderMock(t *testing.T) *frostfsIDProviderMock {
|
||||||
|
return &frostfsIDProviderMock{
|
||||||
|
m: map[util.Uint160]*client.Subject{
|
||||||
|
scriptHashFromSenderKey(t, senderKey): {
|
||||||
|
Namespace: "testnamespace",
|
||||||
|
Name: "test",
|
||||||
|
KV: map[string]string{
|
||||||
|
"tag-attr1": "value1",
|
||||||
|
"tag-attr2": "value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func scriptHashFromSenderKey(t *testing.T, senderKey string) util.Uint160 {
|
||||||
|
pk, err := keys.NewPublicKeyFromString(senderKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return pk.GetScriptHash()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *frostfsIDProviderMock) GetSubject(key util.Uint160) (*client.Subject, error) {
|
||||||
|
v, ok := f.m[key]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("%s", subjectNotFoundErrorMessage)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestAPECheck(t *testing.T) {
|
func TestAPECheck(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -321,6 +358,7 @@ func TestAPECheck(t *testing.T) {
|
||||||
for _, method := range test.methods {
|
for _, method := range test.methods {
|
||||||
t.Run(method, func(t *testing.T) {
|
t.Run(method, func(t *testing.T) {
|
||||||
headerProvider := newHeaderProviderMock()
|
headerProvider := newHeaderProviderMock()
|
||||||
|
frostfsidProvider := newFrostfsIDProviderMock(t)
|
||||||
|
|
||||||
cnr := newContainerIDSDK(t, test.container)
|
cnr := newContainerIDSDK(t, test.container)
|
||||||
obj := newObjectIDSDK(t, test.object)
|
obj := newObjectIDSDK(t, test.object)
|
||||||
|
@ -335,7 +373,7 @@ func TestAPECheck(t *testing.T) {
|
||||||
|
|
||||||
router := policyengine.NewDefaultChainRouterWithLocalOverrides(ms, ls)
|
router := policyengine.NewDefaultChainRouterWithLocalOverrides(ms, ls)
|
||||||
|
|
||||||
checker := NewChecker(router, headerProvider)
|
checker := NewChecker(router, headerProvider, frostfsidProvider)
|
||||||
|
|
||||||
prm := Prm{
|
prm := Prm{
|
||||||
Method: method,
|
Method: method,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
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"
|
||||||
|
@ -12,7 +13,13 @@ import (
|
||||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
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"
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
subjectNotFoundErrorMessage = "subject not found"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultRequest = aperequest.Request{}
|
var defaultRequest = aperequest.Request{}
|
||||||
|
@ -115,15 +122,45 @@ func (c *checkerImpl) newAPERequest(ctx context.Context, prm Prm) (aperequest.Re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reqProps := map[string]string{
|
||||||
|
nativeschema.PropertyKeyActorPublicKey: prm.SenderKey,
|
||||||
|
nativeschema.PropertyKeyActorRole: prm.Role,
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
reqProps, err = c.fillWithUserClaimTags(reqProps, prm)
|
||||||
|
if err != nil {
|
||||||
|
return defaultRequest, err
|
||||||
|
}
|
||||||
|
|
||||||
return aperequest.NewRequest(
|
return aperequest.NewRequest(
|
||||||
prm.Method,
|
prm.Method,
|
||||||
aperequest.NewResource(
|
aperequest.NewResource(
|
||||||
resourceName(prm.Container, prm.Object, prm.Namespace),
|
resourceName(prm.Container, prm.Object, prm.Namespace),
|
||||||
objectProperties(prm.Container, prm.Object, prm.ContainerOwner, header),
|
objectProperties(prm.Container, prm.Object, prm.ContainerOwner, header),
|
||||||
),
|
),
|
||||||
map[string]string{
|
reqProps,
|
||||||
nativeschema.PropertyKeyActorPublicKey: prm.SenderKey,
|
|
||||||
nativeschema.PropertyKeyActorRole: prm.Role,
|
|
||||||
},
|
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fillWithUserClaimTags fills ape request properties with user claim tags getting them from frostfsid contract by actor public key.
|
||||||
|
func (c *checkerImpl) fillWithUserClaimTags(reqProps map[string]string, prm Prm) (map[string]string, error) {
|
||||||
|
if reqProps == nil {
|
||||||
|
reqProps = make(map[string]string)
|
||||||
|
}
|
||||||
|
pk, err := keys.NewPublicKeyFromString(prm.SenderKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
subj, err := c.frostFSIDClient.GetSubject(pk.GetScriptHash())
|
||||||
|
if err != nil {
|
||||||
|
if !strings.Contains(err.Error(), subjectNotFoundErrorMessage) {
|
||||||
|
return nil, fmt.Errorf("get subject error: %w", err)
|
||||||
|
}
|
||||||
|
return reqProps, nil
|
||||||
|
}
|
||||||
|
for k, v := range subj.KV {
|
||||||
|
properyKey := fmt.Sprintf(commonschema.PropertyKeyFormatFrostFSIDUserClaim, k)
|
||||||
|
reqProps[properyKey] = v
|
||||||
|
}
|
||||||
|
return reqProps, nil
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
|
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
|
||||||
|
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/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -234,6 +235,7 @@ func TestNewAPERequest(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
headerSource := newHeaderProviderMock()
|
headerSource := newHeaderProviderMock()
|
||||||
|
ffidProvider := newFrostfsIDProviderMock(t)
|
||||||
|
|
||||||
var headerObjSDK *objectSDK.Object
|
var headerObjSDK *objectSDK.Object
|
||||||
if test.header.headerObjSDK != nil {
|
if test.header.headerObjSDK != nil {
|
||||||
|
@ -247,7 +249,8 @@ func TestNewAPERequest(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c := checkerImpl{
|
c := checkerImpl{
|
||||||
headerProvider: headerSource,
|
headerProvider: headerSource,
|
||||||
|
frostFSIDClient: ffidProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := c.newAPERequest(context.TODO(), prm)
|
r, err := c.newAPERequest(context.TODO(), prm)
|
||||||
|
@ -268,8 +271,10 @@ func TestNewAPERequest(t *testing.T) {
|
||||||
return prm.Header
|
return prm.Header
|
||||||
}())),
|
}())),
|
||||||
map[string]string{
|
map[string]string{
|
||||||
nativeschema.PropertyKeyActorPublicKey: prm.SenderKey,
|
nativeschema.PropertyKeyActorPublicKey: prm.SenderKey,
|
||||||
nativeschema.PropertyKeyActorRole: prm.Role,
|
nativeschema.PropertyKeyActorRole: prm.Role,
|
||||||
|
fmt.Sprintf(commonschema.PropertyKeyFormatFrostFSIDUserClaim, "tag-attr1"): "value1",
|
||||||
|
fmt.Sprintf(commonschema.PropertyKeyFormatFrostFSIDUserClaim, "tag-attr2"): "value2",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue