3 | 3 |
"context"
|
4 | 4 |
"testing"
|
5 | 5 |
|
|
6 |
"crypto/subtle"
|
|
7 |
|
6 | 8 |
jwt "github.com/dgrijalva/jwt-go"
|
|
9 |
"github.com/go-kit/kit/endpoint"
|
7 | 10 |
)
|
8 | 11 |
|
|
12 |
type customClaims struct {
|
|
13 |
MyProperty string `json:"my_property"`
|
|
14 |
jwt.StandardClaims
|
|
15 |
}
|
|
16 |
|
|
17 |
func (c customClaims) VerifyMyProperty(p string) bool {
|
|
18 |
return subtle.ConstantTimeCompare([]byte(c.MyProperty), []byte(p)) != 0
|
|
19 |
}
|
|
20 |
|
9 | 21 |
var (
|
10 | |
kid = "kid"
|
11 | |
key = []byte("test_signing_key")
|
12 | |
method = jwt.SigningMethodHS256
|
13 | |
invalidMethod = jwt.SigningMethodRS256
|
14 | |
claims = Claims{"user": "go-kit"}
|
|
22 |
kid = "kid"
|
|
23 |
key = []byte("test_signing_key")
|
|
24 |
myProperty = "some value"
|
|
25 |
method = jwt.SigningMethodHS256
|
|
26 |
invalidMethod = jwt.SigningMethodRS256
|
|
27 |
mapClaims = jwt.MapClaims{"user": "go-kit"}
|
|
28 |
standardClaims = jwt.StandardClaims{Audience: "go-kit"}
|
|
29 |
myCustomClaims = customClaims{MyProperty: myProperty, StandardClaims: standardClaims}
|
15 | 30 |
// Signed tokens generated at https://jwt.io/
|
16 | |
signedKey = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ28ta2l0In0.14M2VmYyApdSlV_LZ88ajjwuaLeIFplB8JpyNy0A19E"
|
17 | |
invalidKey = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.e30.vKVCKto-Wn6rgz3vBdaZaCBGfCBDTXOENSo_X2Gq7qA"
|
|
31 |
signedKey = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ28ta2l0In0.14M2VmYyApdSlV_LZ88ajjwuaLeIFplB8JpyNy0A19E"
|
|
32 |
standardSignedKey = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJnby1raXQifQ.L5ypIJjCOOv3jJ8G5SelaHvR04UJuxmcBN5QW3m_aoY"
|
|
33 |
customSignedKey = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJteV9wcm9wZXJ0eSI6InNvbWUgdmFsdWUiLCJhdWQiOiJnby1raXQifQ.s8F-IDrV4WPJUsqr7qfDi-3GRlcKR0SRnkTeUT_U-i0"
|
|
34 |
invalidKey = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.e30.vKVCKto-Wn6rgz3vBdaZaCBGfCBDTXOENSo_X2Gq7qA"
|
18 | 35 |
)
|
19 | 36 |
|
20 | |
func TestSigner(t *testing.T) {
|
21 | |
e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil }
|
22 | |
|
23 | |
signer := NewSigner(kid, key, method, claims)(e)
|
|
37 |
func signingValidator(t *testing.T, signer endpoint.Endpoint, expectedKey string) {
|
24 | 38 |
ctx, err := signer(context.Background(), struct{}{})
|
25 | 39 |
if err != nil {
|
26 | 40 |
t.Fatalf("Signer returned error: %s", err)
|
|
31 | 45 |
t.Fatal("Token did not exist in context")
|
32 | 46 |
}
|
33 | 47 |
|
34 | |
if token != signedKey {
|
35 | |
t.Fatalf("JWT tokens did not match: expecting %s got %s", signedKey, token)
|
|
48 |
if token != expectedKey {
|
|
49 |
t.Fatalf("JWT tokens did not match: expecting %s got %s", expectedKey, token)
|
36 | 50 |
}
|
|
51 |
}
|
|
52 |
|
|
53 |
func TestNewSigner(t *testing.T) {
|
|
54 |
e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil }
|
|
55 |
|
|
56 |
signer := NewSigner(kid, key, method, mapClaims)(e)
|
|
57 |
signingValidator(t, signer, signedKey)
|
|
58 |
|
|
59 |
signer = NewSigner(kid, key, method, standardClaims)(e)
|
|
60 |
signingValidator(t, signer, standardSignedKey)
|
|
61 |
|
|
62 |
signer = NewSigner(kid, key, method, myCustomClaims)(e)
|
|
63 |
signingValidator(t, signer, customSignedKey)
|
37 | 64 |
}
|
38 | 65 |
|
39 | 66 |
func TestJWTParser(t *testing.T) {
|
|
43 | 70 |
return key, nil
|
44 | 71 |
}
|
45 | 72 |
|
46 | |
parser := NewParser(keys, method)(e)
|
|
73 |
parser := NewParser(keys, method, jwt.MapClaims{})(e)
|
47 | 74 |
|
48 | 75 |
// No Token is passed into the parser
|
49 | 76 |
_, err := parser(context.Background(), struct{}{})
|
|
63 | 90 |
}
|
64 | 91 |
|
65 | 92 |
// Invalid Method is used in the parser
|
66 | |
badParser := NewParser(keys, invalidMethod)(e)
|
|
93 |
badParser := NewParser(keys, invalidMethod, jwt.MapClaims{})(e)
|
67 | 94 |
ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey)
|
68 | 95 |
_, err = badParser(ctx, struct{}{})
|
69 | 96 |
if err == nil {
|
|
79 | 106 |
return []byte("bad"), nil
|
80 | 107 |
}
|
81 | 108 |
|
82 | |
badParser = NewParser(invalidKeys, method)(e)
|
|
109 |
badParser = NewParser(invalidKeys, method, jwt.MapClaims{})(e)
|
83 | 110 |
ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey)
|
84 | 111 |
_, err = badParser(ctx, struct{}{})
|
85 | 112 |
if err == nil {
|
|
93 | 120 |
t.Fatalf("Parser returned error: %s", err)
|
94 | 121 |
}
|
95 | 122 |
|
96 | |
cl, ok := ctx1.(context.Context).Value(JWTClaimsContextKey).(Claims)
|
|
123 |
cl, ok := ctx1.(context.Context).Value(JWTClaimsContextKey).(jwt.MapClaims)
|
97 | 124 |
if !ok {
|
98 | 125 |
t.Fatal("Claims were not passed into context correctly")
|
99 | 126 |
}
|
100 | 127 |
|
101 | |
if cl["user"] != claims["user"] {
|
102 | |
t.Fatalf("JWT Claims.user did not match: expecting %s got %s", claims["user"], cl["user"])
|
|
128 |
if cl["user"] != mapClaims["user"] {
|
|
129 |
t.Fatalf("JWT Claims.user did not match: expecting %s got %s", mapClaims["user"], cl["user"])
|
|
130 |
}
|
|
131 |
|
|
132 |
parser = NewParser(keys, method, &jwt.StandardClaims{})(e)
|
|
133 |
ctx = context.WithValue(context.Background(), JWTTokenContextKey, standardSignedKey)
|
|
134 |
ctx1, err = parser(ctx, struct{}{})
|
|
135 |
if err != nil {
|
|
136 |
t.Fatalf("Parser returned error: %s", err)
|
|
137 |
}
|
|
138 |
stdCl, ok := ctx1.(context.Context).Value(JWTClaimsContextKey).(*jwt.StandardClaims)
|
|
139 |
if !ok {
|
|
140 |
t.Fatal("Claims were not passed into context correctly")
|
|
141 |
}
|
|
142 |
if !stdCl.VerifyAudience("go-kit", true) {
|
|
143 |
t.Fatalf("JWT jwt.StandardClaims.Audience did not match: expecting %s got %s", standardClaims.Audience, stdCl.Audience)
|
|
144 |
}
|
|
145 |
|
|
146 |
parser = NewParser(keys, method, &customClaims{})(e)
|
|
147 |
ctx = context.WithValue(context.Background(), JWTTokenContextKey, customSignedKey)
|
|
148 |
ctx1, err = parser(ctx, struct{}{})
|
|
149 |
if err != nil {
|
|
150 |
t.Fatalf("Parser returned error: %s", err)
|
|
151 |
}
|
|
152 |
custCl, ok := ctx1.(context.Context).Value(JWTClaimsContextKey).(*customClaims)
|
|
153 |
if !ok {
|
|
154 |
t.Fatal("Claims were not passed into context correctly")
|
|
155 |
}
|
|
156 |
if !custCl.VerifyAudience("go-kit", true) {
|
|
157 |
t.Fatalf("JWT customClaims.Audience did not match: expecting %s got %s", standardClaims.Audience, custCl.Audience)
|
|
158 |
}
|
|
159 |
if !custCl.VerifyMyProperty(myProperty) {
|
|
160 |
t.Fatalf("JWT customClaims.MyProperty did not match: expecting %s got %s", myProperty, custCl.MyProperty)
|
103 | 161 |
}
|
104 | 162 |
}
|