feature/269-cache_frostfsid #333

Merged
alexvanin merged 4 commits from dkirillov/frostfs-s3-gw:feature/269-cache_frostfsid into master 2024-09-04 19:51:13 +00:00
15 changed files with 339 additions and 98 deletions

View file

@ -29,6 +29,7 @@ This document outlines major changes between releases.
- Authmate: support custom attributes (#292)
- Add new `reconnect_interval` config param (#291)
- Support `GetBucketPolicyStatus` (#301)
- Add FrostfsID cache (#269)
### Changed
- Generalise config param `use_default_xmlns_for_complete_multipart` to `use_default_xmlns` so that use default xmlns for all requests (#221)

View file

@ -3,10 +3,13 @@ package cache
import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"go.uber.org/zap/zaptest/observer"
@ -194,6 +197,44 @@ func TestNotificationConfigurationCacheType(t *testing.T) {
assertInvalidCacheEntry(t, cache.GetNotificationConfiguration(key), observedLog)
}
func TestFrostFSIDSubjectCacheType(t *testing.T) {
logger, observedLog := getObservedLogger()
cache := NewFrostfsIDCache(DefaultFrostfsIDConfig(logger))
key, err := util.Uint160DecodeStringLE("4ea976429703418ef00fc4912a409b6a0b973034")
require.NoError(t, err)
value := &client.SubjectExtended{}
err = cache.PutSubject(key, value)
require.NoError(t, err)
val := cache.GetSubject(key)
require.Equal(t, value, val)
require.Equal(t, 0, observedLog.Len())
err = cache.cache.Set(key, "tmp")
require.NoError(t, err)
assertInvalidCacheEntry(t, cache.GetSubject(key), observedLog)
}
func TestFrostFSIDUserKeyCacheType(t *testing.T) {
logger, observedLog := getObservedLogger()
cache := NewFrostfsIDCache(DefaultFrostfsIDConfig(logger))
ns, name := "ns", "name"
value, err := keys.NewPrivateKey()
require.NoError(t, err)
err = cache.PutUserKey(ns, name, value.PublicKey())
require.NoError(t, err)
val := cache.GetUserKey(ns, name)
require.Equal(t, value.PublicKey(), val)
require.Equal(t, 0, observedLog.Len())
err = cache.cache.Set(ns+"/"+name, "tmp")
require.NoError(t, err)
assertInvalidCacheEntry(t, cache.GetUserKey(ns, name), observedLog)
}
func assertInvalidCacheEntry(t *testing.T, val interface{}, observedLog *observer.ObservedLogs) {
require.Nil(t, val)
require.Equal(t, 1, observedLog.Len())

77
api/cache/frostfsid.go vendored Normal file
View file

@ -0,0 +1,77 @@
package cache
import (
"fmt"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"github.com/bluele/gcache"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util"
"go.uber.org/zap"
)
// FrostfsIDCache provides lru cache for frostfsid contract.
type FrostfsIDCache struct {
cache gcache.Cache
logger *zap.Logger
}
const (
// DefaultFrostfsIDCacheSize is a default maximum number of entries in cache.
DefaultFrostfsIDCacheSize = 1e4
Review

Seems to be unused

Seems to be unused
// DefaultFrostfsIDCacheLifetime is a default lifetime of entries in cache.
DefaultFrostfsIDCacheLifetime = time.Minute
)
// DefaultFrostfsIDConfig returns new default cache expiration values.
func DefaultFrostfsIDConfig(logger *zap.Logger) *Config {
return &Config{
Size: DefaultFrostfsIDCacheSize,
Lifetime: DefaultFrostfsIDCacheLifetime,
Logger: logger,
}
}
// NewFrostfsIDCache creates an object of FrostfsIDCache.
func NewFrostfsIDCache(config *Config) *FrostfsIDCache {
gc := gcache.New(config.Size).LRU().Expiration(config.Lifetime).Build()
return &FrostfsIDCache{cache: gc, logger: config.Logger}
}
// GetSubject returns a cached client.SubjectExtended. Returns nil if value is missing.
func (c *FrostfsIDCache) GetSubject(key util.Uint160) *client.SubjectExtended {
return get[client.SubjectExtended](c, key)
}
// PutSubject puts a client.SubjectExtended to cache.
func (c *FrostfsIDCache) PutSubject(key util.Uint160, subject *client.SubjectExtended) error {
return c.cache.Set(key, subject)
}
// GetUserKey returns a cached *keys.PublicKey. Returns nil if value is missing.
func (c *FrostfsIDCache) GetUserKey(ns, name string) *keys.PublicKey {
return get[keys.PublicKey](c, ns+"/"+name)
}
// PutUserKey puts a client.SubjectExtended to cache.
func (c *FrostfsIDCache) PutUserKey(ns, name string, userKey *keys.PublicKey) error {
return c.cache.Set(ns+"/"+name, userKey)
}
func get[T any](c *FrostfsIDCache, key any) *T {
entry, err := c.cache.Get(key)
if err != nil {
return nil
}
result, ok := entry.(*T)
if !ok {
c.logger.Warn(logs.InvalidCacheEntryType, zap.String("actual", fmt.Sprintf("%T", entry)),
zap.String("expected", fmt.Sprintf("%T", result)))
return nil
}
return result
}

View file

@ -82,11 +82,6 @@ type FrostFS interface {
TimeToEpoch(context.Context, time.Time) (uint64, uint64, error)
}
// FrostFSID represents interface to interact with frostfsid contract.
type FrostFSID interface {
RegisterPublicKey(ns string, key *keys.PublicKey) error
}
// Agent contains client communicating with FrostFS and logger.
type Agent struct {
frostFS FrostFS

View file

@ -8,7 +8,7 @@ import (
"time"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -170,7 +170,7 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
if rpcAddress == "" {
return wrapPreparationError(fmt.Errorf("you can use '%s' flag only along with '%s'", frostfsIDFlag, rpcEndpointFlag))
}
cfg := frostfsid.Config{
cfg := contract.Config{
RPCAddress: rpcAddress,
Contract: frostFSID,
ProxyContract: viper.GetString(frostfsIDProxyFlag),
@ -182,7 +182,7 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
return wrapFrostFSIDInitError(err)
}
if err = frostfsIDClient.RegisterPublicKey(viper.GetString(frostfsIDNamespaceFlag), key.PublicKey()); err != nil {
if err = registerPublicKey(frostfsIDClient, viper.GetString(frostfsIDNamespaceFlag), key.PublicKey()); err != nil {
return wrapBusinessLogicError(fmt.Errorf("failed to register key in frostfsid: %w", err))
}
}

View file

@ -7,7 +7,7 @@ import (
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -106,7 +106,7 @@ func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error {
if rpcAddress == "" {
return wrapPreparationError(fmt.Errorf("you can use '%s' flag only along with '%s'", frostfsIDFlag, rpcEndpointFlag))
}
cfg := frostfsid.Config{
cfg := contract.Config{
RPCAddress: rpcAddress,
Contract: frostFSID,
ProxyContract: viper.GetString(frostfsIDProxyFlag),
@ -118,7 +118,7 @@ func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error {
return wrapFrostFSIDInitError(err)
}
if err = frostfsIDClient.RegisterPublicKey(viper.GetString(frostfsIDNamespaceFlag), key.PublicKey()); err != nil {
if err = registerPublicKey(frostfsIDClient, viper.GetString(frostfsIDNamespaceFlag), key.PublicKey()); err != nil {
return wrapBusinessLogicError(fmt.Errorf("failed to register key in frostfsid: %w", err))
}
}

View file

@ -11,7 +11,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
@ -145,10 +145,10 @@ func getLogger() *zap.Logger {
return log
}
func createFrostFSID(ctx context.Context, log *zap.Logger, cfg frostfsid.Config) (authmate.FrostFSID, error) {
func createFrostFSID(ctx context.Context, log *zap.Logger, cfg contract.Config) (*contract.FrostFSID, error) {
log.Debug(logs.PrepareFrostfsIDClient)
cli, err := frostfsid.New(ctx, cfg)
cli, err := contract.New(ctx, cfg)
if err != nil {
return nil, fmt.Errorf("create frostfsid client: %w", err)
}
@ -156,6 +156,15 @@ func createFrostFSID(ctx context.Context, log *zap.Logger, cfg frostfsid.Config)
return cli, nil
}
func registerPublicKey(cli *contract.FrostFSID, namespace string, key *keys.PublicKey) error {
err := cli.Wait(cli.CreateSubject(namespace, key))
if err != nil && !strings.Contains(err.Error(), "subject already exists") {
return err
}
return nil
}
func parseObjectAttrs(attributes string) ([]object.Attribute, error) {
if len(attributes) == 0 {
return nil, nil

View file

@ -30,6 +30,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
ffidcontract "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy/contract"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services"
@ -457,8 +458,7 @@ func (a *App) initMetrics() {
}
func (a *App) initFrostfsID(ctx context.Context) {
var err error
a.frostfsid, err = frostfsid.New(ctx, frostfsid.Config{
cli, err := ffidcontract.New(ctx, ffidcontract.Config{
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
Contract: a.cfg.GetString(cfgFrostfsIDContract),
ProxyContract: a.cfg.GetString(cfgProxyContract),
@ -467,6 +467,15 @@ func (a *App) initFrostfsID(ctx context.Context) {
if err != nil {
a.log.Fatal(logs.InitFrostfsIDContractFailed, zap.Error(err))
}
a.frostfsid, err = frostfsid.NewFrostFSID(frostfsid.Config{
Cache: cache.NewFrostfsIDCache(getFrostfsIDCacheConfig(a.cfg, a.log)),
FrostFSID: cli,
Logger: a.log,
})
if err != nil {
a.log.Fatal(logs.InitFrostfsIDContractFailed, zap.Error(err))
}
}
func (a *App) initPolicyStorage(ctx context.Context) {
@ -958,6 +967,15 @@ func getMorphPolicyCacheConfig(v *viper.Viper, l *zap.Logger) *cache.Config {
return cacheCfg
}
func getFrostfsIDCacheConfig(v *viper.Viper, l *zap.Logger) *cache.Config {
cacheCfg := cache.DefaultFrostfsIDConfig(l)
cacheCfg.Lifetime = fetchCacheLifetime(v, l, cfgFrostfsIDCacheLifetime, cacheCfg.Lifetime)
cacheCfg.Size = fetchCacheSize(v, l, cfgFrostfsIDCacheSize, cacheCfg.Size)
return cacheCfg
}
func (a *App) initHandler() {
var err error

View file

@ -116,6 +116,8 @@ const ( // Settings.
cfgAccessControlCacheSize = "cache.accesscontrol.size"
cfgMorphPolicyCacheLifetime = "cache.morph_policy.lifetime"
cfgMorphPolicyCacheSize = "cache.morph_policy.size"
cfgFrostfsIDCacheLifetime = "cache.frostfsid.lifetime"
cfgFrostfsIDCacheSize = "cache.frostfsid.size"
cfgAccessBoxCacheRemovingCheckInterval = "cache.accessbox.removing_check_interval"

View file

@ -107,6 +107,9 @@ S3_GW_CACHE_ACCESSCONTROL_SIZE=100000
# Cache which stores list of policy chains
S3_GW_CACHE_MORPH_POLICY_LIFETIME=1m
S3_GW_CACHE_MORPH_POLICY_SIZE=10000
# Cache which stores frostfsid subject info
S3_GW_CACHE_FROSTFSID_LIFETIME=1m
S3_GW_CACHE_FROSTFSID_SIZE=10000
# NATS
S3_GW_NATS_ENABLED=true

View file

@ -131,6 +131,10 @@ cache:
morph_policy:
lifetime: 1m
size: 10000
# Cache which stores frostfsid subject info
frostfsid:
lifetime: 1m
size: 10000
nats:
enabled: true

View file

@ -421,6 +421,9 @@ cache:
morph_policy:
lifetime: 30s
size: 10000
frostfsid:
lifetime: 1m
size: 10000
```
| Parameter | Type | Default value | Description |
@ -434,6 +437,7 @@ cache:
| `accessbox` | [Accessbox cache config](#accessbox-subsection) | `lifetime: 10m`<br>`size: 100` | Cache which stores access box with tokens by its address. |
| `accesscontrol` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 100000` | Cache which stores owner to cache operation mapping. |
| `morph_policy` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 10000` | Cache which stores list of policy chains. |
| `frostfsid` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 10000` | Cache which stores FrostfsID subject info. |
#### `cache` subsection

View file

@ -0,0 +1,84 @@
package contract
import (
"context"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
)
type FrostFSID struct {
cli *client.Client
}
type Config struct {
// RPCAddress is an endpoint to connect to neo rpc.
RPCAddress string
// Contract is hash of contract or its name in NNS.
Contract string
// ProxyContract is hash of proxy contract or its name in NNS to interact with frostfsid.
ProxyContract string
// Key is used to interact with frostfsid contract.
// If this is nil than random key will be generated.
Key *keys.PrivateKey
}
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
if err != nil {
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
}
key := cfg.Key
if key == nil {
if key, err = keys.NewPrivateKey(); err != nil {
return nil, fmt.Errorf("generate anon private key for frostfsid: %w", err)
}
}
rpcCli, err := rpcclient.New(ctx, cfg.RPCAddress, rpcclient.Options{})
if err != nil {
return nil, fmt.Errorf("init rpc client: %w", err)
}
var opt client.Options
opt.ProxyContract, err = frostfsutil.ResolveContractHash(cfg.ProxyContract, cfg.RPCAddress)
if err != nil {
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
}
cli, err := client.New(rpcCli, wallet.NewAccountFromPrivateKey(key), contractHash, opt)
if err != nil {
return nil, fmt.Errorf("init frostfsid client: %w", err)
}
return &FrostFSID{
cli: cli,
}, nil
}
func (f *FrostFSID) GetSubjectExtended(userHash util.Uint160) (*client.SubjectExtended, error) {
return f.cli.GetSubjectExtended(userHash)
}
func (f *FrostFSID) GetSubjectKeyByName(namespace, name string) (*keys.PublicKey, error) {
return f.cli.GetSubjectKeyByName(namespace, name)
}
func (f *FrostFSID) CreateSubject(namespace string, key *keys.PublicKey) (util.Uint256, uint32, error) {
return f.cli.CreateSubject(namespace, key)
}
func (f *FrostFSID) Wait(tx util.Uint256, vub uint32, err error) error {
_, err = f.cli.Wait(tx, vub, err)
return err
}

View file

@ -1,128 +1,128 @@
package frostfsid
import (
"context"
"encoding/hex"
"fmt"
"errors"
"strconv"
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"go.uber.org/zap"
)
type FrostFSID struct {
cli *client.Client
frostfsid *contract.FrostFSID
cache *cache.FrostfsIDCache
log *zap.Logger
}
type Config struct {
// RPCAddress is an endpoint to connect to neo rpc.
RPCAddress string
// Contract is hash of contract or its name in NNS.
Contract string
// ProxyContract is hash of proxy contract or its name in NNS to interact with frostfsid.
ProxyContract string
// Key is used to interact with frostfsid contract.
// If this is nil than random key will be generated.
Key *keys.PrivateKey
Cache *cache.FrostfsIDCache
FrostFSID *contract.FrostFSID
Logger *zap.Logger
}
var (
_ api.FrostFSID = (*FrostFSID)(nil)
_ authmate.FrostFSID = (*FrostFSID)(nil)
_ handler.FrostFSID = (*FrostFSID)(nil)
_ api.FrostFSID = (*FrostFSID)(nil)
_ handler.FrostFSID = (*FrostFSID)(nil)
)
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
if err != nil {
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
}
key := cfg.Key
if key == nil {
if key, err = keys.NewPrivateKey(); err != nil {
return nil, fmt.Errorf("generate anon private key for frostfsid: %w", err)
}
}
rpcCli, err := rpcclient.New(ctx, cfg.RPCAddress, rpcclient.Options{})
if err != nil {
return nil, fmt.Errorf("init rpc client: %w", err)
}
var opt client.Options
opt.ProxyContract, err = frostfsutil.ResolveContractHash(cfg.ProxyContract, cfg.RPCAddress)
if err != nil {
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
}
cli, err := client.New(rpcCli, wallet.NewAccountFromPrivateKey(key), contractHash, opt)
if err != nil {
return nil, fmt.Errorf("init frostfsid client: %w", err)
// NewFrostFSID creates new FrostfsID wrapper.
func NewFrostFSID(cfg Config) (*FrostFSID, error) {
switch {
case cfg.FrostFSID == nil:
return nil, errors.New("missing frostfsid client")
case cfg.Cache == nil:
return nil, errors.New("missing frostfsid cache")
case cfg.Logger == nil:
return nil, errors.New("missing frostfsid logger")
}
return &FrostFSID{
cli: cli,
frostfsid: cfg.FrostFSID,
cache: cfg.Cache,
log: cfg.Logger,
}, nil
}
func (f *FrostFSID) ValidatePublicKey(key *keys.PublicKey) error {
_, err := f.cli.GetSubjectByKey(key)
_, err := f.getSubject(key.GetScriptHash())
return err
}
func (f *FrostFSID) RegisterPublicKey(ns string, key *keys.PublicKey) error {
_, err := f.cli.Wait(f.cli.CreateSubject(ns, key))
if err != nil && !strings.Contains(err.Error(), "subject already exists") {
return err
}
return nil
}
func (f *FrostFSID) GetUserAddress(namespace, name string) (string, error) {
key, err := f.cli.GetSubjectKeyByName(namespace, name)
if err != nil {
return "", err
}
return key.Address(), nil
}
func (f *FrostFSID) GetUserKey(account, name string) (string, error) {
key, err := f.cli.GetSubjectKeyByName(account, name)
if err != nil {
return "", err
}
return hex.EncodeToString(key.Bytes()), nil
}
func (f *FrostFSID) GetUserGroupIDs(userHash util.Uint160) ([]string, error) {
subjExt, err := f.cli.GetSubjectExtended(userHash)
subj, err := f.getSubject(userHash)
if err != nil {
if strings.Contains(err.Error(), "not found") {
f.log.Debug(logs.UserGroupsListIsEmpty, zap.Error(err))
return nil, nil
}
return nil, err
}
res := make([]string, len(subjExt.Groups))
for i, group := range subjExt.Groups {
res := make([]string, len(subj.Groups))
for i, group := range subj.Groups {
res[i] = strconv.FormatInt(group.ID, 10)
}
return res, nil
}
func (f *FrostFSID) getSubject(addr util.Uint160) (*client.SubjectExtended, error) {
if subj := f.cache.GetSubject(addr); subj != nil {
return subj, nil
}
subj, err := f.frostfsid.GetSubjectExtended(addr)
if err != nil {
return nil, err
}
if err = f.cache.PutSubject(addr, subj); err != nil {
f.log.Warn(logs.CouldntCacheSubject, zap.Error(err))
}
return subj, nil
}
func (f *FrostFSID) GetUserAddress(namespace, name string) (string, error) {
userKey, err := f.getUserKey(namespace, name)
if err != nil {
return "", err
}
return userKey.Address(), nil
}
func (f *FrostFSID) GetUserKey(namespace, name string) (string, error) {
userKey, err := f.getUserKey(namespace, name)
if err != nil {
return "", err
}
return hex.EncodeToString(userKey.Bytes()), nil
}
func (f *FrostFSID) getUserKey(namespace, name string) (*keys.PublicKey, error) {
if userKey := f.cache.GetUserKey(namespace, name); userKey != nil {
return userKey, nil
}
userKey, err := f.frostfsid.GetSubjectKeyByName(namespace, name)
if err != nil {
return nil, err
}
if err = f.cache.PutUserKey(namespace, name, userKey); err != nil {
f.log.Warn(logs.CouldntCacheUserKey, zap.Error(err))
}
return userKey, nil
}

View file

@ -154,4 +154,7 @@ const (
FailedToWriteResponse = "failed to write response"
WarnDuplicateAddress = "duplicate address"
PolicyCouldntBeConvertedToNativeRules = "policy couldn't be converted to native rules, only s3 rules be applied"
CouldntCacheSubject = "couldn't cache subject info"
UserGroupsListIsEmpty = "user groups list is empty, subject not found"
CouldntCacheUserKey = "couldn't cache user key"
)