@sap/xssec
Version:
XS Advanced Container Security API for node.js
84 lines (71 loc) • 3.15 kB
JavaScript
const createSecurityContext = require("../context/createSecurityContext");
const ConfigurationError = require("../error/configuration/ConfigurationError");
const ValidationError = require("../error/validation/ValidationError");
const { getLogger } = require("../util/logging");
/**
* @typedef {import("../service/Service")} Service
* @typedef {import("../token/Token")} Token
*/
const LOG = getLogger("XssecPassportStrategy.js");
class XssecPassportStrategy {
/** @type {Service|Service[]} service(s) against which incoming JWTs are authenticated */
services;
/** @type {string|Symbol} the property on the req object where the SecurityContext is placed after authentication. */
reqProperty;
/**
* Creates a new XssecPassportStrategy that uses the provided service(s) to create security contexts for incoming requests.
* @param {Service|Service[]} services
* @param {string|Symbol} [reqProperty="securityContext"] the property (Default: "securityContext") on the req object where the SecurityContext is placed after authentication.
*/
constructor(services, reqProperty = "securityContext") {
this.name = "JWT";
this.services = services;
this.reqProperty = reqProperty;
}
async authenticate(req, passportOptions = {}) {
try {
const securityContext = await createSecurityContext(this.services, {req});
if (passportOptions.scope) {
if (!(typeof securityContext.checkScope === "function")) {
return this.error(new ConfigurationError("XssecPassportStrategy was configured with scope but the authentication was performed via a Service whose SecurityContext does not support checkLocalScope."));
}
const hasScope = [passportOptions.scope]
.flatMap(s => s)
.some(s => securityContext.checkLocalScope(s));
if (!hasScope) {
return this.fail("Token is missing required scope.", 403);
}
}
const passportUser = XssecPassportStrategy.#buildPassportUser(securityContext.token);
req[this.reqProperty] = securityContext;
req.tokenInfo = securityContext.token;
return this.success(passportUser, securityContext); // passport will set these in req.user & req.authInfo respectively
} catch (error) {
req.xssecError = error;
if (error instanceof ValidationError) {
LOG.debug("ValidationError:", error);
return this.fail(401);
} else {
return this.error(error);
}
}
}
/**
* @param {Token} token
*/
static #buildPassportUser(token) {
return {
id: token.logonName || token.userName,
name: {
givenName: token.givenName,
familyName: token.familyName
},
emails: [
{
value: token.email
}
]
}
}
}
module.exports = XssecPassportStrategy;