Files
query-orchestration/internal/cognitoauth/validation.go
T
Jay Brown 2ff6e05ffc Merged in feature/permit-integration-1 (pull request #172)
Permit integration - part 1

* WIP permit integration

* slim down build

* Merge branch 'main' of bitbucket.org:aarete/query-orchestration into feature/permit-integration-1

* omit swagger from auth

* clean build

* comment

* part 1 completed

this is the initial permitio parts and tests without integration. Also testing.md since we have a new test target `task test:permitio`

* feature flag for no jwt validation

* permit integration

* fix ci unit tests

* ci fix

* build fix

* fix home handler

* fix redirect

* test fix

* update docs for auth
2025-07-11 19:27:14 +00:00

108 lines
3.7 KiB
Go

package cognitoauth
import (
"fmt"
"log/slog"
"net/http"
"os"
"strings"
"time"
)
// ValidatePermitIOConfiguration validates both PDP connectivity and API key at startup
// This function should be called during application startup to ensure configuration is correct
// before processing any real authorization requests.
//
// It performs two checks:
// 1. PDP Health Check: Tests connectivity to the PDP URL using the /healthy endpoint
// 2. API Key Validation: Makes a dummy permission check to verify the API key is valid
//
// If DISABLE_AUTH=true, validation is skipped and function returns success.
// Returns an error if either check fails, which should cause the application to halt startup.
func ValidatePermitIOConfiguration() error {
// Skip validation if auth is disabled
disableAuth := os.Getenv("DISABLE_AUTH")
if strings.ToLower(disableAuth) == "true" {
fmt.Println("✓ Permit.io validation skipped (DISABLE_AUTH=true)")
return nil
}
pdpURL := os.Getenv("PERMIT_IO_PDP_URL")
apiKey := os.Getenv("PERMIT_IO_API_KEY")
// Apply default for PDP URL if not set
if pdpURL == "" {
pdpURL = "http://localhost:7766"
}
if apiKey == "" {
return fmt.Errorf("PERMIT_IO_API_KEY environment variable must be set")
}
// 1. Test PDP connectivity with /healthy endpoint
client := &http.Client{Timeout: 10 * time.Second}
healthURL := strings.TrimSuffix(pdpURL, "/") + "/healthy"
req, err := http.NewRequest("GET", healthURL, nil)
if err != nil {
return fmt.Errorf("failed to create health check request: %v", err)
}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("Permit.io PDP connectivity failed with PDP_URL=%s: %v", pdpURL, err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return fmt.Errorf("Permit.io PDP health check failed with PDP_URL=%s: HTTP %d", pdpURL, resp.StatusCode)
}
// 2. Test API key validity with a dummy permission check
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelWarn}))
permitClient := NewPermitIOClient(apiKey, pdpURL, logger)
// Use dummy test data that will likely be denied but should work with valid API key
testUser := "startup-validation-user-12345"
testAction := "read"
testResource := "startup-validation-resource"
_, err = permitClient.CheckPermission(testUser, testAction, testResource)
if err != nil {
// Check for specific error patterns to distinguish error types
errStr := err.Error()
if strings.Contains(errStr, "UnexpectedError") && (strings.Contains(errStr, "connection refused") || strings.Contains(errStr, "no such host")) {
return fmt.Errorf("Permit.io PDP connectivity failed with PDP_URL=%s: %v", pdpURL, err)
}
if strings.Contains(errStr, "Unauthorized") || strings.Contains(errStr, "Invalid PDP token") || strings.Contains(errStr, "api_error") {
return fmt.Errorf("Permit.io API key validation failed with API_KEY=%s and PDP_URL=%s: %v",
maskAPIKey(apiKey), pdpURL, err)
}
if strings.Contains(errStr, "UnprocessableEntityError") {
return fmt.Errorf("Permit.io API configuration error with API_KEY=%s and PDP_URL=%s: %v",
maskAPIKey(apiKey), pdpURL, err)
}
// Any other error is also a configuration problem
return fmt.Errorf("Permit.io validation failed with API_KEY=%s and PDP_URL=%s: %v",
maskAPIKey(apiKey), pdpURL, err)
}
// Success - both PDP connectivity and API key are valid
fmt.Printf("✓ Permit.io configuration validated successfully (PDP_URL=%s, API_KEY=%s)\n",
pdpURL, maskAPIKey(apiKey))
return nil
}
// maskAPIKey masks the API key for logging, showing only the first 8 characters
func maskAPIKey(apiKey string) string {
if len(apiKey) <= 8 {
return "***masked***"
}
return apiKey[:8] + "..."
}