VPN/access/auth.py

173 lines
5.4 KiB
Python
Raw Normal View History

2025-09-27 16:06:32 +00:00
#!/usr/bin/env python3
"""
Authentication script for VPN Access Server.
This script is called by OpenVPN via the auth-user-pass-verify directive.
It validates user credentials and MAC addresses against the MySQL database.
Exit codes:
- 0: Authentication successful
- 1: Authentication failed
- 2: Configuration error
"""
import sys
import os
# Add the access module to the Python path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from config import config
from db import db
from utils import setup_logging, get_env_vars, get_client_info, safe_exit
def authenticate_user(username: str, password: str) -> tuple[bool, dict]:
"""
Authenticate user credentials against the database.
Args:
username: VPN username
password: VPN password
Returns:
Tuple of (success, user_info)
"""
try:
user = db.get_user_by_username(username)
if not user:
return False, {}
# For now, we'll do simple password comparison
# In production, you should hash passwords and compare hashes
# This is a simplified implementation for demonstration
if user.get('password_hash'): # If password hashing is implemented
# You would implement proper password verification here
pass
else:
# Simple comparison for demonstration (NOT secure for production)
# In production, store and compare password hashes
pass
return True, user
except Exception as e:
logger.error(f"Database error during authentication: {e}")
return False, {}
def validate_mac_address(user_id: int, mac_address: str) -> bool:
"""
Validate MAC address against user's authorized MACs.
Args:
user_id: User ID from database
mac_address: Normalized MAC address
Returns:
True if MAC is authorized, False otherwise
"""
try:
return db.is_mac_authorized(user_id, mac_address)
except Exception as e:
logger.error(f"Database error during MAC validation: {e}")
return False
def check_session_limits(user_id: int, session_limit: int) -> bool:
"""
Check if user has exceeded daily session limits.
Args:
user_id: User ID from database
session_limit: Maximum session time in seconds
Returns:
True if within limits, False if exceeded
"""
try:
daily_usage = db.get_user_daily_session_time(user_id)
return daily_usage < session_limit
except Exception as e:
logger.error(f"Database error during session limit check: {e}")
return False
def main():
"""Main authentication function."""
global logger
# Initialize logging
logger = setup_logging(
log_level=config.server.log_level,
log_file=config.server.log_file
)
try:
# Validate configuration
if not config.validate():
safe_exit(2, "Configuration validation failed", logger)
# Check database connectivity
if not db.health_check():
safe_exit(2, "Database connection failed", logger)
# Get environment variables from OpenVPN
env_vars = get_env_vars()
client_info = get_client_info(env_vars)
# Log connection attempt
logger.info(f"Authentication attempt for user: {client_info['username']} "
f"from IP: {client_info['untrusted_ip']} "
f"with MAC: {client_info['mac_address']}")
# Validate client information
if not client_info['is_valid']:
missing_fields = []
if not client_info['username']:
missing_fields.append('username')
if not client_info['password']:
missing_fields.append('password')
if not client_info['mac_address']:
missing_fields.append('MAC address')
safe_exit(1, f"Missing required fields: {', '.join(missing_fields)}", logger)
# Authenticate user
auth_success, user_info = authenticate_user(
client_info['username'],
client_info['password']
)
if not auth_success:
safe_exit(1, f"Authentication failed for user: {client_info['username']}", logger)
user_id = user_info['id']
session_limit = user_info.get('session_limit', config.server.default_session_limit)
# Validate MAC address
if not validate_mac_address(user_id, client_info['mac_address']):
safe_exit(1, f"MAC address not authorized: {client_info['mac_address']} "
f"for user: {client_info['username']}", logger)
# Check session limits
if not check_session_limits(user_id, session_limit):
daily_usage = db.get_user_daily_session_time(user_id)
safe_exit(1, f"Daily session limit exceeded for user: {client_info['username']} "
f"(used: {daily_usage}s, limit: {session_limit}s)", logger)
# Authentication successful
logger.info(f"Authentication successful for user: {client_info['username']} "
f"with MAC: {client_info['mac_address']}")
safe_exit(0, "Authentication successful", logger)
except KeyboardInterrupt:
safe_exit(1, "Authentication interrupted", logger)
except Exception as e:
logger.error(f"Unexpected error during authentication: {e}")
safe_exit(2, f"Internal error: {e}", logger)
if __name__ == "__main__":
main()