UNPKG

@sap/xssec

Version:

XS Advanced Container Security API for node.js

195 lines (158 loc) 6.06 kB
const SecurityContext = require("./SecurityContext"); const { getLogger } = require('../util/logging'); const { GRANTTYPE_CLIENTCREDENTIALS } = require("../util/constants"); /** * @typedef {import("../token/XsuaaToken")} XsuaaToken * @typedef {import("../service/XsuaaService")} XsuaaService * @typedef {import('../util/Types').SecurityContextConfig} SecurityContextConfig */ const LOG = getLogger("XsuaaSecurityContext.js"); /** @extends {SecurityContext<XsuaaService, XsuaaToken>} */ class XsuaaSecurityContext extends SecurityContext { /** * An IdentityServiceSecurityContext that may be available if an XsuaaLegacyExtension instance has been configured. * @type {import("./IdentityServiceSecurityContext")} */ iasContext; /** * @param {XsuaaService|null} service * @param {XsuaaToken} token * @param {SecurityContextConfig} [contextConfig] */ constructor(service, token, contextConfig) { super(service, token, contextConfig); } /** * Checks if the token of this context was issued for the given scope. * @param {String} scope * @returns {Boolean} */ checkScope(scope) { return this.token.scopes.includes(scope); } /** * Checks if the token of this context was issued for the given scope, ignoring the xsappname prefix of the service that was used to create this context when copmaring with the token's scopes. * @param {String} scope * @returns {Boolean} */ checkLocalScope(scope) { return this.token.scopes.includes(`${this.service.credentials.xsappname}.${scope}`); } checkFollowingInstanceScope(scope) { const clientId = this.token.payload.client_id; if (!clientId?.startsWith('sb-')) { return false; } const appId = clientId.substring(3); if (!appId.includes("|")) { return false; } return this.checkScope(`${appId}.${scope}`); } // Methods for backward-compatibility getAttributes() { // must return null instead of empty attributes for backward-compatibility const attributes = this.token.xsUserAttributes ?? {}; return Object.keys(attributes).length !== 0 ? attributes : null; } getAttribute(name) { return this.token.getXsUserAttribute(name) || null; } getAdditionalAuthAttribute(name) { const additionalAuthAttributes = this.getAdditionalAuthAttributes(); if (!additionalAuthAttributes) { LOG.debug('\nThe access token contains no additional authentication attributes.\n'); return null; } if (!name) { LOG.debug('\nInvalid attribute name (may not be null, empty, or undefined).'); return null; } if (!additionalAuthAttributes[name]) { LOG.debug('\nNo attribute "' + name + '" found as additional authentication attribute.'); return null; } return additionalAuthAttributes[name]; } getAdditionalAuthAttributes() { return this.token.azAttributes || null; } /** * @deprecated Use token.zid instead */ getAppTID() { return this.token.zid; } getClientId() { return this.token.getClientId(); } getCloneServiceInstanceId() { return this.token.extAttributes?.serviceinstanceid || null; } getEmail() { return this.#ifNotClientCredentialsToken("XsuaaSecurityContext.getEmail", this.getUserInfo().email); } getFamilyName() { return this.#ifNotClientCredentialsToken("XsuaaSecurityContext.getFamilyName", this.getUserInfo().familyName); } getGivenName() { return this.#ifNotClientCredentialsToken("XsuaaSecurityContext.getGivenName", this.getUserInfo().givenName); } getLogonName() { return this.#ifNotClientCredentialsToken("XsuaaSecurityContext.getLogonName", this.getUserInfo().logonName); } getOrigin() { return this.token.origin; } getSubaccountId() { return this.token.subAccountId; } getSubdomain() { return this.token.extAttributes?.zdn ?? null; } getUniquePrincipalName(origin, logonName) { if (!this.#ifNotClientCredentialsToken('XsuaaSecurityContext.getUniquePrincipalName', true)) { return null; } if (!origin) { LOG.debug('Origin claim not set in JWT. Cannot create unique user name. Returning null.'); return null; } if (!logonName) { LOG.debug('User login name claim not set in JWT. Cannot create unique user name. Returning null.'); return null; } if (origin.includes('/')) { LOG.debug('Illegal \'/\' character detected in origin claim of JWT. Cannot create unique user name. Retuning null.'); return null; } return `user/${origin}/${logonName}`; } getUserName() { if (this.token.grantType === GRANTTYPE_CLIENTCREDENTIALS) { return `client/${this.getClientId()}`; } else { return this.getUniquePrincipalName(this.token.origin, this.getLogonName()); } } /** * @deprecated Use token.zid instead */ getZoneId() { return this.token.zid; } hasAttributes() { return this.#ifNotClientCredentialsToken('XsuaaSecurityContext.hasAttributes', this.token.xsUserAttributes != null); } isInForeignMode() { return this.service.credentials.clientid.includes("!b") && this.token.audiences.some(aud => aud.includes(`|${this.service.credentials.clientid}`)); } #ifNotClientCredentialsToken(functionName, value) { if (this.token.grantType === GRANTTYPE_CLIENTCREDENTIALS) { LOG.debug(`Call to ${functionName} not allowed with a token of grant type ${GRANTTYPE_CLIENTCREDENTIALS}.`); return null; } return value; } } module.exports = XsuaaSecurityContext;