Implement comprehensive authentication system with support for Basic Auth, Flask-Login, and OAuth2 providers. Features: - Pluggable architecture via factory pattern - Multiple authentication providers: * None: No authentication (development/testing) * Basic Auth: HTTP Basic with bcrypt support * Flask-Login: Session-based with multiple users * OAuth2: Google, GitHub, GitLab, and generic providers - Decorator-based route protection (@auth.require_auth) - User authorization by domain or email (OAuth) - bcrypt password hashing support - Comprehensive documentation and examples Components: - libtisbackup/auth/__init__.py: Factory function and exports - libtisbackup/auth/base.py: Base provider interface - libtisbackup/auth/basic_auth.py: HTTP Basic Auth implementation - libtisbackup/auth/flask_login_auth.py: Flask-Login implementation - libtisbackup/auth/oauth_auth.py: OAuth2 implementation - libtisbackup/auth/example_integration.py: Integration examples - libtisbackup/auth/README.md: API reference and examples Documentation: - AUTHENTICATION.md: Complete authentication guide * Setup instructions for each provider * Configuration examples * Security best practices * Troubleshooting guide * Migration guide - samples/auth-config-examples.ini: Configuration templates Dependencies: - Add optional dependencies in pyproject.toml: * auth-basic: bcrypt>=4.0.0 * auth-login: flask-login>=0.6.0, bcrypt>=4.0.0 * auth-oauth: authlib>=1.3.0, requests>=2.32.0 * auth-all: All auth providers Installation: ```bash # Install specific provider uv sync --extra auth-basic # Install all providers uv sync --extra auth-all ``` Usage: ```python from libtisbackup.auth import get_auth_provider # Initialize auth = get_auth_provider("basic", { "username": "admin", "password": "$2b$12$...", "use_bcrypt": True }) auth.init_app(app) # Protect routes @app.route("/") @auth.require_auth def index(): user = auth.get_current_user() return f"Hello {user['username']}" ``` Security features: - bcrypt password hashing (work factor 12) - OAuth domain/user restrictions - Session-based authentication - Clear separation of concerns - Environment variable support for secrets OAuth providers supported: - Google (OpenID Connect) - GitHub - GitLab - Generic OAuth2 provider Breaking change: None - new feature, backward compatible Users can continue without authentication (type=none) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
444 lines
9.6 KiB
Markdown
444 lines
9.6 KiB
Markdown
# TISBackup Authentication System
|
|
|
|
TISBackup provides a pluggable authentication system for securing the Flask web interface. You can choose between multiple authentication methods based on your security requirements.
|
|
|
|
## Supported Authentication Methods
|
|
|
|
1. **None** - No authentication (default, NOT recommended for production)
|
|
2. **Basic Auth** - HTTP Basic Authentication with username/password
|
|
3. **Flask-Login** - Session-based authentication with username/password
|
|
4. **OAuth2** - OAuth authentication (Google, GitHub, GitLab, or generic provider)
|
|
|
|
## Quick Start
|
|
|
|
### 1. Choose Authentication Method
|
|
|
|
Add an `[authentication]` section to `/etc/tis/tisbackup_gui.ini`:
|
|
|
|
```ini
|
|
[authentication]
|
|
type = basic
|
|
username = admin
|
|
password = $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5GyYWv.5qVQK6
|
|
use_bcrypt = True
|
|
```
|
|
|
|
### 2. Install Dependencies
|
|
|
|
```bash
|
|
# For Basic Auth
|
|
uv sync --extra auth-basic
|
|
|
|
# For Flask-Login
|
|
uv sync --extra auth-login
|
|
|
|
# For OAuth
|
|
uv sync --extra auth-oauth
|
|
|
|
# For all auth methods
|
|
uv sync --extra auth-all
|
|
```
|
|
|
|
### 3. Restart TISBackup
|
|
|
|
```bash
|
|
docker compose restart tisbackup_gui
|
|
```
|
|
|
|
## Configuration Guide
|
|
|
|
### Basic Authentication
|
|
|
|
Simple HTTP Basic Auth with username and password.
|
|
|
|
**Pros:**
|
|
- Easy to set up
|
|
- Works with all HTTP clients
|
|
- No session management needed
|
|
|
|
**Cons:**
|
|
- Credentials sent with every request
|
|
- No logout functionality
|
|
- Browser password prompt can be confusing
|
|
|
|
**Configuration:**
|
|
|
|
```ini
|
|
[authentication]
|
|
type = basic
|
|
username = admin
|
|
# Use bcrypt hash (recommended)
|
|
password = $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5GyYWv.5qVQK6
|
|
use_bcrypt = True
|
|
realm = TISBackup Admin
|
|
```
|
|
|
|
**Generate bcrypt hash:**
|
|
|
|
```bash
|
|
python3 -c "import bcrypt; print(bcrypt.hashpw(b'yourpassword', bcrypt.gensalt()).decode())"
|
|
```
|
|
|
|
**Docker environment:**
|
|
|
|
```yaml
|
|
services:
|
|
tisbackup_gui:
|
|
environment:
|
|
- TISBACKUP_SECRET_KEY=your-secret-key
|
|
# Optional: Pass credentials via env vars
|
|
# Then reference in config with ${AUTH_PASSWORD}
|
|
```
|
|
|
|
---
|
|
|
|
### Flask-Login Authentication
|
|
|
|
Session-based authentication with login page and user management.
|
|
|
|
**Pros:**
|
|
- Clean login/logout workflow
|
|
- Session-based (no credentials in each request)
|
|
- Multiple users supported
|
|
- Password hashing with bcrypt
|
|
|
|
**Cons:**
|
|
- Requires custom login page
|
|
- Session management overhead
|
|
- Cookies must be enabled
|
|
|
|
**Configuration:**
|
|
|
|
```ini
|
|
[authentication]
|
|
type = flask-login
|
|
users_file = /etc/tis/users.txt
|
|
use_bcrypt = True
|
|
login_view = login
|
|
```
|
|
|
|
**Create users file** (`/etc/tis/users.txt`):
|
|
|
|
```
|
|
admin:$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5GyYWv.5qVQK6
|
|
operator:$2b$12$abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNO
|
|
viewer:$2b$12$ANOTHERBCRYPTHASHHERE1234567890ABCDEFGHIJKLMNOPQRS
|
|
```
|
|
|
|
**Generate user entry:**
|
|
|
|
```bash
|
|
USERNAME="admin"
|
|
PASSWORD="yourpassword"
|
|
HASH=$(python3 -c "import bcrypt; print(bcrypt.hashpw(b'$PASSWORD', bcrypt.gensalt()).decode())")
|
|
echo "$USERNAME:$HASH" >> /etc/tis/users.txt
|
|
```
|
|
|
|
**Permissions:**
|
|
|
|
```bash
|
|
chmod 600 /etc/tis/users.txt
|
|
chown root:root /etc/tis/users.txt
|
|
```
|
|
|
|
---
|
|
|
|
### OAuth2 Authentication
|
|
|
|
Delegate authentication to external OAuth providers (Google, GitHub, GitLab, etc.)
|
|
|
|
**Pros:**
|
|
- No password management
|
|
- Leverage existing identity providers
|
|
- Support for SSO
|
|
- Can restrict by domain or specific users
|
|
|
|
**Cons:**
|
|
- Requires OAuth app registration
|
|
- Internet connectivity required
|
|
- More complex setup
|
|
- External dependency
|
|
|
|
#### Google OAuth
|
|
|
|
**Setup:**
|
|
|
|
1. Go to [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
|
|
2. Create OAuth 2.0 Client ID
|
|
3. Add authorized redirect URI: `http://your-server:8080/oauth/callback`
|
|
4. Note the Client ID and Client Secret
|
|
|
|
**Configuration:**
|
|
|
|
```ini
|
|
[authentication]
|
|
type = oauth
|
|
provider = google
|
|
client_id = 123456789-abcdefghijklmnop.apps.googleusercontent.com
|
|
client_secret = GOCSPX-your-client-secret-here
|
|
redirect_uri = http://your-server:8080/oauth/callback
|
|
|
|
# Restrict to specific domain(s)
|
|
authorized_domains = example.com,mycompany.com
|
|
|
|
# Or restrict to specific users
|
|
authorized_users = admin@example.com,backup-admin@example.com
|
|
```
|
|
|
|
#### GitHub OAuth
|
|
|
|
**Setup:**
|
|
|
|
1. Go to GitHub Settings > Developer settings > [OAuth Apps](https://github.com/settings/developers)
|
|
2. Register a new application
|
|
3. Set Authorization callback URL: `http://your-server:8080/oauth/callback`
|
|
4. Note the Client ID and Client Secret
|
|
|
|
**Configuration:**
|
|
|
|
```ini
|
|
[authentication]
|
|
type = oauth
|
|
provider = github
|
|
client_id = your-github-client-id
|
|
client_secret = your-github-client-secret
|
|
redirect_uri = http://your-server:8080/oauth/callback
|
|
authorized_users = admin@example.com,devops@example.com
|
|
```
|
|
|
|
#### GitLab OAuth
|
|
|
|
**Setup:**
|
|
|
|
1. Go to GitLab User Settings > [Applications](https://gitlab.com/-/profile/applications)
|
|
2. Create application with scopes: `read_user`, `email`
|
|
3. Set Redirect URI: `http://your-server:8080/oauth/callback`
|
|
4. Note the Application ID and Secret
|
|
|
|
**Configuration:**
|
|
|
|
```ini
|
|
[authentication]
|
|
type = oauth
|
|
provider = gitlab
|
|
client_id = your-gitlab-application-id
|
|
client_secret = your-gitlab-secret
|
|
redirect_uri = http://your-server:8080/oauth/callback
|
|
authorized_domains = example.com
|
|
```
|
|
|
|
#### Generic OAuth Provider
|
|
|
|
For custom OAuth providers:
|
|
|
|
```ini
|
|
[authentication]
|
|
type = oauth
|
|
provider = generic
|
|
client_id = your-client-id
|
|
client_secret = your-client-secret
|
|
redirect_uri = http://your-server:8080/oauth/callback
|
|
|
|
# Custom endpoints
|
|
authorization_endpoint = https://auth.example.com/oauth/authorize
|
|
token_endpoint = https://auth.example.com/oauth/token
|
|
userinfo_endpoint = https://auth.example.com/oauth/userinfo
|
|
scopes = openid,email,profile
|
|
|
|
# Authorization rules
|
|
authorized_domains = example.com
|
|
```
|
|
|
|
---
|
|
|
|
## Security Best Practices
|
|
|
|
### 1. Use HTTPS in Production
|
|
|
|
Always use a reverse proxy with TLS:
|
|
|
|
```nginx
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name tisbackup.example.com;
|
|
|
|
ssl_certificate /etc/letsencrypt/live/tisbackup.example.com/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/tisbackup.example.com/privkey.pem;
|
|
|
|
location / {
|
|
proxy_pass http://localhost:8080/;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto https;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. Set Strong Flask Secret Key
|
|
|
|
```bash
|
|
# Generate secret
|
|
python3 -c "import secrets; print(secrets.token_hex(32))"
|
|
|
|
# Set in environment
|
|
export TISBACKUP_SECRET_KEY=your-generated-secret-key
|
|
```
|
|
|
|
### 3. Protect Configuration Files
|
|
|
|
```bash
|
|
chmod 600 /etc/tis/tisbackup_gui.ini
|
|
chmod 600 /etc/tis/users.txt # if using Flask-Login
|
|
chown root:root /etc/tis/*.ini
|
|
```
|
|
|
|
### 4. Use Environment Variables for Secrets
|
|
|
|
Instead of hardcoding secrets in config files:
|
|
|
|
```ini
|
|
[authentication]
|
|
type = oauth
|
|
client_id = ${OAUTH_CLIENT_ID}
|
|
client_secret = ${OAUTH_CLIENT_SECRET}
|
|
```
|
|
|
|
Then set in Docker Compose:
|
|
|
|
```yaml
|
|
services:
|
|
tisbackup_gui:
|
|
environment:
|
|
- OAUTH_CLIENT_ID=your-client-id
|
|
- OAUTH_CLIENT_SECRET=your-client-secret
|
|
- TISBACKUP_SECRET_KEY=your-secret-key
|
|
```
|
|
|
|
### 5. Regularly Rotate Credentials
|
|
|
|
- Change passwords/secrets every 90 days
|
|
- Rotate OAuth client secrets annually
|
|
- Review authorized users/domains regularly
|
|
|
|
### 6. Monitor Authentication Logs
|
|
|
|
Check logs for failed authentication attempts:
|
|
|
|
```bash
|
|
docker logs tisbackup_gui | grep -i "auth"
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Basic Auth Not Working
|
|
|
|
1. **Check bcrypt installation:**
|
|
```bash
|
|
uv sync --extra auth-basic
|
|
```
|
|
|
|
2. **Verify password hash:**
|
|
```bash
|
|
python3 -c "import bcrypt; print(bcrypt.checkpw(b'yourpassword', b'$2b$12$your-hash'))"
|
|
```
|
|
|
|
3. **Check browser credentials:**
|
|
- Clear browser cache
|
|
- Try incognito/private mode
|
|
|
|
### Flask-Login Issues
|
|
|
|
1. **Users file not found:**
|
|
```bash
|
|
ls -la /etc/tis/users.txt
|
|
chmod 600 /etc/tis/users.txt
|
|
```
|
|
|
|
2. **Module not found:**
|
|
```bash
|
|
uv sync --extra auth-login
|
|
```
|
|
|
|
3. **Session problems:**
|
|
- Check `TISBACKUP_SECRET_KEY` is set
|
|
- Ensure cookies are enabled
|
|
|
|
### OAuth Problems
|
|
|
|
1. **Redirect URI mismatch:**
|
|
- Ensure redirect URI in config matches OAuth app settings exactly
|
|
- Check for http vs https mismatch
|
|
|
|
2. **Unauthorized domain/user:**
|
|
- Verify email matches `authorized_users` or domain matches `authorized_domains`
|
|
- Check OAuth provider returns email in user info
|
|
|
|
3. **Module not found:**
|
|
```bash
|
|
uv sync --extra auth-oauth
|
|
```
|
|
|
|
4. **Token errors:**
|
|
- Verify client ID and secret are correct
|
|
- Check OAuth app is enabled
|
|
- Ensure scopes are correct
|
|
|
|
## API Access with Authentication
|
|
|
|
### Basic Auth
|
|
|
|
```bash
|
|
curl -u admin:password http://localhost:8080/api/backups
|
|
```
|
|
|
|
### OAuth (with access token)
|
|
|
|
```bash
|
|
# Not recommended for API access - use service account or API keys instead
|
|
```
|
|
|
|
### Recommendation for API Access
|
|
|
|
For programmatic API access, use Basic Auth with a dedicated API user:
|
|
|
|
```ini
|
|
[authentication]
|
|
type = basic
|
|
username = api-user
|
|
password = $2b$12$...
|
|
```
|
|
|
|
Or implement API key authentication separately for API endpoints.
|
|
|
|
## Migration Guide
|
|
|
|
### From No Auth to Basic Auth
|
|
|
|
1. Add authentication section to config
|
|
2. Install bcrypt: `uv sync --extra auth-basic`
|
|
3. Restart service
|
|
4. Update client scripts with credentials
|
|
|
|
### From Basic Auth to OAuth
|
|
|
|
1. Register OAuth application
|
|
2. Update configuration
|
|
3. Install dependencies: `uv sync --extra auth-oauth`
|
|
4. Test OAuth login flow
|
|
5. Update redirect URI if needed
|
|
|
|
### From Flask-Login to OAuth
|
|
|
|
1. Register OAuth application
|
|
2. Map user emails to OAuth provider
|
|
3. Update configuration
|
|
4. Test migration with test users first
|
|
|
|
## Support
|
|
|
|
For issues or questions:
|
|
- Check logs: `docker logs tisbackup_gui`
|
|
- Review configuration syntax
|
|
- Verify dependencies are installed
|
|
- See [SECURITY_IMPROVEMENTS.md](../SECURITY_IMPROVEMENTS.md) for security context
|