@zowe/imperative
Version:
framework for building configurable CLIs
214 lines • 12.1 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.BaseAuthHandler = void 0;
const rest_1 = require("../../../../rest");
const error_1 = require("../../../../error");
const utilities_1 = require("../../../../utilities");
const ConfigUtils_1 = require("../../../../config/src/ConfigUtils");
const AbstractAuthHandler_1 = require("./AbstractAuthHandler");
/**
* This class is used by the auth command handlers as the base class for their implementation.
*/
class BaseAuthHandler extends AbstractAuthHandler_1.AbstractAuthHandler {
/**
* Returns auth handler API that provides convenient functions to create a
* session from args, and use it to login or logout of an auth service.
*/
getAuthHandlerApi() {
return {
promptParams: {
defaultTokenType: this.mDefaultTokenType,
serviceDescription: this.mServiceDescription
},
createSessCfg: this.createSessCfgFromArgs,
sessionLogin: this.doLogin,
sessionLogout: this.doLogout
};
}
/**
* Performs the login operation. Builds a session to connect to the auth
* service, sends a login request to it to obtain a token, and stores the
* resulting token in the profile of type `mProfileType`.
* @param {IHandlerParameters} params Command parameters sent by imperative.
*/
processLogin(params) {
return __awaiter(this, void 0, void 0, function* () {
const sessCfg = this.createSessCfgFromArgs(params.arguments);
const sessCfgWithCreds = yield rest_1.ConnectionPropsForSessCfg.addPropsOrPrompt(sessCfg, params.arguments, { requestToken: true, defaultTokenType: this.mDefaultTokenType, parms: params, autoStore: false });
this.mSession = new rest_1.Session(sessCfgWithCreds);
this.mSession.ISession.storeCookie = true;
// login to obtain a token.
const tokenValue = yield this.doLogin(this.mSession);
this.mSession.ISession.storeCookie = false;
// validate a token was returned
if (tokenValue == null) {
throw new error_1.ImperativeError({ msg: "A token value was not returned from the login handler." });
}
if (params.arguments.showToken) {
// show token instead of updating profile
this.showToken(params.response, tokenValue);
}
else if (utilities_1.ImperativeConfig.instance.config.api.secure.loadFailed) {
throw ConfigUtils_1.ConfigUtils.secureSaveError(`Instead of secure storage, ` +
`rerun this command with the "--show-token" flag to print the token to console. ` +
`Store the token in an environment variable ${utilities_1.ImperativeConfig.instance.loadedConfig.envVariablePrefix}_OPT_TOKEN_VALUE to use it ` +
`in future commands.`);
}
else {
// update the profile given
// TODO Should config be added to IHandlerParameters?
const config = utilities_1.ImperativeConfig.instance.config;
const profileName = this.getBaseProfileName(params);
const profileProps = Object.keys(config.api.profiles.get(profileName, false));
const profileExists = config.api.profiles.exists(profileName);
profileProps.push(...config.api.secure.securePropsForProfile(profileName));
const beforeLayer = config.api.layers.get();
// If base profile is null or empty, prompt user before saving token to disk
if (!profileExists) {
const ok = yield this.promptForBaseProfile(params, profileName);
if (!ok) {
this.showToken(params.response, tokenValue);
return;
}
config.api.profiles.set(profileName, {
type: this.mProfileType,
properties: {
host: this.mSession.ISession.hostname,
port: this.mSession.ISession.port
}
});
config.api.profiles.defaultSet(this.mProfileType, profileName);
}
else {
const layer = config.api.layers.find(profileName);
if (layer != null) {
const { user, global } = layer;
config.api.layers.activate(user, global);
}
}
const profilePath = config.api.profiles.getProfilePathFromName(profileName);
config.set(`${profilePath}.properties.tokenType`, this.mSession.ISession.tokenType);
config.set(`${profilePath}.properties.tokenValue`, tokenValue, { secure: true });
yield config.save();
// Restore original active layer
config.api.layers.activate(beforeLayer.user, beforeLayer.global);
params.response.console.log(`\n` +
`Login successful. The authentication token is stored in the '${profileName}' ` +
`${this.mProfileType} profile for future use. To revoke this token and remove it from your profile, review the ` +
`'zowe auth logout' command.`);
}
});
}
getBaseProfileName(params) {
return ConfigUtils_1.ConfigUtils.getActiveProfileName(this.mProfileType, params.arguments, `${this.mProfileType}`);
}
promptForBaseProfile(params, profileName) {
return __awaiter(this, void 0, void 0, function* () {
const answer = yield params.response.console.prompt(`Do you want to store the host, port, and token on disk for use with future commands? If you answer Yes, the credentials will ` +
`be saved to a ${this.mProfileType} profile named '${profileName}'. If you answer No, the token will be printed to the ` +
`terminal and will not be stored on disk. [y/N]: `);
return answer != null && (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
});
}
showToken(response, tokenValue) {
response.console.log(`\n` +
`Received a token of type = ${this.mSession.ISession.tokenType}.\n` +
`The following token was retrieved and will not be stored in your profile:\n` +
`${tokenValue}\n\n` +
`Login successful. To revoke this token, review the 'zowe auth logout' command.`);
response.data.setObj({ tokenType: this.mSession.ISession.tokenType, tokenValue });
}
/**
* Performs the logout operation. Deletes the token and token type from the profile,
* and rebuilds the session.
* @param {IHandlerParameters} params Command parameters sent by imperative.
*/
processLogout(params) {
return __awaiter(this, void 0, void 0, function* () {
// Force the use of token value, in case user and/or password are also provided.
if (params.arguments.tokenValue != null &&
(params.arguments.user != null || params.arguments.password != null)) {
params.arguments.user = undefined;
params.arguments.password = undefined;
}
if (params.arguments.tokenType == null) {
params.arguments.tokenType = this.mDefaultTokenType;
}
const sessCfg = this.createSessCfgFromArgs(params.arguments);
const sessCfgWithCreds = yield rest_1.ConnectionPropsForSessCfg.addPropsOrPrompt(sessCfg, params.arguments, { requestToken: false, doPrompting: false, parms: params });
let logoutError;
if (params.arguments.tokenValue != null) {
this.mSession = new rest_1.Session(sessCfgWithCreds);
try {
yield this.doLogout(this.mSession);
}
catch (err) {
logoutError = err;
}
}
const config = utilities_1.ImperativeConfig.instance.config;
const profileName = this.getBaseProfileName(params);
const profileProps = config.api.profiles.get(profileName, false);
let profileWithToken = null;
let noDeleteReason = "";
// If you specified a token on the command line, then don't delete the one in the profile if it doesn't match
if (Object.keys(profileProps).length > 0 && profileProps.tokenType != null && profileProps.tokenValue != null &&
profileProps.tokenType === params.arguments.tokenType && profileProps.tokenValue === params.arguments.tokenValue) {
const profilePath = config.api.profiles.getProfilePathFromName(profileName);
config.delete(`${profilePath}.properties.tokenType`);
config.delete(`${profilePath}.properties.tokenValue`);
yield config.save();
profileWithToken = profileName;
}
else {
if (Object.keys(profileProps).length === 0)
noDeleteReason = "Empty profile was provided.";
else if (profileProps.tokenType == null)
noDeleteReason = "Token type was not provided.";
else if (profileProps.tokenValue == null)
noDeleteReason = "Token value was not provided.";
else if (profileProps.tokenType !== params.arguments.tokenType)
noDeleteReason = "Token type does not match the authentication service";
else if (profileProps.tokenValue !== params.arguments.tokenValue)
noDeleteReason = "Token value does not match the securely stored value";
}
if (params.arguments.tokenValue != null) {
let logoutMessage = "Logout successful. The authentication token has been revoked.";
if ((logoutError === null || logoutError === void 0 ? void 0 : logoutError.errorCode) === rest_1.RestConstants.HTTP_STATUS_401.toString()) {
logoutMessage = "Token is not valid or expired.";
}
logoutMessage += `\nToken was${profileWithToken == null ? " not" : ""} removed from ` +
`your '${profileName}' ${this.mProfileType} profile.`;
logoutMessage += `${!noDeleteReason ? "" : "\nReason: " + noDeleteReason}`;
params.response.console.log(logoutMessage);
}
else {
params.response.console.errorHeader("Command Error");
params.response.console.error("Token was not provided, so can't log out." +
"\nYou need to authenticate first using `zowe auth login`.");
params.response.data.setExitCode(1);
}
});
}
}
exports.BaseAuthHandler = BaseAuthHandler;
//# sourceMappingURL=BaseAuthHandler.js.map
;