332 lines
10 KiB
Markdown
332 lines
10 KiB
Markdown
# 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
|