Large cleanup of AzureCore - Introduction of getAccountSecurityToken and deprecation of getSecurityToken (#11446)

* do a large cleanup of azurecore

* Fix tests

* Rework Device Code

* Fix tests

* Fix AE scenario

* Fix firewall rule - clenaup logging

* Shorthand syntax

* Fix firewall tests

* Start on tests for azureAuth

* Add more tests

* Address comments

* Add a few more important tests

* Don't throw error on old code

* Fill in todo
This commit is contained in:
Amir Omidi
2020-07-22 15:03:42 -07:00
committed by GitHub
parent a61b85c9ff
commit 587abd43c2
40 changed files with 1045 additions and 895 deletions

View File

@@ -35,7 +35,6 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
const accountNode = node as AzureResourceAccountTreeNode;
const azureAccount = accountNode.account as AzureAccount;
const tokens = await azdata.accounts.getSecurityToken(azureAccount, azdata.AzureResource.MicrosoftResourceManagement);
const terminalService = appContext.getService<IAzureTerminalService>(AzureResourceServiceNames.terminalService);
@@ -64,7 +63,7 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
tenant = azureAccount.properties.tenants[listOfTenants.indexOf(pickedTenant)];
}
await terminalService.getOrCreateCloudConsole(azureAccount, tenant, tokens);
await terminalService.getOrCreateCloudConsole(azureAccount, tenant);
} catch (ex) {
console.error(ex);
vscode.window.showErrorMessage(ex);
@@ -91,13 +90,14 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
const subscriptions = (await accountNode.getCachedSubscriptions()) || <azureResource.AzureResourceSubscription[]>[];
if (subscriptions.length === 0) {
try {
const tokens = await azdata.accounts.getSecurityToken(account, azdata.AzureResource.ResourceManagement);
for (const tenant of account.properties.tenants) {
const token = tokens[tenant.id].token;
const tokenType = tokens[tenant.id].tokenType;
const response = await azdata.accounts.getAccountSecurityToken(account, tenant.id, azdata.AzureResource.ResourceManagement);
subscriptions.push(...await subscriptionService.getSubscriptions(account, new TokenCredentials(token, tokenType)));
const token = response.token;
const tokenType = response.tokenType;
subscriptions.push(...await subscriptionService.getSubscriptions(account, new TokenCredentials(token, tokenType), tenant.id));
}
} catch (error) {
account.isStale = true;

View File

@@ -8,10 +8,10 @@ import * as msRest from '@azure/ms-rest-js';
import { Account } from 'azdata';
import { azureResource } from './azure-resource';
import { AzureAccount, AzureAccountSecurityToken, Tenant } from '../account-provider/interfaces';
import { AzureAccount, Tenant } from '../account-provider/interfaces';
export interface IAzureResourceSubscriptionService {
getSubscriptions(account: Account, credential: msRest.ServiceClientCredentials): Promise<azureResource.AzureResourceSubscription[]>;
getSubscriptions(account: Account, credential: msRest.ServiceClientCredentials, tenantId: string): Promise<azureResource.AzureResourceSubscription[]>;
}
export interface IAzureResourceSubscriptionFilterService {
@@ -20,7 +20,7 @@ export interface IAzureResourceSubscriptionFilterService {
}
export interface IAzureTerminalService {
getOrCreateCloudConsole(account: AzureAccount, tenant: Tenant, tokens: { [key: string]: AzureAccountSecurityToken }): Promise<void>;
getOrCreateCloudConsole(account: AzureAccount, tenant: Tenant): Promise<void>;
}
export interface IAzureResourceCacheService {
@@ -31,9 +31,6 @@ export interface IAzureResourceCacheService {
update<T>(key: string, value: T): void;
}
export interface IAzureResourceTenantService {
getTenantId(subscription: azureResource.AzureResourceSubscription, account: Account, credential: msRest.ServiceClientCredentials): Promise<string>;
}
export interface IAzureResourceNodeWithProviderId {
resourceProviderId: string;

View File

@@ -41,8 +41,8 @@ export abstract class ResourceTreeDataProviderBase<T extends azureResource.Azure
}
private async getResources(element: azureResource.IAzureResourceNode): Promise<T[]> {
const tokens = await azdata.accounts.getSecurityToken(element.account, azdata.AzureResource.ResourceManagement);
const credential = new msRest.TokenCredentials(tokens[element.tenantId].token, tokens[element.tenantId].tokenType);
const response = await azdata.accounts.getAccountSecurityToken(element.account, element.tenantId, azdata.AzureResource.ResourceManagement);
const credential = new msRest.TokenCredentials(response.token, response.tokenType);
const resources: T[] = await this._resourceService.getResources(element.subscription, credential, element.account) || <T[]>[];
return resources;

View File

@@ -10,14 +10,15 @@ import { azureResource } from '../azure-resource';
import { IAzureResourceSubscriptionService } from '../interfaces';
export class AzureResourceSubscriptionService implements IAzureResourceSubscriptionService {
public async getSubscriptions(account: Account, credential: any): Promise<azureResource.AzureResourceSubscription[]> {
public async getSubscriptions(account: Account, credential: any, tenantId: string): Promise<azureResource.AzureResourceSubscription[]> {
const subscriptions: azureResource.AzureResourceSubscription[] = [];
const subClient = new SubscriptionClient(credential, { baseUri: account.properties.providerSettings.settings.armResource.endpoint });
const subs = await subClient.subscriptions.list();
subs.forEach((sub) => subscriptions.push({
id: sub.subscriptionId,
name: sub.displayName
name: sub.displayName,
tenant: tenantId
}));
return subscriptions;

View File

@@ -1,18 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SubscriptionClient } from '@azure/arm-subscriptions';
import { azureResource } from '../azure-resource';
import { IAzureResourceTenantService } from '../interfaces';
import { Account } from 'azdata';
export class AzureResourceTenantService implements IAzureResourceTenantService {
public async getTenantId(subscription: azureResource.AzureResourceSubscription, account: Account, credentials: any): Promise<string> {
const subClient = new SubscriptionClient(credentials, { baseUri: account.properties.providerSettings.settings.armResource.endpoint });
const result = await subClient.subscriptions.get(subscription.id);
return result.subscriptionId;
}
}

View File

@@ -2,14 +2,14 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import * as WS from 'ws';
import { IAzureTerminalService } from '../interfaces';
import { AzureAccount, AzureAccountSecurityToken, Tenant } from '../../account-provider/interfaces';
import { AzureAccount, Tenant } from '../../account-provider/interfaces';
const localize = nls.loadMessageBundle();
@@ -48,13 +48,13 @@ export class AzureTerminalService implements IAzureTerminalService {
}
public async getOrCreateCloudConsole(account: AzureAccount, tenant: Tenant, tokens: { [key: string]: AzureAccountSecurityToken }): Promise<void> {
const token = tokens[tenant.id].token;
public async getOrCreateCloudConsole(account: AzureAccount, tenant: Tenant): Promise<void> {
const token = await azdata.accounts.getAccountSecurityToken(account, tenant.id, azdata.AzureResource.MicrosoftResourceManagement);
const settings: AxiosRequestConfig = {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
'Authorization': `Bearer ${token.token}`
},
validateStatus: () => true
};
@@ -93,7 +93,7 @@ export class AzureTerminalService implements IAzureTerminalService {
}
const consoleUri = provisionResult.data.properties.uri;
return this.createTerminal(consoleUri, token, account.displayInfo.displayName, preferredShell);
return this.createTerminal(consoleUri, token.token, account.displayInfo.displayName, preferredShell);
}

View File

@@ -20,11 +20,12 @@ import { AzureResourceSubscriptionTreeNode } from './subscriptionTreeNode';
import { AzureResourceMessageTreeNode } from '../messageTreeNode';
import { AzureResourceErrorMessageUtil } from '../utils';
import { IAzureResourceTreeChangeHandler } from './treeChangeHandler';
import { IAzureResourceSubscriptionService, IAzureResourceSubscriptionFilterService, IAzureResourceTenantService } from '../../azureResource/interfaces';
import { IAzureResourceSubscriptionService, IAzureResourceSubscriptionFilterService } from '../../azureResource/interfaces';
import { AzureAccount } from '../../account-provider/interfaces';
export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNodeBase {
public constructor(
public readonly account: azdata.Account,
public readonly account: AzureAccount,
appContext: AppContext,
treeChangeHandler: IAzureResourceTreeChangeHandler
) {
@@ -32,7 +33,6 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
this._subscriptionService = this.appContext.getService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService);
this._subscriptionFilterService = this.appContext.getService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService);
this._tenantService = this.appContext.getService<IAzureResourceTenantService>(AzureResourceServiceNames.tenantService);
this._id = `account_${this.account.key.accountId}`;
this.setCacheKey(`${this._id}.subscriptions`);
@@ -42,15 +42,13 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
public async getChildren(): Promise<TreeNode[]> {
try {
let subscriptions: azureResource.AzureResourceSubscription[] = [];
const tokens = await azdata.accounts.getSecurityToken(this.account, azdata.AzureResource.ResourceManagement);
if (this._isClearingCache) {
try {
for (const tenant of this.account.properties.tenants) {
const token = tokens[tenant.id].token;
const tokenType = tokens[tenant.id].tokenType;
const token = await azdata.accounts.getAccountSecurityToken(this.account, tenant.id, azdata.AzureResource.ResourceManagement);
subscriptions.push(...(await this._subscriptionService.getSubscriptions(this.account, new TokenCredentials(token, tokenType)) || <azureResource.AzureResourceSubscription[]>[]));
subscriptions.push(...(await this._subscriptionService.getSubscriptions(this.account, new TokenCredentials(token.token, token.tokenType), tenant.id) || <azureResource.AzureResourceSubscription[]>[]));
}
} catch (error) {
throw new AzureResourceCredentialError(localize('azure.resource.tree.accountTreeNode.credentialError', "Failed to get credential for account {0}. Please refresh the account.", this.account.key.accountId), error);
@@ -80,8 +78,8 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
return [AzureResourceMessageTreeNode.create(AzureResourceAccountTreeNode.noSubscriptionsLabel, this)];
} else {
// Filter out everything that we can't authenticate to.
subscriptions = subscriptions.filter(s => {
const token = tokens[s.id];
subscriptions = subscriptions.filter(async s => {
const token = await azdata.accounts.getAccountSecurityToken(this.account, s.tenant, azdata.AzureResource.ResourceManagement);
if (!token) {
console.info(`Account does not have permissions to view subscription ${JSON.stringify(s)}.`);
return false;
@@ -90,10 +88,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
});
let subTreeNodes = await Promise.all(subscriptions.map(async (subscription) => {
const token = tokens[subscription.id];
const tenantId = await this._tenantService.getTenantId(subscription, this.account, new TokenCredentials(token.token, token.tokenType));
return new AzureResourceSubscriptionTreeNode(this.account, subscription, tenantId, this.appContext, this.treeChangeHandler, this);
return new AzureResourceSubscriptionTreeNode(this.account, subscription, subscription.tenant, this.appContext, this.treeChangeHandler, this);
}));
return subTreeNodes.sort((a, b) => a.subscription.name.localeCompare(b.subscription.name));
}
@@ -166,7 +161,6 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
private _subscriptionService: IAzureResourceSubscriptionService = undefined;
private _subscriptionFilterService: IAzureResourceSubscriptionFilterService = undefined;
private _tenantService: IAzureResourceTenantService = undefined;
private _id: string = undefined;
private _label: string = undefined;

View File

@@ -151,13 +151,13 @@ export async function getSubscriptions(appContext: AppContext, account?: azdata.
}
const subscriptionService = appContext.getService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService);
const tokens = await azdata.accounts.getSecurityToken(account, azdata.AzureResource.ResourceManagement);
await Promise.all(account.properties.tenants.map(async (tenant: { id: string | number; }) => {
await Promise.all(account.properties.tenants.map(async (tenant: { id: string; }) => {
try {
const token = tokens[tenant.id].token;
const tokenType = tokens[tenant.id].tokenType;
const response = await azdata.accounts.getAccountSecurityToken(account, tenant.id, azdata.AzureResource.ResourceManagement);
const token = response.token;
const tokenType = response.tokenType;
result.subscriptions.push(...await subscriptionService.getSubscriptions(account, new TokenCredentials(token, tokenType)));
result.subscriptions.push(...await subscriptionService.getSubscriptions(account, new TokenCredentials(token, tokenType), tenant.id));
} catch (err) {
const error = new Error(localize('azure.accounts.getSubscriptions.queryError', "Error fetching subscriptions for account {0} tenant {1} : {2}",
account.displayInfo.displayName,