@sap/xssec
Version:
XS Advanced Container Security API for node.js
79 lines (65 loc) • 3.04 kB
JavaScript
;
const SecurityContext = require('../context/SecurityContext');
const UaaSecurityContext = require('../context/UaaSecurityContext');
const Token = require('../token/Token');
const UaaToken = require('../token/UaaToken');
const XsuaaService = require('./XsuaaService');
/**
* @typedef {import('../util/Types').ServiceCredentials} ServiceCredentials
* @typedef {import('../util/Types').UaaServiceCredentials} UaaServiceCredentials
* @typedef {import('../util/Types').ServiceConfig} ServiceConfig
* @typedef {import('../util/Types').SecurityContextConfig} SecurityContextConfig
*/
/**
* New SAP BTP applications should start with SAP Identity Services instead of CF UAA! See README for details.\
* This {@link Service} class is constructed from CF UAA credentials to provide an API with selected functionality against that UAA service instance, e.g. token validation and token fetches.
*/
class UaaService extends XsuaaService {
/**
* @param {ServiceCredentials | UaaServiceCredentials} credentials
* @param {ServiceConfig} [serviceConfig={}]
*/
constructor(credentials, serviceConfig) {
super(credentials, serviceConfig);
}
/**
* @override
* @param {String|UaaToken} token token as JWT or UaaToken object
* @param {SecurityContextConfig} contextConfig
* @returns {Promise<UaaSecurityContext>}
*/
async createSecurityContext(token, contextConfig = {}) {
if (typeof token === "string") {
token = new UaaToken(token);
} else if (token instanceof Token && !(token instanceof UaaToken)) {
token = new UaaToken(token.jwt, { header: token.header, payload: token.payload });
}
SecurityContext.buildContextConfig(contextConfig);
if (contextConfig.skipValidation !== true && this.config.validation.enabled !== false) {
await this.validateToken(token, contextConfig);
}
let ctx = new UaaSecurityContext(this, token, contextConfig);
for (let extension of this.contextExtensions) {
ctx = await extension.extendSecurityContext(ctx) ?? ctx;
}
return ctx;
}
/**
* @overrides
* @inheritdoc
*/
acceptsTokenAudience(token) {
this.validateCredentials("validate token audience", "clientid");
if(!(token instanceof UaaToken)) {
// cast to UaaToken, so token.scopes getter exists for the checks below
token = new UaaToken(null, { header: token.header, payload: token.payload });
}
// CF UAA tokens with grant_type === 'user_token' might not have audiences filled, so a fallback to scopes is needed
const tokenAudiences = token.audiences?.length > 0 ? token.audiences : (token.scopes ?? []);
if(token.payload.cid) {
tokenAudiences.push(token.payload.cid);
}
return tokenAudiences.some(a => a === this.credentials.clientid || a.startsWith(`${this.credentials.clientid}.`))
}
}
module.exports = UaaService;