Files
drone-detector/server/middleware/rbac.js
2025-09-15 07:05:38 +02:00

304 lines
8.2 KiB
JavaScript

/**
* Role-Based Access Control (RBAC) System
* Defines granular permissions for different roles
*/
// Define specific permissions
const PERMISSIONS = {
// General tenant management
'tenant.view': 'View tenant information',
'tenant.edit': 'Edit basic tenant settings',
// Branding permissions
'branding.view': 'View branding settings',
'branding.edit': 'Edit branding and appearance',
// Security permissions
'security.view': 'View security settings',
'security.edit': 'Edit security settings and IP restrictions',
// User management permissions
'users.view': 'View user list',
'users.create': 'Create new users',
'users.edit': 'Edit user details',
'users.delete': 'Delete or deactivate users',
'users.manage_roles': 'Change user roles',
// Authentication permissions
'auth.view': 'View authentication settings',
'auth.edit': 'Edit authentication provider settings',
// Operational permissions
'dashboard.view': 'View dashboard',
'devices.view': 'View devices',
'devices.manage': 'Add, edit, delete devices',
'detections.view': 'View detections',
'alerts.view': 'View alerts',
'alerts.manage': 'Manage alert configurations',
'debug.access': 'Access debug information'
};
// Role definitions with their permissions
const ROLES = {
// Full tenant administrator
'admin': [
'tenant.view', 'tenant.edit',
'branding.view', 'branding.edit',
'security.view', 'security.edit',
'users.view', 'users.create', 'users.edit', 'users.delete', 'users.manage_roles',
'auth.view', 'auth.edit',
'dashboard.view',
'devices.view', 'devices.manage',
'detections.view',
'alerts.view', 'alerts.manage',
'debug.access'
],
// User management specialist
'user_admin': [
'tenant.view',
'users.view', 'users.create', 'users.edit', 'users.delete', 'users.manage_roles',
'dashboard.view',
'devices.view',
'detections.view',
'alerts.view'
],
// Security specialist
'security_admin': [
'tenant.view',
'security.view', 'security.edit',
'auth.view', 'auth.edit',
'users.view',
'dashboard.view',
'devices.view',
'detections.view',
'alerts.view', 'alerts.create', 'alerts.edit',
'audit_logs.view'
],
// Branding/marketing specialist
'branding_admin': [
'tenant.view',
'branding.view', 'branding.edit', 'branding.create',
'dashboard.view',
'devices.view',
'detections.view',
'alerts.view'
],
// Operations manager
'operator': [
'tenant.view',
'dashboard.view',
'devices.view', 'devices.manage',
'detections.view', 'detections.create',
'alerts.view', 'alerts.manage'
],
// Read-only user
'viewer': [
'dashboard.view',
'devices.view',
'detections.view',
'alerts.view'
]
};
/**
* Check if a user has a specific permission
* @param {string} userRole - The user's role
* @param {string} permission - The permission to check
* @returns {boolean} - True if user has permission
*/
const hasPermission = (userRole, permission) => {
if (!userRole || !ROLES[userRole]) {
return false;
}
return ROLES[userRole].includes(permission);
};
/**
* Compatibility function for tests - converts resource.action format to permission
* @param {string} userRole - The user's role
* @param {string} resource - The resource (e.g., 'devices', 'users')
* @param {string} action - The action (e.g., 'read', 'create', 'update', 'delete')
* @returns {boolean} - True if user has permission
*/
const checkPermission = (userRole, resource, action) => {
// Normalize inputs to lowercase for case-insensitive comparison
const normalizedRole = userRole ? userRole.toLowerCase() : '';
const normalizedResource = resource ? resource.toLowerCase() : '';
const normalizedAction = action ? action.toLowerCase() : '';
// Map common actions to our permission system
const actionMap = {
'read': 'view',
'create': 'create',
'update': 'edit',
'delete': 'delete',
'manage': 'manage'
};
// Special cases for resource mapping
const resourceMap = {
'devices': 'devices',
'users': 'users',
'detections': 'detections',
'alerts': 'alerts',
'dashboard': 'dashboard',
'branding': 'branding',
'security': 'security',
'ip_restrictions': 'security',
'audit_logs': 'security',
'ui_customization': 'branding'
};
const mappedResource = resourceMap[normalizedResource] || normalizedResource;
const mappedAction = actionMap[normalizedAction] || normalizedAction;
const permission = `${mappedResource}.${mappedAction}`;
return hasPermission(normalizedRole, permission);
};
/**
* Compatibility function for tests - creates middleware for specific resource.action
* @param {string} resource - The resource (e.g., 'devices', 'users')
* @param {string} action - The action (e.g., 'read', 'create', 'update', 'delete')
* @returns {Function} - Express middleware function
*/
const requirePermission = (resource, action) => {
return (req, res, next) => {
if (!req.user || !req.user.role) {
return res.status(403).json({
success: false,
message: 'Insufficient permissions'
});
}
if (!checkPermission(req.user.role, resource, action)) {
return res.status(403).json({
success: false,
message: 'Insufficient permissions'
});
}
next();
};
};
/**
* Check if a user has any of the specified permissions
* @param {string} userRole - The user's role
* @param {Array<string>} permissions - Array of permissions to check
* @returns {boolean} - True if user has at least one permission
*/
const hasAnyPermission = (userRole, permissions) => {
return permissions.some(permission => hasPermission(userRole, permission));
};
/**
* Check if a user has all of the specified permissions
* @param {string} userRole - The user's role
* @param {Array<string>} permissions - Array of permissions to check
* @returns {boolean} - True if user has all permissions
*/
const hasAllPermissions = (userRole, permissions) => {
return permissions.every(permission => hasPermission(userRole, permission));
};
/**
* Get all permissions for a role
* @param {string} userRole - The user's role
* @returns {Array<string>} - Array of permissions
*/
const getPermissions = (userRole) => {
return ROLES[userRole] || [];
};
/**
* Get all available roles
* @returns {Array<string>} - Array of role names
*/
const getRoles = () => {
return Object.keys(ROLES);
};
/**
* Express middleware to check permissions
* @param {Array<string>} requiredPermissions - Required permissions
* @returns {Function} - Express middleware function
*/
const requirePermissions = (requiredPermissions) => {
return (req, res, next) => {
if (!req.user || !req.user.role) {
return res.status(401).json({
success: false,
message: 'Authentication required'
});
}
const userRole = req.user.role;
const hasRequiredPermissions = requiredPermissions.every(permission =>
hasPermission(userRole, permission)
);
if (!hasRequiredPermissions) {
return res.status(403).json({
success: false,
message: 'Insufficient permissions',
required_permissions: requiredPermissions,
user_role: userRole
});
}
next();
};
};
/**
* Express middleware to check if user has any of the specified permissions
* @param {Array<string>} permissions - Array of permissions
* @returns {Function} - Express middleware function
*/
const requireAnyPermission = (permissions) => {
return (req, res, next) => {
if (!req.user || !req.user.role) {
return res.status(401).json({
success: false,
message: 'Authentication required'
});
}
const userRole = req.user.role;
const hasRequiredPermission = permissions.some(permission =>
hasPermission(userRole, permission)
);
if (!hasRequiredPermission) {
return res.status(403).json({
success: false,
message: 'Insufficient permissions',
required_permissions: permissions,
user_role: userRole
});
}
next();
};
};
module.exports = {
PERMISSIONS,
ROLES,
hasPermission,
checkPermission,
requirePermission,
hasAnyPermission,
hasAllPermissions,
getPermissions,
getRoles,
requirePermissions,
requireAnyPermission
};