// MIT License // // Copyright (c) 2024 vinchent // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. package authn import ( "context" "encoding/json" "fmt" "net/http" "testing" "time" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/errno" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/shared" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/test" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/token" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" ) var loggedOutID string type testCache struct{} func (tc *testCache) Get(ctx context.Context, key string) (string, error) { loggedOutKey := fmt.Sprintf("jwt:%s", loggedOutID) if key == loggedOutKey { return "found", nil } return "", nil } func (c *testCache) Set( ctx context.Context, key string, value interface{}, expiration time.Duration, ) error { return nil } func (c *testCache) Close() error { return nil } func TestAuthn(t *testing.T) { token.Init("secret", 1*time.Second) tk, _ := token.Sign("user") tkParsed, _ := token.Parse(tk) loggedOutID = tkParsed.Identity cache := &testCache{} t.Run("token found in cache", func(t *testing.T) { r := gin.New() r.Use(Authn(cache)) r.GET("/example", func(c *gin.Context) { c.Status(http.StatusOK) }) res := test.PerformRequest( t, r, "GET", "/example", nil, test.Header{Key: shared.XUserName, Value: "user"}, test.Header{Key: "Authorization", Value: fmt.Sprintf("Bearer %s", tk)}, ) assert.Equal(t, http.StatusUnauthorized, res.Result().StatusCode, res.Body) var err errno.Errno json.NewDecoder(res.Result().Body).Decode(&err) assert.Equal(t, "AuthFailure.LoggedOut", err.Code) }) t.Run("token not found in cache", func(t *testing.T) { newTk, _ := token.Sign("user2") r := gin.New() r.Use(Authn(cache)) r.GET("/example", func(c *gin.Context) { c.Status(http.StatusOK) }) res := test.PerformRequest( t, r, "GET", "/example", nil, test.Header{Key: shared.XUserName, Value: "user2"}, test.Header{Key: "Authorization", Value: fmt.Sprintf("Bearer %s", newTk)}, ) assert.Equal(t, http.StatusOK, res.Result().StatusCode, res.Body) }) }