UNPKG

@sap-cloud-sdk/core

Version:
315 lines • 13.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EnvironmentAccessor = exports.extractClientCredentials = exports.resolveService = exports.getXsuaaServiceCredentials = exports.getDestinationServiceUri = exports.getEnvironmentVariable = exports.getVcapService = exports.getDestinationService = exports.getService = exports.getServiceList = exports.getServiceCredentialsList = exports.getDestinationServiceCredentialsList = exports.getDestinationServiceCredentials = exports.getDestinationBasicCredentials = void 0; var util_1 = require("@sap-cloud-sdk/util"); var xsenv = __importStar(require("@sap/xsenv")); var jwt_1 = require("./jwt"); var logger = (0, util_1.createLogger)({ package: 'core', messageContext: 'environment-accessor' }); /** * Basic Credentials Getter from Destination service credentials needed for JWT generator. * * @returns Basic credentials. */ function getDestinationBasicCredentials() { var destinationCredentials = getDestinationServiceCredentials(); var basicCredentials = { clientid: destinationCredentials.clientid ? destinationCredentials.clientid : null, clientsecret: destinationCredentials.clientsecret ? destinationCredentials.clientsecret : null }; return basicCredentials; } exports.getDestinationBasicCredentials = getDestinationBasicCredentials; /** * First 'destination' credentials getter. * * @returns The 'destination' credentials object or `null`, if it does not exist. */ function getDestinationServiceCredentials() { return (0, util_1.first)(getDestinationServiceCredentialsList()); } exports.getDestinationServiceCredentials = getDestinationServiceCredentials; /** * Destination credentials getter. * * @returns A list of 'credentials' objects in 'destination' service. */ function getDestinationServiceCredentialsList() { return getServiceList('destination').map(function (s) { return s.credentials; }); } exports.getDestinationServiceCredentialsList = getDestinationServiceCredentialsList; /** * Credentials list getter for a given service. * @param service - Service name * @returns Fetched credentials objects of existing service in 'VCAP_SERVICES'. */ function getServiceCredentialsList(service) { var credentials = []; getServiceList(service).forEach(function (entry) { if ('credentials' in entry) { credentials.push(entry['credentials']); } else { logger.warn("Skipping a service in ".concat(service, ". Object has no 'credentials'.")); } }); return credentials; } exports.getServiceCredentialsList = getServiceCredentialsList; /** * Services getter for a given service. * @param service - Service name. * @returns List of service bindings of the given type. Returns an empty array if no service binding exists for the given type. */ function getServiceList(service) { return xsenv.filterServices({ label: service }); // TODO: how do we allow propagating custom secret paths for k8s? } exports.getServiceList = getServiceList; /** * Returns the first found instance for the given service type. * @param service - The service type. * @returns The first found service. */ function getService(service) { var services = xsenv.filterServices({ label: service }); if (!services.length) { logger.warn("No services of type ".concat(service, " found! This might cause errors in other parts of the application.")); return undefined; } if (services.length > 1) { logger.warn("Found more than one service instance for service type ".concat(service, ". Found: ").concat(services .map(function (s) { return s.name; }) .join(', '), ". Selecting the first one.")); } return services[0]; } exports.getService = getService; /** * Get destination service if one is present. * * @returns Destination service * @throws Error in case no destination service is found in the VCAP variables */ function getDestinationService() { var destinationService = getService('destination'); if (!destinationService) { throw Error('No binding to a destination service found.'); } return destinationService; } exports.getDestinationService = getDestinationService; /** * 'VCAP_SERVICES' Getter from environment variables. * This function returns the VCAP_SERVICES as object or `null`, if it is not defined (i.e. no services are bound to the application). * * @returns 'VCAP_SERVICES' found in environment variables or `null`, if not defined. The key denotes the name ov the service and the value is the definition. */ function getVcapService() { var env = getEnvironmentVariable('VCAP_SERVICES'); var vcapServices; if (!env) { logger.warn("Environment variable 'VCAP_SERVICES' is not defined."); return null; } try { vcapServices = JSON.parse(env); } catch (error) { throw new util_1.ErrorWithCause("Failed to parse environment variable 'VCAP_SERVICES'.", error); } if (!Object.keys(vcapServices).length) { throw new Error("Environment variable 'VCAP_SERVICES' is defined but empty. This should not happen."); } return vcapServices; } exports.getVcapService = getVcapService; /** * Environment variables accessor. * @param name - Environment variable name. * @returns Env variable value if defined. * null: If not defined. */ function getEnvironmentVariable(name) { if (process.env[name]) { return process.env[name]; } logger.info('Environment variable ' + name + ' is not defined.'); return null; } exports.getEnvironmentVariable = getEnvironmentVariable; /** * Destination URI getter * NOTICE: If there exist more than one destination/uri, the function * returns the first entry. * * @returns The first existing uri in destination or `null`, if not found. */ function getDestinationServiceUri() { var destinationServiceCredentials = getDestinationServiceCredentialsList(); var uris = []; for (var _i = 0, destinationServiceCredentials_1 = destinationServiceCredentials; _i < destinationServiceCredentials_1.length; _i++) { var credential = destinationServiceCredentials_1[_i]; if ('uri' in credential) { uris.push(credential['uri']); } else { logger.info("Skipping credentials in 'destination'. 'uri' property not defined"); } } return uris[0] || null; } exports.getDestinationServiceUri = getDestinationServiceUri; /** * Takes a decoded JWT and uses the client_id and audience claims to determine the XSUAA service instance * that issued the JWT. Returns the credentials if a match is found, otherwise throws an error. * If no decoded JWT is specified, then returns the first existing XSUAA credential service plan "application". * @param token - Either an encoded or decoded JWT. * @returns The credentials for a match, otherwise `null`. */ function getXsuaaServiceCredentials(token) { return typeof token === 'string' ? selectXsuaaInstance((0, jwt_1.decodeJwt)(token)) : selectXsuaaInstance(token); } exports.getXsuaaServiceCredentials = getXsuaaServiceCredentials; /** * Takes a string that represents the service type and resolves it by calling [[getService]]. * If the parameter is already an instance of [[Service]], it is returned directly. * * Throws an error when no service can be found for the given type. * @param service - A string representing the service type or a [[Service]] instance. * @returns A [[Service]] instance. */ function resolveService(service) { if (typeof service === 'string') { var serviceInstance = getService(service); if (!serviceInstance) { throw Error("Unable to get access token for \"".concat(service, "\" service. No service instance of type \"").concat(service, "\" found.")); } return serviceInstance; } return service; } exports.resolveService = resolveService; /** * Extracts the credentials of a service into an instance of [[ClientCredentials]]. * @param serviceCreds - The credentials of a service as read from VCAP_SERVICES. * @returns A [[ClientCredentials]] instance. */ function extractClientCredentials(serviceCreds) { if (!serviceCreds.clientsecret) { throw new Error("Cloud not extract client secret for clientId: ".concat(serviceCreds.clientid, ".")); } return { username: serviceCreds.clientid, password: serviceCreds.clientsecret }; } exports.extractClientCredentials = extractClientCredentials; function selectXsuaaInstance(token) { var xsuaaCredentials = getServiceList('xsuaa').map(function (service) { return service.credentials; }); if (!arrayHasAtLeastOneElement(xsuaaCredentials)) { throw Error('No binding to an XSUAA service instance found. Please make sure to bind an instance of the XSUAA service to your application.'); } return token ? selectXsuaaInstanceWithJwt(xsuaaCredentials, token) : selectXsuaaInstanceWithoutJwt(xsuaaCredentials); } function handleOneXsuuaInstance(xsuaaCredentials) { logger.debug("Only one XSUAA instance bound. This one is used: ".concat(xsuaaCredentials[0].xsappname)); return xsuaaCredentials[0]; } function arrayHasAtLeastOneElement(array) { return !!array.length && array.length > 0; } function arrayHasExactlyOneElement(array) { return array.length === 1; } function selectXsuaaInstanceWithoutJwt(xsuaaCredentials) { if (!arrayHasExactlyOneElement(xsuaaCredentials)) { logger.warn("The following XSUAA instances are bound: ".concat(xsuaaCredentials.map(function (x) { return "\n\t- ".concat(x.xsappname); }), "\n No JWT given to select XSUAA instance. ").concat(choseFirstOneText(xsuaaCredentials))); return xsuaaCredentials[0]; } return handleOneXsuuaInstance(xsuaaCredentials); } function selectXsuaaInstanceWithJwt(xsuaaCredentials, jwt) { var selectedAll = __spreadArray(__spreadArray([], matchingClientId(xsuaaCredentials, jwt), true), matchingAudience(xsuaaCredentials, jwt), true); var selectedUnique = (0, util_1.unique)(selectedAll.map(function (x) { return x.clientid; })).map(function (id) { return selectedAll.find(function (y) { return y.clientid === id; }); }); if (selectedUnique.length === 1) { logger.debug("One XSUAA instance found using JWT in service binding. Used service name is: ".concat(xsuaaCredentials[0].xsappname)); return xsuaaCredentials[0]; } if (selectedUnique.length > 1) { logger.warn("Multiple XSUAA instances could be matched to the given JWT: ".concat(xsuaaCredentials.map(function (x) { return "\n\t- ".concat(x.xsappname); }), "\n ").concat(choseFirstOneText(xsuaaCredentials))); return selectedUnique[0]; } if (!arrayHasExactlyOneElement(xsuaaCredentials)) { logger.warn("Multiple XSUAA instances found: ".concat(xsuaaCredentials.map(function (x) { return "\n\t- ".concat(x.xsappname); }), "\n None of those match either client id or audience from the given JWT. ").concat(choseFirstOneText(xsuaaCredentials))); return xsuaaCredentials[0]; } return handleOneXsuuaInstance(xsuaaCredentials); } function choseFirstOneText(xsuaaCredentials) { return "Choosing the first one (xsappname: \"".concat((0, util_1.first)(xsuaaCredentials).xsappname, "\")."); } function matchingClientId(xsuaaCredentials, token) { return xsuaaCredentials.filter(function (credentials) { return credentials.clientid === token.client_id; }); } function matchingAudience(xsuaaCredentials, token) { return xsuaaCredentials.filter(function (credentials) { return (0, jwt_1.audiences)(token).has(credentials.xsappname); }); } /** * @deprecated Since v1.5.0. Use directly exported functions instead */ exports.EnvironmentAccessor = { getDestinationBasicCredentials: getDestinationBasicCredentials, getDestinationServiceCredentials: getDestinationServiceCredentials, getDestinationServiceCredentialsList: getDestinationServiceCredentialsList, getServiceCredentialsList: getServiceCredentialsList, getServiceList: getServiceList, getVcapService: getVcapService, getEnvironmentVariable: getEnvironmentVariable, getDestinationServiceUri: getDestinationServiceUri, getXsuaaServiceCredentials: getXsuaaServiceCredentials }; //# sourceMappingURL=environment-accessor.js.map