feat(admin): add proxy-only auth bypass and configurable auth header (closes #28)

This commit is contained in:
Ryan
2025-05-08 04:43:33 -04:00
committed by GitHub
parent d48b15a5f4
commit b4d6f01432
7 changed files with 278 additions and 75 deletions

View File

@@ -54,11 +54,22 @@ class AdminController
{
header('Content-Type: application/json');
$config = AdminModel::getConfig();
// If an error was encountered, send a 500 status.
if (isset($config['error'])) {
http_response_code(500);
}
if (!isset($config['loginOptions']) || !is_array($config['loginOptions'])) {
$config['loginOptions'] = [];
}
if (!array_key_exists('authBypass', $config['loginOptions'])) {
$config['loginOptions']['authBypass'] = false;
}
if (!array_key_exists('authHeaderName', $config['loginOptions'])) {
$config['loginOptions']['authHeaderName'] = 'X-Remote-User';
}
// ← END INSERT
echo json_encode($config);
exit;
}
@@ -203,6 +214,12 @@ class AdminController
$sharedMaxUploadSize = filter_var($data['features']['sharedMaxUploadSize'], FILTER_VALIDATE_INT);
}
$authBypass = filter_var(
$data['loginOptions']['authBypass'] ?? false,
FILTER_VALIDATE_BOOLEAN
);
$authHeaderName = trim($data['loginOptions']['authHeaderName'] ?? '') ?: 'X-Remote-User';
$configUpdate = [
'header_title' => $headerTitle,
'oidc' => [
@@ -215,6 +232,8 @@ class AdminController
'disableFormLogin' => $disableFormLogin,
'disableBasicAuth' => $disableBasicAuth,
'disableOIDCLogin' => $disableOIDCLogin,
'authBypass' => $authBypass,
'authHeaderName' => $authHeaderName,
],
'globalOtpauthUrl' => $globalOtpauthUrl,
'enableWebDAV' => $enableWebDAV,

View File

@@ -342,48 +342,48 @@ class AuthController
public function checkAuth(): void
{
// 1) Remember-me re-login
if (empty($_SESSION['authenticated']) && !empty($_COOKIE['remember_me_token'])) {
$payload = AuthModel::validateRememberToken($_COOKIE['remember_me_token']);
if ($payload) {
$old = $_SESSION['csrf_token'] ?? bin2hex(random_bytes(32));
session_regenerate_id(true);
$_SESSION['csrf_token'] = $old;
$_SESSION['authenticated'] = true;
$_SESSION['username'] = $payload['username'];
$_SESSION['isAdmin'] = !empty($payload['isAdmin']);
$_SESSION['folderOnly'] = $payload['folderOnly'] ?? false;
$_SESSION['readOnly'] = $payload['readOnly'] ?? false;
$_SESSION['disableUpload'] = $payload['disableUpload'] ?? false;
// regenerate CSRF if you use one
// 1) Remember-me re-login
if (empty($_SESSION['authenticated']) && !empty($_COOKIE['remember_me_token'])) {
$payload = AuthModel::validateRememberToken($_COOKIE['remember_me_token']);
if ($payload) {
$old = $_SESSION['csrf_token'] ?? bin2hex(random_bytes(32));
session_regenerate_id(true);
$_SESSION['csrf_token'] = $old;
$_SESSION['authenticated'] = true;
$_SESSION['username'] = $payload['username'];
$_SESSION['isAdmin'] = !empty($payload['isAdmin']);
$_SESSION['folderOnly'] = $payload['folderOnly'] ?? false;
$_SESSION['readOnly'] = $payload['readOnly'] ?? false;
$_SESSION['disableUpload'] = $payload['disableUpload'] ?? false;
// regenerate CSRF if you use one
// TOTP enabled? (same logic as below)
$usersFile = USERS_DIR . USERS_FILE;
$totp = false;
if (file_exists($usersFile)) {
foreach (file($usersFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
$parts = explode(':', trim($line));
if ($parts[0] === $_SESSION['username'] && !empty($parts[3])) {
$totp = true;
break;
// TOTP enabled? (same logic as below)
$usersFile = USERS_DIR . USERS_FILE;
$totp = false;
if (file_exists($usersFile)) {
foreach (file($usersFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
$parts = explode(':', trim($line));
if ($parts[0] === $_SESSION['username'] && !empty($parts[3])) {
$totp = true;
break;
}
}
}
}
echo json_encode([
'authenticated' => true,
'csrf_token' => $_SESSION['csrf_token'],
'isAdmin' => $_SESSION['isAdmin'],
'totp_enabled' => $totp,
'username' => $_SESSION['username'],
'folderOnly' => $_SESSION['folderOnly'],
'readOnly' => $_SESSION['readOnly'],
'disableUpload' => $_SESSION['disableUpload']
]);
exit();
echo json_encode([
'authenticated' => true,
'csrf_token' => $_SESSION['csrf_token'],
'isAdmin' => $_SESSION['isAdmin'],
'totp_enabled' => $totp,
'username' => $_SESSION['username'],
'folderOnly' => $_SESSION['folderOnly'],
'readOnly' => $_SESSION['readOnly'],
'disableUpload' => $_SESSION['disableUpload']
]);
exit();
}
}
}
$usersFile = USERS_DIR . USERS_FILE;
@@ -453,11 +453,11 @@ class AuthController
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// 2) Emit headers
header('Content-Type: application/json');
header('X-CSRF-Token: ' . $_SESSION['csrf_token']);
// 3) Return JSON payload
echo json_encode([
'csrf_token' => $_SESSION['csrf_token'],

View File

@@ -16,10 +16,14 @@ class AdminModel
$unit = strtolower(substr($val, -1));
$num = (int) rtrim($val, 'bkmgtpezyBKMGTPESY');
switch ($unit) {
case 'g': return $num * 1024 ** 3;
case 'm': return $num * 1024 ** 2;
case 'k': return $num * 1024;
default: return $num;
case 'g':
return $num * 1024 ** 3;
case 'm':
return $num * 1024 ** 2;
case 'k':
return $num * 1024;
default:
return $num;
}
}
@@ -63,6 +67,24 @@ class AdminModel
$configUpdate['sharedMaxUploadSize'] = $sms;
}
// ── NEW: normalize authBypass & authHeaderName ─────────────────────────
if (!isset($configUpdate['loginOptions']['authBypass'])) {
$configUpdate['loginOptions']['authBypass'] = false;
}
$configUpdate['loginOptions']['authBypass'] = (bool)$configUpdate['loginOptions']['authBypass'];
if (
!isset($configUpdate['loginOptions']['authHeaderName'])
|| !is_string($configUpdate['loginOptions']['authHeaderName'])
|| trim($configUpdate['loginOptions']['authHeaderName']) === ''
) {
$configUpdate['loginOptions']['authHeaderName'] = 'X-Remote-User';
} else {
$configUpdate['loginOptions']['authHeaderName'] =
trim($configUpdate['loginOptions']['authHeaderName']);
}
// ───────────────────────────────────────────────────────────────────────────
// Convert configuration to JSON.
$plainTextConfig = json_encode($configUpdate, JSON_PRETTY_PRINT);
if ($plainTextConfig === false) {
@@ -128,6 +150,19 @@ class AdminModel
$config['loginOptions']['disableOIDCLogin'] = (bool)$config['loginOptions']['disableOIDCLogin'];
}
if (!array_key_exists('authBypass', $config['loginOptions'])) {
$config['loginOptions']['authBypass'] = false;
} else {
$config['loginOptions']['authBypass'] = (bool)$config['loginOptions']['authBypass'];
}
if (
!array_key_exists('authHeaderName', $config['loginOptions'])
|| !is_string($config['loginOptions']['authHeaderName'])
|| trim($config['loginOptions']['authHeaderName']) === ''
) {
$config['loginOptions']['authHeaderName'] = 'X-Remote-User';
}
// Default values for other keys
if (!isset($config['globalOtpauthUrl'])) {
$config['globalOtpauthUrl'] = "";
@@ -166,4 +201,4 @@ class AdminModel
];
}
}
}
}