github.com/cs3org/reva/v2@v2.27.7/pkg/token/manager/jwt/jwt.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package jwt 20 21 import ( 22 "context" 23 "time" 24 25 auth "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" 26 user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 27 "github.com/cs3org/reva/v2/pkg/errtypes" 28 "github.com/cs3org/reva/v2/pkg/sharedconf" 29 "github.com/cs3org/reva/v2/pkg/token" 30 "github.com/cs3org/reva/v2/pkg/token/manager/registry" 31 "github.com/golang-jwt/jwt/v5" 32 "github.com/mitchellh/mapstructure" 33 "github.com/pkg/errors" 34 ) 35 36 const defaultExpiration int64 = 86400 // 1 day 37 const defaultLeeway int64 = 5 // 5 seconds 38 39 func init() { 40 registry.Register("jwt", New) 41 } 42 43 type config struct { 44 Secret string `mapstructure:"secret"` 45 Expires int64 `mapstructure:"expires"` 46 tokenTimeLeeway int64 `mapstructure:"token_leeway"` 47 } 48 49 type manager struct { 50 conf *config 51 } 52 53 // claims are custom claims for the JWT token. 54 type claims struct { 55 jwt.RegisteredClaims 56 User *user.User `json:"user"` 57 Scope map[string]*auth.Scope `json:"scope"` 58 } 59 60 func parseConfig(m map[string]interface{}) (*config, error) { 61 c := &config{} 62 if err := mapstructure.Decode(m, c); err != nil { 63 err = errors.Wrap(err, "error decoding conf") 64 return nil, err 65 } 66 return c, nil 67 } 68 69 // New returns an implementation of the token manager that uses JWT as tokens. 70 func New(value map[string]interface{}) (token.Manager, error) { 71 c, err := parseConfig(value) 72 if err != nil { 73 return nil, errors.Wrap(err, "error parsing config") 74 } 75 76 if c.Expires == 0 { 77 c.Expires = defaultExpiration 78 } 79 80 if c.tokenTimeLeeway == 0 { 81 c.tokenTimeLeeway = defaultLeeway 82 } 83 84 c.Secret = sharedconf.GetJWTSecret(c.Secret) 85 86 if c.Secret == "" { 87 return nil, errors.New("jwt: secret for signing payloads is not defined in config") 88 } 89 90 m := &manager{conf: c} 91 return m, nil 92 } 93 94 func (m *manager) MintToken(ctx context.Context, u *user.User, scope map[string]*auth.Scope) (string, error) { 95 ttl := time.Duration(m.conf.Expires) * time.Second 96 newClaims := claims{ 97 RegisteredClaims: jwt.RegisteredClaims{ 98 ExpiresAt: jwt.NewNumericDate(time.Now().Add(ttl)), 99 Issuer: u.Id.Idp, 100 Audience: jwt.ClaimStrings{"reva"}, 101 IssuedAt: jwt.NewNumericDate(time.Now()), 102 }, 103 User: u, 104 Scope: scope, 105 } 106 107 t := jwt.NewWithClaims(jwt.GetSigningMethod("HS256"), newClaims) 108 109 tkn, err := t.SignedString([]byte(m.conf.Secret)) 110 if err != nil { 111 return "", errors.Wrapf(err, "error signing token with claims %+v", newClaims) 112 } 113 114 return tkn, nil 115 } 116 117 func (m *manager) DismantleToken(ctx context.Context, tkn string) (*user.User, map[string]*auth.Scope, error) { 118 keyfunc := func(token *jwt.Token) (interface{}, error) { 119 return []byte(m.conf.Secret), nil 120 } 121 token, err := jwt.ParseWithClaims(tkn, &claims{}, keyfunc, jwt.WithLeeway(time.Duration(m.conf.tokenTimeLeeway)*time.Second)) 122 123 if err != nil { 124 return nil, nil, errors.Wrap(err, "error parsing token") 125 } 126 127 if claims, ok := token.Claims.(*claims); ok && token.Valid { 128 return claims.User, claims.Scope, nil 129 } 130 131 return nil, nil, errtypes.InvalidCredentials("invalid token") 132 }