Files
vtl-appliance/web-ui/auth.php
Othman H. Suseno 01080498af feat: Major VTL System Upgrade (Auth, Monitoring, CLI, Installer)
- Web UI:
  - Added secure Authentication system (Login, 2 Roles: Admin/Viewer)
  - Added System Monitoring Dashboard (Health, Services, Power Mgmt)
  - Added User Management Interface (Create, Delete, Enable/Disable)
  - Added Device Mapping view in iSCSI tab (lsscsi output)
- Backend:
  - Implemented secure session management (auth.php)
  - Added power management APIs (restart/shutdown appliance)
  - Added device mapping API
- CLI:
  - Created global 'vtl' management tool
  - Added scripts for reliable startup (vtllibrary fix)
- Installer:
  - Updated install.sh with new dependencies (tgt, sudoers, permissions)
  - Included all new components in build-installer.sh
- Docs:
  - Consolidated documentation into docs/ folder
2025-12-09 18:15:36 +00:00

313 lines
8.0 KiB
PHP

<?php
/**
* Authentication and User Management
* Handles login, sessions, and user roles
*/
session_start();
// Configuration
$USERS_FILE = '/etc/mhvtl/users.json';
$SESSION_TIMEOUT = 3600; // 1 hour
// Initialize users file if it doesn't exist
function initializeUsersFile() {
global $USERS_FILE;
if (!file_exists($USERS_FILE)) {
// Create default admin user
$defaultUsers = [
[
'username' => 'admin',
'password' => password_hash('admin123', PASSWORD_BCRYPT),
'role' => 'admin',
'created' => date('Y-m-d H:i:s'),
'enabled' => true
]
];
file_put_contents($USERS_FILE, json_encode($defaultUsers, JSON_PRETTY_PRINT));
chmod($USERS_FILE, 0600);
}
}
// Load users from file
function loadUsers() {
global $USERS_FILE;
if (!file_exists($USERS_FILE)) {
initializeUsersFile();
}
$content = file_get_contents($USERS_FILE);
return json_decode($content, true) ?: [];
}
// Save users to file
function saveUsers($users) {
global $USERS_FILE;
file_put_contents($USERS_FILE, json_encode($users, JSON_PRETTY_PRINT));
chmod($USERS_FILE, 0600);
}
// Authenticate user
function authenticateUser($username, $password) {
$users = loadUsers();
foreach ($users as $user) {
if ($user['username'] === $username && $user['enabled']) {
if (password_verify($password, $user['password'])) {
// Set session
$_SESSION['user'] = [
'username' => $user['username'],
'role' => $user['role'],
'login_time' => time()
];
return true;
}
}
}
return false;
}
// Check if user is logged in
function isLoggedIn() {
global $SESSION_TIMEOUT;
if (!isset($_SESSION['user'])) {
return false;
}
// Check session timeout
if (time() - $_SESSION['user']['login_time'] > $SESSION_TIMEOUT) {
logout();
return false;
}
// Update last activity time
$_SESSION['user']['login_time'] = time();
return true;
}
// Check if user has admin role
function isAdmin() {
return isLoggedIn() && $_SESSION['user']['role'] === 'admin';
}
// Check if user has viewer role
function isViewer() {
return isLoggedIn() && $_SESSION['user']['role'] === 'viewer';
}
// Get current user
function getCurrentUser() {
return isset($_SESSION['user']) ? $_SESSION['user'] : null;
}
// Logout user
function logout() {
session_destroy();
$_SESSION = [];
}
// Require login
function requireLogin() {
if (!isLoggedIn()) {
http_response_code(401);
echo json_encode(['success' => false, 'error' => 'Unauthorized', 'redirect' => 'login.html']);
exit;
}
}
// Require admin role
function requireAdmin() {
requireLogin();
if (!isAdmin()) {
http_response_code(403);
echo json_encode(['success' => false, 'error' => 'Forbidden: Admin access required']);
exit;
}
}
// Get all users (admin only)
function getAllUsers() {
requireAdmin();
$users = loadUsers();
// Remove password hashes from response
$safeUsers = array_map(function($user) {
unset($user['password']);
return $user;
}, $users);
echo json_encode([
'success' => true,
'users' => array_values($safeUsers)
]);
}
// Create new user (admin only)
function createUser($data) {
requireAdmin();
$username = trim($data['username'] ?? '');
$password = $data['password'] ?? '';
$role = $data['role'] ?? 'viewer';
if (empty($username) || empty($password)) {
echo json_encode(['success' => false, 'error' => 'Username and password are required']);
return;
}
if (!in_array($role, ['admin', 'viewer'])) {
echo json_encode(['success' => false, 'error' => 'Invalid role']);
return;
}
$users = loadUsers();
// Check if username already exists
foreach ($users as $user) {
if ($user['username'] === $username) {
echo json_encode(['success' => false, 'error' => 'Username already exists']);
return;
}
}
// Create new user
$newUser = [
'username' => $username,
'password' => password_hash($password, PASSWORD_BCRYPT),
'role' => $role,
'created' => date('Y-m-d H:i:s'),
'enabled' => true
];
$users[] = $newUser;
saveUsers($users);
echo json_encode(['success' => true, 'message' => 'User created successfully']);
}
// Update user (admin only)
function updateUser($data) {
requireAdmin();
$username = trim($data['username'] ?? '');
$newPassword = $data['password'] ?? null;
$role = $data['role'] ?? null;
$enabled = $data['enabled'] ?? null;
if (empty($username)) {
echo json_encode(['success' => false, 'error' => 'Username is required']);
return;
}
$users = loadUsers();
$found = false;
foreach ($users as &$user) {
if ($user['username'] === $username) {
$found = true;
// Update password if provided
if ($newPassword) {
$user['password'] = password_hash($newPassword, PASSWORD_BCRYPT);
}
// Update role if provided
if ($role && in_array($role, ['admin', 'viewer'])) {
$user['role'] = $role;
}
// Update enabled status if provided
if ($enabled !== null) {
$user['enabled'] = (bool)$enabled;
}
break;
}
}
if (!$found) {
echo json_encode(['success' => false, 'error' => 'User not found']);
return;
}
saveUsers($users);
echo json_encode(['success' => true, 'message' => 'User updated successfully']);
}
// Delete user (admin only)
function deleteUser($username) {
requireAdmin();
if (empty($username)) {
echo json_encode(['success' => false, 'error' => 'Username is required']);
return;
}
// Prevent deleting yourself
if ($_SESSION['user']['username'] === $username) {
echo json_encode(['success' => false, 'error' => 'Cannot delete your own account']);
return;
}
$users = loadUsers();
$newUsers = array_filter($users, function($user) use ($username) {
return $user['username'] !== $username;
});
if (count($newUsers) === count($users)) {
echo json_encode(['success' => false, 'error' => 'User not found']);
return;
}
saveUsers(array_values($newUsers));
echo json_encode(['success' => true, 'message' => 'User deleted successfully']);
}
// Change own password
function changePassword($data) {
requireLogin();
$currentPassword = $data['current_password'] ?? '';
$newPassword = $data['new_password'] ?? '';
if (empty($currentPassword) || empty($newPassword)) {
echo json_encode(['success' => false, 'error' => 'Current and new password are required']);
return;
}
$users = loadUsers();
$currentUsername = $_SESSION['user']['username'];
foreach ($users as &$user) {
if ($user['username'] === $currentUsername) {
// Verify current password
if (!password_verify($currentPassword, $user['password'])) {
echo json_encode(['success' => false, 'error' => 'Current password is incorrect']);
return;
}
// Update password
$user['password'] = password_hash($newPassword, PASSWORD_BCRYPT);
saveUsers($users);
echo json_encode(['success' => true, 'message' => 'Password changed successfully']);
return;
}
}
echo json_encode(['success' => false, 'error' => 'User not found']);
}
// Initialize users file on first load
initializeUsersFile();
?>