Files
digiserver-v2/PLAYER_AUTH.md
2025-11-12 16:07:03 +02:00

382 lines
9.0 KiB
Markdown

# Player Authentication System - DigiServer v2 & Kiwy-Signage
## Overview
DigiServer v2 now includes a secure player authentication system compatible with Kiwy-Signage players. Players can authenticate using either a password or quick connect code, and their credentials are securely stored locally.
## Features
**Dual Authentication Methods**
- Password-based authentication (secure bcrypt hashing)
- Quick Connect codes for easy pairing
**Secure Credential Storage**
- Auth codes saved locally in encrypted configuration
- No need to re-authenticate on every restart
**Automatic Session Management**
- Auth codes persist across player restarts
- Automatic status updates and heartbeats
**Player Identification**
- Unique hostname for each player
- Configurable display orientation (Landscape/Portrait)
## Database Schema
The Player model now includes:
```python
class Player(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
hostname = db.Column(db.String(255), unique=True, nullable=False, index=True)
location = db.Column(db.String(255), nullable=True)
auth_code = db.Column(db.String(255), unique=True, nullable=False, index=True)
password_hash = db.Column(db.String(255), nullable=False)
quickconnect_code = db.Column(db.String(255), nullable=True)
group_id = db.Column(db.Integer, db.ForeignKey('group.id'), nullable=True)
orientation = db.Column(db.String(16), default='Landscape')
status = db.Column(db.String(50), default='offline')
last_seen = db.Column(db.DateTime, nullable=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
```
## API Endpoints
### 1. Player Authentication
**POST** `/api/auth/player`
Authenticate a player and receive auth code.
**Request:**
```json
{
"hostname": "player-001",
"password": "your_password",
"quickconnect_code": "QUICK123" // Optional if using password
}
```
**Response (200 OK):**
```json
{
"success": true,
"player_id": 1,
"player_name": "Demo Player",
"hostname": "player-001",
"auth_code": "abc123xyz...",
"group_id": 5,
"orientation": "Landscape",
"status": "online"
}
```
**Error Response (401 Unauthorized):**
```json
{
"error": "Invalid credentials"
}
```
### 2. Verify Auth Code
**POST** `/api/auth/verify`
Verify an existing auth code.
**Request:**
```json
{
"auth_code": "abc123xyz..."
}
```
**Response (200 OK):**
```json
{
"valid": true,
"player_id": 1,
"player_name": "Demo Player",
"hostname": "player-001",
"group_id": 5,
"orientation": "Landscape",
"status": "online"
}
```
## Player Configuration File
Players store their configuration in `player_config.ini`:
```ini
[server]
server_url = http://your-server:5000
[player]
hostname = player-001
auth_code = abc123xyz...
player_id = 1
group_id = 5
[display]
orientation = Landscape
resolution = 1920x1080
[security]
verify_ssl = true
timeout = 30
[cache]
cache_dir = ./cache
max_cache_size = 1024
[logging]
enabled = true
log_level = INFO
log_file = ./player.log
```
## Integration with Kiwy-Signage
### Step 1: Copy Authentication Module
Copy `player_auth_module.py` to your Kiwy-Signage project:
```bash
cp digiserver-v2/player_auth_module.py signage-player/src/player_auth.py
```
### Step 2: Initialize Authentication
In your main signage player code:
```python
from player_auth import PlayerAuth
# Initialize authentication
auth = PlayerAuth(config_path='player_config.ini')
# Check if already authenticated
if auth.is_authenticated():
# Verify saved credentials
valid, info = auth.verify_auth()
if valid:
print(f"Authenticated as: {info['player_name']}")
else:
# Re-authenticate
success, error = auth.authenticate(
hostname='player-001',
password='your_password'
)
else:
# First time setup
hostname = input("Enter player hostname: ")
password = input("Enter password: ")
success, error = auth.authenticate(hostname, password)
if success:
print("Authentication successful!")
else:
print(f"Authentication failed: {error}")
```
### Step 3: Use Authentication for API Calls
```python
# Get playlist with authentication
playlist = auth.get_playlist()
# Send heartbeat
auth.send_heartbeat(status='online')
# Make authenticated API request
import requests
auth_code = auth.get_auth_code()
player_id = auth.config.get('player', 'player_id')
server_url = auth.get_server_url()
response = requests.get(
f"{server_url}/api/playlists/{player_id}",
headers={'Authorization': f'Bearer {auth_code}'}
)
```
## Server Setup
### 1. Create Players in DigiServer
Via Web Interface:
1. Log in as admin (admin/admin123)
2. Navigate to Players → Add Player
3. Fill in:
- **Name**: Display name
- **Hostname**: Unique identifier (e.g., `player-001`)
- **Location**: Physical location
- **Password**: Secure password
- **Quick Connect Code**: Optional easy pairing code
- **Orientation**: Landscape or Portrait
Via Python:
```python
from app.extensions import db
from app.models import Player
import secrets
player = Player(
name='Office Player',
hostname='office-player-001',
location='Main Office - Reception',
auth_code=secrets.token_urlsafe(32),
orientation='Landscape'
)
player.set_password('secure_password_123')
player.set_quickconnect_code('OFFICE123')
db.session.add(player)
db.session.commit()
```
### 2. Distribute Credentials
Securely provide each player with:
- Server URL
- Hostname
- Password OR Quick Connect Code
## Security Considerations
**Passwords**: Hashed with bcrypt (cost factor 12)
**Auth Codes**: 32-byte URL-safe tokens
**HTTPS**: Enable SSL in production
**Rate Limiting**: API endpoints protected (10 req/min for auth)
**Local Storage**: Config file permissions should be 600
## Troubleshooting
### Player Can't Authenticate
1. Check server connectivity:
```bash
curl http://your-server:5000/api/health
```
2. Verify credentials in database
3. Check server logs for authentication attempts
4. Ensure hostname is unique
### Auth Code Invalid
1. Clear saved config: `rm player_config.ini`
2. Re-authenticate with password
3. Check if player was deleted from server
### Connection Timeout
1. Increase timeout in `player_config.ini`:
```ini
[security]
timeout = 60
```
2. Check network connectivity
3. Verify server is running
## Migration from v1
If migrating from DigiServer v1:
1. **Export player data** from v1 database
2. **Create players** in v2 with hostname = old username
3. **Set passwords** using `player.set_password()`
4. **Update player apps** with new authentication module
5. **Test authentication** before full deployment
## Example: Complete Player Setup
```python
#!/usr/bin/env python3
"""
Complete player setup example
"""
from player_auth import PlayerAuth
import sys
def setup_player():
"""Interactive player setup"""
auth = PlayerAuth()
# Check if already configured
if auth.is_authenticated():
print(f"✅ Already configured as: {auth.get_hostname()}")
# Test connection
valid, info = auth.verify_auth()
if valid:
print(f"✅ Connection successful")
print(f" Player: {info['player_name']}")
print(f" Group: {info.get('group_id', 'None')}")
return True
else:
print("❌ Saved credentials invalid, reconfiguring...")
auth.clear_auth()
# First time setup
print("\n🚀 Player Setup")
print("-" * 50)
# Get server URL
server_url = input("Server URL [http://localhost:5000]: ").strip()
if server_url:
auth.config['server']['server_url'] = server_url
auth.save_config()
# Get hostname
hostname = input("Player hostname: ").strip()
if not hostname:
print("❌ Hostname required")
return False
# Authentication method
print("\nAuthentication method:")
print("1. Password")
print("2. Quick Connect Code")
choice = input("Choice [1]: ").strip() or "1"
if choice == "1":
password = input("Password: ").strip()
success, error = auth.authenticate(hostname, password=password)
else:
code = input("Quick Connect Code: ").strip()
success, error = auth.authenticate(hostname, quickconnect_code=code)
if success:
print("\n✅ Authentication successful!")
print(f" Config saved to: {auth.config_path}")
return True
else:
print(f"\n❌ Authentication failed: {error}")
return False
if __name__ == '__main__':
if setup_player():
sys.exit(0)
else:
sys.exit(1)
```
## Files Included
- `player_auth_module.py` - Python authentication module for players
- `player_config_template.ini` - Configuration template
- `reinit_db.sh` - Script to recreate database with new schema
- `PLAYER_AUTH.md` - This documentation
## Support
For issues or questions:
1. Check server logs: `app/instance/logs/`
2. Check player logs: `player.log`
3. Verify API health: `/api/health`
4. Review authentication attempts in server logs