mirror of
https://github.com/wahyd4/passkey-auth.git
synced 2026-08-09 04:15:55 +10:00
196 lines
5.0 KiB
Go
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)
|
|
}
|
|
}
|