const jwt = require('jsonwebtoken'); const sequelize = require('sequelize'); class RBACManager { constructor(databaseModel, SECRET_KEY, service) { this.db = databaseModel; this.SECRET_KEY = SECRET_KEY; this.service = service; } async resolvePermissions(objectGuid) { const AuthenticationGroups = this.db.get('authenticationGroupsModel'); const GroupClosure = this.db.get('groupClosureModel'); const AuthenticationRoles = this.db.get('authenticationRolesModel'); const GroupRoles = this.db.get('groupRolesModel'); const RolePermissions = this.db.get('rolePermissionsModel'); const Permission = this.db.get('permissionModel'); // 1. USER GROUPS const userGroups = await AuthenticationGroups.findAll({ where: { Authentication_ObjectGUID: objectGuid } }); const directGroupIds = userGroups.map(g => g.Group_ObjectGUID); // 2. NESTED GROUPS let allGroupIds = [...directGroupIds]; if (directGroupIds.length) { const closure = await GroupClosure.findAll({ where: { ParentGroup_ObjectGUID: directGroupIds } }); allGroupIds.push(...closure.map(c => c.ChildGroup_ObjectGUID)); } allGroupIds = [...new Set(allGroupIds)]; // 3. ROLES const userRoles = await AuthenticationRoles.findAll({ where: { Authentication_ObjectGUID: objectGuid } }); const groupRoles = await GroupRoles.findAll({ where: { Group_ObjectGUID: allGroupIds } }); const roleIds = [ ...new Set([ ...userRoles.map(r => r.Role_ID), ...groupRoles.map(r => r.Role_ID) ]) ]; // 4. PERMISSIONS const rolePerms = await RolePermissions.findAll({ where: { Role_ID: roleIds } }); const permissionIds = rolePerms.map(r => r.Permission_ID); const permissions = await Permission.findAll({ where: { ID: permissionIds } }); return { groups: allGroupIds, roles: roleIds, permissions: permissions.map(p => ({ id: p.ID, scope: p.Scope, resource: p.Resource, action: p.Action })) }; } // πŸ”₯ SUPER CLEAN CHECK (wiederverwendbar ΓΌberall) isSuperAdmin(permissions) { return permissions.some(p => p.scope === 'SYSTEM' && p.resource === 'ALL' && p.action === 'ALL' ); } // πŸ”₯ GENERIC CHECK FUNCTION (WICHTIG) hasPermission(userPerms, requiredPerms, isSuperAdmin = false) { if (isSuperAdmin) return true; return userPerms.some(userPerm => requiredPerms.some(required => { const scopeMatch = userPerm.scope === required.scope; const actionMatch = userPerm.action === 'ALL' || userPerm.action === required.action || required.action === 'ALL'; const resourceMatch = !userPerm.resource || userPerm.resource === 'ALL' || userPerm.resource === required.resource; return scopeMatch && actionMatch && resourceMatch; }) ); } // ========================================================= // πŸ” GLOBAL RBAC MIDDLEWARE (app.use) // ========================================================= // // USAGE: // app.get('/admin/users', (req, res) => { // if (!req.auth.hasPermission([ // { scope: 'USER', action: 'READ', resource: 'USERS' } // ])) { // return res.status(403).send('Forbidden'); // } // res.json({ ok: true }); // }); requirePermissionMiddleware() { return async (req, res, next) => { try { // πŸ”₯ wenn noch kein User da ist β†’ Auth Middleware fehlt if (!req.user) { return next(); // oder 401 wenn du streng sein willst } const permissions = req.user.permissions || []; const isSuperAdmin = req.user.isSuperAdmin || false; req.auth = { permissions, isSuperAdmin, hasPermission: (required) => this.hasPermission(permissions, required, isSuperAdmin) }; next(); } catch (err) { return res.status(500).json('[RBAC MIDDLEWARE ERROR]', err); } }; } // ========================================================= // πŸ”₯ MIDDLEWARE BLEIBT HIER // ========================================================= authenticate() { return async (req, res, next) => { try { // ===================================================== // πŸ”₯ GLOBAL PUBLIC ROUTE BYPASS (ROBUST) // ===================================================== const url = req.originalUrl.split('?')[0]; const publicRoutes = [ '/login', '/public', '/css', '/js', '/images', '/favicon.ico' ]; const isPublicRoute = publicRoutes.some(route => url === route || url.startsWith(route + '/') ); if (isPublicRoute) { return next(); } // ===================================================== // πŸ” AUTH FLOW // ===================================================== const sAMAccountName = req.cookies?.sAMAccountName; if (!sAMAccountName) { return res.redirect('/login'); } const user = await this.db.get('authentication').findOne( { where: { sAMAccountName } } ); if (!user || !user.active) { return res.redirect('/login'); } let payload; try { payload = jwt.verify(user.refreshtoken, this.SECRET_KEY); } catch { return res.redirect('/login'); } const rbac = await this.resolvePermissions(user.ObjectGUID); const normalized = this.normalize(rbac.permissions); const isSuperAdmin = this.isSuperAdmin(normalized); req.user = { ...user.toJSON(), jwt: payload, groups: rbac.groups, roles: rbac.roles, permissions: normalized, isSuperAdmin }; next(); } catch (err) { console.error(err); return res.redirect('/login'); } }; } normalize(permissions) { return permissions.map(p => ({ scope: p.scope, action: p.action, resource: p.resource || null })); } //#region CRUD // ========================================================= // πŸ‘€ AUTH CRUD // ========================================================= async getAuth() { const Auth = this.db.get('authenticationOverviewView'); return await Auth.findAll({ raw: true }); } async syncAuthByActiveDirectory() { const auth = await this.db.get('authentication'); const all = await this.service.get('activeDirectoryManager').getAllUsers(); await Promise.all( all.map(async (user) => { user = {...user, userAccountControl_ID: user.userAccountControl}; const [record, created] = await auth.findOrCreate({ where: { dn: user.dn }, defaults: user }); if (!created) { await record.update(user); } }) ); // return all; } async createAuth(data) { const Auth = this.db.get('authentication'); return await Auth.create({ sAMAccountName: data.sAMAccountName, mail: data.mail, sn: data.sn, givenName: data.givenName, ObjectSource_ID: 1, active: true }); } async updateAuth(id, data) { const Auth = this.db.get('authentication'); return await Auth.update(data, { where: { ObjectGUID: id } }); } async deleteAuth(id) { const Auth = this.db.get('authentication'); const AuthGroups = this.db.get('authenticationGroupsModel'); await AuthGroups.destroy({ where: { Authentication_ObjectGUID: id } }); return await Auth.destroy({ where: { ObjectGUID: id } }); } // ========================================================= // πŸ‘₯ GROUP CRUD // ========================================================= async getGroup() { const group = this.db.get('groupOverviewView'); return await group.findAll({ raw: true }) || []; } async createGroup(data) { const group = this.db.get('group'); return await group.create({ Name: data.name, ObjectSource_ID: 1 }); } async updateGroup(id, data) { const Group = this.db.get('group'); return await Group.update(data, { where: { ObjectGUID: id } }); } async deleteGroup(id) { const Group = this.db.get('group'); const AuthGroups = this.db.get('authenticationGroupsModel'); await AuthGroups.destroy({ where: { Group_ObjectGUID: id } }); return await Group.destroy({ where: { ObjectGUID: id } }); } // ========================================================= // πŸ”— AUTH ↔ GROUP RELATION // ========================================================= async addUserToGroup(authGuid, groupGuid) { const AuthGroups = this.db.get('authenticationGroupsModel'); if(await AuthGroups.findOne({ where: { Authentication_ObjectGUID: authGuid } })) { // AuthGroups. return false } const group = await AuthGroups.create({ Authentication_ObjectGUID: authGuid, Group_ObjectGUID: groupGuid }); return group; } async removeUserFromGroup(authId, groupId) { const AuthGroups = this.db.get('authenticationGroupsModel'); return await AuthGroups.destroy({ where: { Authentication_ObjectGUID: authId, Group_ObjectGUID: groupId } }); } // ========================================================= // 🎭 ROLE CRUD // ========================================================= async getRole() { const role = this.db.get('roleOverviewView'); return await role.findAll({ raw: true }) || []; } async createRole(data) { const Role = this.db.get('roleModel'); return await Role.create({ Name: data.name, Description: data.description || null }); } async updateRole(id, data) { const Role = this.db.get('roleModel'); return await Role.update(data, { where: { ID: id } }); } async deleteRole(id) { const Role = this.db.get('roleModel'); const RolePermissions = this.db.get('rolePermissionsModel'); const GroupRoles = this.db.get('groupRolesModel'); const AuthRoles = this.db.get('authenticationRolesModel'); await AuthRoles.destroy({ where: { Role_ID: id } }); await GroupRoles.destroy({ where: { Role_ID: id } }); await RolePermissions.destroy({ where: { Role_ID: id } }); return await Role.destroy({ where: { ID: id } }); } // ========================================================= // πŸ”— ROLE ASSIGNMENTS // ========================================================= async assignRoleToUser(authId, roleId) { const AuthRoles = this.db.get('authenticationRolesModel'); return await AuthRoles.create({ Authentication_ObjectGUID: authId, Role_ID: roleId }); } async assignRoleToGroup(groupId, roleId) { const GroupRoles = this.db.get('groupRolesModel'); return await GroupRoles.create({ Group_ObjectGUID: groupId, Role_ID: roleId }); } async removeRoleFromUser(authId, roleId) { const AuthRoles = this.db.get('authenticationRolesModel'); return await AuthRoles.destroy({ where: { Authentication_ObjectGUID: authId, Role_ID: roleId } }); } // ========================================================= // πŸ” PERMISSION CRUD // ========================================================= async getPermission() { const permission = this.db.get('permissionOverviewView'); return await permission.findAll({ raw: true }) || []; } async createPermission(data) { const Permission = this.db.get('permissionModel'); return await Permission.create({ Scope: data.scope, Resource: data.resource, Action: data.action }); } async updatePermission(id, data) { const Permission = this.db.get('permissionModel'); return await Permission.update(data, { where: { ID: id } }); } async deletePermission(id) { const Permission = this.db.get('permissionModel'); return await Permission.destroy({ where: { ID: id } }); } // ========================================================= // πŸ”— ROLE ↔ PERMISSION // ========================================================= async addPermissionToRole(roleId, permissionId) { const RolePerms = this.db.get('rolePermissionsModel'); return await RolePerms.create({ Role_ID: roleId, Permission_ID: permissionId }); } async removePermissionFromRole(roleId, permissionId) { const RolePerms = this.db.get('rolePermissionsModel'); return await RolePerms.destroy({ where: { Role_ID: roleId, Permission_ID: permissionId } }); } //#endregion } module.exports = RBACManager;