diff --git a/packages/vsce/CHANGELOG.md b/packages/vsce/CHANGELOG.md index c77b312d..043aafee 100644 --- a/packages/vsce/CHANGELOG.md +++ b/packages/vsce/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to the "cics-extension-for-zowe" extension will be documente ## Recent Changes +- Enhancement: Use LTPA tokens to allow CMCI "sessions". [#217](https://github.com/zowe/cics-for-zowe-client/issues/217) - BugFix: Update documentation to reflect changes to fully support V3 profiles. [#209](https://github.com/zowe/cics-for-zowe-client/issues/209) ## `3.3.1` diff --git a/packages/vsce/__tests__/__unit__/trees/CICSSessionTree.unit.test.ts b/packages/vsce/__tests__/__unit__/trees/CICSSessionTree.unit.test.ts new file mode 100644 index 00000000..4e60a973 --- /dev/null +++ b/packages/vsce/__tests__/__unit__/trees/CICSSessionTree.unit.test.ts @@ -0,0 +1,137 @@ +/** + * 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. + * + */ + +import { imperative } from "@zowe/zowe-explorer-api"; +import { CICSSessionTree } from "../../../src/trees/CICSSessionTree"; +import { getIconFilePathFromName } from "../../../src/utils/iconUtils"; +import { CICSRegionTree } from "../../../src/trees/CICSRegionTree"; + +const cicsProfileMock = { + failNotFound: false, + message: "", + name: "A NAME", + profile: { + host: "A HOST ADDRESS", + port: 12345, + rejectUnauthorized: false, + protocol: "http", + user: "A USER", + password: "A PASSWORD", + }, + type: "cics" +}; + +describe("Test suite for CICSSessionTree", () => { + let cst: CICSSessionTree; + let ses: imperative.Session; + + describe("validation", () => { + beforeEach(() => { + cst = new CICSSessionTree(cicsProfileMock, getIconFilePathFromName("profile")); + ses = cst.getSession(); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it("Should contain the correct hostname", () => { + expect(ses).toBeInstanceOf(imperative.Session) + expect(ses.ISession.hostname).toEqual(cicsProfileMock.profile.host); + }); + + it("Should contain the correct port", () => { + expect(ses).toBeInstanceOf(imperative.Session) + expect(ses.ISession.port).toEqual(cicsProfileMock.profile.port); + }); + + it("Should contain the correct username", () => { + expect(ses).toBeInstanceOf(imperative.Session) + expect(ses.ISession.user).toEqual(cicsProfileMock.profile.user); + }); + + it("Should contain the correct password", () => { + expect(ses).toBeInstanceOf(imperative.Session) + expect(ses.ISession.password).toEqual(cicsProfileMock.profile.password); + }); + + it("Should be able to add a region", () => { + const mockRegion = new CICSRegionTree("testRegion", {cicsstate: true}, cst, undefined, undefined); + + cst.addRegion(mockRegion); + expect(cst.getChildren().length).toEqual(1); + expect(cst.getChildren()[0].label).toEqual("testRegion"); + }); + + it("Should be able to check if authorized", () => { + + cst.setUnauthorized(); + expect(cst.getIsUnauthorized()).toBeTruthy(); + cst.setAuthorized(); + expect(cst.getIsUnauthorized()).toBeFalsy(); + cst.setUnauthorized(); + expect(cst.getIsUnauthorized()).toBeTruthy(); + }); + + it("Should return null or getParent", () => { + expect(cst.getParent()).toBeNull(); + }); + }); + + describe("cookies", () => { + + afterEach(() => { + jest.resetAllMocks(); + }); + + it("Should not store invalid cookie", () => { + const cookie = { + Cookie: "blah=hello" + }; + + cst = new CICSSessionTree(cicsProfileMock, getIconFilePathFromName("profile")); + ses = cst.getSession(); + + ses.storeCookie(cookie); + + expect(ses.ISession.tokenType).toEqual("LtpaToken2"); + expect(ses.ISession.tokenValue).toBeUndefined(); + }); + + it("Should store valid cookie", () => { + const cookies = { + Cookie: "LtpaToken2=testValue" + }; + + cst = new CICSSessionTree(cicsProfileMock, getIconFilePathFromName("profile")); + ses = cst.getSession(); + + ses.storeCookie(cookies); + + expect(ses.ISession.tokenType).toEqual("LtpaToken2"); + expect(ses.ISession.tokenValue).toEqual("testValue"); + }); + + it("Should store valid cookie if more the one returned", () => { + const cookies = { + Cookie: "blah=hello;LtpaToken2=testValue" + }; + + cst = new CICSSessionTree(cicsProfileMock, getIconFilePathFromName("profile")); + ses = cst.getSession(); + + ses.storeCookie(cookies); + + expect(ses.ISession.tokenType).toEqual("LtpaToken2"); + expect(ses.ISession.tokenValue).toEqual("testValue"); + }); + }); +}); diff --git a/packages/vsce/src/extension.ts b/packages/vsce/src/extension.ts index 1bc85d47..c55fa2ae 100644 --- a/packages/vsce/src/extension.ts +++ b/packages/vsce/src/extension.ts @@ -10,7 +10,6 @@ */ import { ExtensionContext, ProgressLocation, TreeItemCollapsibleState, window } from "vscode"; -import { CICSSessionTree } from "./trees/CICSSessionTree"; import { CICSTree } from "./trees/CICSTree"; import { plexExpansionHandler, regionContainerExpansionHandler, sessionExpansionHandler } from "./utils/expansionHandler"; import { ProfileManagement } from "./utils/profileManagement"; @@ -122,8 +121,7 @@ export async function activate(context: ExtensionContext) { try { plexExpansionHandler(node.element, treeDataProv); } catch (error) { - const newSessionTree = new CICSSessionTree(node.element.getParent().profile, getIconFilePathFromName("profile-disconnected")); - treeDataProv.loadedProfiles.splice(treeDataProv.getLoadedProfiles().indexOf(node.element.getParent()), 1, newSessionTree); + node.element.getParent().iconPath = getIconFilePathFromName("profile-disconnected"); treeDataProv._onDidChangeTreeData.fire(undefined); } }, diff --git a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedLibraryTree.ts b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedLibraryTree.ts index 25d71603..d7b8c277 100644 --- a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedLibraryTree.ts +++ b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedLibraryTree.ts @@ -60,6 +60,7 @@ export class CICSCombinedLibraryTree extends TreeItem { let count; const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -72,6 +73,7 @@ export class CICSCombinedLibraryTree extends TreeItem { if (recordsCount <= this.incrementCount) { allLibraries = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -80,6 +82,7 @@ export class CICSCombinedLibraryTree extends TreeItem { } else { allLibraries = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -148,6 +151,7 @@ export class CICSCombinedLibraryTree extends TreeItem { } const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -159,6 +163,7 @@ export class CICSCombinedLibraryTree extends TreeItem { const count = recordsCount; const allLibraries = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, this.currentCount + 1, @@ -203,4 +208,8 @@ export class CICSCombinedLibraryTree extends TreeItem { public getParent() { return this.parentPlex; } + + public getSession() { + return this.getParent().getParent().getSession(); + } } diff --git a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedLocalFileTree.ts b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedLocalFileTree.ts index a77ecfbd..3020eb47 100644 --- a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedLocalFileTree.ts +++ b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedLocalFileTree.ts @@ -60,6 +60,7 @@ export class CICSCombinedLocalFileTree extends TreeItem { try { const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -72,6 +73,7 @@ export class CICSCombinedLocalFileTree extends TreeItem { if (recordsCount <= this.incrementCount) { allLocalFiles = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -80,6 +82,7 @@ export class CICSCombinedLocalFileTree extends TreeItem { } else { allLocalFiles = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -144,6 +147,7 @@ export class CICSCombinedLocalFileTree extends TreeItem { async () => { const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, this.getParent().getGroupName(), @@ -154,6 +158,7 @@ export class CICSCombinedLocalFileTree extends TreeItem { const count = recordsCount; const allLocalFiles = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, this.currentCount + 1, @@ -198,4 +203,8 @@ export class CICSCombinedLocalFileTree extends TreeItem { public getParent() { return this.parentPlex; } + + public getSession() { + return this.getParent().getParent().getSession(); + } } diff --git a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedPipelineTree.ts b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedPipelineTree.ts index dd6405df..c724f6dc 100644 --- a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedPipelineTree.ts +++ b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedPipelineTree.ts @@ -60,6 +60,7 @@ export class CICSCombinedPipelineTree extends TreeItem { let count; const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -72,6 +73,7 @@ export class CICSCombinedPipelineTree extends TreeItem { if (recordsCount <= this.incrementCount) { allPipelines = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -80,6 +82,7 @@ export class CICSCombinedPipelineTree extends TreeItem { } else { allPipelines = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -148,6 +151,7 @@ export class CICSCombinedPipelineTree extends TreeItem { } const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -159,6 +163,7 @@ export class CICSCombinedPipelineTree extends TreeItem { const count = recordsCount; const allPipelines = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, this.currentCount + 1, @@ -203,4 +208,8 @@ export class CICSCombinedPipelineTree extends TreeItem { public getParent() { return this.parentPlex; } + + public getSession() { + return this.getParent().getParent().getSession(); + } } diff --git a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedProgramTree.ts b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedProgramTree.ts index c980e662..cb368bc5 100644 --- a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedProgramTree.ts +++ b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedProgramTree.ts @@ -63,6 +63,7 @@ export class CICSCombinedProgramTree extends TreeItem { let count; const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -75,6 +76,7 @@ export class CICSCombinedProgramTree extends TreeItem { if (recordsCount <= this.incrementCount) { allPrograms = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -83,6 +85,7 @@ export class CICSCombinedProgramTree extends TreeItem { } else { allPrograms = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -160,6 +163,7 @@ export class CICSCombinedProgramTree extends TreeItem { } const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -171,6 +175,7 @@ export class CICSCombinedProgramTree extends TreeItem { const count = recordsCount; const allPrograms = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, this.currentCount + 1, @@ -215,4 +220,8 @@ export class CICSCombinedProgramTree extends TreeItem { public getParent() { return this.parentPlex; } + + public getSession() { + return this.getParent().getParent().getSession(); + } } diff --git a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTCPIPServiceTree.ts b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTCPIPServiceTree.ts index 1d653089..f98e412a 100644 --- a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTCPIPServiceTree.ts +++ b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTCPIPServiceTree.ts @@ -60,6 +60,7 @@ export class CICSCombinedTCPIPServiceTree extends TreeItem { let count; const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -72,6 +73,7 @@ export class CICSCombinedTCPIPServiceTree extends TreeItem { if (recordsCount <= this.incrementCount) { allTCPIPS = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -80,6 +82,7 @@ export class CICSCombinedTCPIPServiceTree extends TreeItem { } else { allTCPIPS = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -151,6 +154,7 @@ export class CICSCombinedTCPIPServiceTree extends TreeItem { } const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -162,6 +166,7 @@ export class CICSCombinedTCPIPServiceTree extends TreeItem { const count = recordsCount; const allTCPIPS = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, this.currentCount + 1, @@ -206,4 +211,8 @@ export class CICSCombinedTCPIPServiceTree extends TreeItem { public getParent() { return this.parentPlex; } + + public getSession() { + return this.getParent().getParent().getSession(); + } } diff --git a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTaskTree.ts b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTaskTree.ts index ca7a638d..d9ebdb4b 100644 --- a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTaskTree.ts +++ b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTaskTree.ts @@ -60,6 +60,7 @@ export class CICSCombinedTaskTree extends TreeItem { let count; const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -72,6 +73,7 @@ export class CICSCombinedTaskTree extends TreeItem { if (recordsCount <= this.incrementCount) { allTasks = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -80,6 +82,7 @@ export class CICSCombinedTaskTree extends TreeItem { } else { allTasks = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -149,6 +152,7 @@ export class CICSCombinedTaskTree extends TreeItem { async () => { const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, this.getParent().getGroupName(), @@ -159,6 +163,7 @@ export class CICSCombinedTaskTree extends TreeItem { const count = recordsCount; const allTasks = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, this.currentCount + 1, @@ -200,4 +205,8 @@ export class CICSCombinedTaskTree extends TreeItem { // direct parent return this.parentPlex; } + + public getSession() { + return this.getParent().getParent().getSession(); + } } diff --git a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTransactionTree.ts b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTransactionTree.ts index 52b1ef7f..d1c1ad19 100644 --- a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTransactionTree.ts +++ b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedTransactionTree.ts @@ -61,6 +61,7 @@ export class CICSCombinedTransactionsTree extends TreeItem { let count; const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -73,6 +74,7 @@ export class CICSCombinedTransactionsTree extends TreeItem { if (recordsCount <= this.incrementCount) { allLocalTransactions = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -81,6 +83,7 @@ export class CICSCombinedTransactionsTree extends TreeItem { } else { allLocalTransactions = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -145,6 +148,7 @@ export class CICSCombinedTransactionsTree extends TreeItem { async () => { const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, this.getParent().getGroupName(), @@ -155,6 +159,7 @@ export class CICSCombinedTransactionsTree extends TreeItem { const count = recordsCount; const allLocalTransactions = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, this.currentCount + 1, @@ -199,4 +204,8 @@ export class CICSCombinedTransactionsTree extends TreeItem { public getParent() { return this.parentPlex; } + + public getSession() { + return this.getParent().getParent().getSession(); + } } diff --git a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedURIMapTree.ts b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedURIMapTree.ts index f71143f6..1fe1f44c 100644 --- a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedURIMapTree.ts +++ b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedURIMapTree.ts @@ -60,6 +60,7 @@ export class CICSCombinedURIMapTree extends TreeItem { let count; const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -72,6 +73,7 @@ export class CICSCombinedURIMapTree extends TreeItem { if (recordsCount <= this.incrementCount) { allURIMaps = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -80,6 +82,7 @@ export class CICSCombinedURIMapTree extends TreeItem { } else { allURIMaps = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -153,6 +156,7 @@ export class CICSCombinedURIMapTree extends TreeItem { } const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -164,6 +168,7 @@ export class CICSCombinedURIMapTree extends TreeItem { const count = recordsCount; const allURIMaps = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, this.currentCount + 1, @@ -208,4 +213,8 @@ export class CICSCombinedURIMapTree extends TreeItem { public getParent() { return this.parentPlex; } + + public getSession() { + return this.getParent().getParent().getSession(); + } } diff --git a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedWebServiceTree.ts b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedWebServiceTree.ts index 431876e1..9d383968 100644 --- a/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedWebServiceTree.ts +++ b/packages/vsce/src/trees/CICSCombinedTrees/CICSCombinedWebServiceTree.ts @@ -60,6 +60,7 @@ export class CICSCombinedWebServiceTree extends TreeItem { let count; const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -72,6 +73,7 @@ export class CICSCombinedWebServiceTree extends TreeItem { if (recordsCount <= this.incrementCount) { allWebServices = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -80,6 +82,7 @@ export class CICSCombinedWebServiceTree extends TreeItem { } else { allWebServices = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, 1, @@ -149,6 +152,7 @@ export class CICSCombinedWebServiceTree extends TreeItem { } const cacheTokenInfo = await ProfileManagement.generateCacheToken( this.parentPlex.getProfile(), + this.getSession(), this.parentPlex.getPlexName(), this.constant, criteria, @@ -160,6 +164,7 @@ export class CICSCombinedWebServiceTree extends TreeItem { const count = recordsCount; const allWebServices = await ProfileManagement.getCachedResources( this.parentPlex.getProfile(), + this.getSession(), cacheTokenInfo.cacheToken, this.constant, this.currentCount + 1, @@ -204,4 +209,8 @@ export class CICSCombinedWebServiceTree extends TreeItem { public getParent() { return this.parentPlex; } + + public getSession() { + return this.getParent().getParent().getSession(); + } } diff --git a/packages/vsce/src/trees/CICSRegionsContainer.ts b/packages/vsce/src/trees/CICSRegionsContainer.ts index 4dd82fb0..bae8aa70 100644 --- a/packages/vsce/src/trees/CICSRegionsContainer.ts +++ b/packages/vsce/src/trees/CICSRegionsContainer.ts @@ -47,7 +47,7 @@ export class CICSRegionsContainer extends TreeItem { }, async (_, token) => { token.onCancellationRequested(() => {}); - const regionInfo = await ProfileManagement.getRegionInfoInPlex(this.parent); + const regionInfo = await ProfileManagement.getRegionInfoInPlex(this.parent, this.getSession()); this.addRegionsUtility(regionInfo); this.collapsibleState = TreeItemCollapsibleState.Expanded; this.iconPath = getFolderIcon(true); @@ -78,7 +78,7 @@ export class CICSRegionsContainer extends TreeItem { public async loadRegionsInPlex() { const parentPlex = this.getParent(); - const regionInfo = await ProfileManagement.getRegionInfoInPlex(parentPlex); + const regionInfo = await ProfileManagement.getRegionInfoInPlex(parentPlex, this.getSession()); if (regionInfo) { this.addRegionsUtility(regionInfo); // Keep container open after label change @@ -145,4 +145,8 @@ export class CICSRegionsContainer extends TreeItem { public clearChildren() { this.children = []; } + + public getSession() { + return this.getParent().getParent().getSession(); + } } diff --git a/packages/vsce/src/trees/CICSSessionTree.ts b/packages/vsce/src/trees/CICSSessionTree.ts index 05aa067b..aced9e75 100644 --- a/packages/vsce/src/trees/CICSSessionTree.ts +++ b/packages/vsce/src/trees/CICSSessionTree.ts @@ -14,6 +14,7 @@ import { CICSRegionTree } from "./CICSRegionTree"; import { CICSPlexTree } from "./CICSPlexTree"; import { imperative } from "@zowe/zowe-explorer-api"; import { getIconFilePathFromName } from "../utils/iconUtils"; +import { SessConstants } from "@zowe/imperative"; export class CICSSessionTree extends TreeItem { children: (CICSPlexTree | CICSRegionTree)[]; @@ -28,8 +29,11 @@ export class CICSSessionTree extends TreeItem { super(profile.name, TreeItemCollapsibleState.Collapsed); this.children = []; this.contextValue = `cicssession.${profile.name}`; + this.session = new imperative.Session({ - type: "basic", + type: SessConstants.AUTH_TYPE_TOKEN, + storeCookie: true, + tokenType: SessConstants.TOKEN_TYPE_LTPA, hostname: profile.profile!.host, port: Number(profile.profile!.port), user: profile.profile!.user || "", @@ -37,6 +41,7 @@ export class CICSSessionTree extends TreeItem { rejectUnauthorized: profile.profile!.rejectUnauthorized, protocol: profile.profile!.protocol, }); + this.profile = profile; this.isUnauthorized = undefined; } @@ -45,6 +50,10 @@ export class CICSSessionTree extends TreeItem { this.children.push(region); } + public clearChildren() { + this.children = []; + } + public addPlex(plex: CICSPlexTree) { this.children.push(plex); } diff --git a/packages/vsce/src/trees/CICSTree.ts b/packages/vsce/src/trees/CICSTree.ts index 5bec29e2..c988a810 100644 --- a/packages/vsce/src/trees/CICSTree.ts +++ b/packages/vsce/src/trees/CICSTree.ts @@ -30,7 +30,7 @@ import { import constants from "../utils/constants"; import { PersistentStorage } from "../utils/PersistentStorage"; import { InfoLoaded, ProfileManagement } from "../utils/profileManagement"; -import { missingSessionParameters, promptCredentials } from "../utils/profileUtils"; +import { updateProfile } from "../utils/profileUtils"; import { getIconFilePathFromName } from "../utils/iconUtils"; import { openConfigFile } from "../utils/workspaceUtils"; import { CICSPlexTree } from "./CICSPlexTree"; @@ -222,7 +222,7 @@ export class CICSTree implements TreeDataProvider { async loadProfile(profile?: imperative.IProfileLoaded, position?: number | undefined, sessionTree?: CICSSessionTree) { const persistentStorage = new PersistentStorage("zowe.cics.persistent"); await persistentStorage.addLoadedCICSProfile(profile.name); - let newSessionTree: CICSSessionTree; + window.withProgress( { title: "Load profile", @@ -238,98 +238,87 @@ export class CICSTree implements TreeDataProvider { try { const configInstance = await ProfileManagement.getConfigInstance(); if (configInstance.getTeamConfig().exists) { - let missingParamters = missingSessionParameters(profile.profile); - if (missingParamters.length) { - const userPass = ["user", "password"]; - if (missingParamters.includes(userPass[0]) || missingParamters.includes(userPass[1])) { - const updatedProfile = await promptCredentials(profile.name, true); - if (!updatedProfile) { - return; + // Initialise session tree + let plexInfo: InfoLoaded[]; + let retry = 0; + while (retry <= 1) { + try { + plexInfo = await ProfileManagement.getPlexInfo(profile, sessionTree.getSession()); + break; + } catch (error) { + if (error?.response?.status == constants.HTTP_ERROR_UNAUTHORIZED && retry === 0) { + retry = retry + 1; + const newProfile = await updateProfile(profile, sessionTree); + + if (!newProfile) { + return; + } + profile = newProfile; + } else { + throw error; } - profile = updatedProfile; - // Remove "user" and "password" from missing params array - missingParamters = missingParamters.filter((param) => userPass.indexOf(param) === -1); } - if (missingParamters.length) { - window.showInformationMessage( - `The following fields are missing from ${profile.name}: ${missingParamters.join(", ")}. Please update them in your config file.`, + } + + // For each InfoLoaded object - happens if there are multiple plexes + for (const item of plexInfo) { + // No plex + if (item.plexname === null) { + + const regionsObtained = await getResource(sessionTree.getSession(), { + name: "CICSRegion", + regionName: item.regions[0].applid, + }); + + // 200 OK received + sessionTree.setAuthorized(); + const newRegionTree = new CICSRegionTree( + item.regions[0].applid, + regionsObtained.response.records.cicsregion, + sessionTree, + undefined, + sessionTree, ); - return; - } - // If profile is expanded and it previously had 401 error code - } else if (sessionTree && sessionTree.getIsUnauthorized()) { - const updatedProfile = await promptCredentials(profile.name, true); - if (!updatedProfile) { - return; + sessionTree.clearChildren(); + sessionTree.addRegion(newRegionTree); + } else { + if (item.group) { + const newPlexTree = new CICSPlexTree(item.plexname, profile, sessionTree, profile.profile.regionName); + newPlexTree.setLabel(`${item.plexname} - ${profile.profile.regionName}`); + sessionTree.clearChildren(); + sessionTree.addPlex(newPlexTree); + } else { + //Plex + const newPlexTree = new CICSPlexTree(item.plexname, profile, sessionTree); + sessionTree.clearChildren(); + sessionTree.addPlex(newPlexTree); + } } - profile = updatedProfile; } - } - const plexInfo: InfoLoaded[] = await ProfileManagement.getPlexInfo(profile); - // Initialise session tree - newSessionTree = new CICSSessionTree(profile, getIconFilePathFromName("profile")); - // For each InfoLoaded object - happens if there are multiple plexes - for (const item of plexInfo) { - // No plex - if (item.plexname === null) { - const session = new imperative.Session({ - type: "basic", - hostname: profile.profile.host, - port: Number(profile.profile.port), - user: profile.profile.user, - password: profile.profile.password, - rejectUnauthorized: profile.profile.rejectUnauthorized, - protocol: profile.profile.protocol, - }); - const regionsObtained = await getResource(session, { - name: "CICSRegion", - regionName: item.regions[0].applid, - }); - // 200 OK received - newSessionTree.setAuthorized(); - const newRegionTree = new CICSRegionTree( - item.regions[0].applid, - regionsObtained.response.records.cicsregion, - newSessionTree, - undefined, - newSessionTree, - ); - newSessionTree.addRegion(newRegionTree); + // If method was called when expanding profile + if (sessionTree) { + this.loadedProfiles.splice(position, 1, sessionTree); + } + // If method was called when updating profile + else if (position || position === 0) { + this.loadedProfiles.splice(position, 0, sessionTree); } else { - if (item.group) { - const newPlexTree = new CICSPlexTree(item.plexname, profile, newSessionTree, profile.profile.regionName); - newPlexTree.setLabel(`${item.plexname} - ${profile.profile.regionName}`); - newSessionTree.addPlex(newPlexTree); - } else { - //Plex - const newPlexTree = new CICSPlexTree(item.plexname, profile, newSessionTree); - newSessionTree.addPlex(newPlexTree); - } + this.loadedProfiles.push(sessionTree); } + this._onDidChangeTreeData.fire(undefined); } - // If method was called when expanding profile - if (sessionTree) { - this.loadedProfiles.splice(position, 1, newSessionTree); - } - // If method was called when updating profile - else if (position || position === 0) { - this.loadedProfiles.splice(position, 0, newSessionTree); - } else { - this.loadedProfiles.push(newSessionTree); - } - this._onDidChangeTreeData.fire(undefined); } catch (error) { // Change session tree icon to disconnected upon error - newSessionTree = new CICSSessionTree(profile, getIconFilePathFromName("profile-disconnected")); + sessionTree = new CICSSessionTree(profile, getIconFilePathFromName("profile-disconnected")); // If method was called when expanding profile if (sessionTree) { - this.loadedProfiles.splice(position, 1, newSessionTree); + this.loadedProfiles.splice(position, 1, sessionTree); } // If method was called when updating profile else if (position || position === 0) { - this.loadedProfiles.splice(position, 0, newSessionTree); + this.loadedProfiles.splice(position, 0, sessionTree); } else { - this.loadedProfiles.push(newSessionTree); + this.loadedProfiles.push(sessionTree); } this._onDidChangeTreeData.fire(undefined); @@ -392,9 +381,9 @@ export class CICSTree implements TreeDataProvider { case constants.HTTP_ERROR_UNAUTHORIZED: window.showErrorMessage(`Error: Request failed with status code 401 for Profile '${profile.name}'`); // set the unauthorized flag to true for reprompting of credentials. - newSessionTree.setUnauthorized(); + sessionTree.setUnauthorized(); // Replace old profile tree with new disconnected profile tree item - this.loadedProfiles.splice(position, 1, newSessionTree); + this.loadedProfiles.splice(position, 1, sessionTree); break; case constants.HTTP_ERROR_NOT_FOUND: window.showErrorMessage(`Error: Request failed with status code 404 for Profile '${profile.name}' - Not Found`); diff --git a/packages/vsce/src/utils/profileManagement.ts b/packages/vsce/src/utils/profileManagement.ts index 2d8f04ed..54283e66 100644 --- a/packages/vsce/src/utils/profileManagement.ts +++ b/packages/vsce/src/utils/profileManagement.ts @@ -53,18 +53,6 @@ export class ProfileManagement { return mProfileInfo; } - public static getSessionFromProfile(profile: imperative.IProfile): Session { - return new Session({ - protocol: profile.protocol, - hostname: profile.host, - port: profile.port, - type: "basic", - user: profile.user, - password: profile.password, - rejectUnauthorized: 'rejectUnauthorized' in profile ? profile.rejectUnauthorized : true, - }); - } - public static async regionIsGroup(session: Session, profile: imperative.IProfile): Promise { let isGroup = false; @@ -264,9 +252,7 @@ export class ProfileManagement { * @param profile * @returns Array of type InfoLoaded */ - public static async getPlexInfo(profile: imperative.IProfileLoaded): Promise { - - const session = this.getSessionFromProfile(profile.profile); + public static async getPlexInfo(profile: imperative.IProfileLoaded, session: Session): Promise { if (profile.profile.cicsPlex && profile.profile.regionName) { return this.regionPlexProvided(session, profile.profile); @@ -282,9 +268,8 @@ export class ProfileManagement { /** * Return all the regions in a given plex */ - public static async getRegionInfoInPlex(plex: CICSPlexTree): Promise { + public static async getRegionInfoInPlex(plex: CICSPlexTree, session: Session): Promise { try { - const session = this.getSessionFromProfile(plex.getProfile().profile); const { response } = await getResource(session, { name: "CICSManagedRegion", cicsPlex: plex.getPlexName(), @@ -301,12 +286,12 @@ export class ProfileManagement { public static async generateCacheToken( profile: imperative.IProfileLoaded, + session: Session, plexName: string, resourceName: string, criteria?: string, group?: string ): Promise<{ cacheToken: string; recordCount: number; }> { - const session = this.getSessionFromProfile(profile.profile); try { const allProgramsResponse = await getResource(session, { name: resourceName, @@ -337,11 +322,11 @@ export class ProfileManagement { public static async getCachedResources( profile: imperative.IProfileLoaded, + session: Session, cacheToken: string, resourceName: string, start = 1, increment = constants.RESOURCES_MAX) { - const session = this.getSessionFromProfile(profile.profile); const allItemsresponse = await getCache(session, { cacheToken, startIndex: start, diff --git a/packages/vsce/src/utils/profileUtils.ts b/packages/vsce/src/utils/profileUtils.ts index c0c767d5..b7cee3fe 100644 --- a/packages/vsce/src/utils/profileUtils.ts +++ b/packages/vsce/src/utils/profileUtils.ts @@ -12,6 +12,7 @@ import { ZoweVsCodeExtension, imperative } from "@zowe/zowe-explorer-api"; import { window } from "vscode"; import { ProfileManagement } from "./profileManagement"; +import { CICSSessionTree } from "../trees/CICSSessionTree"; export function missingSessionParameters(profileProfile: any): (string | undefined)[] { const params = ["host", "port", "user", "password", "rejectUnauthorized", "protocol"]; @@ -24,7 +25,40 @@ export function missingSessionParameters(profileProfile: any): (string | undefin return missing; } +export function missingUsernamePassword(missingParamters: any): boolean { + if (missingParamters.length > 0) { + const userPass = ["user", "password"]; + if (missingParamters.includes(userPass[0]) || missingParamters.includes(userPass[1])) { + return true; + } + } + + return false; +} + +export async function updateProfile(profile?: imperative.IProfileLoaded, sessionTree?: CICSSessionTree): Promise { + let missingParamters = missingSessionParameters(profile.profile); + if (missingUsernamePassword(missingParamters) || + // If profile is expanded and it previously had 401 error code + (sessionTree && sessionTree.getIsUnauthorized())) { + const updatedProfile = await promptCredentials(profile.name, true); + if (updatedProfile) { + profile = updatedProfile; + // Remove "user" and "password" from missing params array + missingParamters = missingParamters.filter((param) => ["user", "password"].indexOf(param) === -1); + } + + if (missingParamters.length) { + window.showInformationMessage( + `The following fields are missing from ${profile.name}: ${missingParamters.join(", ")}. Please update them in your config file.`, + ); + } else { + return profile; + } + } + return undefined; +} export async function promptCredentials(sessionName: string, rePrompt?: boolean): Promise { // const mProfileInfo = new ProfileInfo("zowe", {