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/morph/client"
|
||||
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"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
netmap2 "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
||||
|
@ -415,6 +416,8 @@ type shared struct {
|
|||
|
||||
cnrClient *containerClient.Client
|
||||
|
||||
frostfsidClient *frostfsidClient.Client
|
||||
|
||||
respSvc *response.Service
|
||||
|
||||
replicator *replicator.Replicator
|
||||
|
|
|
@ -35,12 +35,13 @@ func initContainerService(_ context.Context, c *cfg) {
|
|||
|
||||
frostFSIDClient, err := frostfsid.NewFromMorph(c.cfgMorph.client, c.cfgFrostfsID.scriptHash, 0)
|
||||
fatalOnErr(err)
|
||||
c.shared.frostfsidClient = frostFSIDClient
|
||||
|
||||
server := containerTransportGRPC.New(
|
||||
containerService.NewSignService(
|
||||
&c.key.PrivateKey,
|
||||
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),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -444,6 +444,7 @@ func createAPEService(c *cfg, splitSvc *objectService.TransportSplitter) *object
|
|||
objectAPE.NewChecker(
|
||||
c.cfgObject.cfgAccessPolicyEngine.accessPolicyEngine.chainRouter,
|
||||
objectAPE.NewStorageEngineHeaderProvider(c.cfgObject.cfgLocalStorage.localStorage),
|
||||
c.shared.frostfsidClient,
|
||||
),
|
||||
splitSvc,
|
||||
)
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
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"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
|
@ -13,19 +14,28 @@ import (
|
|||
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
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"
|
||||
)
|
||||
|
||||
type checkerImpl struct {
|
||||
chainRouter policyengine.ChainRouter
|
||||
|
||||
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{
|
||||
chainRouter: chainRouter,
|
||||
|
||||
headerProvider: headerProvider,
|
||||
|
||||
frostFSIDClient: frostFSIDClient,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
|
@ -17,6 +18,7 @@ import (
|
|||
"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"
|
||||
)
|
||||
|
||||
|
@ -153,6 +155,41 @@ var (
|
|||
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) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
|
@ -321,6 +358,7 @@ func TestAPECheck(t *testing.T) {
|
|||
for _, method := range test.methods {
|
||||
t.Run(method, func(t *testing.T) {
|
||||
headerProvider := newHeaderProviderMock()
|
||||
frostfsidProvider := newFrostfsIDProviderMock(t)
|
||||
|
||||
cnr := newContainerIDSDK(t, test.container)
|
||||
obj := newObjectIDSDK(t, test.object)
|
||||
|
@ -335,7 +373,7 @@ func TestAPECheck(t *testing.T) {
|
|||
|
||||
router := policyengine.NewDefaultChainRouterWithLocalOverrides(ms, ls)
|
||||
|
||||
checker := NewChecker(router, headerProvider)
|
||||
checker := NewChecker(router, headerProvider, frostfsidProvider)
|
||||
|
||||
prm := Prm{
|
||||
Method: method,
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
||||
aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request"
|
||||
|
@ -12,7 +13,13 @@ import (
|
|||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"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"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
)
|
||||
|
||||
const (
|
||||
subjectNotFoundErrorMessage = "subject not found"
|
||||
)
|
||||
|
||||
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(
|
||||
prm.Method,
|
||||
aperequest.NewResource(
|
||||
resourceName(prm.Container, prm.Object, prm.Namespace),
|
||||
objectProperties(prm.Container, prm.Object, prm.ContainerOwner, header),
|
||||
),
|
||||
map[string]string{
|
||||
nativeschema.PropertyKeyActorPublicKey: prm.SenderKey,
|
||||
nativeschema.PropertyKeyActorRole: prm.Role,
|
||||
},
|
||||
reqProps,
|
||||
), 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"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
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"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -234,6 +235,7 @@ func TestNewAPERequest(t *testing.T) {
|
|||
}
|
||||
|
||||
headerSource := newHeaderProviderMock()
|
||||
ffidProvider := newFrostfsIDProviderMock(t)
|
||||
|
||||
var headerObjSDK *objectSDK.Object
|
||||
if test.header.headerObjSDK != nil {
|
||||
|
@ -247,7 +249,8 @@ func TestNewAPERequest(t *testing.T) {
|
|||
}
|
||||
|
||||
c := checkerImpl{
|
||||
headerProvider: headerSource,
|
||||
headerProvider: headerSource,
|
||||
frostFSIDClient: ffidProvider,
|
||||
}
|
||||
|
||||
r, err := c.newAPERequest(context.TODO(), prm)
|
||||
|
@ -268,8 +271,10 @@ func TestNewAPERequest(t *testing.T) {
|
|||
return prm.Header
|
||||
}())),
|
||||
map[string]string{
|
||||
nativeschema.PropertyKeyActorPublicKey: prm.SenderKey,
|
||||
nativeschema.PropertyKeyActorRole: prm.Role,
|
||||
nativeschema.PropertyKeyActorPublicKey: prm.SenderKey,
|
||||
nativeschema.PropertyKeyActorRole: prm.Role,
|
||||
fmt.Sprintf(commonschema.PropertyKeyFormatFrostFSIDUserClaim, "tag-attr1"): "value1",
|
||||
fmt.Sprintf(commonschema.PropertyKeyFormatFrostFSIDUserClaim, "tag-attr2"): "value2",
|
||||
},
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in a new issue