36e9d5b0b3
An SSH jump host that authenticates users against the shared LDAP directory, authorizes them from the SSO Manager's inventory graph, and bridges them to downstream hosts — auditing everything. - Username-grammar routing (uid_-_target@jump) + interactive TUI picker - Inbound LDAP auth (publickey / password with off|local|all policy) - Directory-driven access (LDAP groups x /api/discovery/resources?group=) - Per-user key injection into sshPublicKey, connects downstream as the user - Shell / exec / SFTP-subsystem bridging (WinSCP works) - Web UI + HTTP API (:3002) for audit + metrics; LDAP-admin gated - Packaged like proxy: ops/install.sh + systemd, all-in-one Docker, compose - Tests: 23 unit + 3 integration (node --test), all green Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
43 lines
1.5 KiB
JavaScript
43 lines
1.5 KiB
JavaScript
'use strict';
|
|
|
|
// Web login: LDAP bind as the user, require an adminGroups membership, mint a
|
|
// session cookie. (OIDC against the SSO is a follow-up.)
|
|
|
|
const express = require('express');
|
|
const conf = require('@simpleworkjs/conf');
|
|
const userLdap = require('../models/user_ldap');
|
|
const Session = require('../models/session');
|
|
|
|
const router = express.Router();
|
|
|
|
router.get('/login', (req, res) => {
|
|
res.render('login', { error: null, name: conf.name });
|
|
});
|
|
|
|
router.post('/login', express.urlencoded({ extended: false }), async (req, res) => {
|
|
const { uid, password } = req.body || {};
|
|
const fail = (msg) => res.status(401).render('login', { error: msg, name: conf.name });
|
|
try {
|
|
const user = await userLdap.getUser(uid);
|
|
if (!user) return fail('Invalid credentials.');
|
|
const ok = await userLdap.checkPassword(user.dn, password);
|
|
if (!ok) return fail('Invalid credentials.');
|
|
const groups = await userLdap.getGroups(user.dn);
|
|
const admin = (conf.auth.adminGroups || []).some((g) => groups.includes(g));
|
|
if (!admin) return fail('Your account is not a jump-host admin.');
|
|
|
|
const session = await Session.start(user.uid, groups, conf.auth.sessionTTLms);
|
|
res.setHeader('Set-Cookie', `jump_session=${session.token}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${Math.floor(conf.auth.sessionTTLms / 1000)}`);
|
|
res.redirect('/');
|
|
} catch (err) {
|
|
return fail('Login failed.');
|
|
}
|
|
});
|
|
|
|
router.post('/logout', (req, res) => {
|
|
res.setHeader('Set-Cookie', 'jump_session=; HttpOnly; Path=/; Max-Age=0');
|
|
res.redirect('/login');
|
|
});
|
|
|
|
module.exports = router;
|