0b701dfc6f
- OAuth Apps and LDAP Info are both "how do other apps/hosts plug into this SSO" concerns -- merged into a single /integrations page with tabs, replacing the two separate nav items with one. /oauth-clients and /ldap-info 301-redirect there for compat. - Add a Service Accounts section under the LDAP tab: bind-only LDAP identities (organizationalRole + simpleSecurityObject, no posixAccount) for apps/hosts, as opposed to real people. Create, rotate password, and delete, all from the UI -- previously the only such account (theta-env's bootstrap-created cn=ldapclient) was invisible to the Users page entirely (filtered out by conf.ldap.userFilter) and had no GUI way to see or rotate it; the new ServiceAccount model uses the exact same objectClasses bootstrap.js already creates cn=ldapclient with, so it recognizes and manages that account too, not just ones created through this UI. - The ldap-client bash snippet now points at "create one under Service Accounts above" instead of a bare textual example. Verified against a real LDAP server (not just the dev sandbox's usual unreachable one): created a service account, confirmed it binds successfully with the generated password, rotated its password, and deleted it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
55 lines
1.5 KiB
JavaScript
55 lines
1.5 KiB
JavaScript
'use strict';
|
|
|
|
const router = require('express').Router();
|
|
const {ServiceAccount} = require('../models/service_account');
|
|
const permission = require('../utils/permission');
|
|
|
|
const ADMIN_GROUP = 'app_sso_admin';
|
|
|
|
router.get('/', async function(req, res, next) {
|
|
try {
|
|
await permission.byGroup(req.user, [ADMIN_GROUP]);
|
|
return res.json({results: await ServiceAccount.list()});
|
|
} catch(error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
router.post('/', async function(req, res, next) {
|
|
try {
|
|
await permission.byGroup(req.user, [ADMIN_GROUP]);
|
|
const result = await ServiceAccount.create({cn: req.body.cn, description: req.body.description});
|
|
return res.json({
|
|
results: result,
|
|
message: `Service account "${result.cn}" created. Save the password now — it will not be shown again.`,
|
|
});
|
|
} catch(error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
router.put('/:cn/password', async function(req, res, next) {
|
|
try {
|
|
await permission.byGroup(req.user, [ADMIN_GROUP]);
|
|
const result = await ServiceAccount.setPassword(req.params.cn, req.body.password);
|
|
return res.json({
|
|
results: result,
|
|
message: `Password rotated for "${req.params.cn}". Save it now — it will not be shown again.`,
|
|
});
|
|
} catch(error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
router.delete('/:cn', async function(req, res, next) {
|
|
try {
|
|
await permission.byGroup(req.user, [ADMIN_GROUP]);
|
|
await ServiceAccount.remove(req.params.cn);
|
|
return res.json({message: `Service account "${req.params.cn}" deleted.`});
|
|
} catch(error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|