Compare commits

...

2 Commits

Author SHA1 Message Date
Dan Milne
bfcc5cdc84 More nuanced domain fetching for host validation
Some checks failed
CI / scan_ruby (push) Has been cancelled
CI / scan_js (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / system-test (push) Has been cancelled
2025-10-29 16:31:56 +11:00
Dan Milne
81871426e9 Update docs 2025-10-29 16:08:49 +11:00
2 changed files with 32 additions and 13 deletions

View File

@@ -83,10 +83,29 @@ Rails.application.configure do
# Enable DNS rebinding protection and other `Host` header attacks. # Enable DNS rebinding protection and other `Host` header attacks.
# Configure allowed hosts based on deployment scenario # Configure allowed hosts based on deployment scenario
allowed_hosts = [ allowed_hosts = [
ENV.fetch('CLINCH_HOST', 'auth.aapamilne.com'), # External domain ENV.fetch('CLINCH_HOST', 'auth.example.com'), # External domain (auth service itself)
/.*#{ENV.fetch('CLINCH_HOST', 'aapamilne\.com').gsub('.', '\.')}/ # Subdomains
] ]
# Use PublicSuffix to extract registrable domain and allow all subdomains
host_domain = ENV.fetch('CLINCH_HOST', 'auth.example.com')
if host_domain.present?
begin
# Use PublicSuffix to properly extract the domain
domain = PublicSuffix.parse(host_domain)
registrable_domain = domain.domain # Gets "example.com" from "auth.example.com"
if registrable_domain.present?
# Create regex to allow any subdomain of the registrable domain
allowed_hosts << /.*#{Regexp.escape(registrable_domain)}/
end
rescue PublicSuffix::DomainInvalid
# Fallback to simple domain extraction if PublicSuffix fails
Rails.logger.warn "Could not parse domain '#{host_domain}' with PublicSuffix, using fallback"
base_domain = host_domain.split('.').last(2).join('.')
allowed_hosts << /.*#{Regexp.escape(base_domain)}/
end
end
# Allow Docker service names if running in same compose # Allow Docker service names if running in same compose
if ENV['CLINCH_DOCKER_SERVICE_NAME'] if ENV['CLINCH_DOCKER_SERVICE_NAME']
allowed_hosts << ENV['CLINCH_DOCKER_SERVICE_NAME'] allowed_hosts << ENV['CLINCH_DOCKER_SERVICE_NAME']

View File

@@ -104,17 +104,17 @@ end
- Secure random generation - Secure random generation
- Session validation before token acceptance - Session validation before token acceptance
## Authelia Analysis ## Implementation Overview
### Implementation Comparison ### Forward Auth Pattern
**Authelia Approach (from analysis of `tmp/authelia/`):** **Standard Forward Auth Approach:**
- Returns `302 Found` or `303 See Other` with `Location` header - Returns `302 Found` or `303 See Other` with `Location` header
- Direct browser redirects (bypasses some proxy logic) - Direct browser redirects to authentication service
- Uses StatusFound (302) or StatusSeeOther (303) - Uses HTTP status codes to communicate authentication state
**Clinch Current Implementation:** **Clinch Current Implementation:**
- Returns `302 Found` directly to login URL (matching Authelia) - Returns `302 Found` directly to login URL
- Includes `rd` (redirect destination) and `rm` (request method) parameters - Includes `rd` (redirect destination) and `rm` (request method) parameters
- Uses root domain cookies for cross-subdomain authentication - Uses root domain cookies for cross-subdomain authentication
@@ -123,7 +123,7 @@ end
### Authentication Flow ### Authentication Flow
1. **User visits** `https://metube.example.com/` 1. **User visits** `https://metube.example.com/`
2. **Caddy forwards** to `http://clinch:9000/api/verify?rd=https://clinch.example.com` 2. **Caddy forwards** to `http://clinch:3000/api/verify?rd=https://clinch.example.com`
3. **Clinch checks session**: 3. **Clinch checks session**:
- **If authenticated**: Returns `200 OK` with user headers - **If authenticated**: Returns `200 OK` with user headers
- **If not authenticated**: Returns `302 Found` to login URL with redirect parameters - **If not authenticated**: Returns `302 Found` to login URL with redirect parameters
@@ -157,12 +157,12 @@ Location: https://clinch.example.com/signin?rd=https://metube.example.com/&rm=GE
```caddyfile ```caddyfile
# Clinch SSO (main authentication server) # Clinch SSO (main authentication server)
clinch.example.com { clinch.example.com {
reverse_proxy clinch:9000 reverse_proxy clinch:3000
} }
# MEtube (protected by Clinch) # MEtube (protected by Clinch)
metube.example.com { metube.example.com {
forward_auth clinch:9000 { forward_auth clinch:3000 {
uri /api/verify?rd=https://clinch.example.com uri /api/verify?rd=https://clinch.example.com
copy_headers Remote-User Remote-Email Remote-Groups Remote-Admin copy_headers Remote-User Remote-Email Remote-Groups Remote-Admin
} }
@@ -181,13 +181,13 @@ metube.example.com {
- **Forward Auth Controller**: `app/controllers/api/forward_auth_controller.rb` - **Forward Auth Controller**: `app/controllers/api/forward_auth_controller.rb`
- **Authentication Logic**: `app/controllers/concerns/authentication.rb` - **Authentication Logic**: `app/controllers/concerns/authentication.rb`
- **Caddy Examples**: `docs/caddy-example.md` - **Caddy Examples**: `docs/caddy-example.md`
- **Authelia Analysis**: `docs/authelia-forward-auth.md` - **Implementation Details**: See technical documentation below
## Testing ## Testing
```bash ```bash
# Test forward auth endpoint directly # Test forward auth endpoint directly
curl -v http://localhost:9000/api/verify?rd=https://clinch.example.com curl -v http://localhost:3000/api/verify?rd=https://clinch.example.com
# Should return 302 redirect to login page # Should return 302 redirect to login page
# Or 200 OK if you have a valid session cookie # Or 200 OK if you have a valid session cookie