package caddyatprotoauth import ( "net/http" "strings" "testing" "time" "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" _ "github.com/caddyserver/caddy/v2/modules/standard" ) func TestCaddyIntegration(t *testing.T) { // Setup Caddyfile // Try: Change the allow list on the gate to include a nonexistent handle. // You should see a warning log that Caddy was unable to resolve it. input := ` { admin off atproto { storage_path :memory: } } :8080 { route /auth/* { uri strip_prefix /auth atproto_portal { name "Test Portal" } } route /protected/* { atproto_gate { allow @tangled.org portal_url http://localhost:8080/auth } respond "Authorized Content" } } ` // Parse and Load Config adapter := caddyfile.Adapter{ ServerType: httpcaddyfile.ServerType{}, } jsonConfig, warnings, err := adapter.Adapt([]byte(input), nil) if err != nil { t.Fatalf("Failed to adapt config: %v", err) } if len(warnings) > 0 { t.Logf("Warnings: %v", warnings) } err = caddy.Load(jsonConfig, true) if err != nil { t.Fatalf("Failed to load caddy: %v", err) } defer caddy.Stop() // Wait a moment for server start time.Sleep(100 * time.Millisecond) baseURL := "http://localhost:8080" client := &http.Client{ CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse // Don't follow redirects }, } t.Run("Unauthorized Access Redirects to Portal", func(t *testing.T) { resp, err := client.Get(baseURL + "/protected/resource") if err != nil { t.Fatalf("Request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusFound { t.Errorf("Expected status 302, got %d", resp.StatusCode) } location := resp.Header.Get("Location") if !strings.Contains(location, "/auth/login") { t.Errorf("Expected redirect to portal login, got %s", location) } }) t.Run("Portal Serves Login Page", func(t *testing.T) { resp, err := client.Get(baseURL + "/auth/login") if err != nil { t.Fatalf("Request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Errorf("Expected status 200, got %d", resp.StatusCode) } // Verify content type (HTML) ct := resp.Header.Get("Content-Type") if !strings.Contains(ct, "text/html") { t.Errorf("Expected HTML content, got %s", ct) } }) t.Run("Portal Serves Metadata", func(t *testing.T) { resp, err := client.Get(baseURL + "/auth/.well-known/oauth-client-metadata.json") if err != nil { t.Fatalf("Request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Errorf("Expected status 200, got %d", resp.StatusCode) } // Verify content type (JSON) ct := resp.Header.Get("Content-Type") if !strings.Contains(ct, "application/json") { t.Errorf("Expected JSON content, got %s", ct) } }) }