Files
ip-manager/webapp/includes/auth.php
2026-01-18 01:38:59 +00:00

230 lines
5.9 KiB
PHP

<?php
/**
* Authentication and RBAC Helper Functions
*
* Provides role-based access control with Cloudflare Access integration
*/
// Role constants
define('ROLE_STAFF', 'staff');
define('ROLE_ADMIN', 'admin');
/**
* Get the currently authenticated user from Cloudflare Access headers
* Falls back to session-based auth if CF headers not present
*
* @return array|null User info array or null if not authenticated
*/
function getCurrentUser() {
// Check for Cloudflare Access headers first
// Try multiple header variations that Cloudflare might use
$cfEmail = null;
$headerChecked = [];
// Standard Cloudflare Access header
if (!empty($_SERVER['HTTP_CF_ACCESS_AUTHENTICATED_USER_EMAIL'])) {
$cfEmail = $_SERVER['HTTP_CF_ACCESS_AUTHENTICATED_USER_EMAIL'];
$headerChecked[] = 'HTTP_CF_ACCESS_AUTHENTICATED_USER_EMAIL';
}
// Alternative: some proxies might pass it differently
elseif (!empty($_SERVER['CF_ACCESS_AUTHENTICATED_USER_EMAIL'])) {
$cfEmail = $_SERVER['CF_ACCESS_AUTHENTICATED_USER_EMAIL'];
$headerChecked[] = 'CF_ACCESS_AUTHENTICATED_USER_EMAIL';
}
// Check via getallheaders() for non-standard server configs
elseif (function_exists('getallheaders')) {
$headers = getallheaders();
if (!empty($headers['Cf-Access-Authenticated-User-Email'])) {
$cfEmail = $headers['Cf-Access-Authenticated-User-Email'];
$headerChecked[] = 'getallheaders:Cf-Access-Authenticated-User-Email';
}
}
if ($cfEmail) {
// User authenticated via Cloudflare Access
return [
'email' => $cfEmail,
'auth_method' => 'cloudflare_access',
'role' => getUserRole($cfEmail)
];
}
// Fall back to session-based auth
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
if (!empty($_SESSION['authenticated']) && !empty($_SESSION['user'])) {
return [
'email' => $_SESSION['user'],
'auth_method' => 'session',
'role' => getUserRole($_SESSION['user'])
];
}
return null;
}
/**
* Get user role from database or default to staff
*
* @param string $email User email
* @return string Role (admin or staff)
*/
function getUserRole($email) {
if (empty($email)) {
return ROLE_STAFF;
}
// First, check environment variable for admin emails (highest priority)
$adminEmails = getenv('ADMIN_EMAILS');
if (!empty($adminEmails)) {
$adminList = array_map('trim', explode(',', $adminEmails));
if (in_array($email, $adminList)) {
return ROLE_ADMIN;
}
}
// Also check if defined as a constant (from config.php)
if (defined('ADMIN_EMAILS') && !empty(ADMIN_EMAILS)) {
$adminList = array_map('trim', explode(',', ADMIN_EMAILS));
if (in_array($email, $adminList)) {
return ROLE_ADMIN;
}
}
// Try database lookup if getDB function exists
if (function_exists('getDB')) {
try {
$db = getDB();
$stmt = $db->prepare("SELECT role FROM users WHERE email = ? AND active = 1");
$stmt->execute([$email]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result && !empty($result['role'])) {
return $result['role'];
}
} catch (Exception $e) {
// Table might not exist yet, fall through to default
}
}
// Default to staff if not found in env or database
return ROLE_STAFF;
}
/**
* Check if current user has a specific role
*
* @param string $requiredRole Role to check for
* @return bool True if user has the role
*/
function hasRole($requiredRole) {
$user = getCurrentUser();
if (!$user) {
return false;
}
// Admin has access to everything
if ($user['role'] === ROLE_ADMIN) {
return true;
}
return $user['role'] === $requiredRole;
}
/**
* Check if current user is an admin
*
* @return bool True if user is admin
*/
function isAdmin() {
return hasRole(ROLE_ADMIN);
}
/**
* Check if current user is staff (or admin)
*
* @return bool True if user is staff or admin
*/
function isStaff() {
return hasRole(ROLE_STAFF) || hasRole(ROLE_ADMIN);
}
/**
* Require a specific role to access a page
* Redirects to appropriate page if not authorized
*
* @param string $requiredRole Role required
* @param string $redirectUrl URL to redirect to if unauthorized
*/
function requireRole($requiredRole, $redirectUrl = '/') {
if (!hasRole($requiredRole)) {
header('HTTP/1.1 403 Forbidden');
header('Location: ' . $redirectUrl . '?error=unauthorized');
exit;
}
}
/**
* Require admin role to access a page
*/
function requireAdmin() {
requireRole(ROLE_ADMIN, '/');
}
/**
* Get user identifier for audit logging
* Returns email or 'anonymous' if not authenticated
*
* @return string User identifier
*/
function getAuditUser() {
$user = getCurrentUser();
if ($user) {
return $user['email'];
}
// Check legacy session
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
return $_SESSION['user'] ?? 'anonymous';
}
/**
* Get user display info for header
*
* @return array User display info
*/
function getUserDisplayInfo() {
$user = getCurrentUser();
if (!$user) {
return [
'name' => 'Guest',
'email' => '',
'role' => '',
'initials' => 'G',
'auth_method' => 'none',
'is_admin' => false
];
}
$email = $user['email'];
$name = explode('@', $email)[0];
$initials = strtoupper(substr($name, 0, 2));
return [
'name' => ucfirst($name),
'email' => $email,
'role' => $user['role'],
'initials' => $initials,
'auth_method' => $user['auth_method'],
'is_admin' => $user['role'] === ROLE_ADMIN
];
}