UNPKG

@zowe/imperative

Version:
866 lines 43.3 kB
"use strict"; /* * This program and the accompanying materials are made available under the terms of the * Eclipse Public License v2.0 which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-v20.html * * SPDX-License-Identifier: EPL-2.0 * * Copyright Contributors to the Zowe Project. * */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AuthOrder = exports.PropUse = void 0; const censor_1 = require("../../../censor"); const error_1 = require("../../../error"); const logger_1 = require("../../../logger"); const SessConstants = require("./SessConstants"); const utilities_1 = require("../../../utilities"); /** * This enum is used to specify if a property is to be used in * a session or in a config file. */ var PropUse; (function (PropUse) { PropUse[PropUse["IN_SESS"] = 0] = "IN_SESS"; PropUse[PropUse["IN_CFG"] = 1] = "IN_CFG"; })(PropUse || (exports.PropUse = PropUse = {})); /** * The purpose of this class is to detect an authentication order property * supplied by a user in a profile, command line, or environment variable. * That authOrder is then used to place the correct set of credentials into * a session for authentication. * * To accomplish this behavior, we call AuthOrder.addCredsToSession * early in the processing of a command (when both a session * configuration and command arguments are available). For example in: * ConnectionPropsForSessCfg.addPropsOrPrompt or * ProfileInfo.createSession * * Before we use the session, we call AuthOrder.putTopAuthInSession. * For example in: * AbstractRestClient.constructor * AbstractRestClient.request * AuthOrder.putTopAuthInSession ensures that the session only contains the * credentials for the desired type of authentication. */ class AuthOrder { // *********************************************************************** /** * Add available credentials (and the authentication order in which * credentials should be chosen) into a cache within the specified session. * Using that cached information put only the top selected credential as * the credential to be used by the session. * * @param sessCfg - Modified. * A session configuration object into which we place cached creds * and the selected creds. * * @param cmdArgs - Input. * The set of arguments with which the calling function is operating. * For CLI, the cmdArgs come from the command line, profile, or * environment. Other apps can place relevant arguments into this * object to be processed by this function. * * If cmdArgs is not supplied, we only cache creds found in the sessCfg. */ static addCredsToSession(sessCfg, cmdArgs = { "$0": "NameNotUsed", "_": [] } // when no cmdArgs are provided, use an empty set of cmdArgs ) { AuthOrder.cacheCredsAndAuthOrder(sessCfg, cmdArgs); // Now that we know our authOrder and available creds, we place // only the top creds into the session. The putTopAuthInSession function // is also called later if our default top auth is modified. It is also // called just before making our REST request (as a failsafe). AuthOrder.putTopAuthInSession(sessCfg); } // *********************************************************************** /** * Cache the default authentication order to be used when the user has NOT * specified an order. No action is performed if the end-user HAS defined * an authentication order in their zowe client configuration. * * For historical reason, we have 2 default orders. Thus, the caller can * specify which of 2 creds to use as the top cred in the authentication order: * SessConstants.AUTH_TYPE_BASIC or SessConstants.AUTH_TYPE_TOKEN * * @internal - Cannot be used outside of the imperative package * * @param sessCfg - Modified. * A session configuration object into which we place the default order. * * @param topDefaultAuth - Input. * The authentication type that will be used first. * * @return True when the default order was cached. * False when the user supplied an order, because you cannot * override the user-supplied order with any default. */ static cacheDefaultAuthOrder(sessCfg, topDefaultAuth) { // create a new auth cache (if needed) in the session config AuthOrder.findOrCreateAuthCache(sessCfg); if (sessCfg._authCache.didUserSetAuthOrder) { // nobody can change what the user specified logger_1.Logger.getImperativeLogger().info(`Because user set authOrder, an attempt to put ${topDefaultAuth} at the top of the order was ignored.`); return false; } // record the top auth that was requested for use in the default order sessCfg._authCache.topDefaultAuth = topDefaultAuth; // start over with an empty auth order. sessCfg.authTypeOrder = []; if (sessCfg._authCache.topDefaultAuth === SessConstants.AUTH_TYPE_BASIC) { // we want user & password auth as the top choice sessCfg.authTypeOrder.push(SessConstants.AUTH_TYPE_BASIC); sessCfg.authTypeOrder.push(SessConstants.AUTH_TYPE_TOKEN); } else { // we want token auth as the top choice sessCfg.authTypeOrder.push(SessConstants.AUTH_TYPE_TOKEN); sessCfg.authTypeOrder.push(SessConstants.AUTH_TYPE_BASIC); } // add remaining auth types. We do not include 'none' in our defaults. sessCfg.authTypeOrder.push(SessConstants.AUTH_TYPE_BEARER); sessCfg.authTypeOrder.push(SessConstants.AUTH_TYPE_CERT_PEM); return true; } // *********************************************************************** /** * Clears the authentication cache. * * To get the right creds and auth order in your session after calling this * function you must once again call the appropriate combination of: * AuthOrder.addCredsToSession * AuthOrder.cacheDefaultAuthOrder * AuthOrder.putTopAuthInSession * * @internal - Cannot be used outside of the imperative package */ static clearAuthCache(sessCfg) { delete sessCfg._authCache; AuthOrder.findOrCreateAuthCache(sessCfg); } // *********************************************************************** /** * Returns the cached authentication order. * If no auth order exists, we create and return a default auth order. * * @internal - Cannot be used outside of the imperative package * * @param sessCfg - Modified. * The session config from which we retrieve the cached auth order. * When no auth order exists in the sessCfg, a default auth order * is stored in the sessCfg, before returning that newly created value. * * @return {SessConstants.AUTH_TYPE_CHOICES[]} The cached authentication order. */ static getAuthOrder(sessCfg) { if (!sessCfg.authTypeOrder || sessCfg.authTypeOrder.length === 0) { // we have no auth order, so create a default authOrder that we can return sessCfg._authCache.didUserSetAuthOrder = false; AuthOrder.chooseDefaultAuthOrder(sessCfg); } return sessCfg.authTypeOrder; } // *********************************************************************** /** * Get the correct property name for use in either a session * or in a config file. Currently only certificate property names * are different between the two. * * @internal - Cannot be used outside of the imperative package * * @param propName - input. * The name of a property for which we must select the * correct name to. * * @param desiredUse - input. * Specifies where property is to be used. * * @return The cached authentication order. */ static getPropNmFor(propName, desiredUse) { let propNmToUse; if (propName === AuthOrder.SESS_CERT_NAME || propName === "certFile") { if (desiredUse === PropUse.IN_SESS) { propNmToUse = AuthOrder.SESS_CERT_NAME; } else { propNmToUse = "certFile"; } } else if (propName === AuthOrder.SESS_CERT_KEY_NAME || propName === "certKeyFile") { if (desiredUse === PropUse.IN_SESS) { propNmToUse = AuthOrder.SESS_CERT_KEY_NAME; } else { propNmToUse = "certKeyFile"; } } else { // all other properties have the same name in the session and in the config propNmToUse = propName; } return propNmToUse; } // *********************************************************************** /** * Record that the session is being used to make a request for a token * (ie logging into APIML). * * @param sessCfg - Modified. * The session config into which we record that we are requesting a token. */ static makingRequestForToken(sessCfg) { // create a new auth cache (if needed) in the session config AuthOrder.findOrCreateAuthCache(sessCfg); // Just create the property with a placeholder value. // putTopAuthInSession() will later place the correct value into this property sessCfg._authCache.authTypeToRequestToken = SessConstants.AUTH_TYPE_NONE; } // *********************************************************************** /** * Remove any request-for-token from the session config. * * @internal - Cannot be used outside of the imperative package * * @param sessCfg - Modified. * The session config from which we remove a request-for-token. */ static removeRequestForToken(sessCfg) { var _a; if ((_a = sessCfg === null || sessCfg === void 0 ? void 0 : sessCfg._authCache) === null || _a === void 0 ? void 0 : _a.authTypeToRequestToken) { delete sessCfg._authCache.authTypeToRequestToken; } } // *********************************************************************** /** * Find the highest auth type (according to the authOrder) that exists * in availableCreds within the supplied session config. * Then place the credentials associated with that auth type into the * top-level of the session config. Finally, remove credentials * for all other auth types from the top-level of session config. * * @internal - Cannot be used outside of the imperative package * * @param sessCfg - Modified. * Authentication properties are added to and removed from this * session configuration, which can already have properties in * this object when passed to this function. * * @throws {ImperativeError} If an invalid auth type is encountered. */ static putTopAuthInSession(sessCfg) { var _a; // If our caller did not follow best practices in their use of imperative functions, // then addCredsToSession may not have been called, and availableCreds may be empty. if (!((_a = sessCfg._authCache) === null || _a === void 0 ? void 0 : _a.availableCreds) || Object.keys(sessCfg._authCache.availableCreds).length === 0) { // As a last resort, cache our creds now with an empty set of command args. // This will cache any creds from the sessCfg and use a default auth order. AuthOrder.cacheCredsAndAuthOrder(sessCfg, { "$0": "NameNotUsed", "_": [] }); } logger_1.Logger.getImperativeLogger().debug("SessCfg before setting top auth = " + censor_1.Censor.censorSession(sessCfg)); // Detect the first auth type (from our auth order) within our available credentials. // Ensure that the auth properties are placed in the session config. // Record the detected auth type for use as the session type. let sessTypeToUse = null; let errMsg; for (const nextAuth of sessCfg.authTypeOrder) { switch (nextAuth) { case SessConstants.AUTH_TYPE_BASIC: if (sessCfg._authCache.availableCreds.user && sessCfg._authCache.availableCreds.password) { sessCfg.user = sessCfg._authCache.availableCreds.user; sessCfg.password = sessCfg._authCache.availableCreds.password; // always regenerate b64Auth in case it is out-of date with user & password sessCfg.base64EncodedAuth = Buffer.from(sessCfg.user + ":" + sessCfg.password).toString("base64"); sessTypeToUse = SessConstants.AUTH_TYPE_BASIC; } else if (sessCfg._authCache.availableCreds.base64EncodedAuth) { sessCfg.base64EncodedAuth = sessCfg._authCache.availableCreds.base64EncodedAuth; sessTypeToUse = SessConstants.AUTH_TYPE_BASIC; } if (sessTypeToUse === SessConstants.AUTH_TYPE_BASIC && sessCfg._authCache.authTypeToRequestToken) { // The existence of authTypeToRequestToken indicates that we want // to request a token. We record how we will authenticate, // but we change the session type to token (old requirement). sessCfg._authCache.authTypeToRequestToken = SessConstants.AUTH_TYPE_BASIC; sessTypeToUse = SessConstants.AUTH_TYPE_TOKEN; // we also need the tokenType in the session to request the token if (sessCfg._authCache.availableCreds.tokenType) { sessCfg.tokenType = sessCfg._authCache.availableCreds.tokenType; } } break; case SessConstants.AUTH_TYPE_TOKEN: if (sessCfg._authCache.authTypeToRequestToken) { // you cannot use a token to retrieve a new token continue; } if (sessCfg._authCache.availableCreds.tokenType) { sessCfg.tokenType = sessCfg._authCache.availableCreds.tokenType; } if (sessCfg._authCache.availableCreds.tokenValue) { sessCfg.tokenValue = sessCfg._authCache.availableCreds.tokenValue; } if (sessCfg.tokenType && sessCfg.tokenValue) { sessTypeToUse = SessConstants.AUTH_TYPE_TOKEN; } break; case SessConstants.AUTH_TYPE_BEARER: if (sessCfg._authCache.authTypeToRequestToken) { // you cannot use a token to retrieve a new token continue; } if (sessCfg._authCache.availableCreds.tokenType) { sessCfg.tokenType = sessCfg._authCache.availableCreds.tokenType; } if (sessCfg._authCache.availableCreds.tokenValue) { sessCfg.tokenValue = sessCfg._authCache.availableCreds.tokenValue; } // a tokenValue with no tokenType implies a bearer token if (!sessCfg.tokenType && sessCfg.tokenValue) { sessTypeToUse = SessConstants.AUTH_TYPE_BEARER; } break; case SessConstants.AUTH_TYPE_CERT_PEM: if (sessCfg._authCache.availableCreds[AuthOrder.SESS_CERT_NAME] && sessCfg._authCache.availableCreds[AuthOrder.SESS_CERT_KEY_NAME]) { sessTypeToUse = SessConstants.AUTH_TYPE_CERT_PEM; sessCfg[AuthOrder.SESS_CERT_NAME] = sessCfg._authCache.availableCreds[AuthOrder.SESS_CERT_NAME]; sessCfg[AuthOrder.SESS_CERT_KEY_NAME] = sessCfg._authCache.availableCreds[AuthOrder.SESS_CERT_KEY_NAME]; if (sessCfg._authCache.authTypeToRequestToken) { // Record that we are authenticating with a cert to request a token. sessCfg._authCache.authTypeToRequestToken = SessConstants.AUTH_TYPE_CERT_PEM; // we also need the tokenType in the session to request the token if (sessCfg._authCache.availableCreds.tokenType) { sessCfg.tokenType = sessCfg._authCache.availableCreds.tokenType; } } } break; case SessConstants.AUTH_TYPE_NONE: sessTypeToUse = SessConstants.AUTH_TYPE_NONE; break; default: // authOrder was validated. A wrong value now is our programming error. errMsg = `sessCfg.authTypeOrder contains an invalid authentication = ${nextAuth}.`; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } if (sessTypeToUse !== null) { // stop looking for auth types after we find the first one break; } } if (sessTypeToUse === null) { // When no creds are in the session, record the auth type as none. // We know that we do not have a enough standard cred properties to successfully authenticate. // However, some modules (like SSH) use overrides to eliminate some cred properties (like password), // leave some cred properties (like user), and use another cred (like SSH-key). // Therefore, we place every still-available cred into the session. sessCfg.type = SessConstants.AUTH_TYPE_NONE; for (const nextCred of Object.keys(sessCfg._authCache.availableCreds)) { sessCfg[nextCred] = sessCfg._authCache.availableCreds[nextCred]; } } else { // remove all extra auth creds from the session sessCfg.type = sessTypeToUse; AuthOrder.removeExtraCredsFromSess(sessCfg); } logger_1.Logger.getImperativeLogger().debug("SessCfg after setting top auth = " + censor_1.Censor.censorSession(sessCfg)); } // *********************************************************************** /** * Put the specified array of auth types first in the authOrder for the * specified session. Duplicates are removed from the resulting authOrder * array. Any existing auth types remain later in the array, * unless newAuthsOpts.onlyTheseAuths is true. * * Calling apps should NOT use this function to impose a hard-coded * authentication order for the session. Users control that decision. * Apps should only call this function if the app is implementing a directive * from the user which implies that the authOrder should be changed. An example * is when a user logs into APIML. The implication is that the user wants to use * a token, and that tokens should be at the front of the authentication order. * * @param sessCfg - Modified. * The session config into which we place the modified array of auth types. * * @param newFirstAuths - input. * An array of one or more auth types to be placed at the front of the * the existing array of auth types. * * @param newAuthsOpts - input. * Options that control some replacement choices. * * @throws {ImperativeError} * If sessCfg is null or undefined. */ static putNewAuthsFirstInSess(sessCfg, newFirstAuths, newAuthsOpts = { onlyTheseAuths: false }) { if (!sessCfg) { const errMsg = "The supplied sessCfg is null or undefined."; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } sessCfg.authTypeOrder = AuthOrder.formNewAuthOrderArray(sessCfg.authTypeOrder, newFirstAuths, newAuthsOpts); // record that this auth order was done for a user request AuthOrder.findOrCreateAuthCache(sessCfg); sessCfg._authCache.didUserSetAuthOrder = true; // after changing authOrder, ensure that the session uses the top auth AuthOrder.putTopAuthInSession(sessCfg); } // *********************************************************************** /** * Put the specified array of auth types first in the authOrder property * for the specified profile and save it to the client config file on disk. * A new authOrder property will be created if needed. * Duplicates from any existing authOrder are removed from the resulting authOrder. * Any existing auth types remain later in the property value, unless * newAuthsOpts.onlyTheseAuths is true. * * Calling apps should NOT use this function to impose a hard-coded * authentication order for a profile. Users control that decision. * Apps should only call this function if the app is implementing a directive * from the user which implies that the authOrder should be changed. An example * is when a user logs into APIML. The implication is that the user wants to use * a token, and that tokens should be at the front of the authentication order. * * @param profileName - input. * The name of the profile into which the authOrder property will be placed. * * @param newFirstAuths - input. * An array of one or more auth types to be placed at the front of the * the existing array of auth types. * * @param newAuthsOpts - input. * Options that control some replacement choices. * * @throws {ImperativeError} * Any detected error is in the 'message' of the ImperativeError. */ static putNewAuthsFirstOnDisk(profileName_1, newFirstAuths_1) { return __awaiter(this, arguments, void 0, function* (profileName, newFirstAuths, newAuthsOnDiskOpts = { onlyTheseAuths: false, clientConfig: utilities_1.ImperativeConfig.instance.config }) { if (!profileName) { const errMsg = "The supplied profileName is null, undefined, or empty."; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } if (newFirstAuths == null) { const errMsg = "The supplied newFirstAuths is null or undefined."; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } if (!Array.isArray(newFirstAuths)) { const errMsg = "The supplied newFirstAuths is not an array."; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } if (newFirstAuths.length === 0) { const errMsg = "The supplied newFirstAuths is empty."; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } const configObj = newAuthsOnDiskOpts.clientConfig; if (!configObj.api.profiles.exists(profileName)) { const errMsg = `The profile = '${profileName}' does not exist.`; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } const profObj = configObj.api.profiles.get(profileName, true); if (!profObj) { const errMsg = `Failed to retrieve the data for profile = '${profileName}'.`; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } let newAuthArray; if (newAuthsOnDiskOpts.onlyTheseAuths || !profObj.authOrder || profObj.authOrder.length === 0) { // When the caller only wants new auths or no authOrder property currently exists, // new auths are the only ones that we want newAuthArray = newFirstAuths; } else { // convert the old authOrder config value into an array and combine with newFirstAuths const oldAuthArray = AuthOrder.authCfgValToArray(profObj.authOrder); const newAuthsOpts = { onlyTheseAuths: newAuthsOnDiskOpts.onlyTheseAuths }; newAuthArray = AuthOrder.formNewAuthOrderArray(oldAuthArray, newFirstAuths, newAuthsOpts); } // Store our newAuthArray as an authOrder config value into the right profile on disk const beforeLayer = configObj.api.layers.get(); const layer = configObj.api.layers.find(profileName); if (layer != null) { const { user, global } = layer; configObj.api.layers.activate(user, global); } const profilePath = configObj.api.profiles.getProfilePathFromName(profileName); configObj.set(`${profilePath}.properties.authOrder`, AuthOrder.authArrayToCfgVal(newAuthArray)); yield configObj.save(); // Restore the original layer configObj.api.layers.activate(beforeLayer.user, beforeLayer.global); }); } // *********************************************************************** /** * Form a new auth type array from an existing array and a second array * whose members should come first in the new array. * Duplicates are removed from the resulting authOrder array. * Any auth types from the existing array remain later in the array, * unless newAuthsOpts.onlyTheseAuths is true. * * @param existingAuths - input. * An existing array of auth types. * * @param newFirstAuths - input. * An array of one or more auth types to be placed at the front of the * the existing array of auth types. * * @param newAuthsOpts - input. * Options that control some replacement choices. * * @returns A new array of AUTH_TYPE_CHOICES. */ static formNewAuthOrderArray(existingAuths, newFirstAuths, newAuthsOpts = { onlyTheseAuths: false }) { if (newAuthsOpts.onlyTheseAuths || !existingAuths || existingAuths.length === 0) { // When the caller only wants new auths or no old auths currently exist, // new auths are the only ones that we want return newFirstAuths; } // start with the existing auth array const resultingAuthTypeOrder = [...existingAuths]; for (const nextNewAuth of newFirstAuths) { for (let inxToDel = 0; inxToDel < resultingAuthTypeOrder.length; inxToDel++) { if (nextNewAuth === resultingAuthTypeOrder[inxToDel]) { // remove any new auth from the existing array resultingAuthTypeOrder.splice(inxToDel, 1); break; } } } // insert the new first auths to the front of the array resultingAuthTypeOrder.unshift(...newFirstAuths); return resultingAuthTypeOrder; } // *********************************************************************** /** * Convert an AUTH_TYPE_CHOICES array to a string that is an appropriate * value for the "authOrder" configuration property. * * @param authTypesArray - input. * An array of auth types. * * @returns A string containing a valid value for the authOrder configuration property. */ static authArrayToCfgVal(authTypesArray) { return authTypesArray.join(", "); } // *********************************************************************** /** * Convert a string that is an appropriate value for the "authOrder" * configuration property into an array of AUTH_TYPE_CHOICES. * * @param authCfgVal - input. * An authOrder property value. * * @returns An array of AUTH_TYPE_CHOICES. */ static authCfgValToArray(authCfgVal) { return authCfgVal.split(/, */); } // *********************************************************************** /** * Cache all of the credentials that are available in either the supplied * sessCfg object or in the supplied command arguments. Also cache the * authOrder that is specified in the supplied command arguments. The * cache properties are stored into the sessCfg object itself. * * Downstream logic uses this cache to determine which auth type should be * used in the final session used by a client REST request. * * @param sessCfg - Modified. * A session configuration object to which we place the cached creds. * * @param cmdArgs - Input. * The set of arguments with which the calling function is operating. * For CLI, the cmdArgs come from the command line, profile, or * environment. Other apps can place relevant arguments into this * object to be processed by this function. * * If cmdArgs is not supplied, we only cache creds found in the sessCfg. */ static cacheCredsAndAuthOrder(sessCfg, cmdArgs = { "$0": "NameNotUsed", "_": [] } // when no cmdArgs are provided, use an empty set of cmdArgs ) { // create a new auth cache (if needed) in the session config AuthOrder.findOrCreateAuthCache(sessCfg); // add any discovered authOrder to the cache AuthOrder.cacheAuthOrder(sessCfg, cmdArgs); // add every available cred to the cache for (const sessCredName of AuthOrder.ARRAY_OF_CREDS) { AuthOrder.cacheCred(sessCredName, sessCfg, cmdArgs); } } // *********************************************************************** /** * Cache the authOrder property from the supplied cmdArgs. If no authOrder exists * in cmdArgs, a default authOrder is created and cached. * * @param sessCfg - Modified. * A session configuration object into which we store the auth cache. * * @param cmdArgs - Input. * The set of arguments that the calling function is using. */ static cacheAuthOrder(sessCfg, cmdArgs) { // have we already cached an authOrder set by user (or calling service)? if (sessCfg.authTypeOrder.length > 0 && sessCfg._authCache.didUserSetAuthOrder) { // We do not reset an auth order set by the user return; } sessCfg.authTypeOrder = []; sessCfg._authCache.didUserSetAuthOrder = false; if (cmdArgs.authOrder) { if (typeof cmdArgs.authOrder === "string") { if (cmdArgs.authOrder.length > 0) { // user supplied an authOrder // convert user's comma-separated string into an array of auth types, and remove whitespace const userAuthOrder = cmdArgs.authOrder.split(','); for (const nextUserAuth of userAuthOrder.map((val) => val.trim())) { // validate each user-supplied type of authentication switch (nextUserAuth) { case SessConstants.AUTH_TYPE_BASIC: case SessConstants.AUTH_TYPE_TOKEN: case SessConstants.AUTH_TYPE_BEARER: case SessConstants.AUTH_TYPE_CERT_PEM: case SessConstants.AUTH_TYPE_NONE: sessCfg.authTypeOrder.push(nextUserAuth); // The user supplied an authOrder. Record that we used it. sessCfg._authCache.didUserSetAuthOrder = true; break; default: logger_1.Logger.getImperativeLogger().error(`The authentication = '${nextUserAuth}' is not valid and will be ignored.`); break; } } } } else { logger_1.Logger.getImperativeLogger().error(`The authOrder option = '${cmdArgs.authOrder}' is not a valid authOrder string. A default authOrder will be used.`); } } if (sessCfg._authCache.didUserSetAuthOrder) { // remove any duplicates sessCfg.authTypeOrder = Array.from(new Set(sessCfg.authTypeOrder)); } else { // fall back to a default authOrder AuthOrder.chooseDefaultAuthOrder(sessCfg); } } // *********************************************************************** /** * Cache the named credential into our cache of available credentials. * * @param sessCredName - Input. * The name of a cred to be cached in a session. * * @param sessCfg - Modified. * A session configuration object. * * @param cmdArgs - Input. * The set of arguments with which the calling function is operating. */ static cacheCred(sessCredName, sessCfg, cmdArgs) { const cmdArgsCredName = AuthOrder.getPropNmFor(sessCredName, PropUse.IN_CFG); if (cmdArgs[cmdArgsCredName]) { sessCfg._authCache.availableCreds[sessCredName] = cmdArgs[cmdArgsCredName]; } else if (sessCfg[sessCredName]) { sessCfg._authCache.availableCreds[sessCredName] = sessCfg[sessCredName]; } } // *********************************************************************** /** * Choose a default authentication order and place it into the session sessCfg. * * Other classes in the Zowe client API (like AbstractRestClient) call * cacheDefaultAuthOrder to specify the top default authentication type. * If so, we keep any topDefaultAuth that has already been set. * * If topDefaultAuth has NOT been set, we set basic authentication as the * topDefaultAuth. * * @param sessCfg - Modified. * A session configuration object. */ static chooseDefaultAuthOrder(sessCfg) { // when a user sets the auth order, we do not override that choice with a default. if (sessCfg._authCache.didUserSetAuthOrder) { return; } if (sessCfg._authCache.topDefaultAuth === undefined) { AuthOrder.cacheDefaultAuthOrder(sessCfg, SessConstants.AUTH_TYPE_BASIC); } else { AuthOrder.cacheDefaultAuthOrder(sessCfg, sessCfg._authCache.topDefaultAuth); } } // *********************************************************************** /** * Find the auth cache in the session config. If there is no cache * recorded in the session config, create a new auth cache entry. * * @param sessCfg - Input. * A session configuration object into which we record any newly created cache. */ static findOrCreateAuthCache(sessCfg) { // When the session config has no auth cache, we must create a // new auth cache in the session config. if (!sessCfg._authCache) { sessCfg._authCache = { availableCreds: {}, didUserSetAuthOrder: false, topDefaultAuth: undefined // We purposely did not create authTypeToRequestToken. // That property is only set when a consumer of this class // calls makingRequestForToken(). }; } // if we do not have an auth order array, create an empty one. if (!sessCfg.authTypeOrder) { sessCfg.authTypeOrder = []; } } // *********************************************************************** /** * Keep the specified credential by deleting it from the set of * credentials to remove. * * @param credToKeep - Input. * The credential that we want to keep. * * @param credsToRemove - Modified. * The set of credentials that will be removed. */ static keepCred(credToKeep, credsToRemove) { credsToRemove.delete(credToKeep); } // *********************************************************************** /** * Remove all credential properties from the supplied session except for the * creds related to the session type specified within the sessCfg argument. * * @param sessCfg - Modified. * Authentication credentials are removed from this session configuration. * * @throws {ImperativeError} * If an invalid combination of session type and authTypeToRequestToken is encountered. */ static removeExtraCredsFromSess(sessCfg) { if (!sessCfg) { const errMsg = "The supplied session is null or undefined."; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } // Initially set all creds to be removed from the session. // Then delete from this set the creds that we want to keep. const credsToRemove = new Set(AuthOrder.ARRAY_OF_CREDS); // Select the creds that we want to keep. // If we have no type, it is because no creds were provided, // so we we have no creds to keep or remove. let invalidTokenRequest = false; let errMsg; if (sessCfg.type) { switch (sessCfg.type) { case SessConstants.AUTH_TYPE_BASIC: if (sessCfg.base64EncodedAuth) { AuthOrder.keepCred("base64EncodedAuth", credsToRemove); AuthOrder.keepCred("user", credsToRemove); AuthOrder.keepCred("password", credsToRemove); } break; case SessConstants.AUTH_TYPE_TOKEN: // in all cases we keep the supplied token type AuthOrder.keepCred("tokenType", credsToRemove); if (!sessCfg._authCache.authTypeToRequestToken) { // we want to actually use the token, so keep its value AuthOrder.keepCred("tokenValue", credsToRemove); } else if (sessCfg._authCache.authTypeToRequestToken === SessConstants.AUTH_TYPE_BASIC) { // We are requesting a token using basic creds. // Keep our basic creds, but allow tokenValue to be removed. AuthOrder.keepCred("base64EncodedAuth", credsToRemove); AuthOrder.keepCred("user", credsToRemove); AuthOrder.keepCred("password", credsToRemove); } else { invalidTokenRequest = true; } break; case SessConstants.AUTH_TYPE_BEARER: AuthOrder.keepCred("tokenValue", credsToRemove); break; case SessConstants.AUTH_TYPE_CERT_PEM: AuthOrder.keepCred(AuthOrder.SESS_CERT_NAME, credsToRemove); AuthOrder.keepCred(AuthOrder.SESS_CERT_KEY_NAME, credsToRemove); if (sessCfg._authCache.authTypeToRequestToken) { if (sessCfg._authCache.authTypeToRequestToken === SessConstants.AUTH_TYPE_CERT_PEM) { // the token type must be in the session when we are requesting a token AuthOrder.keepCred("tokenType", credsToRemove); } else { invalidTokenRequest = true; } } break; case SessConstants.AUTH_TYPE_NONE: // when user explicitly selects none, remove all creds break; default: // User's authOrder was validated. A wrong value now is due to our programming error. errMsg = `The requested session contains an invalid value for 'type' = ${sessCfg.type}.`; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } // end switch if (invalidTokenRequest) { // Our own code created a bad combination for requesting a token errMsg = "The requested session contains an invalid property combination for requesting a token:\n" + `session type = ${sessCfg.type}\n` + `authTypeToRequestToken = ${sessCfg._authCache.authTypeToRequestToken}`; logger_1.Logger.getImperativeLogger().error(errMsg); throw new error_1.ImperativeError({ msg: errMsg }); } // remove all auth creds from the session, except the creds related to the selected auth type const credIter = credsToRemove.values(); let nextCredToRemove = credIter.next(); while (!nextCredToRemove.done) { delete sessCfg[nextCredToRemove.value]; nextCredToRemove = credIter.next(); } } // end if we have a sessCfg.type } } exports.AuthOrder = AuthOrder; AuthOrder.SESS_CERT_NAME = "cert"; AuthOrder.SESS_CERT_KEY_NAME = "certKey"; AuthOrder.ARRAY_OF_CREDS = [ "user", "password", "base64EncodedAuth", "tokenType", "tokenValue", AuthOrder.SESS_CERT_NAME, AuthOrder.SESS_CERT_KEY_NAME ]; //# sourceMappingURL=AuthOrder.js.map