[#159] Add object context to session tokens

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-02-21 14:30:30 +03:00 committed by Alex Vanin
parent 70c3644e2b
commit 61f9c3392b

View file

@ -15,6 +15,7 @@ import (
"time" "time"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
sessionv2 "github.com/nspcc-dev/neofs-api-go/v2/session"
"github.com/nspcc-dev/neofs-sdk-go/accounting" "github.com/nspcc-dev/neofs-sdk-go/accounting"
"github.com/nspcc-dev/neofs-sdk-go/client" "github.com/nspcc-dev/neofs-sdk-go/client"
"github.com/nspcc-dev/neofs-sdk-go/container" "github.com/nspcc-dev/neofs-sdk-go/container"
@ -182,6 +183,8 @@ type CallOption func(config *callConfig)
type callConfig struct { type callConfig struct {
useDefaultSession bool useDefaultSession bool
verb sessionv2.ObjectSessionVerb
addr *address.Address
key *ecdsa.PrivateKey key *ecdsa.PrivateKey
btoken *token.BearerToken btoken *token.BearerToken
@ -212,6 +215,18 @@ func useDefaultSession() CallOption {
} }
} }
func useAddress(addr *address.Address) CallOption {
return func(config *callConfig) {
config.addr = addr
}
}
func useVerb(verb sessionv2.ObjectSessionVerb) CallOption {
return func(config *callConfig) {
config.verb = verb
}
}
func cfgFromOpts(opts ...CallOption) *callConfig { func cfgFromOpts(opts ...CallOption) *callConfig {
var cfg = new(callConfig) var cfg = new(callConfig)
for _, opt := range opts { for _, opt := range opts {
@ -283,12 +298,8 @@ func newPool(ctx context.Context, options *BuilderOptions) (Pool, error) {
} else if err == nil { } else if err == nil {
healthy, atLeastOneHealthy = true, true healthy, atLeastOneHealthy = true, true
st := sessionTokenForOwner(ownerID, cliRes) st := sessionTokenForOwner(ownerID, cliRes)
// sign the session token and cache it on success
if err = st.Sign(options.Key); err == nil {
_ = cache.Put(formCacheKey(addr, options.Key), st) _ = cache.Put(formCacheKey(addr, options.Key), st)
} }
}
clientPacks[j] = &clientPack{client: c, healthy: healthy, address: addr} clientPacks[j] = &clientPack{client: c, healthy: healthy, address: addr}
} }
source := rand.NewSource(time.Now().UnixNano()) source := rand.NewSource(time.Now().UnixNano())
@ -580,6 +591,7 @@ type callContext struct {
// flag to open default session if session token is missing // flag to open default session if session token is missing
sessionDefault bool sessionDefault bool
sessionTarget func(session.Token) sessionTarget func(session.Token)
sessionContext *session.ObjectContext
} }
func (p *pool) initCallContext(ctx *callContext, cfg *callConfig) error { func (p *pool) initCallContext(ctx *callContext, cfg *callConfig) error {
@ -603,6 +615,11 @@ func (p *pool) initCallContext(ctx *callContext, cfg *callConfig) error {
// note that we don't override session provided by the caller // note that we don't override session provided by the caller
ctx.sessionDefault = cfg.stoken == nil && cfg.useDefaultSession ctx.sessionDefault = cfg.stoken == nil && cfg.useDefaultSession
if ctx.sessionDefault {
ctx.sessionContext = session.NewObjectContext()
ctx.sessionContext.ToV2().SetVerb(cfg.verb)
ctx.sessionContext.ApplyTo(cfg.addr)
}
return err return err
} }
@ -631,12 +648,7 @@ func (p *pool) openDefaultSession(ctx *callContext) error {
cacheKey := formCacheKey(ctx.endpoint, ctx.key) cacheKey := formCacheKey(ctx.endpoint, ctx.key)
tok := p.cache.Get(cacheKey) tok := p.cache.Get(cacheKey)
if tok != nil { if tok == nil {
// use cached token
ctx.sessionTarget(*tok)
return nil
}
// open new session // open new session
cliRes, err := createSessionTokenForDuration(ctx, ctx.client, p.stokenDuration) cliRes, err := createSessionTokenForDuration(ctx, ctx.client, p.stokenDuration)
if err != nil { if err != nil {
@ -644,17 +656,19 @@ func (p *pool) openDefaultSession(ctx *callContext) error {
} }
tok = sessionTokenForOwner(owner.NewIDFromPublicKey(&ctx.key.PublicKey), cliRes) tok = sessionTokenForOwner(owner.NewIDFromPublicKey(&ctx.key.PublicKey), cliRes)
// cache the opened session
p.cache.Put(cacheKey, tok)
}
tokToSign := *tok
tokToSign.SetContext(ctx.sessionContext)
// sign the token // sign the token
err = tok.Sign(ctx.key) if err := tokToSign.Sign(ctx.key); err != nil {
if err != nil {
return fmt.Errorf("sign token of the opened session: %w", err) return fmt.Errorf("sign token of the opened session: %w", err)
} }
// cache the opened session ctx.sessionTarget(tokToSign)
p.cache.Put(cacheKey, tok)
ctx.sessionTarget(*tok)
return nil return nil
} }
@ -685,7 +699,10 @@ func (p *pool) callWithRetry(ctx *callContextWithRetry, f func() error) error {
} }
func (p *pool) PutObject(ctx context.Context, hdr object.Object, payload io.Reader, opts ...CallOption) (*oid.ID, error) { func (p *pool) PutObject(ctx context.Context, hdr object.Object, payload io.Reader, opts ...CallOption) (*oid.ID, error) {
cfg := cfgFromOpts(append(opts, useDefaultSession())...) cfg := cfgFromOpts(append(opts,
useDefaultSession(),
useVerb(sessionv2.ObjectVerbPut),
useAddress(newAddressFromCnrID(hdr.ContainerID())))...)
// Put object is different from other object service methods. Put request // Put object is different from other object service methods. Put request
// can't be resent in case of session token failures (i.e. session token is // can't be resent in case of session token failures (i.e. session token is
@ -791,7 +808,10 @@ func (p *pool) PutObject(ctx context.Context, hdr object.Object, payload io.Read
} }
func (p *pool) DeleteObject(ctx context.Context, addr address.Address, opts ...CallOption) error { func (p *pool) DeleteObject(ctx context.Context, addr address.Address, opts ...CallOption) error {
cfg := cfgFromOpts(append(opts, useDefaultSession())...) cfg := cfgFromOpts(append(opts,
useDefaultSession(),
useVerb(sessionv2.ObjectVerbDelete),
useAddress(&addr))...)
var prm client.PrmObjectDelete var prm client.PrmObjectDelete
@ -843,7 +863,10 @@ type ResGetObject struct {
} }
func (p *pool) GetObject(ctx context.Context, addr address.Address, opts ...CallOption) (*ResGetObject, error) { func (p *pool) GetObject(ctx context.Context, addr address.Address, opts ...CallOption) (*ResGetObject, error) {
cfg := cfgFromOpts(append(opts, useDefaultSession())...) cfg := cfgFromOpts(append(opts,
useDefaultSession(),
useVerb(sessionv2.ObjectVerbGet),
useAddress(&addr))...)
var prm client.PrmObjectGet var prm client.PrmObjectGet
@ -892,7 +915,10 @@ func (p *pool) GetObject(ctx context.Context, addr address.Address, opts ...Call
} }
func (p *pool) HeadObject(ctx context.Context, addr address.Address, opts ...CallOption) (*object.Object, error) { func (p *pool) HeadObject(ctx context.Context, addr address.Address, opts ...CallOption) (*object.Object, error) {
cfg := cfgFromOpts(append(opts, useDefaultSession())...) cfg := cfgFromOpts(append(opts,
useDefaultSession(),
useVerb(sessionv2.ObjectVerbHead),
useAddress(&addr))...)
var prm client.PrmObjectHead var prm client.PrmObjectHead
@ -951,7 +977,10 @@ func (x *ResObjectRange) Close() error {
} }
func (p *pool) ObjectRange(ctx context.Context, addr address.Address, off, ln uint64, opts ...CallOption) (*ResObjectRange, error) { func (p *pool) ObjectRange(ctx context.Context, addr address.Address, off, ln uint64, opts ...CallOption) (*ResObjectRange, error) {
cfg := cfgFromOpts(append(opts, useDefaultSession())...) cfg := cfgFromOpts(append(opts,
useDefaultSession(),
useVerb(sessionv2.ObjectVerbRange),
useAddress(&addr))...)
var prm client.PrmObjectRange var prm client.PrmObjectRange
@ -1024,7 +1053,10 @@ func (x *ResObjectSearch) Close() {
} }
func (p *pool) SearchObjects(ctx context.Context, idCnr cid.ID, filters object.SearchFilters, opts ...CallOption) (*ResObjectSearch, error) { func (p *pool) SearchObjects(ctx context.Context, idCnr cid.ID, filters object.SearchFilters, opts ...CallOption) (*ResObjectSearch, error) {
cfg := cfgFromOpts(append(opts, useDefaultSession())...) cfg := cfgFromOpts(append(opts,
useDefaultSession(),
useVerb(sessionv2.ObjectVerbSearch),
useAddress(newAddressFromCnrID(&idCnr)))...)
var prm client.PrmObjectSearch var prm client.PrmObjectSearch
@ -1265,3 +1297,9 @@ func sessionTokenForOwner(id *owner.ID, cliRes *client.ResSessionCreate) *sessio
return st return st
} }
func newAddressFromCnrID(cnrID *cid.ID) *address.Address {
addr := address.NewAddress()
addr.SetContainerID(cnrID)
return addr
}