ultisuite-backend/internal/authentik/flow_executor_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

86 lines
2.4 KiB
Go

package authentik
import (
"context"
"testing"
"time"
)
func TestFlowExecutorGetChallenge(t *testing.T) {
t.Parallel()
fe, err := NewFlowExecutor("http://localhost:9000", "test-flow")
if err != nil {
t.Fatal(err)
}
if fe.slug != "test-flow" {
t.Fatalf("slug = %q", fe.slug)
}
}
func TestFlowDone(t *testing.T) {
t.Parallel()
done, denied := FlowDone(FlowChallenge{"component": "xak-flow-redirect"})
if !done || denied {
t.Fatalf("redirect: done=%v denied=%v", done, denied)
}
done, denied = FlowDone(FlowChallenge{"component": "ak-stage-access-denied"})
if !done || !denied {
t.Fatalf("denied: done=%v denied=%v", done, denied)
}
done, denied = FlowDone(FlowChallenge{"component": "ak-stage-prompt"})
if done || denied {
t.Fatalf("prompt: done=%v denied=%v", done, denied)
}
}
func TestFlowSessionStoreLifecycle(t *testing.T) {
t.Parallel()
store := NewFlowSessionStore("http://127.0.0.1:1", nil)
_, err := store.Respond(context.Background(), "missing", "ulti-enrollment", "", map[string]any{"component": "x"})
if err != ErrFlowSessionNotFound {
t.Fatalf("expected ErrFlowSessionNotFound, got %v", err)
}
}
func TestCookieRoundTrip(t *testing.T) {
t.Parallel()
fe, err := NewFlowExecutor("http://localhost/auth", "test-flow")
if err != nil {
t.Fatal(err)
}
fe.ImportCookies([]SerializedCookie{
{Name: "authentik_csrf", Value: "abc123", Path: "/auth/", SameSiteName: "Lax", HTTPOnly: true},
{Name: "authentik_session", Value: "sess", Path: "/auth/", SameSiteName: "Lax", HTTPOnly: true},
})
exported := fe.ExportCookies()
if len(exported) != 2 {
t.Fatalf("exported %d cookies", len(exported))
}
fe2, err := RestoreFlowExecutor("http://localhost/auth", "test-flow", exported)
if err != nil {
t.Fatal(err)
}
if fe2.csrfToken() != "abc123" {
t.Fatalf("csrf = %q", fe2.csrfToken())
}
browser := BrowserAuthentikCookies(exported)
if len(browser) != 2 || browser[0].Path != "/auth/" {
t.Fatalf("browser cookies: %+v", browser)
}
}
func TestFlowSessionCompleteRequiresDone(t *testing.T) {
t.Parallel()
store := NewFlowSessionStore("http://127.0.0.1:1", nil)
store.mu.Lock()
store.items["sess1"] = &flowSessionEntry{
slug: "default-authentication-flow",
createdAt: time.Now(),
completed: false,
}
store.mu.Unlock()
_, err := store.CompleteSession(context.Background(), "sess1", "default-authentication-flow")
if err != ErrFlowSessionNotCompleted {
t.Fatalf("expected ErrFlowSessionNotCompleted, got %v", err)
}
}