87c0d024d5
Adds the /__proxy_auth OIDC flow served on every proxied host: - routes/host_auth.js: /start (PKCE+state, per-host redirect_uri), /callback (exchange, enforce the host allow-list via utils/host_sso.identityAllowed, mint session + set __proxy_sso cookie), /logout. - models/sso_session.js: SsoSession (Redis-backed, TTL'd; read directly by the Lua gate) and HostSsoState (in-flight auth request). - utils/oidc.js: per-host redirect_uri override on buildAuthUrl/exchangeCode. - conf.hostSso (reuses conf.oidc). Allow-list logic unit-tested. Enforcement (Lua gate + nginx location) lands next. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
53 lines
1.9 KiB
JavaScript
53 lines
1.9 KiB
JavaScript
'use strict';
|
|
|
|
const Table = require('.');
|
|
const conf = require('@simpleworkjs/conf');
|
|
|
|
/**
|
|
* Per-host SSO models (#57).
|
|
*
|
|
* HostSsoState — short-lived, in-flight OIDC authorization request for a
|
|
* protected host (like OidcState, but carries the target host + post-login
|
|
* redirect). Auto-expires via TTL.
|
|
*
|
|
* SsoSession — an established session after a successful, authorized login.
|
|
* Keyed by a random session id stored in the browser's `__proxy_sso` cookie.
|
|
* OpenResty (ops/nginx_conf/hostfeatures.lua) reads `proxy_SsoSession_<sid>`
|
|
* straight from Redis to gate requests; the allow-list was already enforced at
|
|
* callback time (utils/host_sso.js), so the Lua side only checks that a session
|
|
* exists and belongs to this host. Auto-expires via TTL.
|
|
*/
|
|
|
|
const SESSION_TTL = (conf.hostSso && conf.hostSso.sessionTtl) || 28800; // 8h
|
|
|
|
class HostSsoState extends Table{
|
|
static _key = 'state';
|
|
static _ttl = 300; // 5 minutes bounds the auth round-trip / replay
|
|
static _keyMap = {
|
|
'created_on': {default: function(){return (new Date).getTime()}},
|
|
'state': {isRequired: true, type: 'string', min: 8, max: 500},
|
|
'codeVerifier': {isRequired: true, type: 'string', min: 8, max: 500},
|
|
'host': {isRequired: true, type: 'string', min: 1, max: 500},
|
|
'rd': {default: '/', isRequired: false, type: 'string'},
|
|
}
|
|
}
|
|
HostSsoState.register();
|
|
|
|
class SsoSession extends Table{
|
|
static _key = 'sid';
|
|
static _ttl = SESSION_TTL;
|
|
static _keyMap = {
|
|
'created_on': {default: function(){return (new Date).getTime()}},
|
|
'sid': {isRequired: true, type: 'string', min: 16, max: 500},
|
|
'host': {isRequired: true, type: 'string', min: 1, max: 500},
|
|
'sub': {isRequired: true, type: 'string', min: 1, max: 500},
|
|
'email': {default: '', isRequired: false, type: 'string'},
|
|
'groups': {default: function(){return []}, isRequired: false, type: 'object'},
|
|
}
|
|
|
|
static ttl(){ return SESSION_TTL; }
|
|
}
|
|
SsoSession.register();
|
|
|
|
module.exports = {HostSsoState, SsoSession};
|