@sap/xssec
Version:
XS Advanced Container Security API for node.js
52 lines (45 loc) • 2.59 kB
JavaScript
const Token = require('../token/Token');
const MissingJwtError = require("../error/validation/MissingJwtError");
const SecurityContext = require('./SecurityContext');
const { WrongAudienceError } = require('../error');
module.exports = createSecurityContext;
/**
* @typedef {import("../service/Service")} Service
* @typedef {import("../util/Types").SecurityContextConfig} SecurityContextConfig
*/
/**
* Tries to create a new security context by authenticating the user via the given service(s) based on a jwt token.
* If the jwt is missing or cannot be validated, an error will be thrown.
* The contextConfig must either contain a jwt token directly or a req object from whose Authorization header the jwt can be extracted as Bearer token.
* @template {Service} T - The type of the service from which the security context is created
* @param {T|T[]} services - The service or array of services to authenticate the user
* @param {SecurityContextConfig} contextConfig - The configuration object containing the jwt token or req object
* @returns {ReturnType<T['createSecurityContext']>} - A promise that resolves to the security context created by the target service
* @throws {import('../error/XssecError')} - Error with a descriptive message and a suggested statusCode for the application response. The cause of the error can be checked via instanceof against the various XssecError subclasses.
*/
async function createSecurityContext(services, contextConfig) {
contextConfig = { ...contextConfig };
SecurityContext.buildContextConfig(contextConfig);
if (contextConfig.jwt == null) {
throw new MissingJwtError();
}
const token = new Token(contextConfig.jwt);
// find service for token
services = Array.isArray(services) ? services : services != null ? [services] : [];
const targetService = findServiceForToken(services, token);
if (targetService == null) {
throw new WrongAudienceError(token, services, `The audiences of the token fit none of the supplied services.`);
}
// create context
return targetService.createSecurityContext(token, contextConfig);
}
/**
* Tries to find a service from the list for which the given token was issued based on logic implemented by individual subclasses of {@link Service}.
* @param {Service[]} services
* @param {Token} token
* @returns {Service|undefined}
*/
function findServiceForToken(services, token) {
// TODO: extend with heuristic to filter on XSUAA/IAS services to prevent false positive?
return services.find(s => s.acceptsTokenAudience(token));
}