rbac outsourced
This commit is contained in:
@@ -2,10 +2,10 @@ const jwt = require('jsonwebtoken');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
class AuthenticationManager {
|
||||
constructor(model, secretKey, databaseModel) {
|
||||
constructor(model, secretKey, rbacService) {
|
||||
this.Authentication = model;
|
||||
this.SECRET_KEY = secretKey;
|
||||
this.databaseModel = databaseModel;
|
||||
this.rbac = rbacService;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
@@ -36,79 +36,7 @@ class AuthenticationManager {
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// RBAC RESOLVER (LIVE - WICHTIG!)
|
||||
// =========================================================
|
||||
|
||||
async resolvePermissions(objectGuid) {
|
||||
const AuthenticationGroups = this.databaseModel.get('authenticationGroupsModel');
|
||||
const GroupClosure = this.databaseModel.get('groupClosureModel');
|
||||
const AuthenticationRoles = this.databaseModel.get('authenticationRolesModel');
|
||||
const GroupRoles = this.databaseModel.get('groupRolesModel');
|
||||
const RolePermissions = this.databaseModel.get('rolePermissionsModel');
|
||||
const Permission = this.databaseModel.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 }
|
||||
});
|
||||
|
||||
// 🔥 HIER DIE ÄNDERUNG
|
||||
return {
|
||||
groups: allGroupIds,
|
||||
roles: roleIds,
|
||||
permissions: permissions.map(p => ({
|
||||
id: p.ID,
|
||||
scope: p.Scope,
|
||||
resource: p.Resource,
|
||||
action: p.Action
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// LOGIN (minimal change)
|
||||
// LOGIN
|
||||
// =========================================================
|
||||
|
||||
async login(sAMAccountName, password) {
|
||||
@@ -142,11 +70,7 @@ async resolvePermissions(objectGuid) {
|
||||
user.online = true;
|
||||
await user.save();
|
||||
|
||||
return {
|
||||
token,
|
||||
levelId: 0,
|
||||
message: 'Erfolgreich angemeldet'
|
||||
};
|
||||
return { token, levelId: 0, message: 'Erfolgreich angemeldet' };
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
@@ -168,7 +92,7 @@ async resolvePermissions(objectGuid) {
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// VERIFY TOKEN (unchanged)
|
||||
// VERIFY TOKEN
|
||||
// =========================================================
|
||||
|
||||
async verifyUserToken(sAMAccountName) {
|
||||
@@ -192,22 +116,36 @@ async resolvePermissions(objectGuid) {
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 🔥 AUTH MIDDLEWARE (HIER PASSIERT DIE MAGIE)
|
||||
// 🔥 MIDDLEWARE BLEIBT HIER
|
||||
// =========================================================
|
||||
|
||||
authenticate() {
|
||||
return async (req, res, next) => {
|
||||
|
||||
try {
|
||||
|
||||
// 🔥 SKIP PUBLIC ROUTES
|
||||
if (
|
||||
req.path.startsWith('/login') ||
|
||||
req.path.startsWith('/public')
|
||||
) {
|
||||
// =====================================================
|
||||
// 🔥 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) {
|
||||
@@ -228,14 +166,18 @@ async resolvePermissions(objectGuid) {
|
||||
return res.redirect('/login');
|
||||
}
|
||||
|
||||
const rbac = await this.resolvePermissions(user.ObjectGUID);
|
||||
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: rbac.permissions
|
||||
permissions: normalized,
|
||||
isSuperAdmin
|
||||
};
|
||||
|
||||
next();
|
||||
@@ -246,6 +188,52 @@ async resolvePermissions(objectGuid) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 🔐 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 rbac = this.rbac;
|
||||
|
||||
const permissions = req.user.permissions || [];
|
||||
const isSuperAdmin = req.user.isSuperAdmin || false;
|
||||
|
||||
req.auth = {
|
||||
permissions,
|
||||
isSuperAdmin,
|
||||
hasPermission: (required) =>
|
||||
rbac.hasPermission(permissions, required, isSuperAdmin)
|
||||
};
|
||||
|
||||
return next();
|
||||
|
||||
next();
|
||||
|
||||
} catch (err) {
|
||||
console.error('[RBAC MIDDLEWARE ERROR]', err);
|
||||
return res.status(500).json({ message: 'RBAC Fehler' });
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AuthenticationManager;
|
||||
Reference in New Issue
Block a user