From f5b24c82d9030c2d4a695da0762eea6ff55dcdb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20B=C3=A9ot?= Date: Fri, 26 Apr 2024 10:48:28 +0200 Subject: [PATCH] =?UTF-8?q?=E2=AD=90=20Lock=20tenant=20as=20read-only=20to?= =?UTF-8?q?=20prevent=20any=20change=20(cf.=20#75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + README.md | 1 + package.json | 52 ++++++++++++++++--- src/ISCUriHandler.ts | 3 +- .../NewAttributeSearchConfigCommand.ts | 2 +- .../access-profile/NewAccessProfileCommand.ts | 2 +- src/commands/addTenant.ts | 3 +- src/commands/constants.ts | 3 ++ src/commands/renameTenant.ts | 2 +- src/commands/role/NewRoleCommand.ts | 2 +- src/commands/source/CloneSourceCommand.ts | 2 +- src/commands/source/PeekSourceCommand.ts | 2 +- src/commands/source/PingClusterCommand.ts | 2 +- src/commands/source/TestConnectionCommand.ts | 2 +- .../tenant/generateDigitTokenCommand.ts | 2 +- .../tenant/tenantReadOnlyConfigCommand.ts | 43 +++++++++++++++ src/extension.ts | 17 +++++- src/files/ISCResourceProvider.ts | 25 +++++++-- src/models/ISCTreeItem.ts | 8 +++ src/models/TenantInfo.ts | 1 + src/services/AuthenticationProvider.ts | 4 +- src/services/TenantService.ts | 13 +++-- src/views/ISCDataProvider.ts | 5 +- .../WorkflowTesterWebviewViewProvider.ts | 6 +-- 24 files changed, 168 insertions(+), 35 deletions(-) create mode 100644 src/commands/tenant/tenantReadOnlyConfigCommand.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 164dfca..39b7e01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This changelog is following the recommended format by [keepachangelog](https://k - Add searching and viewing identities by [@henrique-quintino-sp](https://github.com/henrique-quintino-sp) (cf. [#74](https://github.com/yannick-beot-sp/vscode-sailpoint-identitynow/pull/74)) - Add attribute sync, process and delete command on identities by [@henrique-quintino-sp](https://github.com/henrique-quintino-sp) (cf. [#74](https://github.com/yannick-beot-sp/vscode-sailpoint-identitynow/pull/74)) +- Lock tenant as read-only to prevent any change (cf. [#75](https://github.com/yannick-beot-sp/vscode-sailpoint-identitynow/issues/75)) ### Fixed diff --git a/README.md b/README.md index 113872c..22db744 100644 --- a/README.md +++ b/README.md @@ -306,6 +306,7 @@ The patterns defined above use the following tokens: - Add searching and viewing identities by [@henrique-quintino-sp](https://github.com/henrique-quintino-sp) (cf. [#74](https://github.com/yannick-beot-sp/vscode-sailpoint-identitynow/pull/74)) - Add attribute sync, process and delete command on identities by [@henrique-quintino-sp](https://github.com/henrique-quintino-sp) (cf. [#74](https://github.com/yannick-beot-sp/vscode-sailpoint-identitynow/pull/74)) - Fixed normalizeNames (cf. [#73](https://github.com/yannick-beot-sp/vscode-sailpoint-identitynow/issues/73)) +- Lock tenant as read-only to prevent any change (cf. [#75](https://github.com/yannick-beot-sp/vscode-sailpoint-identitynow/issues/75)) ## 1.2.0 diff --git a/package.json b/package.json index 746d157..ed36148 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,16 @@ "title": "ISC: Add tenant...", "icon": "$(add)" }, + { + "command": "vscode-sailpoint-identitynow.tenant.set-writable", + "title": "Read-only", + "icon": "$(lock)" + }, + { + "command": "vscode-sailpoint-identitynow.tenant.set-readonly", + "title": "writable", + "icon": "$(unlock)" + }, { "command": "vscode-sailpoint-identitynow.remove-tenant", "title": "Remove tenant" @@ -126,6 +136,10 @@ "title": "ISC: Import config...", "icon": "$(import)" }, + { + "command": "vscode-sailpoint-identitynow.modified-resource", + "title": "Modified resource" + }, { "command": "vscode-sailpoint-identitynow.refresh-forced", "title": "ISC: Refresh", @@ -514,10 +528,22 @@ ], "menus": { "commandPalette": [ + { + "command": "vscode-sailpoint-identitynow.modified-resource", + "when": "never" + }, { "command": "vscode-sailpoint-identitynow.refresh", "when": "never" }, + { + "command": "vscode-sailpoint-identitynow.tenant.set-readonly", + "when": "never" + }, + { + "command": "vscode-sailpoint-identitynow.tenant.set-writable", + "when": "never" + }, { "command": "vscode-sailpoint-identitynow.rename-tenant", "when": "never" @@ -850,38 +876,48 @@ }, { "command": "vscode-sailpoint-identitynow.remove-tenant", - "when": "view == vscode-sailpoint-identitynow.view && viewItem == tenant" + "when": "view == vscode-sailpoint-identitynow.view && viewItem =~ /^tenant/" + }, + { + "command": "vscode-sailpoint-identitynow.tenant.set-readonly", + "when": "view == vscode-sailpoint-identitynow.view && viewItem == tenantWritable", + "group": "inline@1" + }, + { + "command": "vscode-sailpoint-identitynow.tenant.set-writable", + "when": "view == vscode-sailpoint-identitynow.view && viewItem == tenantReadOnly", + "group": "inline@1" }, { "command": "vscode-sailpoint-identitynow.rename-tenant", - "when": "view == vscode-sailpoint-identitynow.view && viewItem == tenant" + "when": "view == vscode-sailpoint-identitynow.view && viewItem =~ /^tenant/" }, { "command": "vscode-sailpoint-identitynow.tenant.edit.public-identities-config", - "when": "view == vscode-sailpoint-identitynow.view && viewItem == tenant" + "when": "view == vscode-sailpoint-identitynow.view && viewItem =~ /^tenant/" }, { "command": "vscode-sailpoint-identitynow.tenant.edit.access-request-config", - "when": "view == vscode-sailpoint-identitynow.view && viewItem == tenant" + "when": "view == vscode-sailpoint-identitynow.view && viewItem =~ /^tenant/" }, { "command": "vscode-sailpoint-identitynow.tenant.edit.password-org-config", - "when": "view == vscode-sailpoint-identitynow.view && viewItem == tenant", + "when": "view == vscode-sailpoint-identitynow.view && viewItem =~ /^tenant/", "group": "password" }, { "command": "vscode-sailpoint-identitynow.tenant.generate-digit-token", - "when": "view == vscode-sailpoint-identitynow.view && viewItem == tenant", + "when": "view == vscode-sailpoint-identitynow.view && viewItem =~ /^tenant/", "group": "password" }, { "command": "vscode-sailpoint-identitynow.export-config.view", - "when": "view == vscode-sailpoint-identitynow.view && viewItem == tenant", + "when": "view == vscode-sailpoint-identitynow.view && viewItem =~ /^tenant/", "group": "config" }, { "command": "vscode-sailpoint-identitynow.import-config.view", - "when": "view == vscode-sailpoint-identitynow.view && viewItem == tenant", + "when": "view == vscode-sailpoint-identitynow.view && viewItem =~ /^tenant/", "group": "config" }, { diff --git a/src/ISCUriHandler.ts b/src/ISCUriHandler.ts index ad3378a..91ce389 100644 --- a/src/ISCUriHandler.ts +++ b/src/ISCUriHandler.ts @@ -63,7 +63,8 @@ export class ISCUriHandler implements vscode.UriHandler { id: tenantId, name: q.displayName ?? q.tenantName, tenantName: normalizedTenantName, - authenticationMethod: (q.authenticationMethod.toLowerCase() === "accesstoken" ? AuthenticationMethod.accessToken : AuthenticationMethod.personalAccessToken) + authenticationMethod: (q.authenticationMethod.toLowerCase() === "accesstoken" ? AuthenticationMethod.accessToken : AuthenticationMethod.personalAccessToken), + readOnly: true }); } if (q.authenticationMethod.toLowerCase() === "accesstoken") { diff --git a/src/commands/NewAttributeSearchConfigCommand.ts b/src/commands/NewAttributeSearchConfigCommand.ts index 258de85..3cf08d2 100644 --- a/src/commands/NewAttributeSearchConfigCommand.ts +++ b/src/commands/NewAttributeSearchConfigCommand.ts @@ -34,7 +34,7 @@ export class NewAttributeSearchConfigCommand { // if the command is called from the Tree View if (node !== undefined && node instanceof SearchAttributesTreeItem) { - context["tenant"] = await this.tenantService.getTenant(node.tenantId); + context["tenant"] = this.tenantService.getTenant(node.tenantId); } let client: ISCClient | undefined = undefined; diff --git a/src/commands/access-profile/NewAccessProfileCommand.ts b/src/commands/access-profile/NewAccessProfileCommand.ts index bd56b18..a00fd6a 100644 --- a/src/commands/access-profile/NewAccessProfileCommand.ts +++ b/src/commands/access-profile/NewAccessProfileCommand.ts @@ -37,7 +37,7 @@ export class NewAccessProfileCommand { const context: WizardContext = {}; // if the command is called from the Tree View if (accessProfilesTreeItem !== undefined && accessProfilesTreeItem instanceof AccessProfilesTreeItem) { - context["tenant"] = await this.tenantService.getTenant(accessProfilesTreeItem.tenantId); + context["tenant"] = this.tenantService.getTenant(accessProfilesTreeItem.tenantId); } let client: ISCClient | undefined = undefined; diff --git a/src/commands/addTenant.ts b/src/commands/addTenant.ts index 5f51006..abff5e3 100644 --- a/src/commands/addTenant.ts +++ b/src/commands/addTenant.ts @@ -80,7 +80,8 @@ export class AddTenantCommand { id: tenantId, name: displayName, tenantName: normalizedTenantName, - authenticationMethod: authMethod + authenticationMethod: authMethod, + readOnly: true }); try { const session: vscode.AuthenticationSession = await vscode.authentication.getSession( diff --git a/src/commands/constants.ts b/src/commands/constants.ts index 208802c..16d13e3 100644 --- a/src/commands/constants.ts +++ b/src/commands/constants.ts @@ -1,9 +1,12 @@ const COMMAND_PREFIX = 'vscode-sailpoint-identitynow'; export const OPEN_RESOURCE = `${COMMAND_PREFIX}.open-resource`; export const REMOVE_RESOURCE = `${COMMAND_PREFIX}.remove-resource`; +export const MODIFIED_RESOURCE = `${COMMAND_PREFIX}.modified-resource`; export const REFRESH_FORCED = `${COMMAND_PREFIX}.refresh-forced`; export const REFRESH = `${COMMAND_PREFIX}.refresh`; export const ADD_TENANT = `${COMMAND_PREFIX}.add-tenant`; +export const TENANT_SET_READONLY = `${COMMAND_PREFIX}.tenant.set-readonly`; +export const TENANT_SET_WRITABLE = `${COMMAND_PREFIX}.tenant.set-writable`; export const RENAME_TENANT = `${COMMAND_PREFIX}.rename-tenant`; export const REMOVE_TENANT = `${COMMAND_PREFIX}.remove-tenant`; export const EXPORT_CONFIG_VIEW = `${COMMAND_PREFIX}.export-config.view`; diff --git a/src/commands/renameTenant.ts b/src/commands/renameTenant.ts index 99384be..5c63e6e 100644 --- a/src/commands/renameTenant.ts +++ b/src/commands/renameTenant.ts @@ -23,7 +23,7 @@ export class RenameTenantCommand { if (isEmpty(displayName)) { return; } - const tenantInfo = await this.tenantService.getTenant(node.tenantId); + const tenantInfo = this.tenantService.getTenant(node.tenantId); if (tenantInfo) { tenantInfo.name = displayName; await this.tenantService.setTenant(tenantInfo); diff --git a/src/commands/role/NewRoleCommand.ts b/src/commands/role/NewRoleCommand.ts index 19e90b4..6437939 100644 --- a/src/commands/role/NewRoleCommand.ts +++ b/src/commands/role/NewRoleCommand.ts @@ -44,7 +44,7 @@ export class NewRoleCommand { // if the command is called from the Tree View if (rolesTreeItem !== undefined && rolesTreeItem instanceof RolesTreeItem) { - context["tenant"] = await this.tenantService.getTenant(rolesTreeItem.tenantId); + context["tenant"] = this.tenantService.getTenant(rolesTreeItem.tenantId); } let client: ISCClient | undefined = undefined; diff --git a/src/commands/source/CloneSourceCommand.ts b/src/commands/source/CloneSourceCommand.ts index 6804c6c..078aaf2 100644 --- a/src/commands/source/CloneSourceCommand.ts +++ b/src/commands/source/CloneSourceCommand.ts @@ -96,7 +96,7 @@ export class CloneSourceCommand { // if the command is called from the Tree View if (node !== undefined && node instanceof SourceTreeItem) { - context["tenant"] = await this.tenantService.getTenant(node.tenantId); + context["tenant"] = this.tenantService.getTenant(node.tenantId); context["source"] = { id: node.id!, name: node.label! diff --git a/src/commands/source/PeekSourceCommand.ts b/src/commands/source/PeekSourceCommand.ts index 476fed5..f686b91 100644 --- a/src/commands/source/PeekSourceCommand.ts +++ b/src/commands/source/PeekSourceCommand.ts @@ -31,7 +31,7 @@ export class PeekSourceCommand { // if the command is called from the Tree View if (node !== undefined && node instanceof SourceTreeItem) { - context["tenant"] = await this.tenantService.getTenant(node.tenantId); + context["tenant"] = this.tenantService.getTenant(node.tenantId); context["source"] = { id: node.id!, name: node.label! diff --git a/src/commands/source/PingClusterCommand.ts b/src/commands/source/PingClusterCommand.ts index 9cc861f..b71fd80 100644 --- a/src/commands/source/PingClusterCommand.ts +++ b/src/commands/source/PingClusterCommand.ts @@ -25,7 +25,7 @@ export class PingClusterCommand { // if the command is called from the Tree View if (node !== undefined && node instanceof SourceTreeItem) { - context["tenant"] = await this.tenantService.getTenant(node.tenantId); + context["tenant"] = this.tenantService.getTenant(node.tenantId); context["source"] = { id: node.id!, name: node.label! diff --git a/src/commands/source/TestConnectionCommand.ts b/src/commands/source/TestConnectionCommand.ts index 9683582..11b6309 100644 --- a/src/commands/source/TestConnectionCommand.ts +++ b/src/commands/source/TestConnectionCommand.ts @@ -25,7 +25,7 @@ export class TestConnectionCommand { // if the command is called from the Tree View if (node !== undefined && node instanceof SourceTreeItem) { - context["tenant"] = await this.tenantService.getTenant(node.tenantId); + context["tenant"] = this.tenantService.getTenant(node.tenantId); context["source"] = { id: node.id!, name: node.label! diff --git a/src/commands/tenant/generateDigitTokenCommand.ts b/src/commands/tenant/generateDigitTokenCommand.ts index 4d83551..f0f8ee2 100644 --- a/src/commands/tenant/generateDigitTokenCommand.ts +++ b/src/commands/tenant/generateDigitTokenCommand.ts @@ -18,7 +18,7 @@ export class GenerateDigitTokenCommand { // if the command is called from the Tree View if (node !== undefined && node instanceof TenantTreeItem) { - context["tenant"] = await this.tenantService.getTenant(node.tenantId); + context["tenant"] = this.tenantService.getTenant(node.tenantId); } let client: ISCClient | undefined = undefined; diff --git a/src/commands/tenant/tenantReadOnlyConfigCommand.ts b/src/commands/tenant/tenantReadOnlyConfigCommand.ts new file mode 100644 index 0000000..11f1d59 --- /dev/null +++ b/src/commands/tenant/tenantReadOnlyConfigCommand.ts @@ -0,0 +1,43 @@ +import { TenantTreeItem } from "../../models/ISCTreeItem"; +import * as vscode from 'vscode'; +import * as commands from '../constants'; +import { TenantService } from "../../services/TenantService"; + +export class TenantReadOnlyConfigCommand { + + constructor(private readonly tenantService: TenantService) { + + } + + public async setReadOnly(node: TenantTreeItem): Promise { + console.log("> TenantReadOnlyConfigCommand.setReadOnly", node); + await this.updateReadonly(node, true) + } + + public async setWritable(node: TenantTreeItem): Promise { + console.log("> TenantReadOnlyConfigCommand.setWritable", node); + await this.updateReadonly(node, false) + } + + private async updateReadonly(node: TenantTreeItem, readOnly: boolean): Promise { + const tenantInfo = this.tenantService.getTenant(node.tenantId) + tenantInfo.readOnly = readOnly + this.tenantService.setTenant(tenantInfo) + + // force refresh to update icon + await vscode.commands.executeCommand(commands.REFRESH_FORCED); + + const uris = vscode.window.tabGroups?.all?. + flatMap(tabGroup => tabGroup.tabs)?. + map(tab => tab.input). + map(input => typeof input === 'object' && input !== null && 'uri' in input ? input.uri : undefined) + .filter(Boolean) + .filter((uri: vscode.Uri) => uri.authority === tenantInfo.tenantName) + console.log(uris); + + if (uris && uris.length > 0) { + await vscode.commands.executeCommand(commands.MODIFIED_RESOURCE, uris); + } + + } +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index cdb4c69..10f65b6 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -62,6 +62,7 @@ import { onErrorResponse, onRequest, onResponse } from './services/AxiosHandlers import axios from 'axios'; import { OpenScriptCommand } from './commands/rule/openScriptCommand'; import { IdentityTreeViewCommand } from './commands/identity/IdentityTreeViewCommand'; +import { TenantReadOnlyConfigCommand } from './commands/tenant/tenantReadOnlyConfigCommand'; // this method is called when your extension is activated // your extension is activated the very first time the command is executed @@ -153,6 +154,15 @@ export function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand(commands.RESET_SOURCE_ENTITLEMENTS, (tenantTreeItem) => treeManager.resetEntitlements(tenantTreeItem))); const testConnectionCommand = new TestConnectionCommand(tenantService); + + const tenantReadOnlyConfigCommand = new TenantReadOnlyConfigCommand(tenantService) + context.subscriptions.push( + vscode.commands.registerCommand(commands.TENANT_SET_READONLY, + tenantReadOnlyConfigCommand.setReadOnly, tenantReadOnlyConfigCommand)) + context.subscriptions.push( + vscode.commands.registerCommand(commands.TENANT_SET_WRITABLE, + tenantReadOnlyConfigCommand.setWritable, tenantReadOnlyConfigCommand)) + context.subscriptions.push( vscode.commands.registerCommand(commands.TEST_SOURCE, testConnectionCommand.execute, testConnectionCommand)); @@ -290,12 +300,15 @@ export function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand(commands.IMPORT_CONFIG_VIEW, treeviewImporterCommand.execute, treeviewImporterCommand)); + const iscClientResourceProvider = new ISCResourceProvider(tenantService) context.subscriptions.push( vscode.workspace.registerFileSystemProvider( URL_PREFIX, - new ISCResourceProvider(tenantService) + iscClientResourceProvider )); - + context.subscriptions.push( + vscode.commands.registerCommand(commands.MODIFIED_RESOURCE, + iscClientResourceProvider.triggerModified, iscClientResourceProvider)); const newTransformCommand = new NewTransformCommand(); context.subscriptions.push( vscode.commands.registerCommand(commands.NEW_TRANSFORM, diff --git a/src/files/ISCResourceProvider.ts b/src/files/ISCResourceProvider.ts index 19e8ff6..3156d25 100644 --- a/src/files/ISCResourceProvider.ts +++ b/src/files/ISCResourceProvider.ts @@ -43,14 +43,16 @@ export class ISCResourceProvider implements FileSystemProvider { const data = await this.lookupResource(uri); const id = getIdByUri(uri); const resourcePath = getPathByUri(uri); - // const isFile = this.isUUID(id); + const tenantName = uri.authority; + const tenantInfo = await this.tenantService.getTenantByTenantName(tenantName) + const isReadOnly = tenantInfo && tenantInfo.readOnly const isFile = id !== "provisioning-policies" && id !== "schemas"; return { type: (isFile ? FileType.File : FileType.Directory), ctime: toTimestamp(data.created), mtime: toTimestamp(data.modified), size: convertToText(data).length, - permissions: resourcePath.match("identities") ? vscode.FilePermission.Readonly : null + permissions: isReadOnly || resourcePath.match("identities") ? vscode.FilePermission.Readonly : null }; } readDirectory( @@ -102,7 +104,7 @@ export class ISCResourceProvider implements FileSystemProvider { null, true ); - if (response.data.length ===1 ) { + if (response.data.length === 1) { data = response.data[0] } } else { @@ -132,6 +134,13 @@ export class ISCResourceProvider implements FileSystemProvider { const tenantInfo = await this.tenantService.getTenantByTenantName( tenantName ); + + // Additional check just in case + if (tenantInfo.readOnly) { + throw new Error("Tenant is read-only"); + + } + const client = new ISCClient(tenantInfo?.id ?? "", tenantName); let data = uint8Array2Str(content); @@ -274,6 +283,7 @@ export class ISCResourceProvider implements FileSystemProvider { delete(uri: Uri, options: { recursive: boolean }): void | Thenable { throw new Error("Method delete not implemented."); } + rename( oldUri: Uri, newUri: Uri, @@ -281,4 +291,13 @@ export class ISCResourceProvider implements FileSystemProvider { ): void | Thenable { throw new Error("Method rename not implemented."); } + + public triggerModified(uris: vscode.Uri | vscode.Uri[]) { + if (uris === undefined) { return } + + if (!Array.isArray(uris)) { + uris = [uris] + } + uris.forEach(uri => this._emitter.fire([{ type: vscode.FileChangeType.Changed, uri }]), this) + } } diff --git a/src/models/ISCTreeItem.ts b/src/models/ISCTreeItem.ts index 9785045..c072c79 100644 --- a/src/models/ISCTreeItem.ts +++ b/src/models/ISCTreeItem.ts @@ -8,6 +8,7 @@ import { getConfigNumber } from '../utils/configurationUtils'; import * as commands from "../commands/constants"; import * as configuration from '../configurationConstants'; import { isEmpty, isNotEmpty } from "../utils/stringUtils"; +import { TenantService } from "../services/TenantService"; /** @@ -49,6 +50,7 @@ export class TenantTreeItem extends BaseTreeItem { tenantId: string, tenantName: string, tenantDisplayName: string, + private readonly tenantService: TenantService ) { super(tenantLabel, tenantId, @@ -77,6 +79,12 @@ export class TenantTreeItem extends BaseTreeItem { return results } + + get computedContextValue() { + const tenantInfo = this.tenantService.getTenant(this.tenantId); + return tenantInfo && tenantInfo.readOnly ? "tenantReadOnly" : "tenantWritable"; + } + } /** diff --git a/src/models/TenantInfo.ts b/src/models/TenantInfo.ts index 1d2a75e..00afa03 100644 --- a/src/models/TenantInfo.ts +++ b/src/models/TenantInfo.ts @@ -8,6 +8,7 @@ export interface TenantInfo { name: string; tenantName: string; authenticationMethod: AuthenticationMethod; + readOnly: boolean; } export interface TenantCredentials { diff --git a/src/services/AuthenticationProvider.ts b/src/services/AuthenticationProvider.ts index 4268eb9..1b65873 100644 --- a/src/services/AuthenticationProvider.ts +++ b/src/services/AuthenticationProvider.ts @@ -141,7 +141,7 @@ export class SailPointISCAuthenticationProvider implements AuthenticationProvide console.log("> getSessionByTenant", tenantId); // Check if an access token already exists let token = await this.tenantService.getTenantAccessToken(tenantId); - const tenantInfo = await this.tenantService.getTenant(tenantId); + const tenantInfo = this.tenantService.getTenant(tenantId); if (token === undefined || token.expired()) { console.log("INFO: accessToken is expired. Updating Access Token"); if (tenantInfo?.authenticationMethod === AuthenticationMethod.accessToken) { @@ -202,7 +202,7 @@ export class SailPointISCAuthenticationProvider implements AuthenticationProvide } this.ensureInitialized(); const tenantId = _scopes[0]; - const tenantInfo = await this.tenantService.getTenant(tenantId); + const tenantInfo = this.tenantService.getTenant(tenantId); if (tenantInfo?.authenticationMethod === AuthenticationMethod.accessToken) { // Access Token diff --git a/src/services/TenantService.ts b/src/services/TenantService.ts index edf913f..88ec233 100644 --- a/src/services/TenantService.ts +++ b/src/services/TenantService.ts @@ -17,17 +17,17 @@ export class TenantService { if (tenants === undefined) { return []; } - let tenantInfoItems = await Promise.all(tenants - .map(key => this.getTenant(key))); + let tenantInfoItems = tenants.map(key => this.getTenant(key)) tenantInfoItems = tenantInfoItems .filter(Boolean) // this line will remove any "undefined" - .sort(compareByName); + .sort(compareByName) + return tenantInfoItems as TenantInfo[]; } - public async getTenant(key: string): Promise { + public getTenant(key: string): TenantInfo | undefined { const tenantInfo = this.storage.get(TENANT_PREFIX + key); // As not all tenantInfo will have name and a tenantName, changing the tenantInfo if (tenantInfo && !tenantInfo?.tenantName) { @@ -39,6 +39,11 @@ export class TenantService { tenantInfo.id = tenantInfo.tenantName; this.setTenant(tenantInfo); } + + if (tenantInfo && tenantInfo.readOnly === undefined) { + tenantInfo.readOnly = false + } + return tenantInfo; } diff --git a/src/views/ISCDataProvider.ts b/src/views/ISCDataProvider.ts index 40f7643..352a650 100644 --- a/src/views/ISCDataProvider.ts +++ b/src/views/ISCDataProvider.ts @@ -34,7 +34,8 @@ export class ISCDataProvider implements TreeDataProvider { tenant.name, tenant.id, tenant.tenantName, - tenant.name) + tenant.name, + this.tenantService) ); console.log("< getChildren", results); return results; @@ -52,7 +53,7 @@ export class ISCDataProvider implements TreeDataProvider { console.log("> getTreeItem", item); item.updateIcon(this.context); console.log("after update", item); - + if (item.contextValue !== item.computedContextValue) { const newItem = { ...item, diff --git a/src/views/WorkflowTesterWebviewViewProvider.ts b/src/views/WorkflowTesterWebviewViewProvider.ts index 14d3f7f..890823e 100644 --- a/src/views/WorkflowTesterWebviewViewProvider.ts +++ b/src/views/WorkflowTesterWebviewViewProvider.ts @@ -72,7 +72,7 @@ export class WorkflowTesterWebviewViewProvider implements vscode.WebviewViewProv } case 'getWorkflowTriggers': { - const tenantInfo = await this._tenantService.getTenant(data.tenantId); + const tenantInfo = this._tenantService.getTenant(data.tenantId); const client = new ISCClient(data.tenantId, tenantInfo?.tenantName ?? ""); const workflowTriggers = await client.getWorflowTriggers(); @@ -89,7 +89,7 @@ export class WorkflowTesterWebviewViewProvider implements vscode.WebviewViewProv } case 'testWorkflow': { - const tenantInfo = await this._tenantService.getTenant(data.tenantId); + const tenantInfo = this._tenantService.getTenant(data.tenantId); const client = new ISCClient(data.tenantId, tenantInfo?.tenantName ?? ""); await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, @@ -126,7 +126,7 @@ export class WorkflowTesterWebviewViewProvider implements vscode.WebviewViewProv if (this._view) { this._view.show?.(true); - const tenantInfo = await this._tenantService.getTenant(tenantId); + const tenantInfo = this._tenantService.getTenant(tenantId); const client = new ISCClient(tenantId, tenantInfo?.tenantName ?? ""); const workflows = await client.getWorflows();