• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / useradm / 1089910578

29 Nov 2023 08:19PM UTC coverage: 87.17%. First build
1089910578

push

gitlab-ci

web-flow
Merge pull request #392 from merlin-northern/men_6804_key_rotation_support

feat: "kid" support in JWT header and multiple keys.

166 of 232 new or added lines in 9 files covered. (71.55%)

2874 of 3297 relevant lines covered (87.17%)

130.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.74
/jwt/jwt_rsa.go
1
// Copyright 2023 Northern.tech AS
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
package jwt
15

16
import (
17
        "crypto/rsa"
18
        "strconv"
19

20
        "github.com/golang-jwt/jwt/v4"
21
        "github.com/pkg/errors"
22

23
        "github.com/mendersoftware/useradm/common"
24
)
25

26
// JWTHandlerRS256 is an RS256-specific JWTHandler
27
type JWTHandlerRS256 struct {
28
        privKey      map[int]*rsa.PrivateKey
29
        currentKeyId int
30
}
31

32
func NewJWTHandlerRS256(privKey *rsa.PrivateKey, keyId int) *JWTHandlerRS256 {
13✔
33
        return &JWTHandlerRS256{
13✔
34
                privKey:      map[int]*rsa.PrivateKey{keyId: privKey},
13✔
35
                currentKeyId: keyId,
13✔
36
        }
13✔
37
}
13✔
38

39
func (j *JWTHandlerRS256) ToJWT(token *Token) (string, error) {
172✔
40
        //generate
172✔
41
        jt := jwt.NewWithClaims(jwt.SigningMethodRS256, &token.Claims)
172✔
42
        jt.Header["kid"] = token.KeyId
172✔
43
        if _, exists := j.privKey[token.KeyId]; !exists {
172✔
NEW
44
                return "", common.ErrKeyIdNotFound
×
NEW
45
        }
×
46
        //sign
47
        data, err := jt.SignedString(j.privKey[token.KeyId])
172✔
48
        return data, err
172✔
49
}
50

51
func (j *JWTHandlerRS256) FromJWT(tokstr string) (*Token, error) {
155✔
52
        jwttoken, err := jwt.ParseWithClaims(tokstr, &Claims{},
155✔
53
                func(token *jwt.Token) (interface{}, error) {
301✔
54
                        keyId := common.KeyIdZero
146✔
55
                        if _, ok := token.Header["kid"]; ok {
288✔
56
                                if _, isFloat := token.Header["kid"].(float64); isFloat {
284✔
57
                                        keyId = int(token.Header["kid"].(float64))
142✔
58
                                }
142✔
59
                                if _, isInt := token.Header["kid"].(int64); isInt {
142✔
NEW
60
                                        keyId = int(token.Header["kid"].(int64))
×
NEW
61
                                }
×
62
                                if _, isInt := token.Header["kid"].(int); isInt {
142✔
NEW
63
                                        keyId = token.Header["kid"].(int)
×
NEW
64
                                }
×
65
                        }
66
                        if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
146✔
67
                                return nil, errors.New("unexpected signing method: " + token.Method.Alg())
×
68
                        }
×
69
                        if _, exists := j.privKey[keyId]; !exists {
146✔
NEW
70
                                return nil, errors.New("cannot find the key with id " + strconv.Itoa(keyId))
×
NEW
71
                        }
×
72
                        return &j.privKey[keyId].PublicKey, nil
146✔
73
                },
74
        )
75

76
        if err == nil {
299✔
77
                token := Token{}
144✔
78
                if claims, ok := jwttoken.Claims.(*Claims); ok && jwttoken.Valid {
288✔
79
                        token.Claims = *claims
144✔
80
                        return &token, nil
144✔
81
                }
144✔
82
        }
83

84
        return nil, ErrTokenInvalid
11✔
85
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc