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-----`))