Files
passkey-auth/internal/handlers/handlers_test.go
T

196 lines
5.0 KiB
Go

package handlers
import (
"net/http"
"net/http/httptest"
"testing"
"passkey-auth/internal/auth"
"passkey-auth/internal/config"
"passkey-auth/internal/database"
)
func TestAuthCheck(t *testing.T) {
// Setup test config
cfg := &config.Config{
Auth: config.AuthConfig{
SessionSecret: "test-secret",
},
WebAuthn: config.WebAuthnConfig{
RPDisplayName: "Test Passkey Auth",
RPID: "localhost",
RPOrigins: []string{"http://localhost:8080"},
},
}
// Setup test database
db, err := database.New(":memory:")
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer db.Close()
// Setup test WebAuthn (mock)
webAuthn, err := auth.NewWebAuthn(cfg)
if err != nil {
t.Fatalf("Failed to create test WebAuthn: %v", err)
}
// Create handlers
h := New(db, webAuthn, cfg)
tests := []struct {
name string
queryParams string
authenticated bool
expectedStatus int
expectedHeader string
}{
{
name: "Unauthenticated without redirect param (Nginx)",
queryParams: "",
authenticated: false,
expectedStatus: http.StatusUnauthorized,
expectedHeader: "",
},
{
name: "Unauthenticated with rd param (Traefik)",
queryParams: "rd=https://example.com/protected",
authenticated: false,
expectedStatus: http.StatusFound,
expectedHeader: "/login.html?redirect=https://example.com/protected",
},
{
name: "Unauthenticated with redirect param (Traefik)",
queryParams: "redirect=https://example.com/protected",
authenticated: false,
expectedStatus: http.StatusFound,
expectedHeader: "/login.html?redirect=https://example.com/protected",
},
{
name: "Authenticated with redirect param",
queryParams: "rd=https://example.com/protected",
authenticated: true,
expectedStatus: http.StatusOK,
expectedHeader: "",
},
{
name: "Authenticated without redirect param",
queryParams: "",
authenticated: true,
expectedStatus: http.StatusOK,
expectedHeader: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create request
req, err := http.NewRequest("GET", "/auth?"+tt.queryParams, nil)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
// Mock session if authenticated
if tt.authenticated {
// Create a session cookie for testing
session, _ := h.store.Get(req, "auth-session")
session.Values["authenticated"] = true
session.Values["user_id"] = 1
session.Values["user_email"] = "test@example.com"
// Create a response recorder to capture the session cookie
w := httptest.NewRecorder()
session.Save(req, w)
// Extract the cookie and add it to the request
for _, cookie := range w.Result().Cookies() {
if cookie.Name == "auth-session" {
req.AddCookie(cookie)
break
}
}
}
// Create response recorder
w := httptest.NewRecorder()
// Call the handler
h.AuthCheck(w, req)
// Check status code
if w.Code != tt.expectedStatus {
t.Errorf("Expected status %d, got %d", tt.expectedStatus, w.Code)
}
// Check Location header for redirects
if tt.expectedStatus == http.StatusFound {
location := w.Header().Get("Location")
if location != tt.expectedHeader {
t.Errorf("Expected Location header %s, got %s", tt.expectedHeader, location)
}
}
// Check auth headers for authenticated requests
if tt.authenticated && tt.expectedStatus == http.StatusOK {
userHeader := w.Header().Get("X-Auth-User")
if userHeader == "" {
t.Error("Expected X-Auth-User header for authenticated request")
}
}
})
}
}
func TestAuthCheckWithHost(t *testing.T) {
// Setup test config
cfg := &config.Config{
Auth: config.AuthConfig{
SessionSecret: "test-secret",
},
WebAuthn: config.WebAuthnConfig{
RPDisplayName: "Test Passkey Auth",
RPID: "localhost",
RPOrigins: []string{"http://localhost:8080"},
},
}
// Setup test database
db, err := database.New(":memory:")
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer db.Close()
// Setup test WebAuthn
webAuthn, err := auth.NewWebAuthn(cfg)
if err != nil {
t.Fatalf("Failed to create test WebAuthn: %v", err)
}
// Create handlers
h := New(db, webAuthn, cfg)
// Test with Host header
req, err := http.NewRequest("GET", "/auth?rd=https://example.com/protected", nil)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
req.Header.Set("Host", "auth.example.com")
req.Header.Set("X-Forwarded-Proto", "https")
w := httptest.NewRecorder()
h.AuthCheck(w, req)
// Should return 302 with full URL
if w.Code != http.StatusFound {
t.Errorf("Expected status %d, got %d", http.StatusFound, w.Code)
}
expectedLocation := "https://auth.example.com/login.html?redirect=https://example.com/protected"
location := w.Header().Get("Location")
if location != expectedLocation {
t.Errorf("Expected Location header %s, got %s", expectedLocation, location)
}
}