refac: removed 7 direct and 12 indirect go modules for custom code instead
This commit is contained in:
1 parent
cfcf108488
commit
c68e9a7858
73 files changed
+2455
-428
No files matched your search
@@ -0,0 +1,162 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/apperr"
|
||||
"RenewCMS/api/pkg/authtoken"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type authTokenProbe struct {
|
||||
reached bool
|
||||
claims authtoken.Claims
|
||||
err error
|
||||
}
|
||||
|
||||
func authTokenRouter(auth *authtoken.Auth, probe *authTokenProbe, guarded bool) http.Handler {
|
||||
final := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
probe.reached = true
|
||||
probe.claims, probe.err = authtoken.FromContext(r.Context())
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
if guarded {
|
||||
return authtoken.Verifier(auth)(authtoken.Authenticator(final))
|
||||
}
|
||||
return authtoken.Verifier(auth)(final)
|
||||
}
|
||||
|
||||
func serveAuthToken(handler http.Handler, configure func(*http.Request)) *httptest.ResponseRecorder {
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
configure(req)
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
return rec
|
||||
}
|
||||
|
||||
func TestAuthTokenVerifierAndAuthenticator(t *testing.T) {
|
||||
auth := authtoken.New([]byte("test-secret"))
|
||||
valid, _ := auth.Encode(map[string]any{"user_id": uint32(5)})
|
||||
other, _ := auth.Encode(map[string]any{"user_id": uint32(9)})
|
||||
|
||||
t.Run("A valid jwt cookie reaches the handler with its claims", func(t *testing.T) {
|
||||
probe := &authTokenProbe{}
|
||||
|
||||
rec := serveAuthToken(authTokenRouter(auth, probe, true), func(r *http.Request) {
|
||||
r.AddCookie(&http.Cookie{Name: "jwt", Value: valid})
|
||||
})
|
||||
|
||||
if rec.Code != http.StatusOK || probe.claims["user_id"] != float64(5) {
|
||||
t.Errorf("expected 200 with user 5, got %d and %v", rec.Code, probe.claims)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("A bearer header in any letter case is accepted", func(t *testing.T) {
|
||||
for _, scheme := range []string{"Bearer ", "BEARER ", "bearer "} {
|
||||
probe := &authTokenProbe{}
|
||||
|
||||
rec := serveAuthToken(authTokenRouter(auth, probe, true), func(r *http.Request) {
|
||||
r.Header.Set("Authorization", scheme+valid)
|
||||
})
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("scheme %q: expected 200, got %d", scheme, rec.Code)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("The bearer header wins over the cookie", func(t *testing.T) {
|
||||
probe := &authTokenProbe{}
|
||||
|
||||
serveAuthToken(authTokenRouter(auth, probe, true), func(r *http.Request) {
|
||||
r.Header.Set("Authorization", "Bearer "+valid)
|
||||
r.AddCookie(&http.Cookie{Name: "jwt", Value: other})
|
||||
})
|
||||
|
||||
if probe.claims["user_id"] != float64(5) {
|
||||
t.Errorf("expected the header token, got %v", probe.claims)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("A malformed Authorization header falls back to the cookie", func(t *testing.T) {
|
||||
for _, header := range []string{"Bearer", "Bearer ", "Basic abc", "Token " + valid} {
|
||||
probe := &authTokenProbe{}
|
||||
|
||||
rec := serveAuthToken(authTokenRouter(auth, probe, true), func(r *http.Request) {
|
||||
r.Header.Set("Authorization", header)
|
||||
r.AddCookie(&http.Cookie{Name: "jwt", Value: valid})
|
||||
})
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("header %q: expected the cookie to be used, got %d", header, rec.Code)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("The authenticator answers 401 with the standard message when no token is sent", func(t *testing.T) {
|
||||
probe := &authTokenProbe{}
|
||||
|
||||
rec := serveAuthToken(authTokenRouter(auth, probe, true), func(*http.Request) {})
|
||||
|
||||
if rec.Code != http.StatusUnauthorized || probe.reached {
|
||||
t.Fatalf("expected a blocked 401, got %d reached=%v", rec.Code, probe.reached)
|
||||
}
|
||||
if got := rec.Body.String(); got != apperr.UnauthorizedErrorMessage+"\n" {
|
||||
t.Errorf("unexpected body %q", got)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("The authenticator rejects a forged token", func(t *testing.T) {
|
||||
probe := &authTokenProbe{}
|
||||
forged, _ := authtoken.New([]byte("another-secret")).Encode(map[string]any{"user_id": 1})
|
||||
|
||||
rec := serveAuthToken(authTokenRouter(auth, probe, true), func(r *http.Request) {
|
||||
r.AddCookie(&http.Cookie{Name: "jwt", Value: forged})
|
||||
})
|
||||
|
||||
if rec.Code != http.StatusUnauthorized || probe.reached {
|
||||
t.Errorf("expected a blocked 401, got %d reached=%v", rec.Code, probe.reached)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Without the authenticator the handler sees the verification error", func(t *testing.T) {
|
||||
probe := &authTokenProbe{}
|
||||
|
||||
serveAuthToken(authTokenRouter(auth, probe, false), func(r *http.Request) {
|
||||
r.AddCookie(&http.Cookie{Name: "jwt", Value: "garbage"})
|
||||
})
|
||||
|
||||
if !probe.reached || probe.err == nil || probe.claims != nil {
|
||||
t.Errorf("expected an error and no claims, got %v / %v", probe.claims, probe.err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("A context that never passed the verifier reports no token", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
|
||||
if _, err := authtoken.FromContext(req.Context()); err != authtoken.ErrNoToken {
|
||||
t.Errorf("expected ErrNoToken, got %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("A context carrying nil claims and no error still reports no token", func(t *testing.T) {
|
||||
ctx := authtoken.NewContext(httptest.NewRequest(http.MethodGet, "/", nil).Context(), nil, nil)
|
||||
|
||||
if _, err := authtoken.FromContext(ctx); err != authtoken.ErrNoToken {
|
||||
t.Errorf("expected ErrNoToken, got %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("A context injected with claims is authenticated", func(t *testing.T) {
|
||||
probe := &authTokenProbe{}
|
||||
handler := authtoken.Authenticator(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { probe.reached = true }))
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
req = req.WithContext(authtoken.NewContext(req.Context(), authtoken.Claims{"user_id": float64(1)}, nil))
|
||||
|
||||
handler.ServeHTTP(httptest.NewRecorder(), req)
|
||||
|
||||
if !probe.reached {
|
||||
t.Error("expected the handler to be reached")
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user