From a1e17ea1f29de5948692df906377d7da4155b9e1 Mon Sep 17 00:00:00 2001 From: Alex Vanin Date: Wed, 6 Apr 2022 11:05:08 +0300 Subject: [PATCH] [#193] pool: Return copy of session token in cache To avoid side effects after token re-sign. Signed-off-by: Alex Vanin (cherry picked from commit 2104945f9e7631cbb226d9bb97ac937d9e4247b4) --- pool/cache.go | 11 ++++++++++- pool/pool.go | 27 +++++++++++++++++++++++++++ pool/pool_test.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/pool/cache.go b/pool/cache.go index 8eaaefea..73232ef1 100644 --- a/pool/cache.go +++ b/pool/cache.go @@ -26,6 +26,9 @@ func NewCache() (*SessionCache, error) { return &SessionCache{cache: cache}, nil } +// Get returns a copy of the session token from the cache without signature +// and context related fields. Returns nil if token is missing in the cache. +// It is safe to modify and re-sign returned session token. func (c *SessionCache) Get(key string) *session.Token { valueRaw, ok := c.cache.Get(key) if !ok { @@ -35,7 +38,13 @@ func (c *SessionCache) Get(key string) *session.Token { value := valueRaw.(*cacheValue) value.atime = time.Now() - return value.token + if value.token == nil { + return nil + } + + res := copySessionTokenWithoutSignatureAndContext(*value.token) + + return &res } func (c *SessionCache) GetAccessTime(key string) (time.Time, bool) { diff --git a/pool/pool.go b/pool/pool.go index c47ae9d9..0b1dbbbb 100644 --- a/pool/pool.go +++ b/pool/pool.go @@ -1297,3 +1297,30 @@ func newAddressFromCnrID(cnrID *cid.ID) *address.Address { addr.SetContainerID(cnrID) return addr } + +func copySessionTokenWithoutSignatureAndContext(from session.Token) (to session.Token) { + to.SetIat(from.Iat()) + to.SetExp(from.Exp()) + to.SetNbf(from.Nbf()) + + sessionTokenID := make([]byte, len(from.ID())) + copy(sessionTokenID, from.ID()) + to.SetID(sessionTokenID) + + sessionTokenKey := make([]byte, len(from.SessionKey())) + copy(sessionTokenKey, from.SessionKey()) + to.SetSessionKey(sessionTokenKey) + + var sessionTokenOwner owner.ID + buf, err := from.OwnerID().Marshal() + if err != nil { + panic(err) // should never happen + } + err = sessionTokenOwner.Unmarshal(buf) + if err != nil { + panic(err) // should never happen + } + to.SetOwnerID(&sessionTokenOwner) + + return to +} diff --git a/pool/pool_test.go b/pool/pool_test.go index 888685f9..1668c224 100644 --- a/pool/pool_test.go +++ b/pool/pool_test.go @@ -19,6 +19,7 @@ import ( "github.com/nspcc-dev/neofs-sdk-go/object/address" "github.com/nspcc-dev/neofs-sdk-go/owner" "github.com/nspcc-dev/neofs-sdk-go/session" + sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test" "github.com/stretchr/testify/require" "go.uber.org/zap" ) @@ -590,3 +591,32 @@ func TestWaitPresence(t *testing.T) { require.NoError(t, err) }) } + +func TestCopySessionTokenWithoutSignatureAndContext(t *testing.T) { + from := sessiontest.SignedToken() + to := copySessionTokenWithoutSignatureAndContext(*from) + + require.Equal(t, from.Nbf(), to.Nbf()) + require.Equal(t, from.Exp(), to.Exp()) + require.Equal(t, from.Iat(), to.Iat()) + require.Equal(t, from.ID(), to.ID()) + require.Equal(t, from.OwnerID().String(), to.OwnerID().String()) + require.Equal(t, from.SessionKey(), to.SessionKey()) + + require.Empty(t, to.Signature().Sign()) + require.Empty(t, to.Signature().Key()) + + t.Run("empty object context", func(t *testing.T) { + octx := sessiontest.ObjectContext() + from.SetContext(octx) + to = copySessionTokenWithoutSignatureAndContext(*from) + require.Nil(t, to.Context()) + }) + + t.Run("empty container context", func(t *testing.T) { + cctx := sessiontest.ContainerContext() + from.SetContext(cctx) + to = copySessionTokenWithoutSignatureAndContext(*from) + require.Nil(t, to.Context()) + }) +}