diff --git a/docs/concepts-accounts.md b/docs/concepts-accounts.md index 148f3f2..120be02 100644 --- a/docs/concepts-accounts.md +++ b/docs/concepts-accounts.md @@ -46,7 +46,7 @@ on, just like anyone else's. A **group** is just a named list of accounts, used to control access. This app has a handful of built-in groups that grant admin powers (e.g. only -people in the `app_sso_admin` group can see the Users/Groups/Directory/Executive +people in the `app_sso_admin` group can see the Users/Groups/Directory/Overview pages at all), but you can also make your own groups for any app you connect — say, a group listing everyone who should be allowed into your photo server. Once a group exists, add or remove members from the diff --git a/docs/index.md b/docs/index.md index ec9389c..e6ffcfc 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,7 +22,7 @@ one command). ## Screenshots -Executive dashboard +Overview dashboard User list Groups Directory & inventory diff --git a/nodejs/routes/api_metrics.js b/nodejs/routes/api_metrics.js index 4ff6f9d..7929bdb 100644 --- a/nodejs/routes/api_metrics.js +++ b/nodejs/routes/api_metrics.js @@ -3,8 +3,8 @@ const router = require('express').Router(); const permission = require('../utils/permission'); const metrics = require('../utils/metrics'); -// /api/metrics/executive -router.get('/executive', async (req, res, next) => { +// /api/metrics/overview +router.get('/overview', async (req, res, next) => { try { await permission.byGroup(req.user, ['app_sso_admin']); diff --git a/nodejs/routes/index.js b/nodejs/routes/index.js index 05bac0f..6e4c094 100755 --- a/nodejs/routes/index.js +++ b/nodejs/routes/index.js @@ -48,13 +48,14 @@ router.get('/tos', async function(req, res, next) { // Admin dashboard (stats + recent/inactive users) and Notifications // (broadcast + history) merged into one page. -router.get('/executive', function(req, res) { - res.render('executive', {...values}); +router.get('/overview', function(req, res) { + res.render('overview', {...values}); }); -router.get('/admin', (req, res) => res.redirect(301, '/executive')); -router.get('/notifications', (req, res) => res.redirect(301, '/executive')); -router.get('/dashboard', (req, res) => res.redirect(301, '/executive')); +router.get('/admin', (req, res) => res.redirect(301, '/overview')); +router.get('/notifications', (req, res) => res.redirect(301, '/overview')); +router.get('/dashboard', (req, res) => res.redirect(301, '/overview')); +router.get('/executive', (req, res) => res.redirect(301, '/overview')); router.get('/directory', function(req, res) { res.render('directory', {...values}); diff --git a/nodejs/routes/user.js b/nodejs/routes/user.js index 100db7c..0227a56 100755 --- a/nodejs/routes/user.js +++ b/nodejs/routes/user.js @@ -78,11 +78,12 @@ router.get('/me', async function(req, res, next){ // The shared client framework gates the UI on a single effective-rights // flag (the OIDC-client apps send the same key). Here "admin" means - // membership in app_sso_admin; group-level gating still reads memberOf. + // membership in app_sso_admin or the cross-app app_super_admin group; + // group-level gating still reads memberOf. const groups = (user.memberOf || []).map(function(dn){ return String(dn).split(',')[0].replace(/^cn=/i, ''); }); - user.isAdmin = groups.includes('app_sso_admin'); + user.isAdmin = groups.includes('app_sso_admin') || groups.includes(permission.SUPER_ADMIN_GROUP); return res.json(user); }catch(error){ diff --git a/nodejs/utils/permission.js b/nodejs/utils/permission.js index 869d023..a2fa2ca 100644 --- a/nodejs/utils/permission.js +++ b/nodejs/utils/permission.js @@ -2,7 +2,16 @@ const {Group} = require('../models/group_ldap'); +const SUPER_ADMIN_GROUP = 'app_super_admin'; + let byGroup = async function(user, groups, ownerOf){ + try{ + let superAdmin = await Group.get(SUPER_ADMIN_GROUP); + if(superAdmin.member.includes(user.dn)) return true + }catch(error){ + // group not found, continue checking + } + for(let group of groups){ try{ group = await Group.get(group); @@ -28,4 +37,4 @@ let byGroup = async function(user, groups, ownerOf){ throw error; } -module.exports = {byGroup}; +module.exports = {byGroup, SUPER_ADMIN_GROUP}; diff --git a/nodejs/utils/ui.js b/nodejs/utils/ui.js index de8ebc2..545e6ef 100644 --- a/nodejs/utils/ui.js +++ b/nodejs/utils/ui.js @@ -38,9 +38,9 @@ module.exports = { // app-base.js, which reveals .group-required- for each group the user is // in (plus the synthetic `admin` group when user/me reports isAdmin). nav: [ - {href: '/users', icon: 'fa-solid fa-users', label: 'Users', groups: ['app_sso_admin']}, - {href: '/groups', icon: 'fa-solid fa-users-viewfinder', label: 'Groups', groups: ['app_sso_admin']}, - {href: '/directory', icon: 'fa-solid fa-server', label: 'Directory', groups: ['app_sso_admin', 'app_sso_directory_admin']}, - {href: '/executive', icon: 'fa-solid fa-gauge-high', label: 'Executive', groups: ['app_sso_admin']}, + {href: '/users', icon: 'fa-solid fa-users', label: 'Users', groups: ['app_sso_admin', 'admin']}, + {href: '/groups', icon: 'fa-solid fa-users-viewfinder', label: 'Groups', groups: ['app_sso_admin', 'admin']}, + {href: '/directory', icon: 'fa-solid fa-server', label: 'Directory', groups: ['app_sso_admin', 'app_sso_directory_admin', 'admin']}, + {href: '/overview', icon: 'fa-solid fa-gauge-high', label: 'Overview', groups: ['app_sso_admin', 'admin']}, ], }; diff --git a/nodejs/views/directory.ejs b/nodejs/views/directory.ejs index 6d49cb2..f95eeab 100644 --- a/nodejs/views/directory.ejs +++ b/nodejs/views/directory.ejs @@ -73,7 +73,7 @@