github.com/goldeneggg/goa@v1.3.1/middleware/security/jwt/jwt_test.go (about) 1 package jwt_test 2 3 import ( 4 "crypto/ecdsa" 5 "crypto/rsa" 6 "net/http" 7 "net/http/httptest" 8 9 "context" 10 11 jwtpkg "github.com/dgrijalva/jwt-go" 12 "github.com/goadesign/goa" 13 "github.com/goadesign/goa/middleware/security/jwt" 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 ) 17 18 var _ = Describe("Middleware", func() { 19 var securityScheme *goa.JWTSecurity 20 var respRecord *httptest.ResponseRecorder 21 var request *http.Request 22 var handler goa.Handler 23 var middleware goa.Middleware 24 var dispatchResult error 25 var fetchedToken *jwtpkg.Token 26 27 BeforeEach(func() { 28 securityScheme = &goa.JWTSecurity{ 29 In: goa.LocHeader, 30 Name: "Authorization", 31 } 32 respRecord = httptest.NewRecorder() 33 request, _ = http.NewRequest("GET", "http://example.com/", nil) 34 // HS256 {"scopes":"scope1","admin":true}, signed with "keys" 35 request.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZXMiOiJzY29wZTEiLCJhZG1pbiI6dHJ1ZX0.UCvEfbD_yuS5dCZidxZgogVi2yF0ZVecMsQQbY1HJy0") 36 handler = func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { 37 fetchedToken = jwt.ContextJWT(ctx) 38 return nil 39 } 40 }) 41 42 JustBeforeEach(func() { 43 dispatchResult = middleware(handler)(context.Background(), respRecord, request) 44 }) 45 46 Context("HMAC keys signed token", func() { 47 BeforeEach(func() { 48 // HS256 {"scopes":"scope1","admin":true}, signed with "keys" 49 request.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZXMiOiJzY29wZTEiLCJhZG1pbiI6dHJ1ZX0.UCvEfbD_yuS5dCZidxZgogVi2yF0ZVecMsQQbY1HJy0") 50 51 }) 52 53 Context("with a single key", func() { 54 BeforeEach(func() { 55 middleware = jwt.New("keys", nil, securityScheme) 56 }) 57 58 It("should go through", func() { 59 Ω(dispatchResult).ShouldNot(HaveOccurred()) 60 Ω(fetchedToken).ShouldNot(BeNil()) 61 }) 62 }) 63 64 Context("with keys that didn't the JWT", func() { 65 BeforeEach(func() { 66 middleware = jwt.New("otherkey", nil, securityScheme) 67 }) 68 69 It("should fail with an error", func() { 70 Ω(dispatchResult).Should(HaveOccurred()) 71 Ω(dispatchResult.(error)).Should(HaveOccurred()) 72 }) 73 }) 74 75 Context("with multiple keys", func() { 76 BeforeEach(func() { 77 middleware = jwt.New([]string{"firstkey", "keys"}, nil, securityScheme) 78 }) 79 80 It("should go through", func() { 81 Ω(dispatchResult).ShouldNot(HaveOccurred()) 82 Ω(fetchedToken).ShouldNot(BeNil()) 83 }) 84 }) 85 }) 86 87 Context("RSA keys signed token", func() { 88 BeforeEach(func() { 89 // RS256 {"scopes":"scope1 scope2","admin":true}, signed with rsaKey1 below 90 request.Header.Set("Authorization", "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZXMiOiJzY29wZTEgc2NvcGUyIiwiYWRtaW4iOnRydWV9.gT4gSGqXTCUZAJT_TWZ4eknazVo-ulMKwSpHoghWZU8Sm9QXt48ISwFAb_wW2xhR58MUNX95iuiex0bCWvze59r35dEQ2SOZixuDvE8srQi2SRk9qqsVV9-R361qf2D8KfLX9jQ7j-UB40bleg0fOyBAjPLPq0ggBigSjQ2yUz8YDKma-n6Ulc3LJ4gyozmb3MjO9RV2pdD3N-m6ttwkTkUE2jhsL6a3T8f0Y6xSGTMyZasKc6kHbUyz6NjAeplLhbkBDE8-Ak4GaLGlLnLzZ49oTVrh89yauciW5yLQCXzXt2PODqp6zXPC0FFcDr-2USCpA-nqaQQyhliMcgtqVw") 91 }) 92 93 Context("with valid scopes", func() { 94 95 var ctx context.Context 96 97 BeforeEach(func() { 98 middleware = jwt.New("keys", nil, securityScheme) 99 ctx = goa.WithRequiredScopes(context.Background(), []string{"scope1"}) 100 }) 101 102 It("should accept scopes specified using the 'scope' claim", func() { 103 // HS256 {"scope":"scope1","admin":true}, signed with "keys" 104 request.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6InNjb3BlMSIsImFkbWluIjp0cnVlfQ.EwMZtpTUPUoKsiCHqH659JQeMLf3-KdboStmQKjv2IU") 105 dispatchResult = middleware(handler)(ctx, respRecord, request) 106 Ω(dispatchResult).ShouldNot(HaveOccurred()) 107 }) 108 109 It("should accept scopes specified using the 'scopes' claim", func() { 110 // HS256 {"scopes":"scope1","admin":true}, signed with "keys" 111 request.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZXMiOiJzY29wZTEiLCJhZG1pbiI6dHJ1ZX0.UCvEfbD_yuS5dCZidxZgogVi2yF0ZVecMsQQbY1HJy0") 112 dispatchResult = middleware(handler)(ctx, respRecord, request) 113 Ω(dispatchResult).ShouldNot(HaveOccurred()) 114 }) 115 116 It("should fall back to 'scopes' if 'scope' is null", func() { 117 // HS256 {"scope":null, "scopes":"scope1", "admin":true}, signed with "keys" 118 request.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6bnVsbCwic2NvcGVzIjoic2NvcGUxIiwiYWRtaW4iOnRydWV9.h8L_MlWWyB0RnwaUBDVu8nGPn5wPSVPMEm42iH8Jxmg") 119 dispatchResult = middleware(handler)(ctx, respRecord, request) 120 Ω(dispatchResult).ShouldNot(HaveOccurred()) 121 }) 122 123 It("should not fall back to 'scopes' if 'scope' is an empty string", func() { 124 // HS256 {"scope":"", "scopes":"scope1", "admin":true}, signed with "keys" 125 request.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6IiIsInNjb3BlcyI6InNjb3BlMSIsImFkbWluIjp0cnVlfQ.U5r-gAvk8SWRYBK3Hmj7zqHSQ0lSQO1wAAk0soyHkoU") 126 dispatchResult = middleware(handler)(ctx, respRecord, request) 127 Ω(dispatchResult).Should(HaveOccurred()) 128 }) 129 130 }) 131 132 Context("with a single key", func() { 133 BeforeEach(func() { 134 middleware = jwt.New(rsaPubKey1, nil, securityScheme) 135 }) 136 137 It("should go through", func() { 138 Ω(dispatchResult).ShouldNot(HaveOccurred()) 139 Ω(fetchedToken).ShouldNot(BeNil()) 140 }) 141 }) 142 143 Context("with keys that didn't the JWT", func() { 144 BeforeEach(func() { 145 middleware = jwt.New(rsaPubKey2, nil, securityScheme) 146 }) 147 148 It("should fail with an error", func() { 149 Ω(dispatchResult).Should(HaveOccurred()) 150 Ω(dispatchResult.(error)).Should(HaveOccurred()) 151 }) 152 }) 153 154 Context("with multiple keys", func() { 155 BeforeEach(func() { 156 middleware = jwt.New([]*rsa.PublicKey{rsaPubKey1}, nil, securityScheme) 157 }) 158 159 It("should go through", func() { 160 Ω(dispatchResult).ShouldNot(HaveOccurred()) 161 Ω(fetchedToken).ShouldNot(BeNil()) 162 }) 163 }) 164 }) 165 166 Context("ECDSA keys signed token", func() { 167 BeforeEach(func() { 168 // ES256 {"scopes":"scope1 scope2","admin":true}, signed with ecKey1 below 169 request.Header.Set("Authorization", "Bearer "+ 170 "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9."+ 171 "eyJhZG1pbiI6dHJ1ZSwic2NvcGVzIjoic2NvcGUxIHNjb3BlMiJ9."+ 172 "7gM4EblP4cvX5C6PBLSBFpKX2FQ9AsLNmOXEm86uvrd4czBfw1zDO24abQ7gtlbMcjuVvxrpIyRa7Nbbn31G7w") 173 }) 174 175 Context("with a single key", func() { 176 BeforeEach(func() { 177 middleware = jwt.New(ecPubKey1, nil, securityScheme) 178 }) 179 180 It("should go through", func() { 181 Ω(dispatchResult).ShouldNot(HaveOccurred()) 182 Ω(fetchedToken).ShouldNot(BeNil()) 183 }) 184 }) 185 186 Context("with keys that didn't the JWT", func() { 187 BeforeEach(func() { 188 middleware = jwt.New(ecPubKey2, nil, securityScheme) 189 }) 190 191 It("should fail with an error", func() { 192 Ω(dispatchResult).Should(HaveOccurred()) 193 Ω(dispatchResult.(error)).Should(HaveOccurred()) 194 }) 195 }) 196 197 Context("with multiple keys", func() { 198 BeforeEach(func() { 199 middleware = jwt.New([]*ecdsa.PublicKey{ecPubKey1}, nil, securityScheme) 200 }) 201 202 It("should go through", func() { 203 Ω(dispatchResult).ShouldNot(HaveOccurred()) 204 Ω(fetchedToken).ShouldNot(BeNil()) 205 }) 206 }) 207 }) 208 }) 209 210 var rsaKey1, _ = jwtpkg.ParseRSAPrivateKeyFromPEM([]byte(`-----BEGIN RSA PRIVATE KEY----- 211 MIIEogIBAAKCAQEArZIJcPQd7aSGb80wgFpy5SVjzzsGpfIysZ30SdWlTcWMVbAT 212 XmsDNgw98TzIeoyikSbSHEeORbKWKS2clgNsdLjYKv3XLTBaXfLcU3x9mhnk/kUL 213 N/AQgyvsRGynPris2oVzGSib7uOZK/9+u+QAKIrp7prcmMmnwvdcjFXjwzx83RTF 214 1b+iuVGCdV0T4m1XQdm/YtIUh7JNbYrUolkdwZlOxMZuV0FDC+ms02+gyj580Pyl 215 TuAD4JmtSmmijyWfEx5dsZYtGALyUxcm5Hz15RP3FACrv4B++BHI6smO4sWdrSYV 216 l3sHJ60Bm6zbwuyB2twJPOdL5nVIGiIDdf+1IwIDAQABAoIBACF3MtLQfqS/QBx2 217 V4+n4NdFqkTegJ2mYRfV+K/zvXeNS02KMXHW+DuHiLnmmlDmpMGP1psVQN03XbR6 218 0uIprtOigCtp3f8cf4/1r315V05LB9fuwAb9BnIEGf3nZSe2u702VcbYCZi50WKm 219 VG0tvMoUXp5exYG//9SblQCJ3uxZf9D8y5RnrUZtP4Pnjkn/3YeJCF+Kked55Cvi 220 gv56/aiyWp9xEGsSWig5Zt8VNXihgT7D2KZzxcQDQlxw0CR5ECT7/4w7sZVvwc7B 221 I76JJDvpD0UGvzoUgx928efGKxJBrcjzvTNSKgHJYYCvaa6+qX2tjkmOqdG4xl27 222 /TaBISECgYEA4YJ32HKaS2ikn5J2C1qlHy4nRuVNhX8T9qvp6OBdbE2BQq3O5IUt 223 +wdTcjhD88aDdHCZmAd8i3FC4l+CKsQ5sTwRk0vTOZ7axC6+zDHg+na5/+NCq+xm 224 ffoaZ5jsZFyqfbsFn8NiLWLo2JSFV1AnUxwpPA2jbuylAuZVvVbLYHcCgYEAxQnO 225 L+U6NwTvN6EJgt3h1jHfXiQnapsj0O0XgK+g2K6vMovpXAf9noO+r3Qbx/aKxuRg 226 TvRQ08T5yyqysz+sYe0rp8oaMUhYQFMgJOUUBlmUVGxYdARMD6kTy/384B9Azoex 227 UCosMSEAD909MAsyQWB4X6OJKd+V68QpFYeIx7UCgYBHgaRY6PYOBU92He36abLE 228 MVFZBKrRMtt0s0yHgGV/SxA6wXxCMAzFdaw7IqZBbWgPiwjZET6nxLFNsLVItFIK 229 5h44k6mVss5xuNTdUM+i+/S8tCZW964EMkMfKHmE1XFmTuBYqY6/D4b/7hBeAFeH 230 3f0hQr3ZFYa5Zao4UIZKvwKBgGL8lhUBt8lENVlhEYIpLfeJfomw6AxqfAfN1GzV 231 zpyMxX9DQqz1ZrhnvzgtwHcoqHda6/c+TgzVfBhRDw12A4f+ulvE8HupuIw4NoHS 232 g8jc3+O5uoYuUnfbnRJyOsPtb4VSLgXz6deUmI9fugmU1l55tH93jMT4ijyzg2BJ 233 grGxAoGAWX24Yx9qoasqEQ2rgdTsgylwL28UczKQ5KNHt2PcEfPNw6/GpfK7YmlU 234 Heef2umEzb1K2ZK95wlMbF8zpNDWBf4PkxgfW+JEE+pO1kb5KXysBymymyXhGHAP 235 CwH9XHqbjVlsD358AbPeKqLgTCaGo9JgsEZDBpESmBDnIPUahMc= 236 -----END RSA PRIVATE KEY-----`)) 237 238 var rsaPubKey1, _ = jwtpkg.ParseRSAPublicKeyFromPEM([]byte(`-----BEGIN PUBLIC KEY----- 239 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArZIJcPQd7aSGb80wgFpy 240 5SVjzzsGpfIysZ30SdWlTcWMVbATXmsDNgw98TzIeoyikSbSHEeORbKWKS2clgNs 241 dLjYKv3XLTBaXfLcU3x9mhnk/kULN/AQgyvsRGynPris2oVzGSib7uOZK/9+u+QA 242 KIrp7prcmMmnwvdcjFXjwzx83RTF1b+iuVGCdV0T4m1XQdm/YtIUh7JNbYrUolkd 243 wZlOxMZuV0FDC+ms02+gyj580PylTuAD4JmtSmmijyWfEx5dsZYtGALyUxcm5Hz1 244 5RP3FACrv4B++BHI6smO4sWdrSYVl3sHJ60Bm6zbwuyB2twJPOdL5nVIGiIDdf+1 245 IwIDAQAB 246 -----END PUBLIC KEY-----`)) 247 248 var rsaKey2, _ = jwtpkg.ParseRSAPrivateKeyFromPEM([]byte(`-----BEGIN RSA PRIVATE KEY----- 249 MIIEowIBAAKCAQEA4jr/DGbPt0UDGvu6Xo2LV0F6Wf8OnyxF2IFPdG5B4X0YS3DC 250 9SF3clbbBivDVa2bEXppyj+eLEKlfohCWXTrJK0LxTEcneuDkF4re+BdP3q9cKRz 251 FtI/ZVhVnD7+PS1wps7OiTM0iOaIDo9+uFrC6zBTRAiPyrdwh1ApttLdoD6i5D9D 252 7zzvpTXLC/UWaRz/phAaaop6dPPR1YblZEckWgqTMC3KrRX/6QJFFfpgyQzFT09W 253 DYnmXl2gS7C2sk4UejygqmVg96JxaIaT3WiQSjxXddjR/krcA9EGNNEkpZB2W6Ux 254 6d63yWsNG9YJUacwI+M2q5ZW964J1s//FiNZZQIDAQABAoIBAQCoqYtU16Gs5Qq3 255 p0z/CVAFMY/iYMGp8fvwuhdemoULc5QVSnBPCTBgUljgdOggjFm74iPU4TEvllCD 256 0VqGDyDwKwNHdKH9KoTfsRWCOXfLx9pMjI4xSXZyPDU3U8+AFMyT0EMzDrXwCs8M 257 6/Zxw1jmtxSc+DUb0T9X4m/3GaaZvDGGShnU8/XnEh2uEHrNwWnGWYPJ/rZjNZPy 258 PZ9W2VpcHKBMVEowK/cOoouNuflAISoLCCLMNYygr9T4Ylm3HGP9o7JuWL+wGQsa 259 aXrE5qTOpsxmBqTQ8pglnxnhDEFXmx3O+bwRfIwDSYe+wvCINpdIstWuybh4Ed2i 260 ZgLTlx8BAoGBAP9LwmfZ/2XNHBzk+f09TnTnhXzVsKkHu5BlXvWoDigVv4Dzl44j 261 X1Ade5PjiOf0Jti2QCkAaI+CjExdP1zCqDZBQFpKI3QQgvlWoKXHVFV9ziC8gcX+ 262 I6M8wmtIoK8ISnC6A5s1wKIvOPsZyP7aVZgu805BKfVqtFWCK42vnRVRAoGBAOLa 263 t2pOzVttd3vPgzGovD+Mf3RsPg6ygazj0GiDRspRCnoeopFEoBPFcKIQZlPp8rfT 264 NLOuwVkW5TqntrCW0UwixZMXicIaPDo0idXInIfP0+f7JxSYb5q7vmbyRt8uAYY9 265 GU4L/ZIn127JbgQ5n5nuODMvTe7m5Ky+FUYHw43VAoGAE6QOdtLstTZMfWSYXwVC 266 bfgJ6wq9pqNzqK5D2f5t6GOT8iXLeSH7iTxbb4tH0yCThISw9vaTFMdkZ9OctlQ7 267 gMEQZGHjzGAg03H4tghZ0qH1I8uc6FCfCUX5ZyuVQSIQKBAHiv9drJyZc6gOMJ03 268 jJfAHDsjMUBeU13KYAIswaECgYBTYiNSzv5KodTuTFsjsKrpDOJ4T6ULz+88NkyP 269 bdliWiFou8Pzc28HdWYuG6sRIwfVK6vOc+ibr3+4bJcJF5Z8zrcilt9K2kvS9SbI 270 zsFCZlC0jytRNaqoDGQzANCuDgH/bovTlTKyOzTDgwSORwP0F4zOu4+AxZu+Juw4 271 3nextQKBgEAGLuChkztZCVt0W2D8wJYFR7XjezcbsfpoXx9H8htk6u4STu9TwB76 272 DxoYj3qiTV2kRRBQQZRAli1TbDOnJuqFMnRL0aPsqebuW2sqY9Hx9G6TxokN8Nc6 273 RlTE+CbPcjBgAx+AANL/X2KYoXLAjOrYY5kQD8Qbt8Wkme7m6hiP 274 -----END RSA PRIVATE KEY-----`)) 275 276 var rsaPubKey2, _ = jwtpkg.ParseRSAPublicKeyFromPEM([]byte(`-----BEGIN PUBLIC KEY----- 277 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jr/DGbPt0UDGvu6Xo2L 278 V0F6Wf8OnyxF2IFPdG5B4X0YS3DC9SF3clbbBivDVa2bEXppyj+eLEKlfohCWXTr 279 JK0LxTEcneuDkF4re+BdP3q9cKRzFtI/ZVhVnD7+PS1wps7OiTM0iOaIDo9+uFrC 280 6zBTRAiPyrdwh1ApttLdoD6i5D9D7zzvpTXLC/UWaRz/phAaaop6dPPR1YblZEck 281 WgqTMC3KrRX/6QJFFfpgyQzFT09WDYnmXl2gS7C2sk4UejygqmVg96JxaIaT3WiQ 282 SjxXddjR/krcA9EGNNEkpZB2W6Ux6d63yWsNG9YJUacwI+M2q5ZW964J1s//FiNZ 283 ZQIDAQAB 284 -----END PUBLIC KEY-----`)) 285 286 var ecKey1, _ = jwtpkg.ParseECPrivateKeyFromPEM([]byte(`-----BEGIN EC PRIVATE KEY----- 287 MHcCAQEEIM4zAVusfF+Xl4Z5a5LaspGk+OIwGQweubphSqC1R9+VoAoGCCqGSM49 288 AwEHoUQDQgAE3tWSknhfssUVytNbPz3TB7giFfxKtHsFW27Yls+Ohfuui9NW4eEk 289 fLOxYkTI9tyoKfh9Dan5kJFA7ZYEwZ0zMQ== 290 -----END EC PRIVATE KEY-----`)) 291 292 var ecPubKey1, _ = jwtpkg.ParseECPublicKeyFromPEM([]byte(`-----BEGIN PUBLIC KEY----- 293 MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3tWSknhfssUVytNbPz3TB7giFfxK 294 tHsFW27Yls+Ohfuui9NW4eEkfLOxYkTI9tyoKfh9Dan5kJFA7ZYEwZ0zMQ== 295 -----END PUBLIC KEY-----`)) 296 297 var ecKey2, _ = jwtpkg.ParseECPrivateKeyFromPEM([]byte(`-----BEGIN EC PRIVATE KEY----- 298 MHcCAQEEIKQ7EyFGaYMuFpMLnqK+mBnT9CrWOqzVxsF8wBlGrTq/oAoGCCqGSM49 299 AwEHoUQDQgAE8IX3mOtLvBpvrylaRjFpadqGrirXh9dkjJfM/t1dnLu5qPhybMIY 300 tEr3Xs8vYp2wyaSTVKsyj9y+t344T5Bhdw== 301 -----END EC PRIVATE KEY-----`)) 302 303 var ecPubKey2, _ = jwtpkg.ParseECPublicKeyFromPEM([]byte(`-----BEGIN PUBLIC KEY----- 304 MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8IX3mOtLvBpvrylaRjFpadqGrirX 305 h9dkjJfM/t1dnLu5qPhybMIYtEr3Xs8vYp2wyaSTVKsyj9y+t344T5Bhdw== 306 -----END PUBLIC KEY-----`))