mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-13 17:22:15 -05:00
Fix azure account tree subscription check (#16822)
* Fix azure account tree subscription check * comment
This commit is contained in:
@@ -68,14 +68,21 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
|
||||
return [AzureResourceMessageTreeNode.create(AzureResourceAccountTreeNode.noSubscriptionsLabel, this)];
|
||||
} else {
|
||||
// Filter out everything that we can't authenticate to.
|
||||
subscriptions = subscriptions.filter(async s => {
|
||||
const token = await azdata.accounts.getAccountSecurityToken(this.account, s.tenant, azdata.AzureResource.ResourceManagement);
|
||||
const hasTokenResults = await Promise.all(subscriptions.map(async s => {
|
||||
let token: azdata.accounts.AccountSecurityToken | undefined = undefined;
|
||||
let errMsg = '';
|
||||
try {
|
||||
token = await azdata.accounts.getAccountSecurityToken(this.account, s.tenant, azdata.AzureResource.ResourceManagement);
|
||||
} catch (err) {
|
||||
errMsg = AzureResourceErrorMessageUtil.getErrorMessage(err);
|
||||
}
|
||||
if (!token) {
|
||||
console.info(`Account does not have permissions to view subscription ${JSON.stringify(s)}.`);
|
||||
vscode.window.showWarningMessage(localize('azure.unableToAccessSubscription', "Unable to access subscription {0} ({1})}. Please [refresh the account](command:azure.resource.signin) to try again. {2}", s.name, s.id, errMsg));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}));
|
||||
subscriptions = subscriptions.filter((_s, i) => hasTokenResults[i]);
|
||||
|
||||
let subTreeNodes = await Promise.all(subscriptions.map(async (subscription) => {
|
||||
return new AzureResourceSubscriptionTreeNode(this.account, subscription, subscription.tenant, this.appContext, this.treeChangeHandler, this);
|
||||
|
||||
@@ -353,7 +353,7 @@ export async function makeHttpRequest(account: azdata.Account, subscription: azu
|
||||
return result;
|
||||
}
|
||||
|
||||
let securityToken: { token: string, tokenType?: string };
|
||||
let securityToken: azdata.accounts.AccountSecurityToken;
|
||||
try {
|
||||
securityToken = await azdata.accounts.getAccountSecurityToken(
|
||||
account,
|
||||
|
||||
@@ -131,6 +131,7 @@ describe('AzureResourceAccountTreeNode.info', function (): void {
|
||||
it('Should be correct when there are subscriptions listed.', async function (): Promise<void> {
|
||||
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, TypeMoq.It.isAny())).returns(() => Promise.resolve(mockSubscriptions));
|
||||
mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve(undefined));
|
||||
sinon.stub(azdata.accounts, 'getAccountSecurityToken').resolves(mockToken);
|
||||
|
||||
const accountTreeNodeLabel = `${mockAccount.displayInfo.displayName} (${mockSubscriptions.length} / ${mockSubscriptions.length} subscriptions)`;
|
||||
|
||||
@@ -148,10 +149,30 @@ describe('AzureResourceAccountTreeNode.info', function (): void {
|
||||
should(nodeInfo.label).equal(accountTreeNodeLabel);
|
||||
});
|
||||
|
||||
it('Should be correct when there are subscriptions filtered.', async function (): Promise<void> {
|
||||
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, TypeMoq.It.isAny())).returns(() => Promise.resolve(mockSubscriptions));
|
||||
it('Should only show subscriptions with valid tokens.', async function (): Promise<void> {
|
||||
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount)).returns(() => Promise.resolve(mockSubscriptions));
|
||||
mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve(mockFilteredSubscriptions));
|
||||
sinon.stub(azdata.accounts, 'getAccountSecurityToken').onFirstCall().resolves(mockToken);
|
||||
const accountTreeNodeLabel = `${mockAccount.displayInfo.displayName} (${mockFilteredSubscriptions.length} / ${mockSubscriptions.length} subscriptions)`;
|
||||
|
||||
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockAppContext, mockTreeChangeHandler.object);
|
||||
|
||||
const subscriptionNodes = await accountTreeNode.getChildren();
|
||||
|
||||
should(subscriptionNodes).Array();
|
||||
should(subscriptionNodes.length).equal(1);
|
||||
|
||||
const treeItem = await accountTreeNode.getTreeItem();
|
||||
should(treeItem.label).equal(accountTreeNodeLabel);
|
||||
|
||||
const nodeInfo = accountTreeNode.getNodeInfo();
|
||||
should(nodeInfo.label).equal(accountTreeNodeLabel);
|
||||
});
|
||||
|
||||
it('Should be correct when there are subscriptions filtered.', async function (): Promise<void> {
|
||||
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount)).returns(() => Promise.resolve(mockSubscriptions));
|
||||
mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve(mockFilteredSubscriptions));
|
||||
sinon.stub(azdata.accounts, 'getAccountSecurityToken').resolves(mockToken);
|
||||
const accountTreeNodeLabel = `${mockAccount.displayInfo.displayName} (${mockFilteredSubscriptions.length} / ${mockSubscriptions.length} subscriptions)`;
|
||||
|
||||
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockAppContext, mockTreeChangeHandler.object);
|
||||
|
||||
@@ -99,7 +99,7 @@ export class ApiWrapper {
|
||||
return azdata.accounts.getAllAccounts();
|
||||
}
|
||||
|
||||
public getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Thenable<{ token: string, tokenType?: string } | undefined> {
|
||||
public getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Thenable<azdata.accounts.AccountSecurityToken | undefined> {
|
||||
return azdata.accounts.getAccountSecurityToken(account, tenant, resource);
|
||||
}
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ export class AzureModelRegistryService {
|
||||
if (this._amlClient) {
|
||||
return this._amlClient;
|
||||
} else {
|
||||
const tokens: { token: string, tokenType?: string } | undefined = await this._apiWrapper.getAccountSecurityToken(account, tenant.id, azdata.AzureResource.ResourceManagement);
|
||||
const tokens: azdata.accounts.AccountSecurityToken | undefined = await this._apiWrapper.getAccountSecurityToken(account, tenant.id, azdata.AzureResource.ResourceManagement);
|
||||
let token: string = '';
|
||||
let tokenType: string | undefined = undefined;
|
||||
if (tokens) {
|
||||
|
||||
16
src/sql/azdata.d.ts
vendored
16
src/sql/azdata.d.ts
vendored
@@ -2175,6 +2175,20 @@ declare module 'azdata' {
|
||||
*/
|
||||
export function getSecurityToken(account: Account, resource?: AzureResource): Thenable<{ [key: string]: any }>;
|
||||
|
||||
/**
|
||||
* The token used to authenticate an account.
|
||||
*/
|
||||
export interface AccountSecurityToken {
|
||||
/**
|
||||
* The token to use
|
||||
*/
|
||||
token: string,
|
||||
/**
|
||||
* What type of token this is (such as Bearer)
|
||||
*/
|
||||
tokenType?: string | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a security token by asking the account's provider
|
||||
* @param account The account to retrieve the security token for
|
||||
@@ -2182,7 +2196,7 @@ declare module 'azdata' {
|
||||
* @param resource Type of resource to get the security token for (defaults to
|
||||
* AzureResource.ResourceManagement if not given)
|
||||
*/
|
||||
export function getAccountSecurityToken(account: Account, tenantId: string, resource: AzureResource): Thenable<{ token: string, tokenType?: string | undefined } | undefined>;
|
||||
export function getAccountSecurityToken(account: Account, tenantId: string, resource: AzureResource): Thenable<AccountSecurityToken | undefined>;
|
||||
|
||||
/**
|
||||
* An [event](#Event) which fires when the accounts have changed.
|
||||
|
||||
2
src/sql/azdata.proposed.d.ts
vendored
2
src/sql/azdata.proposed.d.ts
vendored
@@ -836,7 +836,7 @@ declare module 'azdata' {
|
||||
* @param resource The resource to get the token for
|
||||
* @return Promise to return a security token object
|
||||
*/
|
||||
getAccountSecurityToken(account: Account, tenant: string, resource: AzureResource): Thenable<{ token: string } | undefined>;
|
||||
getAccountSecurityToken(account: Account, tenant: string, resource: AzureResource): Thenable<accounts.AccountSecurityToken | undefined>;
|
||||
}
|
||||
|
||||
export interface AccountKey {
|
||||
|
||||
@@ -25,7 +25,7 @@ export interface IAccountManagementService {
|
||||
* @deprecated
|
||||
*/
|
||||
getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Promise<{ [key: string]: { token: string } } | undefined>;
|
||||
getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Promise<{ token: string } | undefined>;
|
||||
getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Promise<azdata.accounts.AccountSecurityToken | undefined>;
|
||||
removeAccount(accountKey: azdata.AccountKey): Promise<boolean>;
|
||||
removeAccounts(): Promise<boolean>;
|
||||
refreshAccount(account: azdata.Account): Promise<azdata.Account>;
|
||||
|
||||
@@ -55,7 +55,7 @@ export class TestAccountManagementService implements IAccountManagementService {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Promise<{ token: string }> {
|
||||
getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Promise<azdata.accounts.AccountSecurityToken> {
|
||||
return Promise.resolve(undefined!);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ export class MainThreadAccountManagement extends Disposable implements MainThrea
|
||||
getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Thenable<{}> {
|
||||
return self._proxy.$getSecurityToken(account, resource);
|
||||
},
|
||||
getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Thenable<{ token: string }> {
|
||||
getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Thenable<azdata.accounts.AccountSecurityToken> {
|
||||
return self._proxy.$getAccountSecurityToken(account, tenant, resource);
|
||||
},
|
||||
initialize(restoredAccounts: azdata.Account[]): Thenable<azdata.Account[]> {
|
||||
|
||||
@@ -104,7 +104,7 @@ export class ExtHostAccountManagement extends ExtHostAccountManagementShape {
|
||||
});
|
||||
}
|
||||
|
||||
public override $getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource = AzureResource.ResourceManagement): Thenable<{ token: string }> {
|
||||
public override $getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource = AzureResource.ResourceManagement): Thenable<azdata.accounts.AccountSecurityToken> {
|
||||
return this.getAllProvidersAndAccounts().then(providerAndAccounts => {
|
||||
const providerAndAccount = providerAndAccounts.find(providerAndAccount => providerAndAccount.account.key.accountId === account.key.accountId);
|
||||
if (providerAndAccount) {
|
||||
|
||||
@@ -165,7 +165,7 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp
|
||||
getSecurityToken(account: azdata.Account, resource?: azdata.AzureResource): Thenable<{}> {
|
||||
return extHostAccountManagement.$getSecurityToken(account, resource);
|
||||
},
|
||||
getAccountSecurityToken(account: azdata.Account, tenant: string, resource?: azdata.AzureResource): Thenable<{ token: string }> {
|
||||
getAccountSecurityToken(account: azdata.Account, tenant: string, resource?: azdata.AzureResource): Thenable<azdata.accounts.AccountSecurityToken> {
|
||||
return extHostAccountManagement.$getAccountSecurityToken(account, tenant, resource);
|
||||
},
|
||||
onDidChangeAccounts(listener: (e: azdata.DidChangeAccountsParams) => void, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
|
||||
|
||||
@@ -32,7 +32,7 @@ export abstract class ExtHostAccountManagementShape {
|
||||
$autoOAuthCancelled(handle: number): Thenable<void> { throw ni(); }
|
||||
$clear(handle: number, accountKey: azdata.AccountKey): Thenable<void> { throw ni(); }
|
||||
$getSecurityToken(account: azdata.Account, resource?: azdata.AzureResource): Thenable<{}> { throw ni(); }
|
||||
$getAccountSecurityToken(account: azdata.Account, tenant: string, resource?: azdata.AzureResource): Thenable<{ token: string }> { throw ni(); }
|
||||
$getAccountSecurityToken(account: azdata.Account, tenant: string, resource?: azdata.AzureResource): Thenable<azdata.accounts.AccountSecurityToken> { throw ni(); }
|
||||
$initialize(handle: number, restoredAccounts: azdata.Account[]): Thenable<azdata.Account[]> { throw ni(); }
|
||||
$prompt(handle: number): Thenable<azdata.Account | azdata.PromptFailedResult> { throw ni(); }
|
||||
$refresh(handle: number, account: azdata.Account): Thenable<azdata.Account | azdata.PromptFailedResult> { throw ni(); }
|
||||
|
||||
@@ -246,7 +246,7 @@ export class AccountManagementService implements IAccountManagementService {
|
||||
* @param resource The resource to get the security token for
|
||||
* @return Promise to return the security token
|
||||
*/
|
||||
public getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Promise<{ token: string } | undefined> {
|
||||
public getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Promise<azdata.accounts.AccountSecurityToken | undefined> {
|
||||
return this.doWithProvider(account.key.providerId, provider => {
|
||||
return Promise.resolve(provider.provider.getAccountSecurityToken(account, tenant, resource));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user