Update error for ignored tenants (#22881)

This commit is contained in:
Cheena Malhotra
2023-04-28 16:19:29 -07:00
committed by GitHub
parent 29ff6ca16c
commit ed8149599c
9 changed files with 112 additions and 59 deletions

View File

@@ -330,12 +330,6 @@ export abstract class AzureAuth implements vscode.Disposable {
return null;
}
// The user wants to ignore this tenant.
if (getTenantIgnoreList().includes(tenantId)) {
Logger.info(`Tenant ${tenantId} found in the ignore list, authentication will not be attempted.`);
return null;
}
// Resource endpoint must end with '/' to form a valid scope for MSAL token request.
const endpoint = resource.endpoint.endsWith('/') ? resource.endpoint : resource.endpoint + '/';
@@ -509,6 +503,7 @@ export abstract class AzureAuth implements vscode.Disposable {
tenantCategory: tenantInfo.tenantCategory
} as Tenant;
});
Logger.verbose(`Tenants: ${tenantList}`);
const homeTenantIndex = tenants.findIndex(tenant => tenant.tenantCategory === Constants.HomeCategory);
// remove home tenant from list of tenants
@@ -683,7 +678,7 @@ export abstract class AzureAuth implements vscode.Disposable {
interface ConsentMessageItem extends vscode.MessageItem {
booleanResult: boolean;
action?: (tenantId: string) => Promise<void>;
action?: (tenantId: string) => Promise<boolean>;
}
const openItem: ConsentMessageItem = {
@@ -697,23 +692,50 @@ export abstract class AzureAuth implements vscode.Disposable {
booleanResult: false
};
const cancelAndAuthenticate: ConsentMessageItem = {
title: localize('azurecore.consentDialog.authenticate', "Cancel and Authenticate"),
isCloseAffordance: true,
booleanResult: true
};
const dontAskAgainItem: ConsentMessageItem = {
title: localize('azurecore.consentDialog.ignore', "Ignore Tenant"),
booleanResult: false,
action: async (tenantId: string) => {
return await confirmIgnoreTenantDialog();
}
};
const confirmIgnoreTenantItem: ConsentMessageItem = {
title: localize('azurecore.confirmIgnoreTenantDialog.confirm', "Confirm"),
booleanResult: false,
action: async (tenantId: string) => {
tenantIgnoreList.push(tenantId);
await updateTenantIgnoreList(tenantIgnoreList);
return false;
}
};
const messageBody = localize('azurecore.consentDialog.body', "Your tenant '{0} ({1})' requires you to re-authenticate again to access {2} resources. Press Open to start the authentication process.", tenant.displayName, tenant.id, resource.endpoint);
const result = await vscode.window.showInformationMessage(messageBody, { modal: true }, openItem, closeItem, dontAskAgainItem);
const confirmIgnoreTenantDialog = async () => {
const confirmMessage = localize('azurecore.confirmIgnoreTenantDialog.body', "Azure Data Studio will no longer trigger authentication for this tenant {0} ({1}) and resources will not be accessible. \n\nTo allow access to resources for this tenant again, you will need to remove the tenant from the exclude list in the '{2}' setting.\n\nDo you wish to proceed?", tenant.displayName, tenant.id, Constants.AzureTenantConfigFilterSetting);
let confirmation = await vscode.window.showInformationMessage(confirmMessage, { modal: true }, cancelAndAuthenticate, confirmIgnoreTenantItem);
if (result?.action) {
await result.action(tenant.id);
if (confirmation?.action) {
await confirmation.action(tenant.id);
}
return confirmation?.booleanResult || false;
}
return result?.booleanResult || false;
const messageBody = localize('azurecore.consentDialog.body', "Your tenant {0} ({1}) requires you to re-authenticate again to access {2} resources. Press Open to start the authentication process.", tenant.displayName, tenant.id, resource.endpoint);
const result = await vscode.window.showInformationMessage(messageBody, { modal: true }, openItem, closeItem, dontAskAgainItem);
let response = false;
if (result?.action) {
response = await result.action(tenant.id);
}
return response;
}
//#endregion

View File

@@ -22,6 +22,8 @@ import { AzureDeviceCode } from './auths/azureDeviceCode';
import { filterAccounts } from '../azureResource/utils';
import * as Constants from '../constants';
import { MsalCachePluginProvider } from './utils/msalCachePlugin';
import { getTenantIgnoreList } from '../utils';
import { TenantIgnoredError } from '../utils/TenantIgnoredError';
const localize = nls.loadMessageBundle();
@@ -133,7 +135,6 @@ export class AzureAccountProvider implements azdata.AccountProvider, vscode.Disp
return accounts;
}
getSecurityToken(account: AzureAccount, resource: azdata.AzureResource): Thenable<MultiTenantTokenResponse | undefined> {
return this._getSecurityToken(account, resource);
}
@@ -159,29 +160,35 @@ export class AzureAccountProvider implements azdata.AccountProvider, vscode.Disp
Logger.info(`Could not fetch access token from cache: ${e}, fetching new access token instead.`);
}
tenantId = tenantId || account.properties.owningTenant.id;
let authResult = await azureAuth.getTokenMsal(account.key.accountId, resource, tenantId);
if (this.isAuthenticationResult(authResult) && authResult.account && authResult.account.idTokenClaims) {
const token: Token = {
key: authResult.account.homeAccountId,
token: authResult.accessToken,
tokenType: authResult.tokenType,
expiresOn: authResult.account.idTokenClaims.exp!,
tenantId: tenantId,
resource: resource
};
try {
await this.msalCacheProvider.writeTokenToLocalCache(token);
} catch (e) {
Logger.error(`Could not save access token to local cache: ${e}, this might cause throttling of AAD requests.`);
}
return token;
if (getTenantIgnoreList().includes(tenantId)) {
// Tenant found in ignore list, don't fetch access token.
Logger.info(`Tenant ${tenantId} found in the ignore list, authentication will not be attempted. Please remove tenant from setting: '${Constants.AzureTenantConfigFilterSetting}' if you want to re-enable tenant for authentication.`);
throw new TenantIgnoredError(localize('tenantIgnoredError', 'Tenant found in ignore list, authentication not attempted. You can remove tenant {0} from ignore list in settings.json file: {1} if you wish to access resources from this tenant.', tenantId, Constants.AzureTenantConfigFilterSetting));
} else {
Logger.error(`MSAL: getToken call failed`);
// Throw error with MSAL-specific code/message, else throw generic error message
if (this.isProviderError(authResult)) {
throw new Error(localize('msalTokenError', `{0} occurred when acquiring token. \n{1}`, authResult.errorCode, authResult.errorMessage));
let authResult = await azureAuth.getTokenMsal(account.key.accountId, resource, tenantId);
if (this.isAuthenticationResult(authResult) && authResult.account && authResult.account.idTokenClaims) {
const token: Token = {
key: authResult.account.homeAccountId,
token: authResult.accessToken,
tokenType: authResult.tokenType,
expiresOn: authResult.account.idTokenClaims.exp!,
tenantId: tenantId,
resource: resource
};
try {
await this.msalCacheProvider.writeTokenToLocalCache(token);
} catch (e) {
Logger.error(`Could not save access token to local cache: ${e}, this might cause throttling of AAD requests.`);
}
return token;
} else {
throw new Error(localize('genericTokenError', 'Failed to get token'));
Logger.error(`MSAL: getToken call failed`);
// Throw error with MSAL-specific code/message, else throw generic error message
if (this.isProviderError(authResult)) {
throw new Error(localize('msalTokenError', `{0} occurred when acquiring token. \n{1}`, authResult.errorCode, authResult.errorMessage));
} else {
throw new Error(localize('genericTokenError', 'Failed to get token'));
}
}
}
} else { // fallback to ADAL as default
@@ -226,7 +233,13 @@ export class AzureAccountProvider implements azdata.AccountProvider, vscode.Disp
const azureAccount = account as AzureAccount;
const response: MultiTenantTokenResponse = {};
for (const tenant of azureAccount.properties.tenants) {
response[tenant.id] = await this._getAccountSecurityToken(account, tenant.id, resource);
try {
response[tenant.id] = await this._getAccountSecurityToken(account, tenant.id, resource);
} catch (e) {
if (!(e instanceof TenantIgnoredError)) {
throw e;
}
}
}
return response;