func TestNewDefault(t *testing.T) { jm, err := ctxjwt.NewService() assert.NoError(t, err) assert.Equal(t, time.Hour, jm.Expire) assert.Nil(t, jm.Blacklist.Set("test", time.Hour)) assert.False(t, jm.Blacklist.Has("test")) assert.Len(t, jm.JTI.Get(), uuidLen) testClaims := map[string]interface{}{ "mascot": "gopher", } theToken, jti, err := jm.GenerateToken(testClaims) assert.NoError(t, err) assert.Empty(t, jti) assert.NotEmpty(t, theToken) haveToken, err := jm.Parse(theToken) assert.NoError(t, err) assert.True(t, haveToken.Valid) assert.Equal(t, "gopher", haveToken.Claims["mascot"]) failedToken, err := jm.Parse(theToken + "c") assert.Error(t, err) assert.Nil(t, failedToken) jmRSA, err := ctxjwt.NewService(ctxjwt.WithRSAFromFile("invalid.key")) assert.Nil(t, jmRSA) assert.Contains(t, err.Error(), "open invalid.key: no such file or directory") }
func TestRSAEncryptedNoOrFailedPassword(t *testing.T) { jm, err := ctxjwt.NewService(ctxjwt.WithRSAFromFile(pkFile)) assert.EqualError(t, err, ctxjwt.ErrPrivateKeyNoPassword.Error()) assert.Nil(t, jm) jm2, err2 := ctxjwt.NewService(ctxjwt.WithRSAFromFile(pkFile, []byte(`adfasdf`))) assert.EqualError(t, err2, x509.IncorrectPasswordError.Error()) assert.Nil(t, jm2) }
func TestWithParseAndValidateInBlackList(t *testing.T) { bl := &testRealBL{} jm, err := ctxjwt.NewService( ctxjwt.WithBlacklist(bl), ) assert.NoError(t, err) theToken, _, err := jm.GenerateToken(nil) bl.token = theToken assert.NoError(t, err) assert.NotEmpty(t, theToken) req, err := http.NewRequest("GET", "http://auth.xyz", nil) assert.NoError(t, err) ctxjwt.SetHeaderAuthorization(req, theToken) finalHandler := ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { w.WriteHeader(http.StatusTeapot) return nil }) authHandler := jm.WithParseAndValidate()(finalHandler) wRec := httptest.NewRecorder() assert.NoError(t, authHandler.ServeHTTPContext(context.Background(), wRec, req)) assert.NotEqual(t, http.StatusTeapot, wRec.Code) assert.Equal(t, http.StatusUnauthorized, wRec.Code) }
func TestWithParseAndValidateSuccess(t *testing.T) { jm, err := ctxjwt.NewService() assert.NoError(t, err) theToken, _, err := jm.GenerateToken(map[string]interface{}{ "xfoo": "bar", "zfoo": 4711, }) assert.NoError(t, err) assert.NotEmpty(t, theToken) req, err := http.NewRequest("GET", "http://auth.xyz", nil) assert.NoError(t, err) ctxjwt.SetHeaderAuthorization(req, theToken) finalHandler := ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { w.WriteHeader(http.StatusTeapot) fmt.Fprintf(w, "I'm more of a coffee pot") ctxToken, err := ctxjwt.FromContext(ctx) assert.NoError(t, err) assert.NotNil(t, ctxToken) assert.Exactly(t, "bar", ctxToken.Claims["xfoo"].(string)) return nil }) authHandler := jm.WithParseAndValidate()(finalHandler) wRec := httptest.NewRecorder() assert.NoError(t, authHandler.ServeHTTPContext(context.Background(), wRec, req)) assert.Equal(t, http.StatusTeapot, wRec.Code) assert.Equal(t, `I'm more of a coffee pot`, wRec.Body.String()) }
// newApp creates a new application. function can only be called once func newApp() *app { a := new(app) var err error // make sure env var CS_DSN is set and points to the appropriate database if a.dbc, err = csdb.Connect(); err != nil { log.Fatal("MySQL Connect", "err", err) } if err := config.TableCollection.Init(a.dbc.NewSession()); err != nil { log.Fatal("config.TableCollection.Init", "err", err) } if err := store.TableCollection.Init(a.dbc.NewSession()); err != nil { log.Fatal("store.TableCollection.Init", "err", err) } a.config = config.NewService(config.WithDBStorage(a.dbc.DB)) // create JSON web token instance if a.jwtSrv, err = ctxjwt.NewService(); err != nil { log.Fatal("ctxjwt.NewService", "err", err) } a.jwtSrv.EnableJTI = true return a }
func TestWithRSAReaderFail(t *testing.T) { jm, err := ctxjwt.NewService( ctxjwt.WithRSA(bytes.NewReader([]byte(`invalid pem data`))), ) assert.Nil(t, jm) assert.Equal(t, "Private Key from io.Reader no found", err.Error()) }
func TestJTI(t *testing.T) { jm, err := ctxjwt.NewService() assert.NoError(t, err) jm.EnableJTI = true theToken, jti, err := jm.GenerateToken(nil) assert.NoError(t, err) assert.NotEmpty(t, jti) assert.NotEmpty(t, theToken) assert.Len(t, jti, uuidLen) }
func testRsaOption(t *testing.T, opt ctxjwt.Option) { jm, err := ctxjwt.NewService(opt) assert.NoError(t, err) assert.NotNil(t, jm) theToken, _, err := jm.GenerateToken(nil) assert.NoError(t, err) assert.NotEmpty(t, theToken) tk, err := jm.Parse(theToken) assert.NoError(t, err) assert.NotNil(t, tk) assert.True(t, tk.Valid) }
func testAuth(t *testing.T, errH ctxhttp.Handler, opts ...ctxjwt.Option) (ctxhttp.Handler, string) { jm, err := ctxjwt.NewService(opts...) assert.NoError(t, err) theToken, _, err := jm.GenerateToken(map[string]interface{}{ "xfoo": "bar", "zfoo": 4711, }) assert.NoError(t, err) final := ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { w.WriteHeader(http.StatusOK) return nil }) authHandler := jm.WithParseAndValidate(errH)(final) return authHandler, theToken }
func TestPasswordFromConfig(t *testing.T) { cfg := config.NewMockGetter( config.WithMockValues(config.MockPV{ scope.StrDefault.FQPathInt64(ctxjwt.PathJWTPassword): `Rump3lst!lzch3n`, }), ) jm, err := ctxjwt.NewService( ctxjwt.WithPasswordFromConfig(cfg), ) assert.NoError(t, err) theToken, _, err := jm.GenerateToken(nil) assert.NoError(t, err) assert.NotEmpty(t, theToken) }
func TestInvalidSigningMethod(t *testing.T) { password := []byte(`Rump3lst!lzch3n`) jm, err := ctxjwt.NewService( ctxjwt.WithPassword(password), ) assert.NoError(t, err) tk := jwt.New(jwt.SigningMethodHS256) tk.Claims["exp"] = time.Now().Add(time.Hour).Unix() tk.Claims["iat"] = time.Now().Unix() tk.Header["alg"] = "HS384" malformedToken, err := tk.SignedString(password) assert.NoError(t, err) mt, err := jm.Parse(malformedToken) assert.EqualError(t, err, ctxjwt.ErrUnexpectedSigningMethod.Error()) assert.Nil(t, mt) }
func TestLogout(t *testing.T) { tbl := &testBL{T: t} jm, err := ctxjwt.NewService( ctxjwt.WithBlacklist(tbl), ) assert.NoError(t, err) theToken, _, err := jm.GenerateToken(nil) assert.NoError(t, err) tk, err := jm.Parse(theToken) assert.NoError(t, err) assert.NotNil(t, tk) assert.Nil(t, jm.Logout(nil)) assert.Nil(t, jm.Logout(tk)) assert.Equal(t, int(time.Hour.Seconds()), 1+int(tbl.exp.Seconds())) assert.Equal(t, theToken, tbl.theToken) }
func bmServeHTTP(b *testing.B, opts ...ctxjwt.Option) { service, err := ctxjwt.NewService(opts...) if err != nil { b.Error(err) } token, _, err := service.GenerateToken(map[string]interface{}{ "xfoo": "bar", "zfoo": 4711, }) if err != nil { b.Error(err) } final := ctxhttp.HandlerFunc(func(_ context.Context, w http.ResponseWriter, _ *http.Request) error { w.WriteHeader(http.StatusTeapot) return nil }) jwtHandler := service.WithParseAndValidate()(final) req, err := http.NewRequest("GET", "http://abc.xyz", nil) if err != nil { b.Error(err) } ctxjwt.SetHeaderAuthorization(req, token) w := httptest.NewRecorder() ctx := context.Background() b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { if err := jwtHandler.ServeHTTPContext(ctx, w, req); err != nil { b.Error(err) } if w.Code != http.StatusTeapot { b.Errorf("Response Code want %d; have %d", http.StatusTeapot, w.Code) } } }
func ExampleWithInitStoreByToken() { initStore() ctx := store.NewContextReader(context.Background(), testStoreService) jwtService, err := ctxjwt.NewService(ctxjwt.WithPassword([]byte(`GÒph3r`))) finalHandler := ctxhttp.Chain( ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { _, haveReqStore, err := store.FromContextReader(ctx) if err != nil { return err } // now we know that the current request depends on the store view DE. fmt.Fprintf(w, "StoreCode: %s\n", haveReqStore.StoreCode()) return nil }), // executed 3rd store.WithInitStoreByToken(), // executed 2nd jwtService.WithParseAndValidate(), // executed 1st ) ts := httptest.NewServer(ctxhttp.NewAdapter(ctx, finalHandler)) defer ts.Close() // Setup GET request token, _, err := jwtService.GenerateToken( map[string]interface{}{ // Despite default store for Website ID 1 is AT we are currently // in the store context of DE. store.ParamName: "de", }, ) if err != nil { log.Fatal("jwtService.GenerateToken", "err", err) } req, err := http.NewRequest("GET", ts.URL, nil) if err != nil { log.Fatal("http.Get", "err", err) } ctxjwt.SetHeaderAuthorization(req, token) res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal("http.DefaultClient.Do", "err", err) } response, err := ioutil.ReadAll(res.Body) if errC := res.Body.Close(); errC != nil { log.Fatal("res.Body.Close", "err", errC) } if err != nil { log.Fatal("ioutil.ReadAll", "err", err) } fmt.Printf("Response: %s\n", response) fmt.Printf("Log: %s\n", testDebugLogBuf.String()) // Output: // Response: StoreCode: de // // Log: }