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
This commit is contained in:
312
web-ui/auth.php
Normal file
312
web-ui/auth.php
Normal file
@@ -0,0 +1,312 @@
|
||||
<?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();
|
||||
?>
|
||||
Reference in New Issue
Block a user