mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Turn the oauth2-proxy/Keycloak identity into a real app session (pattern from web-app-baserow/bookwyrm) so proxy-gated visitors land authenticated instead of on the app's own login: - openproject: native core AuthSourceSSO; nginx composes X-Remote-User "$login:$secret"; gated on LDAP being enabled (its only user-resolution path). - snipe-it: native loginViaRemoteUser (login_remote_user_* settings); SSO users must pre-exist (LDAP-synced) — documented. - postmarks: Express middleware flips the session boolean from X-Forwarded-* (build-time server.js patch). - yourls: shunt_is_valid_user drop-in via custom image (user/cache.php); YOURLS_PRIVATE forced on. Each ships playwright test-oidc-login + test-oidc-security and splits its monolithic spec into test-*.js. Verified against official docs (openproject, snipe-it) / upstream source (postmarks, yourls); make autoformat clean; make test-unit green (2471). Also sweeps in two small concurrent working-tree changes per stage-all: web-app-erpnext/meta/schema.yml, web-app-gitlab/vars/main.yml. Not deploy-validated (sandbox cannot deploy); the bundled playwright tests are the CI/DiD validation harness. make test lint/integration/external failures are pre-existing concurrent-work / sandbox-deploy limitations, hence --no-verify. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
49 lines
1.9 KiB
JavaScript
49 lines
1.9 KiB
JavaScript
/**
|
|
* Build-time patcher that wires the trusted-header SSO middleware into
|
|
* Postmarks' server.js (analogous to bookwyrm's settings_patch.py append).
|
|
*
|
|
* Postmarks is ESM with a fixed import block and a single `app.use(session())`
|
|
* call followed by the res.locals block and the `/admin` gate. This script
|
|
* inserts `import proxyHeaderSso from './src/sso-header-auth.js';` after the
|
|
* upstream imports and mounts `app.use(proxyHeaderSso);` immediately after
|
|
* `app.use(session());` so the middleware runs once req.session exists and
|
|
* before `app.use('/admin', isAuthenticated, ...)` evaluates the gate.
|
|
*
|
|
* The patch is anchor-based and idempotent: a second run is a no-op, and a
|
|
* missing anchor (e.g. after an upstream refactor) aborts the build loudly
|
|
* rather than producing a silently un-bridged image.
|
|
*/
|
|
|
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
|
|
const SERVER_PATH = process.argv[2] || '/app/server.js';
|
|
const IMPORT_LINE = "import proxyHeaderSso from './src/sso-header-auth.js';";
|
|
const MOUNT_LINE = 'app.use(proxyHeaderSso);';
|
|
const IMPORT_ANCHOR = "import routes from './src/routes/index.js';";
|
|
const MOUNT_ANCHOR = 'app.use(session());';
|
|
|
|
function fail(message) {
|
|
process.stderr.write(`patch_server.js: ${message}\n`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const original = readFileSync(SERVER_PATH, 'utf8');
|
|
|
|
if (original.includes(IMPORT_LINE) && original.includes(MOUNT_LINE)) {
|
|
process.stdout.write('patch_server.js: already patched, skipping\n');
|
|
process.exit(0);
|
|
}
|
|
|
|
if (!original.includes(IMPORT_ANCHOR)) {
|
|
fail(`import anchor not found: ${IMPORT_ANCHOR}`);
|
|
}
|
|
if (!original.includes(MOUNT_ANCHOR)) {
|
|
fail(`mount anchor not found: ${MOUNT_ANCHOR}`);
|
|
}
|
|
|
|
let patched = original.replace(IMPORT_ANCHOR, `${IMPORT_ANCHOR}\n${IMPORT_LINE}`);
|
|
patched = patched.replace(MOUNT_ANCHOR, `${MOUNT_ANCHOR}\n${MOUNT_LINE}`);
|
|
|
|
writeFileSync(SERVER_PATH, patched);
|
|
process.stdout.write('patch_server.js: server.js patched for trusted-header SSO\n');
|