ultisuite-backend/internal/api/auth/handlers_test.go
R3D347HR4Y 8bbc539d77 feat(auth): implement flow completion and rate limiting for authentication flows
- Added a new handler for completing authentication flows, including session validation and cookie management.
- Implemented flow rate limiting to restrict the number of flow start requests per client IP.
- Enhanced flow session management with Redis support for persistent session storage.
- Updated existing handlers to integrate the new flow completion logic and error handling for various session states.
- Introduced unit tests for the new flow completion and rate limiting functionalities to ensure reliability.
2026-06-20 01:09:42 +02:00

75 lines
2.1 KiB
Go

package authapi
import (
"bytes"
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/go-chi/chi/v5"
)
func TestValidateFlowSlugAllowed(t *testing.T) {
t.Parallel()
for _, slug := range []string{FlowEnrollment, FlowRecovery, FlowAuthentication} {
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/flows/"+slug+"/start", nil)
got, ok := validateFlowSlug(rec, req, slug)
if !ok || got != slug {
t.Fatalf("slug %q: ok=%v got=%q code=%d", slug, ok, got, rec.Code)
}
}
}
func TestValidateFlowSlugRejected(t *testing.T) {
t.Parallel()
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/flows/default-invalidation-flow/start", nil)
_, ok := validateFlowSlug(rec, req, "default-invalidation-flow")
if ok {
t.Fatal("expected slug to be rejected")
}
if rec.Code != http.StatusNotFound {
t.Fatalf("status = %d", rec.Code)
}
}
func TestRespondFlowMissingCookie(t *testing.T) {
t.Parallel()
h := NewHandler("http://127.0.0.1:1", "http://localhost:3004", nil)
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/flows/ulti-enrollment/respond", bytes.NewReader([]byte(`{"payload":{"component":"x"}}`)))
rctx := chi.NewRouteContext()
rctx.URLParams.Add("slug", FlowEnrollment)
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))
h.RespondFlow(rec, req)
if rec.Code != http.StatusUnauthorized {
t.Fatalf("status = %d body=%s", rec.Code, rec.Body.String())
}
}
func TestBuildLoginRedirectURL(t *testing.T) {
t.Parallel()
got := buildLoginRedirectURL("http://localhost:3004", "/mail/inbox")
want := "http://localhost:3004/api/auth/login?returnTo=%2Fmail%2Finbox"
if got != want {
t.Fatalf("got %q want %q", got, want)
}
}
func TestFlowRateLimiterMemory(t *testing.T) {
t.Parallel()
lim := NewFlowRateLimiter(nil)
req := httptest.NewRequest(http.MethodPost, "/start", nil)
req.RemoteAddr = "203.0.113.1:1234"
for i := 0; i < flowRateLimitMax; i++ {
if !lim.Allow(req) {
t.Fatalf("attempt %d should be allowed", i+1)
}
}
if lim.Allow(req) {
t.Fatal("expected rate limit block")
}
}