1
17
18 package jwt
19
20 import (
21 "strings"
22 "testing"
23
24 "github.com/stretchr/testify/assert"
25 jose "gopkg.in/go-jose/go-jose.v2"
26 )
27
28 var (
29 hmacSignedToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0.Y6_PfQHrzRJ_Vlxij5VI07-pgDIuJNN3Z_g5sSaGQ0c`
30 rsaSignedToken = `eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzY29wZXMiOlsiczEiLCJzMiJdLCJzdWIiOiJzdWJqZWN0In0.UDDtyK9gC9kyHltcP7E_XODsnqcJWZIiXeGmSAH7SE9YKy3N0KSfFIN85dCNjTfs6zvy4rkrCHzLB7uKAtzMearh3q7jL4nxbhUMhlUcs_9QDVoN4q_j58XmRqBqRnBk-RmDu9TgcV8RbErP4awpIhwWb5UU-hR__4_iNbHdKqwSUPDKYGlf5eicuiYrPxH8mxivk4LRD-vyRdBZZKBt0XIDnEU4TdcNCzAXojkftqcFWYsczwS8R4JHd1qYsMyiaWl4trdHZkO4QkeLe34z4ZAaPMt3wE-gcU-VoqYTGxz-K3Le2VaZ0r3j_z6bOInsv0yngC_cD1dCXMyQJWnWjQ`
31 rsaSignedTokenWithKid = `eyJhbGciOiJSUzI1NiIsImtpZCI6ImZvb2JhciJ9.eyJpc3MiOiJpc3N1ZXIiLCJzY29wZXMiOlsiczEiLCJzMiJdLCJzdWIiOiJzdWJqZWN0In0.RxZhTRfPDb6UJ58FwvC89GgJGC8lAO04tz5iLlBpIJsyPZB0X_UgXSj0SGVFm2jbP_i-ZVH4HFC2fMB1n-so9CnCOpunWwhYNdgF6ewQJ0ADTWwfDGsK12UOmyT2naaZN8ZUBF8cgPtOgdWqQjk2Ng9QFRJxlUuKYczBp7vjWvgX8WMwQcaA-eK7HtguR4e9c4FMbeFK8Soc4jCsVTjIKdSn9SErc42gFu65NI1hZ3OPe_T7AZqdDjCkJpoiJ65GdD_qvGkVndJSEcMp3riXQpAy0JbctVkYecdFaGidbxHRrdcQYHtKn-XGMCh2uoBKleUr1fTMiyCGPQQesy3xHw`
32 invalidPayloadSignedToken = `eyJhbGciOiJIUzI1NiJ9.aW52YWxpZC1wYXlsb2Fk.ScBKKm18jcaMLGYDNRUqB5gVMRZl4DM6dh3ShcxeNgY`
33 invalidPartsSignedToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0`
34 hmacEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4.1-zuiZ4RbHrTTUoA8Dvfhg`
35 rsaEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.IvkVHHiI8JwwavvTR80xGjYvkzubMrZ-TDDx8k8SNJMEylfFfNUc7F2rC3WAABF_xmJ3SW2A6on-S6EAG97k0RsjqHHNqZuaFpDvjeuLqZFfYKzI45aCtkGG4C2ij2GbeySqJ784CcvFJPUWJ-6VPN2Ho2nhefUSqig0jE2IvOKy1ywTj_VBVBxF_dyXFnXwxPKGUQr3apxrWeRJfDh2Cf8YPBlLiRznjfBfwgePB1jP7WCZNwItj10L7hsT_YWEx01XJcbxHaXFLwKyVzwWaDhreFyaWMRbGqEfqVuOT34zfmhLDhQlgLLwkXrvYqX90NsQ9Ftg0LLIfRMbsfdgug.BFy2Tj1RZN8yq2Lk-kMiZQ.9Z0eOyPiv5cEzmXh64RlAQ36Uvz0WpZgqRcc2_69zHTmUOv0Vnl1I6ks8sTraUEvukAilolNBjBj47s0b4b-Og.VM8-eJg5ZsqnTqs0LtGX_Q`
36 invalidPayloadEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..T4jCS4Yyw1GCH0aW.y4gFaMITdBs_QZM8RKrL.6MPyk1cMVaOJFoNGlEuaRQ`
37 invalidPartsEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4`
38 signedAndEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiY3R5IjoiSldUIn0.icnR7M1HSgMDaUnJhfzT5nLmT0eRPeNsKPkioNcyq9TZsm-LgbE7wZkNFGfQqYwvbmrZ3UpOhNkrq4n2KN3N1dtjH9TVxzfMxz2OMh0dRWUNMi58EMadhmIpH3PLyyaeDyd0dyHpOIRPFTAoOdn2GoO_flV5CvPMhgdVKYB3h3vQW-ZZDu4cOZwXAjTuThdoUZCNWFhJhXyj-PrKLyVpX6rE1o4X05IS8008SLZyx-PZlsUPyLs6CJi7Z4PzZRzOJTV00a-7UOi-fBKBZV5V8eRpWuzJ673pMALlRCBzrRin-JeEA_QnAejtMAHG7RSGP60easQN4I-0jLTQNNNynw.oFrO-5ZgRrnWmbkPsbyMiQ.BVaWUzlrdfhe0otPJpb3DGoDCT6-BOmN_Pgq5NOqVFYIAwG5pM4pf7TaiPUJeQLf0phbLgpT4RfJ20Zhwfc2MH5unCqc8TZEP2dOrYRhb8o-X57x6IQppIDbjK2i_CAWf3yF5JUB7qRqOizpKZTh3HFTVEglY3WF8tAJ8KpnatTUmwcnqlyjdBFvYu4usiyvc_u9wNbXx5-lFt0slQYleHQMUirBprKyswIBjMoFJEe7kDvU_MCKI4NI9_fSfWJpaUdNxQEvRYR1PV4ZQdwBY0X9u2n2QH5iVQMrmgmQ5hPbWxwRv1-7jXBMPBpGeFQZHeEtSwif1_Umwyt8cDyRChb3OM7XQ3eY0UJRrbmvhcLWIcMp8FpblDaBinbjD6qIVXZVmaAdIbi2a_HblfoeL3-UABb82AAxOqQcAFjDEDTR2TFalDXSwgPZrAaQ_Mql3eFe9r2y0UVkgG7XYF4ik8sSK48CkZPUvkZFr-K9QMq-RZLzT3Zw0edxNaKgje27S26H9qClh6CCr9nk38AZZ76_Xz7f-Fil5xI0Dq95UzvwW__U3JJWE6OVUVx_RVJgdOJn8_B7hluckwBLUblscA.83pPXNnH0sKgHvFboiJVDA`
39 invalidSignedAndEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.QKYu3DkFEXBUa2U0Sgtm-e44BMuaFVbMu2T-GB3qEGONrmOuaB5BtNCvBUnuj6HR0v6u-tvawToRSzExQQLFTvPcLiQR8iclWirqAFUqLrg8kRU3qIRLkmErYeGIfCML1jq9ofKg0DI5-YrU5RSyUg9cwfXKEx8KNwFcjeVeDZwWEACdU8xBnQp57rNfr0Tj-dPnGKID7LU5ZV0vhK90FpEG7UqOeSHFmvONQyz6Ca-ZkE8X2swqGad-q5xl8f9pApdFqHzADox5OlgtxPkr-Khkm6WGfvf1K_e-iW5LYtvWIAjNByft2TexsNcYpdAO2oNAgh2nkhoohl-zCWU-og.UAU65JWKqvHZ_Z0V-xLyjQ.M6sQ4lAzKFelSmL6C6uoK00rB8IFCAK-eJ0iByGhtg8eYtmSBFsP_oUySfKPtxcPRkQ7YxnEX5D-DOo20wCV7il2Be9No__0R6_5heISOMXcKmKP3D6pFusaPisNGOgLw8SKXBuVpe20PvOJ9RgOXRKucSR2UMINXtqIn9RdxbKOlBBmMJhnX4TeQ00fRILng2sMbUHsWExSthQODHGx6VcwLFp-Aqmsnv2q2KkLpA8sEm48AHHFQXSGtlVGVgWKi3dOQYUnDJW4P64Xxr1Uq3yT7w_dRwK4BA7l3Biecj5dwkKrFMJ_RaCt-ED_R15zpxg6PmnXeeJnif58Fai40ZWOsGvLZNYwL1jbi-TrsargpdUQedfzuTk8Na2NkCzFNg2BYXVDHJ_WAX1daVyhvunaURwAlBatAcmnOGxWebwV1xQoQ7iHg6ZGohCannn_pqGwJlMHMgnCcnCIhwfj9uL9Ejz_TVceZNMlT1KvLRafVfxGhkp48bdnd8OcXmjT9pQzZUB3OqrstWKhbItZ1xMpy6dZ54ldWvtTTyQ4tQJaVWgXERUM1erDT6Ypyl15-fumOB9MRcgMG3NDblKowA.P9WTBITvVUgrLjX6bS0opQ`
40 )
41
42 type customClaims struct {
43 Scopes []string `json:"scopes,omitempty"`
44 }
45
46 func TestGetClaimsWithoutVerification(t *testing.T) {
47 tok, err := ParseSigned(hmacSignedToken)
48 if assert.NoError(t, err, "Error parsing signed token.") {
49 c := &Claims{}
50 c2 := &customClaims{}
51
52 err := tok.UnsafeClaimsWithoutVerification(c, c2)
53 if err != nil {
54 t.Errorf("Error not expected: %s", err)
55 }
56 assert.Equal(t, "subject", c.Subject)
57 assert.Equal(t, "issuer", c.Issuer)
58 assert.Equal(t, []string{"s1", "s2"}, c2.Scopes)
59
60 }
61 tok, err = ParseEncrypted(hmacEncryptedToken)
62 if assert.NoError(t, err, "Error parsing encrypted token.") {
63 c := Claims{}
64 err := tok.UnsafeClaimsWithoutVerification(c)
65 if err == nil {
66 t.Errorf("Error expected")
67 }
68 }
69 }
70
71 func TestDecodeTokenWithJWKS(t *testing.T) {
72 jwks := &jose.JSONWebKeySet{
73 Keys: []jose.JSONWebKey{
74 {
75 KeyID: "foobar",
76 Key: &testPrivRSAKey1.PublicKey,
77 },
78 },
79 }
80
81 tok, err := ParseSigned(rsaSignedTokenWithKid)
82 if assert.NoError(t, err, "Error parsing signed token.") {
83 cl := make(map[string]interface{})
84 expected := map[string]interface{}{
85 "sub": "subject",
86 "iss": "issuer",
87 "scopes": []interface{}{"s1", "s2"},
88 }
89
90 if assert.NoError(t, tok.Claims(jwks, &cl)) {
91 assert.Equal(t, expected, cl)
92 }
93
94 cl = make(map[string]interface{})
95 if assert.NoError(t, tok.Claims(*jwks, &cl)) {
96 assert.Equal(t, expected, cl)
97 }
98 }
99 }
100
101 func TestDecodeToken(t *testing.T) {
102 tok, err := ParseSigned(hmacSignedToken)
103 if assert.NoError(t, err, "Error parsing signed token.") {
104 c := &Claims{}
105 c2 := &customClaims{}
106 if assert.NoError(t, tok.Claims(sharedKey, c, c2)) {
107 assert.Equal(t, "subject", c.Subject)
108 assert.Equal(t, "issuer", c.Issuer)
109 assert.Equal(t, []string{"s1", "s2"}, c2.Scopes)
110 }
111 }
112 assert.EqualError(t, tok.Claims([]byte("invalid-secret")), "go-jose/go-jose: error in cryptographic primitive")
113
114 tok2, err := ParseSigned(rsaSignedToken)
115 if assert.NoError(t, err, "Error parsing encrypted token.") {
116 c := make(map[string]interface{})
117 if assert.NoError(t, tok2.Claims(&testPrivRSAKey1.PublicKey, &c)) {
118 assert.Equal(t, map[string]interface{}{
119 "sub": "subject",
120 "iss": "issuer",
121 "scopes": []interface{}{"s1", "s2"},
122 }, c)
123 }
124 }
125 assert.EqualError(t, tok.Claims(&testPrivRSAKey2.PublicKey), "go-jose/go-jose: error in cryptographic primitive")
126
127 tok3, err := ParseSigned(invalidPayloadSignedToken)
128 if assert.NoError(t, err, "Error parsing signed token.") {
129 assert.Error(t, tok3.Claims(sharedKey, &Claims{}), "Expected unmarshaling claims to fail.")
130 }
131
132 _, err = ParseSigned(invalidPartsSignedToken)
133 assert.EqualError(t, err, "go-jose/go-jose: compact JWS format must have three parts")
134
135 tok4, err := ParseEncrypted(hmacEncryptedToken)
136 if assert.NoError(t, err, "Error parsing encrypted token.") {
137 c := Claims{}
138 if assert.NoError(t, tok4.Claims(sharedEncryptionKey, &c)) {
139 assert.Equal(t, "foo", c.Subject)
140 }
141 }
142 assert.EqualError(t, tok4.Claims([]byte("invalid-secret-key")), "go-jose/go-jose: error in cryptographic primitive")
143
144 tok5, err := ParseEncrypted(rsaEncryptedToken)
145 if assert.NoError(t, err, "Error parsing encrypted token.") {
146 c := make(map[string]interface{})
147 if assert.NoError(t, tok5.Claims(testPrivRSAKey1, &c)) {
148 assert.Equal(t, map[string]interface{}{
149 "sub": "subject",
150 "iss": "issuer",
151 "scopes": []interface{}{"s1", "s2"},
152 }, c)
153 }
154 }
155 assert.EqualError(t, tok5.Claims(testPrivRSAKey2), "go-jose/go-jose: error in cryptographic primitive")
156
157 tok6, err := ParseEncrypted(invalidPayloadEncryptedToken)
158 if assert.NoError(t, err, "Error parsing encrypted token.") {
159 assert.Error(t, tok6.Claims(sharedEncryptionKey, &Claims{}))
160 }
161
162 _, err = ParseEncrypted(invalidPartsEncryptedToken)
163 assert.EqualError(t, err, "go-jose/go-jose: compact JWE format must have five parts")
164
165 tok7, err := ParseSignedAndEncrypted(signedAndEncryptedToken)
166 if assert.NoError(t, err, "Error parsing signed-then-encrypted token.") {
167 c := make(map[string]interface{})
168 if nested, err := tok7.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
169 assert.NoError(t, nested.Claims(testPrivRSAKey1.Public(), &c))
170 assert.Equal(t, map[string]interface{}{
171 "sub": "subject",
172 "iss": "issuer",
173 "scopes": []interface{}{"s1", "s2"},
174 }, c)
175 assert.EqualError(t, nested.Claims(testPrivRSAKey2.Public()), "go-jose/go-jose: error in cryptographic primitive")
176 }
177 }
178 _, err = tok7.Decrypt(testPrivRSAKey2)
179 assert.EqualError(t, err, "go-jose/go-jose: error in cryptographic primitive")
180
181 _, err = ParseSignedAndEncrypted(invalidSignedAndEncryptedToken)
182 assert.EqualError(t, err, "go-jose/go-jose/jwt: expected content type to be JWT (cty header)")
183 }
184
185 func TestTamperedJWT(t *testing.T) {
186 key := []byte("1234567890123456")
187
188 sig, _ := jose.NewEncrypter(
189 jose.A128GCM,
190 jose.Recipient{Algorithm: jose.DIRECT, Key: key},
191 (&jose.EncrypterOptions{}).WithType("JWT"))
192
193 cl := Claims{
194 Subject: "foo",
195 Issuer: "bar",
196 }
197
198 raw, _ := Encrypted(sig).Claims(cl).CompactSerialize()
199
200
201 r := strings.Split(raw, ".")
202 r[2] = "b3RoZXJ0aGluZw"
203 raw = strings.Join(r, ".")
204
205 tok, _ := ParseEncrypted(raw)
206
207 cl = Claims{}
208 err := tok.Claims(key, &cl)
209 if err == nil {
210 t.Error("Claims() on invalid token should fail")
211 }
212 }
213
214 func BenchmarkDecodeSignedToken(b *testing.B) {
215 for i := 0; i < b.N; i++ {
216 ParseSigned(hmacSignedToken)
217 }
218 }
219
220 func BenchmarkDecodeEncryptedHMACToken(b *testing.B) {
221 for i := 0; i < b.N; i++ {
222 ParseEncrypted(hmacEncryptedToken)
223 }
224 }
225
View as plain text