mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Handle multiple matching tokens error (#23441)
Surfaces when fetching subscriptions
This commit is contained in:
@@ -332,46 +332,52 @@ export abstract class AzureAuth implements vscode.Disposable {
|
||||
|
||||
// Resource endpoint must end with '/' to form a valid scope for MSAL token request.
|
||||
const endpoint = resource.endpoint.endsWith('/') ? resource.endpoint : resource.endpoint + '/';
|
||||
|
||||
let account: AccountInfo | null = await this.getAccountFromMsalCache(accountId);
|
||||
if (!account) {
|
||||
Logger.error('Error: Could not fetch account when acquiring token');
|
||||
throw new Error(localize('msal.accountNotFoundError', `Unable to find account info when acquiring token.`));
|
||||
}
|
||||
let account: AccountInfo | null;
|
||||
let newScope;
|
||||
if (resource.azureResourceId === azdata.AzureResource.ResourceManagement) {
|
||||
newScope = [`${endpoint}user_impersonation`];
|
||||
} else {
|
||||
newScope = [`${endpoint}.default`];
|
||||
}
|
||||
|
||||
// construct request
|
||||
// forceRefresh needs to be set true here in order to fetch the correct token, due to this issue
|
||||
// https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/3687
|
||||
// Even for full tenants, access token is often received expired - force refresh is necessary when token expires.
|
||||
const tokenRequest = {
|
||||
account: account,
|
||||
authority: `${this.loginEndpointUrl}${tenantId}`,
|
||||
scopes: newScope,
|
||||
forceRefresh: true
|
||||
};
|
||||
try {
|
||||
return await this.clientApplication.acquireTokenSilent(tokenRequest);
|
||||
} catch (e) {
|
||||
Logger.error('Failed to acquireTokenSilent', e);
|
||||
if (e instanceof AuthError && this.accountNeedsRefresh(e)) {
|
||||
// build refresh token request
|
||||
const tenant: Tenant = {
|
||||
id: tenantId,
|
||||
displayName: ''
|
||||
};
|
||||
return this.handleInteractionRequiredMsal(tenant, resource);
|
||||
} else {
|
||||
if (e.name === 'ClientAuthError') {
|
||||
Logger.verbose('[ClientAuthError] Failed to silently acquire token');
|
||||
}
|
||||
return errorToPromptFailedResult(e);
|
||||
account = await this.getAccountFromMsalCache(accountId);
|
||||
if (!account) {
|
||||
Logger.error('Error: Could not fetch account when acquiring token');
|
||||
throw new Error(localize('msal.accountNotFoundError', `Unable to find account info when acquiring token, please remove account and add again.`));
|
||||
}
|
||||
if (resource.azureResourceId === azdata.AzureResource.ResourceManagement) {
|
||||
newScope = [`${endpoint}user_impersonation`];
|
||||
} else {
|
||||
newScope = [`${endpoint}.default`];
|
||||
}
|
||||
|
||||
// construct request
|
||||
// forceRefresh needs to be set true here in order to fetch the correct token, due to this issue
|
||||
// https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/3687
|
||||
// Even for full tenants, access token is often received expired - force refresh is necessary when token expires.
|
||||
const tokenRequest = {
|
||||
account: account,
|
||||
authority: `${this.loginEndpointUrl}${tenantId}`,
|
||||
scopes: newScope,
|
||||
forceRefresh: true
|
||||
};
|
||||
try {
|
||||
return await this.clientApplication.acquireTokenSilent(tokenRequest);
|
||||
} catch (e) {
|
||||
Logger.error('Failed to acquireTokenSilent', e);
|
||||
if (e instanceof AuthError && this.accountNeedsRefresh(e)) {
|
||||
// build refresh token request
|
||||
const tenant: Tenant = {
|
||||
id: tenantId,
|
||||
displayName: ''
|
||||
};
|
||||
return this.handleInteractionRequiredMsal(tenant, resource);
|
||||
} else {
|
||||
if (e.name === 'ClientAuthError') {
|
||||
Logger.verbose('[ClientAuthError] Failed to silently acquire token');
|
||||
}
|
||||
return errorToPromptFailedResult(e);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error(`[ClientAuthError] Failed to find account: ${error}`);
|
||||
return errorToPromptFailedResult(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,12 +910,16 @@ export abstract class AzureAuth implements vscode.Disposable {
|
||||
|
||||
private async deleteAccountCacheMsal(accountKey: azdata.AccountKey): Promise<void> {
|
||||
const tokenCache = this.clientApplication.getTokenCache();
|
||||
let msalAccount: AccountInfo | null = await this.getAccountFromMsalCache(accountKey.accountId);
|
||||
if (!msalAccount) {
|
||||
Logger.error(`MSAL: Unable to find account ${accountKey.accountId} for removal`);
|
||||
throw Error(`Unable to find account ${accountKey.accountId}`);
|
||||
try {
|
||||
let msalAccount: AccountInfo | null = await this.getAccountFromMsalCache(accountKey.accountId);
|
||||
if (!msalAccount) {
|
||||
Logger.error(`MSAL: Unable to find account ${accountKey.accountId} for removal`);
|
||||
throw Error(`Unable to find account ${accountKey.accountId}`);
|
||||
}
|
||||
await tokenCache.removeAccount(msalAccount);
|
||||
} catch (error) {
|
||||
Logger.error(`[ClientAuthError] Failed to find account: ${error}`);
|
||||
}
|
||||
await tokenCache.removeAccount(msalAccount);
|
||||
await this.msalCacheProvider.clearAccountFromLocalCache(accountKey.accountId);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Logger } from '../../utils/Logger';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import { TenantIgnoredError } from '../../utils/TenantIgnoredError';
|
||||
import { multiple_matching_tokens_error } from '../../constants';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class AzureResourceSubscriptionService implements IAzureResourceSubscriptionService {
|
||||
@@ -52,8 +53,12 @@ export class AzureResourceSubscriptionService implements IAzureResourceSubscript
|
||||
}
|
||||
} catch (error) {
|
||||
if (!account.isStale && !(error instanceof TenantIgnoredError)) {
|
||||
const errorMsg = localize('azure.resource.tenantSubscriptionsError', "Failed to get subscriptions for account {0} (tenant '{1}'). {2}", account.displayInfo.displayName, tenantId, AzureResourceErrorMessageUtil.getErrorMessage(error));
|
||||
Logger.error(`Failed to get subscriptions for account ${account.displayInfo.displayName} (tenant '${tenantId}'). ${AzureResourceErrorMessageUtil.getErrorMessage(error)}`);
|
||||
const msg = AzureResourceErrorMessageUtil.getErrorMessage(error);
|
||||
let errorMsg = localize('azure.resource.tenantSubscriptionsError', "Failed to get subscriptions for account {0} (tenant '{1}'). {2}", account.displayInfo.displayName, tenantId, msg);
|
||||
if (msg.includes(multiple_matching_tokens_error)) {
|
||||
errorMsg = errorMsg.concat(` To resolve this error, please clear token cache, and refresh account credentials.`);
|
||||
}
|
||||
Logger.error(`Failed to get subscriptions for account ${account.displayInfo.displayName} (tenant '${tenantId}'). ${msg}`);
|
||||
errors.push(error);
|
||||
void vscode.window.showWarningMessage(errorMsg);
|
||||
}
|
||||
|
||||
@@ -93,6 +93,14 @@ export const AADSTS70043 = 'AADSTS70043';
|
||||
*/
|
||||
export const AADSTS50173 = 'AADSTS50173';
|
||||
|
||||
/**
|
||||
* multiple_matching_tokens error can occur in scenarios when users try to run ADS as different users, reference issue:
|
||||
* https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/5134
|
||||
* Error message: multiple_matching_tokens The cache contains multiple tokens satisfying the requirements.
|
||||
* Call AcquireToken again providing more requirements such as authority or account.
|
||||
*/
|
||||
export const multiple_matching_tokens_error = 'multiple_matching_tokens';
|
||||
|
||||
export enum BuiltInCommands {
|
||||
SetContext = 'setContext'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user