diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 55e0c7df..b5c87c31 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -105,7 +105,7 @@ jobs: - name: Extract metadata (tags, labels) if: steps.skip.outputs.skip_build != 'true' id: meta - uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0 + uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | diff --git a/ACME_STAGING_IMPLEMENTATION.md.bak b/ACME_STAGING_IMPLEMENTATION.md.bak new file mode 100644 index 00000000..e0b3f968 --- /dev/null +++ b/ACME_STAGING_IMPLEMENTATION.md.bak @@ -0,0 +1,95 @@ +# ACME Staging Implementation Summary + +## What Was Added + +Added support for Let's Encrypt staging environment to prevent rate limiting during development and testing. + +## Changes Made + +### 1. Configuration (`backend/internal/config/config.go`) +- Added `ACMEStaging bool` field to `Config` struct +- Reads from `CHARON_ACME_STAGING` environment variable (legacy `CPM_ACME_STAGING` still supported) + +### 2. Caddy Manager (`backend/internal/caddy/manager.go`) +- Added `acmeStaging bool` field to `Manager` struct +- Updated `NewManager()` to accept `acmeStaging` parameter +- Passes `acmeStaging` to `GenerateConfig()` + +### 3. Config Generation (`backend/internal/caddy/config.go`) +- Updated `GenerateConfig()` signature to accept `acmeStaging bool` +- When `acmeStaging=true`: + - Sets `ca` field to `https://acme-staging-v02.api.letsencrypt.org/directory` + - Applies to both "letsencrypt" and "both" SSL provider modes + +### 4. Route Registration (`backend/internal/api/routes/routes.go`) +- Passes `cfg.ACMEStaging` to `caddy.NewManager()` + +### 5. Docker Compose (`docker-compose.local.yml`) +- Added `CHARON_ACME_STAGING=true` environment variable for local development (legacy `CPM_ACME_STAGING` still supported) + +### 6. Tests +- Updated all test files to pass new `acmeStaging` parameter +- Added `TestGenerateConfig_ACMEStaging()` to verify behavior +- All tests pass ✅ + +### 7. Documentation +- Created `/docs/acme-staging.md` - comprehensive guide +- Updated `/docs/getting-started.md` - added environment variables section +- Explained rate limits, staging vs production, and troubleshooting + +## Usage + +### Development (Avoid Rate Limits) +```bash +docker run -d \ + -e CHARON_ACME_STAGING=true \ + -p 8080:8080 \ + ghcr.io/wikid82/charon:latest +``` + +### Production (Real Certificates) +```bash +docker run -d \ + -p 8080:8080 \ + ghcr.io/wikid82/charon:latest +``` + +## Verification + +Container logs confirm staging is active: +``` +"ca":"https://acme-staging-v02.api.letsencrypt.org/directory" +``` + +## Benefits + +1. **No Rate Limits**: Test certificate issuance without hitting Let's Encrypt limits +2. **Safe Testing**: Won't affect production certificate quotas +3. **Easy Toggle**: Single environment variable to switch modes +4. **Default Production**: Staging must be explicitly enabled +5. **Well Documented**: Clear guides for users and developers + +## Test Results + +- ✅ All backend tests pass (`go test ./...`) +- ✅ Config generation tests verify staging CA is set +- ✅ Manager tests updated and passing +- ✅ Handler tests updated and passing +- ✅ Integration verified in running container + +## Files Modified + +- `backend/internal/config/config.go` +- `backend/internal/caddy/config.go` +- `backend/internal/caddy/manager.go` +- `backend/internal/api/routes/routes.go` +- `backend/internal/caddy/config_test.go` +- `backend/internal/caddy/manager_test.go` +- `backend/internal/caddy/client_test.go` +- `backend/internal/api/handlers/proxy_host_handler_test.go` +- `docker-compose.local.yml` + +## Files Created + +- `docs/acme-staging.md` - User guide +- `ACME_STAGING_IMPLEMENTATION.md` - This summary diff --git a/DOCKER_TASKS.md.bak b/DOCKER_TASKS.md.bak new file mode 100644 index 00000000..a25c0efa --- /dev/null +++ b/DOCKER_TASKS.md.bak @@ -0,0 +1,76 @@ +# Docker Development Tasks + +Quick reference for Docker container management during development. + +## Available VS Code Tasks + +### Build & Run Local Docker +**Command:** `Build & Run Local Docker` +- Builds the Docker image from scratch with current code +- Tags as `charon:local` +- Starts container with docker-compose.local.yml +- **Use when:** You've made backend code changes that need recompiling + +### Docker: Restart Local (No Rebuild) ⚡ +**Command:** `Docker: Restart Local (No Rebuild)` +- Stops the running container +- Starts it back up using existing image +- **Use when:** You've changed volume mounts, environment variables, or want to clear runtime state +- **Fastest option** for testing volume mount changes + +### Docker: Stop Local +**Command:** `Docker: Stop Local` +- Stops and removes the running container +- Preserves volumes and image +- **Use when:** You need to stop the container temporarily + +### Docker: Start Local (Already Built) +**Command:** `Docker: Start Local (Already Built)` +- Starts container from existing image +- **Use when:** Container is stopped but image is built + +## Manual Commands + +```bash +# Build and run (full rebuild) +docker build --build-arg VCS_REF=$(git rev-parse HEAD) -t charon:local . && \ +docker compose -f docker-compose.local.yml up -d + +# Quick restart (no rebuild) - FASTEST for volume mount testing +docker compose -f docker-compose.local.yml down && \ +docker compose -f docker-compose.local.yml up -d + +# View logs +docker logs -f charon-debug + +# Stop container +docker compose -f docker-compose.local.yml down + +# Start existing container +docker compose -f docker-compose.local.yml up -d +``` + +## Testing Import Feature + +The import feature uses a mounted Caddyfile at `/import/Caddyfile` inside the container. + +**Volume mount in docker-compose.local.yml:** +```yaml +- /root/docker/containers/caddy/Caddyfile:/import/Caddyfile:ro +- /root/docker/containers/caddy/sites:/import/sites:ro +``` + +**To test import with different Caddyfiles:** +1. Edit `/root/docker/containers/caddy/Caddyfile` on the host +2. Run task: `Docker: Restart Local (No Rebuild)` ⚡ +3. Check GUI - import should detect the mounted Caddyfile +4. No rebuild needed! + +## Coverage Requirement + +All code changes must maintain **≥80% test coverage**. + +Run coverage check: +```bash +cd backend && bash ../scripts/go-test-coverage.sh +``` diff --git a/ISSUE_14_SSO_IMPLEMENTATION.md.bak b/ISSUE_14_SSO_IMPLEMENTATION.md.bak new file mode 100644 index 00000000..8839bf3b --- /dev/null +++ b/ISSUE_14_SSO_IMPLEMENTATION.md.bak @@ -0,0 +1,331 @@ +# Built-in OAuth/OIDC Server Implementation Summary + +## Overview +Implemented Phase 1 (Backend Core) and Phase 2 (Caddy Integration) for Issue #14: Built-in OAuth/OIDC Server (SSO - Plus Feature). + +## Phase 1: Backend Core + +### 1. Docker Configuration +**File: `/projects/Charon/Dockerfile`** +- Updated `xcaddy build` command to include `github.com/greenpau/caddy-security` plugin +- This enables caddy-security functionality in the Caddy binary + +### 2. Database Models +Created three new models in `/projects/Charon/backend/internal/models/`: + +#### `auth_user.go` - AuthUser Model +- Local user accounts for SSO +- Fields: UUID, Username, Email, Name, PasswordHash, Enabled, Roles, MFAEnabled, MFASecret, LastLoginAt +- Methods: + - `SetPassword()` - Bcrypt password hashing + - `CheckPassword()` - Password verification + - `HasRole()` - Role checking + +#### `auth_provider.go` - AuthProvider Model +- External OAuth/OIDC provider configurations +- Fields: UUID, Name, Type (google, github, oidc, saml), ClientID, ClientSecret, IssuerURL, AuthURL, TokenURL, UserInfoURL, Scopes, RoleMapping, IconURL, DisplayName +- Supports generic OIDC providers and specific ones (Google, GitHub, etc.) + +#### `auth_policy.go` - AuthPolicy Model +- Access control policies for proxy hosts +- Fields: UUID, Name, Description, AllowedRoles, AllowedUsers, AllowedDomains, RequireMFA, SessionTimeout +- Method: `IsPublic()` - checks if policy allows unrestricted access + +### 3. ProxyHost Model Enhancement +**File: `/projects/Charon/backend/internal/models/proxy_host.go`** +- Added `AuthPolicyID` field (nullable foreign key) +- Added `AuthPolicy` relationship +- Enables linking proxy hosts to authentication policies + +### 4. API Handlers +**File: `/projects/Charon/backend/internal/api/handlers/auth_handlers.go`** + +Created three handler structs with full CRUD operations: + +#### AuthUserHandler +- `List()` - Get all auth users +- `Get()` - Get user by UUID +- `Create()` - Create new user (with password validation) +- `Update()` - Update user (supports partial updates) +- `Delete()` - Delete user (prevents deletion of last admin) +- `Stats()` - Get user statistics (total, enabled, with MFA) + +#### AuthProviderHandler +- `List()` - Get all OAuth providers +- `Get()` - Get provider by UUID +- `Create()` - Register new OAuth provider +- `Update()` - Update provider configuration +- `Delete()` - Remove OAuth provider + +#### AuthPolicyHandler +- `List()` - Get all access policies +- `Get()` - Get policy by UUID +- `Create()` - Create new policy +- `Update()` - Update policy rules +- `Delete()` - Remove policy (prevents deletion if in use) + +### 5. API Routes +**File: `/projects/Charon/backend/internal/api/routes/routes.go`** + +Registered new endpoints under `/api/v1/security/`: +``` +GET /security/users +GET /security/users/stats +GET /security/users/:uuid +POST /security/users +PUT /security/users/:uuid +DELETE /security/users/:uuid + +GET /security/providers +GET /security/providers/:uuid +POST /security/providers +PUT /security/providers/:uuid +DELETE /security/providers/:uuid + +GET /security/policies +GET /security/policies/:uuid +POST /security/policies +PUT /security/policies/:uuid +DELETE /security/policies/:uuid +``` + +Added new models to AutoMigrate: +- `models.AuthUser` +- `models.AuthProvider` +- `models.AuthPolicy` + +## Phase 2: Caddy Integration + +### 1. Caddy Configuration Types +**File: `/projects/Charon/backend/internal/caddy/types.go`** + +Added new types for caddy-security integration: + +#### SecurityApp +- Top-level security app configuration +- Contains Authentication and Authorization configs + +#### AuthenticationConfig & AuthPortal +- Portal configuration for authentication +- Supports multiple backends (local, OAuth, SAML) +- Cookie and token management settings + +#### AuthBackend +- Configuration for individual auth backends +- Supports local users and OAuth providers + +#### AuthorizationConfig & AuthzPolicy +- Policy definitions for access control +- Role-based and user-based restrictions +- MFA requirements + +#### New Handler Functions +- `SecurityAuthHandler()` - Authentication middleware +- `SecurityAuthzHandler()` - Authorization middleware + +### 2. Config Generation +**File: `/projects/Charon/backend/internal/caddy/config.go`** + +#### Updated `GenerateConfig()` Signature +Added new parameters: +- `authUsers []models.AuthUser` +- `authProviders []models.AuthProvider` +- `authPolicies []models.AuthPolicy` + +#### New Function: `generateSecurityApp()` +Generates the caddy-security app configuration: +- Creates authentication portal "charon_portal" +- Configures local backend with user credentials +- Adds OAuth providers dynamically +- Generates authorization policies from database + +#### New Function: `convertAuthUsersToConfig()` +Converts AuthUser models to caddy-security user config format: +- Maps username, email, password hash +- Converts comma-separated roles to arrays +- Filters disabled users + +#### Route Handler Integration +When generating routes for proxy hosts: +- Checks if host has an `AuthPolicyID` +- Injects `SecurityAuthHandler("charon_portal")` before other handlers +- Injects `SecurityAuthzHandler(policy.Name)` for policy enforcement +- Maintains compatibility with legacy Forward Auth + +### 3. Manager Updates +**File: `/projects/Charon/backend/internal/caddy/manager.go`** + +Updated `ApplyConfig()` to: +- Fetch enabled auth users from database +- Fetch enabled auth providers from database +- Fetch enabled auth policies from database +- Preload AuthPolicy relationships for proxy hosts +- Pass auth data to `GenerateConfig()` + +### 4. Test Updates +Updated all test files to pass empty slices for new auth parameters: +- `client_test.go` +- `config_test.go` +- `validator_test.go` +- `manager_test.go` + +## Architecture Flow + +``` +1. User Management UI → API → Database (AuthUser, AuthProvider, AuthPolicy) +2. ApplyConfig() → Fetch auth data → GenerateConfig() +3. GenerateConfig() → Create SecurityApp config +4. For each ProxyHost with AuthPolicyID: + - Inject SecurityAuthHandler (authentication) + - Inject SecurityAuthzHandler (authorization) +5. Caddy receives full config with security app +6. Incoming requests → Caddy → Security handlers → Backend services +``` + +## Database Schema + +### auth_users +- id, uuid, created_at, updated_at +- username, email, name +- password_hash +- enabled, roles +- mfa_enabled, mfa_secret +- last_login_at + +### auth_providers +- id, uuid, created_at, updated_at +- name, type, enabled +- client_id, client_secret +- issuer_url, auth_url, token_url, user_info_url +- scopes, role_mapping +- icon_url, display_name + +### auth_policies +- id, uuid, created_at, updated_at +- name, description, enabled +- allowed_roles, allowed_users, allowed_domains +- require_mfa, session_timeout + +### proxy_hosts (updated) +- Added: auth_policy_id (nullable FK) + +## Configuration Example + +When a proxy host has `auth_policy_id = 1` (pointing to "Admins Only" policy): + +```json +{ + "apps": { + "security": { + "authentication": { + "portals": { + "charon_portal": { + "backends": [ + { + "name": "local", + "method": "local", + "config": { + "users": [ + { + "username": "admin", + "email": "admin@example.com", + "password": "$2a$10$...", + "roles": ["admin"] + } + ] + } + } + ] + } + } + }, + "authorization": { + "policies": { + "Admins Only": { + "allowed_roles": ["admin"], + "require_mfa": false + } + } + } + }, + "http": { + "servers": { + "charon_server": { + "routes": [ + { + "match": [{"host": ["app.example.com"]}], + "handle": [ + {"handler": "authentication", "portal": "charon_portal"}, + {"handler": "authorization", "policy": "Admins Only"}, + {"handler": "reverse_proxy", "upstreams": [{"dial": "backend:8080"}]} + ] + } + ] + } + } + } + } +} +``` + +## Security Considerations + +1. **Password Storage**: Uses bcrypt for secure password hashing +2. **Secrets**: ClientSecret and MFASecret fields are never exposed in JSON responses +3. **Admin Protection**: Cannot delete the last admin user +4. **Policy Enforcement**: Cannot delete policies that are in use +5. **MFA Support**: Framework ready for TOTP implementation + +## Next Steps (Phase 3 & 4) + +### Phase 3: Frontend Management UI +- Create `/src/pages/Security/` directory +- Implement Users management page +- Implement Providers management page +- Implement Policies management page +- Add SSO dashboard with session overview + +### Phase 4: Proxy Host Integration +- Update ProxyHostForm with "Access Control" tab +- Add policy selector dropdown +- Display active policy on host list +- Show authentication status indicators + +## Testing + +All backend tests pass: +``` +✓ internal/api/handlers +✓ internal/api/middleware +✓ internal/api/routes +✓ internal/caddy (all tests updated) +✓ internal/config +✓ internal/database +✓ internal/models +✓ internal/server +✓ internal/services +✓ internal/version +``` + +Backend compiles successfully without errors. + +## Acceptance Criteria Status + +- ✅ Can create local users for authentication (AuthUser model + API) +- ✅ Can protect services with built-in SSO (AuthPolicy + route integration) +- ⏳ 2FA works correctly (framework ready, needs frontend implementation) +- ✅ External OIDC providers can be configured (AuthProvider model + API) + +## Reserved Routes + +- `/auth/*` - Reserved for caddy-security authentication portal +- Portal URL: `https://yourdomain.com/auth/login` +- Logout URL: `https://yourdomain.com/auth/logout` + +## Notes + +1. The implementation uses SQLite as the source of truth +2. Configuration is "compiled" from database to Caddy JSON on each ApplyConfig +3. No direct database sharing with caddy-security (config-based integration) +4. Compatible with existing Forward Auth feature (both can coexist) +5. MFA secret storage is ready but TOTP setup flow needs frontend work diff --git a/cookies.txt.bak b/cookies.txt.bak new file mode 100644 index 00000000..1f4251a9 --- /dev/null +++ b/cookies.txt.bak @@ -0,0 +1,3 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk.