@zowe/imperative
Version:
framework for building configurable CLIs
247 lines • 15.2 kB
JavaScript
/*
* 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.ConfigAutoStore = void 0;
const lodash = require("lodash");
const ConfigUtils_1 = require("./ConfigUtils");
const AbstractAuthHandler_1 = require("../../imperative/src/auth/handlers/AbstractAuthHandler");
const utilities_1 = require("../../utilities");
const Session_1 = require("../../rest/src/session/Session");
const SessConstants_1 = require("../../rest/src/session/SessConstants");
const logger_1 = require("../../logger");
/**
* Class to manage automatic storage of properties in team config.
*/
class ConfigAutoStore {
/**
* Finds the profile where auto-store properties should be saved.
* @param params CLI handler parameters object
* @param profileProps List of properties required in the profile schema
* @returns Tuple containing profile type and name, or undefined if no profile was found
*/
static findActiveProfile(params, profileProps) {
return this._findActiveProfile({ params, profileProps });
}
/**
* Helper method to find an active profile based on the optional CLI handler parameters
* @param opts Set of options required to find an active profile
* @returns Tuple containing profile type and name, or undefined if no profile was found
*/
static _findActiveProfile(opts) {
var _a, _b, _c, _d;
const profileTypes = typeof opts.params !== "undefined" ? [
...((_a = opts.params.definition.profile) === null || _a === void 0 ? void 0 : _a.required) || [],
...((_b = opts.params.definition.profile) === null || _b === void 0 ? void 0 : _b.optional) || []
] : opts.profileTypes || [];
for (const profType of profileTypes) {
const profileMatch = (_c = utilities_1.ImperativeConfig.instance.loadedConfig.profiles) === null || _c === void 0 ? void 0 : _c.find(p => p.type === profType);
if (profileMatch != null && opts.profileProps.every(propName => propName in profileMatch.schema.properties)) {
return [profType, ConfigUtils_1.ConfigUtils.getActiveProfileName(profType, (_d = opts.params) === null || _d === void 0 ? void 0 : _d.arguments, opts.defaultProfileName)];
}
}
}
/**
* Finds the token auth handler class for a team config profile.
* @param profilePath JSON path of profile
* @param cmdArguments CLI arguments which may specify a profile
* @returns Auth handler class or undefined if none was found
*/
static findAuthHandlerForProfile(profilePath, cmdArguments) {
return this._findAuthHandlerForProfile({ profilePath, cmdArguments });
}
/**
* Helper method that finds the token auth handler class for a team config profile
* @param opts Set of options required to find the auth handler for a given profile path
* @returns Auth handler class or undefined if none was found
*/
static _findAuthHandlerForProfile(opts) {
var _a;
const config = opts.config || utilities_1.ImperativeConfig.instance.config;
const profileType = lodash.get(config.properties, `${opts.profilePath}.type`);
const profile = config.api.profiles.get(opts.profilePath.replace(/profiles\./g, ""), false);
if (profile == null || profileType == null) { // Profile must exist and have type defined
return;
}
else if (profileType === "base") {
if (profile.tokenType == null) { // Base profile must have tokenType defined
return;
}
}
else {
if (profile.basePath == null) { // Service profiles must have basePath defined
return;
}
if (profile.tokenType == null) { // If tokenType undefined in service profile, fall back to base profile
const baseProfileName = ConfigUtils_1.ConfigUtils.getActiveProfileName("base", opts.cmdArguments, opts.defaultBaseProfileName);
return this._findAuthHandlerForProfile(Object.assign(Object.assign({}, opts), { profilePath: config.api.profiles.getProfilePathFromName(baseProfileName) }));
}
}
const authConfigs = [];
(_a = utilities_1.ImperativeConfig.instance.loadedConfig.profiles) === null || _a === void 0 ? void 0 : _a.forEach((profCfg) => {
if ((profCfg.type === profileType || profCfg.type === "base") && profCfg.authConfig != null) {
authConfigs.push(...profCfg.authConfig);
}
});
for (const authConfig of authConfigs) {
const authHandler = require(authConfig.handler);
const authHandlerClass = new authHandler.default();
if (authHandlerClass instanceof AbstractAuthHandler_1.AbstractAuthHandler) {
const { promptParams } = authHandlerClass.getAuthHandlerApi();
if (profile.tokenType === promptParams.defaultTokenType || profile.tokenType.startsWith(SessConstants_1.TOKEN_TYPE_APIML)) {
return authHandlerClass; // Auth service must have matching token type
}
}
}
}
/**
* Stores session config properties into a team config profile.
* @param params CLI handler parameters object
* @param sessCfg Session config containing properties to store
* @param propsToStore Names of properties that should be stored
*/
static storeSessCfgProps(params, sessCfg, propsToStore) {
return __awaiter(this, void 0, void 0, function* () {
return this._storeSessCfgProps({ params, sessCfg, propsToStore });
});
}
/**
* Stores session config properties into a team config profile.
* @param opts Set of options required to store session config properties
*/
static _storeSessCfgProps(opts) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e;
const config = opts.config || utilities_1.ImperativeConfig.instance.config;
// TODO Which autoStore value should take priority if it conflicts between layers
if (opts.propsToStore.length == 0 || !(config === null || config === void 0 ? void 0 : config.exists) || !config.properties.autoStore) {
logger_1.Logger.getAppLogger().info("Skipping update of profile properties. Check that config file exists and autoStore is true.");
return;
}
let profileProps = opts.propsToStore.map(propName => propName === "hostname" ? "host" : propName);
const profileData = this._findActiveProfile(Object.assign(Object.assign({}, opts), { profileProps }));
if (profileData == null && opts.profileName == null && opts.profileType == null) {
return;
}
const [profileType, profileName] = profileData !== null && profileData !== void 0 ? profileData : [opts.profileType, opts.profileName];
const profilePath = config.api.profiles.getProfilePathFromName(profileName);
// Replace user and password with tokenValue if tokenType is defined in config
if (profileProps.includes("user") && profileProps.includes("password") && (yield this._fetchTokenForSessCfg(Object.assign(Object.assign({}, opts), { profilePath })))) {
profileProps = profileProps.filter(propName => propName !== "user" && propName !== "password");
profileProps.push("tokenValue");
}
const beforeLayer = config.api.layers.get();
const profileObj = config.api.profiles.get(profileName, false);
const profileSchema = (_b = (_a = utilities_1.ImperativeConfig.instance.loadedConfig.profiles) === null || _a === void 0 ? void 0 : _a.find(p => p.type === profileType)) === null || _b === void 0 ? void 0 : _b.schema;
const profileSecureProps = config.api.secure.securePropsForProfile(profileName);
const baseProfileName = ConfigUtils_1.ConfigUtils.getActiveProfileName("base", (_c = opts.params) === null || _c === void 0 ? void 0 : _c.arguments, opts.defaultBaseProfileName);
const baseProfileObj = config.api.profiles.get(baseProfileName, false);
const baseProfileSchema = utilities_1.ImperativeConfig.instance.loadedConfig.baseProfile.schema;
const baseProfileSecureProps = config.api.secure.securePropsForProfile(baseProfileName);
for (const propName of profileProps) {
let propProfilePath = profilePath;
let isSecureProp = ((_d = profileSchema === null || profileSchema === void 0 ? void 0 : profileSchema.properties[propName]) === null || _d === void 0 ? void 0 : _d.secure) || profileSecureProps.includes(propName);
/* If any of the following is true, then property should be stored in base profile:
(1) Service profile does not exist, but base profile does
(2) Property is missing from service profile properties/secure objects, but present in base profile
(3) Property is tokenValue and tokenType is missing from service profile, but present in base profile
(4) Given profile is just a base profile :yum:
*/
if (!config.api.profiles.exists(profileName) && config.api.profiles.exists(baseProfileName) ||
profileObj[propName] == null && !profileSecureProps.includes(propName) &&
(baseProfileObj[propName] != null || baseProfileSecureProps.includes(propName)) ||
(propName === "tokenValue" && profileObj.tokenType == null && baseProfileObj.tokenType != null ||
profileType === "base")) {
propProfilePath = config.api.profiles.getProfilePathFromName(baseProfileName);
isSecureProp = baseProfileSchema.properties[propName].secure || baseProfileSecureProps.includes(propName);
}
// If secure array at higher level includes this property, then property should be stored at higher level
if (isSecureProp) {
const secureProfile = config.api.secure.secureInfoForProp(`${propProfilePath}.properties.${propName}`, true);
let secureProfilePath;
if (secureProfile != null)
secureProfilePath = secureProfile.path;
if (secureProfilePath != null && secureProfilePath.split(".").length < propProfilePath.split(".").length) {
propProfilePath = secureProfilePath.slice(0, secureProfilePath.lastIndexOf("."));
}
}
const foundLayer = config.api.layers.find(config.api.profiles.getProfileNameFromPath(propProfilePath));
if (foundLayer != null)
config.api.layers.activate(foundLayer.user, foundLayer.global);
const sessCfgPropName = propName === "host" ? "hostname" : propName;
config.set(`${propProfilePath}.properties.${propName}`, opts.sessCfg[sessCfgPropName], {
secure: (_e = opts.setSecure) !== null && _e !== void 0 ? _e : isSecureProp
});
}
yield config.save();
const storedMsg = `Stored properties in ${config.layerActive().path}: ${profileProps.join(", ")}`;
if (opts.params) {
opts.params.response.console.log(storedMsg);
}
else {
logger_1.Logger.getAppLogger().info(storedMsg);
}
// Restore original active layer
config.api.layers.activate(beforeLayer.user, beforeLayer.global);
});
}
/**
* Retrieves token value that will be auto-stored into session config.
* @param params CLI handler parameters object
* @param sessCfg Session config with credentials for basic or cert auth
* @param profilePath JSON path of profile containing tokenType
* @returns True if auth handler was found and token was fetched
*/
static fetchTokenForSessCfg(params, sessCfg, profilePath) {
return __awaiter(this, void 0, void 0, function* () {
return this._fetchTokenForSessCfg({ params, sessCfg, profilePath });
});
}
/**
* Helper function that retrieves token value that will be auto-stored into session config
* @param opts Set of options required to fetch the token value to be auto-stored
* @returns True if auth handler was found and token was fetched
*/
static _fetchTokenForSessCfg(opts) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
const authHandlerClass = this._findAuthHandlerForProfile(opts);
if (authHandlerClass == null) {
return false;
}
const api = authHandlerClass.getAuthHandlerApi();
opts.sessCfg.type = SessConstants_1.AUTH_TYPE_TOKEN;
opts.sessCfg.tokenType = (_c = (_b = (_a = opts.params) === null || _a === void 0 ? void 0 : _a.arguments) === null || _b === void 0 ? void 0 : _b.tokenType) !== null && _c !== void 0 ? _c : api.promptParams.defaultTokenType;
const baseSessCfg = { type: opts.sessCfg.type };
for (const propName of Object.keys(utilities_1.ImperativeConfig.instance.loadedConfig.baseProfile.schema.properties)) {
const sessCfgPropName = propName === "host" ? "hostname" : propName;
if (opts.sessCfg[sessCfgPropName] != null) {
baseSessCfg[sessCfgPropName] = opts.sessCfg[sessCfgPropName];
}
}
logger_1.Logger.getAppLogger().info(`Fetching ${opts.sessCfg.tokenType} for ${opts.profilePath}`);
opts.sessCfg.tokenValue = yield api.sessionLogin(new Session_1.Session(baseSessCfg));
opts.sessCfg.user = opts.sessCfg.password = undefined;
return true;
});
}
}
exports.ConfigAutoStore = ConfigAutoStore;
//# sourceMappingURL=ConfigAutoStore.js.map
;