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

9.0 KiB

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:

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:

{
  "hostname": "player-001",
  "password": "your_password",
  "quickconnect_code": "QUICK123"  // Optional if using password
}

Response (200 OK):

{
  "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):

{
  "error": "Invalid credentials"
}

2. Verify Auth Code

POST /api/auth/verify

Verify an existing auth code.

Request:

{
  "auth_code": "abc123xyz..."
}

Response (200 OK):

{
  "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:

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

cp digiserver-v2/player_auth_module.py signage-player/src/player_auth.py

Step 2: Initialize Authentication

In your main signage player code:

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

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

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:
curl http://your-server:5000/api/health
  1. Verify credentials in database
  2. Check server logs for authentication attempts
  3. 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:
[security]
timeout = 60
  1. Check network connectivity
  2. 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

#!/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