From 17d3ff3ea73b2fdbf5713758960a6ee18bde89fc Mon Sep 17 00:00:00 2001 From: Ishank Arora Date: Wed, 28 Jul 2021 16:15:16 +0200 Subject: [PATCH] JWT token mananger now returns the hash of the token --- changelog/unreleased/jwt-token-hash.md | 10 ++++++++ pkg/token/manager/jwt/jwt.go | 34 +++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 changelog/unreleased/jwt-token-hash.md diff --git a/changelog/unreleased/jwt-token-hash.md b/changelog/unreleased/jwt-token-hash.md new file mode 100644 index 00000000000..b0bba6379e0 --- /dev/null +++ b/changelog/unreleased/jwt-token-hash.md @@ -0,0 +1,10 @@ +Enhancement: JWT token mananger now returns the hash of the token + +We encode the complete CS3APIs user object along with the scopes the user has +access to in the JWT token. In case the list of scopes is long or the user +belongs to a lot of groups, the token size got pretty big previously, and for +use-cases where we needed to pass it as a URI parameter, led to server limits +on the size of the URI being hit. Now we cache the token return its hash, which +makes the size of the token constant. + +https://github.com/cs3org/reva/pull/1935 diff --git a/pkg/token/manager/jwt/jwt.go b/pkg/token/manager/jwt/jwt.go index e54df4dae99..0a264666c71 100644 --- a/pkg/token/manager/jwt/jwt.go +++ b/pkg/token/manager/jwt/jwt.go @@ -20,8 +20,10 @@ package jwt import ( "context" + "crypto/sha1" "time" + "github.com/bluele/gcache" auth "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" "github.com/cs3org/reva/pkg/errtypes" @@ -45,7 +47,8 @@ type config struct { } type manager struct { - conf *config + conf *config + tokenCache gcache.Cache } // claims are custom claims for the JWT token. @@ -81,7 +84,10 @@ func New(value map[string]interface{}) (token.Manager, error) { return nil, errors.New("jwt: secret for signing payloads is not defined in config") } - m := &manager{conf: c} + m := &manager{ + conf: c, + tokenCache: gcache.New(1000000).LFU().Build(), + } return m, nil } @@ -105,11 +111,16 @@ func (m *manager) MintToken(ctx context.Context, u *user.User, scope map[string] return "", errors.Wrapf(err, "error signing token with claims %+v", claims) } - return tkn, nil + return m.cacheAndReturnHash(tkn) } func (m *manager) DismantleToken(ctx context.Context, tkn string) (*user.User, map[string]*auth.Scope, error) { - token, err := jwt.ParseWithClaims(tkn, &claims{}, func(token *jwt.Token) (interface{}, error) { + cachedToken, err := m.getCachedToken(tkn) + if err != nil { + return nil, nil, err + } + + token, err := jwt.ParseWithClaims(cachedToken, &claims{}, func(token *jwt.Token) (interface{}, error) { return []byte(m.conf.Secret), nil }) @@ -123,3 +134,18 @@ func (m *manager) DismantleToken(ctx context.Context, tkn string) (*user.User, m return nil, nil, errtypes.InvalidCredentials("invalid token") } + +func (m *manager) cacheAndReturnHash(token string) (string, error) { + h := sha1.New() + h.Write([]byte(token)) + hash := string(h.Sum(nil)) + err := m.tokenCache.SetWithExpire(hash, token, time.Second*time.Duration(m.conf.Expires)) + return hash, err +} + +func (m *manager) getCachedToken(hashedToken string) (string, error) { + if tknIf, err := m.tokenCache.Get(hashedToken); err == nil { + return tknIf.(string), nil + } + return "", errtypes.InvalidCredentials("invalid token") +}