Merge branch 'development' into main

This commit is contained in:
Jeremy
2025-11-29 18:56:09 -05:00
committed by GitHub
5 changed files with 506 additions and 1 deletions

View File

@@ -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: |

View File

@@ -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

76
DOCKER_TASKS.md.bak Normal file
View File

@@ -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
```

View File

@@ -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

3
cookies.txt.bak Normal file
View File

@@ -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.