51 lines
2.2 KiB
JavaScript
51 lines
2.2 KiB
JavaScript
// OIDC discovery document + issuer derivation.
|
|
//
|
|
// The issuer MUST exactly equal the URL prefix a relying party used to fetch
|
|
// /.well-known/openid-configuration. We prefer the tenant's configured base_url
|
|
// (the trustworthy source); otherwise we fall back to the request scheme+host.
|
|
//
|
|
// SECURITY: the request-host fallback is vulnerable to Host-header injection
|
|
// (an attacker forging Host could poison the advertised issuer/endpoints).
|
|
// base_url should be set in any multi-tenant or proxied deployment; the
|
|
// fallback exists for single-tenant localhost/dev. This is revisited in the
|
|
// multi-tenancy phase (validate host against the tenant's known domains).
|
|
|
|
const constants = require("../constants");
|
|
|
|
|
|
const issuerForReq = (req) => {
|
|
let base = "";
|
|
try {
|
|
const { getState } = require("@saltcorn/data/db/state");
|
|
const configured = getState().getConfig("base_url", "");
|
|
if (configured) {
|
|
base = configured;
|
|
}
|
|
} catch (e) {
|
|
// getState unavailable; fall back to request-derived host
|
|
}
|
|
if (!base) {
|
|
const host = req.get("host") || "";
|
|
// Defensive: only a clean single host[:port] may seed the issuer in the
|
|
// fallback path. A forged/garbage Host (multiple values, schemes, control
|
|
// chars) must never be reflected into the advertised issuer/endpoints.
|
|
// (A valid-but-wrong Host still requires the operational fix: set base_url.)
|
|
if (!/^[A-Za-z0-9.-]+(:[0-9]{1,5})?$/.test(host)) {
|
|
throw new Error(`${constants.PLUGIN_NAME}: refusing to derive issuer from malformed Host "${host}"; set base_url`);
|
|
}
|
|
base = req.protocol + "://" + host;
|
|
// eslint-disable-next-line no-console
|
|
console.warn(`[${constants.PLUGIN_NAME}] base_url not set; deriving issuer from request Host (${base}). Set base_url to prevent Host-header issuer poisoning.`);
|
|
}
|
|
base = base.replace(/\/+$/, "");
|
|
return base + constants.IDP_BASE_PATH;
|
|
};
|
|
|
|
|
|
// NOTE: the discovery document and JWKS are now generated and served by
|
|
// oidc-provider itself (see oidc/provider.js + oidc/routes.js); we only keep the
|
|
// issuer derivation here, which feeds the Provider's issuer.
|
|
|
|
module.exports = {
|
|
issuerForReq
|
|
};
|