From 5f494bb837c1d7fc96ce5c905e0d28b9c038127f Mon Sep 17 00:00:00 2001 From: "manuel.sowada" Date: Mon, 27 Apr 2026 15:49:56 +0200 Subject: [PATCH] bugfix rbac --- dbcreate.sql | 18 ++++--- server.js | 4 +- src/routes/loginRoutes.js | 4 +- src/services/authenticationManager.js | 76 +-------------------------- src/services/rbacManager.js | 76 +++++++++++++++++++++++++++ utils.js | 5 +- 6 files changed, 93 insertions(+), 90 deletions(-) diff --git a/dbcreate.sql b/dbcreate.sql index add13b2..7b555aa 100644 --- a/dbcreate.sql +++ b/dbcreate.sql @@ -149,7 +149,7 @@ CREATE TABLE dbo.GroupClosure ( Depth INT, PRIMARY KEY (ParentGroup_ObjectGUID, ChildGroup_ObjectGUID) ); - +GO /* ========================================================= RBAC @@ -160,25 +160,28 @@ CREATE TABLE dbo.AuthenticationRoles ( Role_ID INT, PRIMARY KEY (Authentication_ObjectGUID, Role_ID) ); +GO CREATE TABLE dbo.AuthenticationGroups ( Authentication_ObjectGUID UNIQUEIDENTIFIER, Group_ObjectGUID UNIQUEIDENTIFIER, PRIMARY KEY (Authentication_ObjectGUID, Group_ObjectGUID) ); +GO CREATE TABLE dbo.GroupRoles ( Group_ObjectGUID UNIQUEIDENTIFIER, Role_ID INT, PRIMARY KEY (Group_ObjectGUID, Role_ID) ); +GO CREATE TABLE dbo.RolePermissions ( Role_ID INT, Permission_ID INT, PRIMARY KEY (Role_ID, Permission_ID) ); - +GO /* ========================================================= EVENT SYSTEM @@ -215,6 +218,7 @@ CREATE TABLE dbo.NotifyTrayObjects ( CreatedAt DATETIME2, ExpiresAt DATETIME2 ); +GO CREATE TABLE dbo.NotifyTray ( ID INT IDENTITY(1,1) PRIMARY KEY, @@ -222,7 +226,7 @@ CREATE TABLE dbo.NotifyTray ( NotifyTrayObject_ID INT, SeenAt DATETIME2 ); - +GO /* ========================================================= SECURITY VIEWS @@ -241,7 +245,7 @@ FROM dbo.Authentication a JOIN dbo.AuthenticationGroups ag ON ag.Authentication_ObjectGUID = a.ObjectGUID JOIN dbo.GroupRoles gr ON gr.Group_ObjectGUID = ag.Group_ObjectGUID JOIN dbo.[Role] r ON r.ID = gr.Role_ID; - +GO CREATE VIEW dbo.vAuthenticationEffectivePermissions AS SELECT DISTINCT @@ -254,7 +258,7 @@ FROM dbo.Authentication a JOIN dbo.vAuthenticationRoles r ON r.ObjectGUID = a.ObjectGUID JOIN dbo.RolePermissions rp ON rp.Role_ID = r.Role_ID JOIN dbo.Permission p ON p.ID = rp.Permission_ID; - +GO /* ========================================================= FIXED vEventLog (SEQUELIZE MATCH + SYSTEM FIX) @@ -308,7 +312,7 @@ CREATE VIEW dbo.vAuthentications AS SELECT a.*, os.Name AS ObjectSource FROM dbo.Authentication a LEFT JOIN dbo.ObjectSource os ON os.ID = a.ObjectSource_ID; - +GO /* ========================================================= GROUP VIEW @@ -316,7 +320,7 @@ LEFT JOIN dbo.ObjectSource os ON os.ID = a.ObjectSource_ID; CREATE VIEW dbo.vGroupHierarchy AS SELECT * FROM dbo.GroupClosure; - +GO /* ========================================================= NOTIFY VIEWS diff --git a/server.js b/server.js index bb32de6..05730e6 100644 --- a/server.js +++ b/server.js @@ -135,8 +135,8 @@ const server = https.createServer(httpsOptions, app); databaseModel.set('roleModel', require(`@models/roleModel`)(service.get('sqlManager').getInstance('main'))); databaseModel.set('rolePermissionsModel', require(`@models/rolePermissionsModel`)(service.get('sqlManager').getInstance('main'))); - service.set('authenticationManager', new AuthenticationManager(databaseModel.get('authentication'), app.locals.configuration.integration.token.secret)); service.set('rbacManager', new RBACManager(databaseModel)); + service.set('authenticationManager', new AuthenticationManager(databaseModel.get('authentication'), app.locals.configuration.integration.token.secret)); service.set('activeDirectoryManager', new ActiveDirectory(app.locals.configuration.integration.activedirectory)) @@ -228,7 +228,7 @@ const server = https.createServer(httpsOptions, app); require(`${app.locals.path.source}/routes/adminRoutes.js`).route(app, service); // #3 - token security always enabled //#endregion - app.use(service.get('authenticationManager').authenticate()); + app.use(service.get('rbacManager').authenticate()); //#region Implements sockets require(`${app.locals.path.source}/sockets/mainSocket.js`)( diff --git a/src/routes/loginRoutes.js b/src/routes/loginRoutes.js index a63eca4..6b7ff84 100644 --- a/src/routes/loginRoutes.js +++ b/src/routes/loginRoutes.js @@ -40,7 +40,7 @@ module.exports = { // Geschützte Route - app.get('/me', service.get('authenticationManager').authenticate(), (req, res) => { + app.get('/me', service.get('rbacManager').authenticate(), (req, res) => { res.json(JSON.stringify({ user: { name: req.user @@ -63,7 +63,7 @@ module.exports = { }); // Logout - app.post('/logout', service.get('authenticationManager').authenticate(), async (req, res) => { + app.post('/logout', service.get('rbacManager').authenticate(), async (req, res) => { const logout = await service.get('authenticationManager').logout(req.user.sAMAccountName); // socketManager.sendTo('/', req.user.objectGuid, 'login_status', { levelId: logout.levelId, message: logout.message } ) diff --git a/src/services/authenticationManager.js b/src/services/authenticationManager.js index 859033e..368907e 100644 --- a/src/services/authenticationManager.js +++ b/src/services/authenticationManager.js @@ -2,6 +2,7 @@ const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); class AuthenticationManager { + constructor(model, secretKey) { this.Authentication = model; this.SECRET_KEY = secretKey; @@ -113,81 +114,6 @@ class AuthenticationManager { return { valid: false, levelId: 4 }; } } - - // ========================================================= - // 🔥 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' - ]; - - 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.findUser(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.rbac.resolvePermissions(user.ObjectGUID); - - const normalized = this.rbac.normalize(rbac.permissions); - const isSuperAdmin = this.rbac.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'); - } - }; - } - } module.exports = AuthenticationManager; \ No newline at end of file diff --git a/src/services/rbacManager.js b/src/services/rbacManager.js index 37be2dd..73c3c81 100644 --- a/src/services/rbacManager.js +++ b/src/services/rbacManager.js @@ -151,6 +151,82 @@ class RBACManager { }; } + + // ========================================================= + // 🔥 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' + ]; + + 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, diff --git a/utils.js b/utils.js index 7009de6..5fa665f 100644 --- a/utils.js +++ b/utils.js @@ -54,10 +54,7 @@ module.exports = startMenuItems = async function (app, objectGuid, debug = false // Load user permissions // ========================= const rbacManager = service.get('rbacManager'); - - const userPermissions = - (await rbacManager.resolvePermissions(objectGuid)) - ?.permissions || []; + const userPermissions = objectGuid === undefined ? [] : (await rbacManager.resolvePermissions(objectGuid))?.permissions; const normalizedPermissions = userPermissions.map(p => ({ scope: p.scope,