From 15f3a5f80d9175296d4e5e20196ae28cfde270db Mon Sep 17 00:00:00 2001 From: "manuel.sowada" Date: Tue, 28 Apr 2026 16:24:21 +0200 Subject: [PATCH] rbac crud --- public/javascript/customModal.js | 38 +-- public/javascript/rbacAPI.js | 46 +++ public/styles/default.css | 2 +- public/views/rbac.hbs | 35 ++ src/models/integratedStartMenuItems.json | 2 +- src/routes/adminRoutes.js | 10 + src/services/rbacManager.js | 415 +++++++++++++++++++++++ 7 files changed, 527 insertions(+), 21 deletions(-) create mode 100644 public/javascript/rbacAPI.js diff --git a/public/javascript/customModal.js b/public/javascript/customModal.js index 9797456..8bce03c 100644 --- a/public/javascript/customModal.js +++ b/public/javascript/customModal.js @@ -147,25 +147,25 @@ function slideOutMessage(message) { //#region Feedbox /** - * feedbox({ - * title: `⚠ Upload abbrechen?`, - * message: ` - *

Es laufen noch aktive Uploads.

- *

Möchtest du wirklich alle abbrechen?

- * `, - * buttons: { - * yes: { - * text: 'Ja, abbrechen', - * onClick: () => stopUploadQueue() - * }, - * no: { - * text: 'Weiter hochladen' - * }, - * cancel: { - * text: 'Zurück' - * } - * } - *}); + feedbox({ + title: `⚠ Upload abbrechen?`, + message: ` +

Es laufen noch aktive Uploads.

+

Möchtest du wirklich alle abbrechen?

+ `, + buttons: { + yes: { + text: 'Ja, abbrechen', + onClick: () => stopUploadQueue() + }, + no: { + text: 'Weiter hochladen' + }, + cancel: { + text: 'Zurück' + } + } + }); */ function feedbox({ title = '', diff --git a/public/javascript/rbacAPI.js b/public/javascript/rbacAPI.js new file mode 100644 index 0000000..8cbf38a --- /dev/null +++ b/public/javascript/rbacAPI.js @@ -0,0 +1,46 @@ +function test() { + function createInput({ id, placeholder }) { + const input = document.createElement('input'); + input.type = 'text'; + input.id = id; + input.style.width = 'calc(100% - 30px)'; + input.placeholder = placeholder; + input.required = true; + return input; + } + + const container = document.createElement('div'); + container.id = 'rbacAuthCreation'; + + container.append( + createInput({ id: 'rbacAuthsAMAccountName', placeholder: 'sAMAccountName ' }), + createInput({ id: 'rbacAuthsMail', placeholder: 'E-Mail' }), + createInput({ id: 'rbacAuthsSn', placeholder: 'Vorname' }), + createInput({ id: 'rbacAuthsGivenName', placeholder: 'Nachname' }) + ); + + feedbox({ + title: `Erstelle eine neue Authentifizierung`, + message: container.outerHTML, + buttons: { + cancel: { + text: 'Abbrechen' + }, + yes: { + text: 'Erstellen', + onClick: () => { + fetch('/api/rbac/auths/create', { + method: 'POST', + body: JSON.stringify({ + sAMAccountName: document.getElementById('rbacAuthsAMAccountName').value, + mail: document.getElementById('rbacAuthsMail').value, + sn: document.getElementById('rbacAuthsSn').value, + givenName: document.getElementById('rbacAuthsGivenName').value + }) + }) + } + } + }, + lock: true + }); +} \ No newline at end of file diff --git a/public/styles/default.css b/public/styles/default.css index e7a10fc..bc44d9e 100644 --- a/public/styles/default.css +++ b/public/styles/default.css @@ -235,7 +235,7 @@ table .cb input:checked + .cb-box::after { transform:scale(1) translate(1px, 1px /* #region Feebox */ .feedbox-overlay { position:fixed; top:0; left:0; width:100vw; height:100vh; display:flex; align-items:center; justify-content:center; z-index:999; } -.feedbox { border-radius:8px; max-width:50vw; width:100%; padding:20px; animation:feedboxFadeIn 0.2s ease-out; max-height:80vh; display:flex; flex-direction:column; overflow:hidden; } +.feedbox { border-radius:8px; max-width:50vw; max-width:100%; padding:20px; animation:feedboxFadeIn 0.2s ease-out; max-height:80vh; display:flex; flex-direction:column; overflow:hidden; } .feedbox h3 { margin:0 0 10px 0; } .feedbox-message { margin-bottom:20px; line-height:1.4; flex:1; overflow-y: auto; /* font-size:1rem; */ } .feedbox-actions { display:flex; justify-content:flex-end; gap:10px; flex-wrap:wrap; flex-shrink:0; } diff --git a/public/views/rbac.hbs b/public/views/rbac.hbs index e69de29..55da696 100644 --- a/public/views/rbac.hbs +++ b/public/views/rbac.hbs @@ -0,0 +1,35 @@ + + + + + + Document + + +
+
+ +
+ +
+ +
+
+ +
+ +
+ + + + \ No newline at end of file diff --git a/src/models/integratedStartMenuItems.json b/src/models/integratedStartMenuItems.json index 999453c..2ac4d0a 100644 --- a/src/models/integratedStartMenuItems.json +++ b/src/models/integratedStartMenuItems.json @@ -35,7 +35,7 @@ { "label": "RBAC", "description": "Role-Based Access Control ist eine rollenbasierte Zugriffskontrolle, die auf Basis von Rollen und Gruppen, systemweite Berechtigungen vergibt", - "view": "rbac.hbs", + "view": "rbac", "defaultSize": { "width": "800px", "height": "600px" diff --git a/src/routes/adminRoutes.js b/src/routes/adminRoutes.js index e12304e..d20ecdc 100644 --- a/src/routes/adminRoutes.js +++ b/src/routes/adminRoutes.js @@ -76,6 +76,16 @@ module.exports = { }); + app.post('/api/rbac/getEntities', async (req, res) => { + // res.status(200).json(await service.get('rbacManager').getEntities()); + }) + + app.post('/api/rbac/auths/create', async (req, res) => { + const { auths } = req.body; + // await service.get('rbacManager').createAuths(auths); + res.status(200).json({ ok: true }); + }) + app.post('/api/plugins/activation', async (req, res) => { const { name, state } = req.body; let result = null; diff --git a/src/services/rbacManager.js b/src/services/rbacManager.js index e8e4a46..4fcdf3b 100644 --- a/src/services/rbacManager.js +++ b/src/services/rbacManager.js @@ -232,6 +232,421 @@ class RBACManager { resource: p.resource || null })); } + + + + + //#region CRUD +// ========================================================= +// 👤 AUTH CRUD +// ========================================================= + +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, + 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'); + + return await Auth.destroy({ + where: { ObjectGUID: id } + }); +} + +// ========================================================= +// 👥 GROUP CRUD +// ========================================================= + +async createGroup(data) { + const Group = this.db.get('groupsModel'); + + return await Group.create({ + Name: data.name, + Description: data.description || null + }); +} + +async updateGroup(id, data) { + const Group = this.db.get('groupsModel'); + + return await Group.update(data, { + where: { ObjectGUID: id } + }); +} + +async deleteGroup(id) { + const Group = this.db.get('groupsModel'); + + return await Group.destroy({ + where: { ObjectGUID: id } + }); +} + +// ========================================================= +// 🔗 AUTH ↔ GROUP RELATION +// ========================================================= + +async addUserToGroup(authId, groupId) { + const AuthGroups = this.db.get('authenticationGroupsModel'); + + return await AuthGroups.create({ + Authentication_ObjectGUID: authId, + Group_ObjectGUID: groupId + }); +} + +async removeUserFromGroup(authId, groupId) { + const AuthGroups = this.db.get('authenticationGroupsModel'); + + return await AuthGroups.destroy({ + where: { + Authentication_ObjectGUID: authId, + Group_ObjectGUID: groupId + } + }); +} + +// ========================================================= +// 🎭 ROLE CRUD +// ========================================================= + +async createRole(data) { + const Role = this.db.get('rolesModel'); + + return await Role.create({ + Name: data.name, + Description: data.description || null + }); +} + +async updateRole(id, data) { + const Role = this.db.get('rolesModel'); + + return await Role.update(data, { + where: { ID: id } + }); +} + +async deleteRole(id) { + const Role = this.db.get('rolesModel'); + + 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 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 + + + + + const express = require('express'); + +function rbacRoutes(rbac) { + const router = express.Router(); + + // ========================================================= + // 👤 AUTH + // ========================================================= + + router.post('/auth/create', async (req, res) => { + try { + const user = await rbac.createAuth(req.body); + res.json(user); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.put('/auth/:id', async (req, res) => { + try { + await rbac.updateAuth(req.params.id, req.body); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.delete('/auth/:id', async (req, res) => { + try { + await rbac.deleteAuth(req.params.id); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + // ========================================================= + // 👥 GROUPS + // ========================================================= + + router.post('/group', async (req, res) => { + try { + const group = await rbac.createGroup(req.body); + res.json(group); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.put('/group/:id', async (req, res) => { + try { + await rbac.updateGroup(req.params.id, req.body); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.delete('/group/:id', async (req, res) => { + try { + await rbac.deleteGroup(req.params.id); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + // ========================================================= + // 🔗 USER ↔ GROUP + // ========================================================= + + router.post('/group/add-user', async (req, res) => { + try { + const { authId, groupId } = req.body; + await rbac.addUserToGroup(authId, groupId); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.post('/group/remove-user', async (req, res) => { + try { + const { authId, groupId } = req.body; + await rbac.removeUserFromGroup(authId, groupId); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + // ========================================================= + // 🎭 ROLES + // ========================================================= + + router.post('/role', async (req, res) => { + try { + const role = await rbac.createRole(req.body); + res.json(role); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.put('/role/:id', async (req, res) => { + try { + await rbac.updateRole(req.params.id, req.body); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.delete('/role/:id', async (req, res) => { + try { + await rbac.deleteRole(req.params.id); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + // ========================================================= + // 🔗 ROLE ASSIGNMENTS + // ========================================================= + + router.post('/role/assign-user', async (req, res) => { + try { + const { authId, roleId } = req.body; + await rbac.assignRoleToUser(authId, roleId); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.post('/role/assign-group', async (req, res) => { + try { + const { groupId, roleId } = req.body; + await rbac.assignRoleToGroup(groupId, roleId); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + // ========================================================= + // 🔐 PERMISSIONS + // ========================================================= + + router.post('/permission', async (req, res) => { + try { + const perm = await rbac.createPermission(req.body); + res.json(perm); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.put('/permission/:id', async (req, res) => { + try { + await rbac.updatePermission(req.params.id, req.body); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.delete('/permission/:id', async (req, res) => { + try { + await rbac.deletePermission(req.params.id); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + // ========================================================= + // 🔗 ROLE ↔ PERMISSION + // ========================================================= + + router.post('/role/add-permission', async (req, res) => { + try { + const { roleId, permissionId } = req.body; + await rbac.addPermissionToRole(roleId, permissionId); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + router.post('/role/remove-permission', async (req, res) => { + try { + const { roleId, permissionId } = req.body; + await rbac.removePermissionFromRole(roleId, permissionId); + res.json({ ok: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + return router; +} + +module.exports = rbacRoutes; } module.exports = RBACManager; \ No newline at end of file