mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-03 23:06:49 +01:00
Misc fixes for Sovereign Clouds (#228591)
* Misc fixes for Sovereign Clouds * For now, use the URL handler since the main flow doesn't work right now because the localhost redirect url needs to be in those environments * Includes the name of the cloud in the PCAs so that we have separation between the auth providers * extra logging for the URL Handler * fix tests
This commit is contained in:
committed by
GitHub
parent
3fd5eb3429
commit
6bd8e90fb7
@@ -50,7 +50,12 @@ export class MsalAuthProvider implements AuthenticationProvider {
|
||||
private readonly _env: Environment = Environment.AzureCloud
|
||||
) {
|
||||
this._disposables = context.subscriptions;
|
||||
this._publicClientManager = new CachedPublicClientApplicationManager(context.globalState, context.secrets, this._logger);
|
||||
this._publicClientManager = new CachedPublicClientApplicationManager(
|
||||
context.globalState,
|
||||
context.secrets,
|
||||
this._logger,
|
||||
this._env.name
|
||||
);
|
||||
const accountChangeEvent = this._eventBufferer.wrapEvent(
|
||||
this._publicClientManager.onDidAccountsChange,
|
||||
(last, newEvent) => {
|
||||
@@ -148,40 +153,52 @@ export class MsalAuthProvider implements AuthenticationProvider {
|
||||
|
||||
this._logger.info('[createSession]', `[${scopeData.scopeStr}]`, 'starting');
|
||||
const cachedPca = await this.getOrCreatePublicClientApplication(scopeData.clientId, scopeData.tenant);
|
||||
let result: AuthenticationResult;
|
||||
try {
|
||||
result = await cachedPca.acquireTokenInteractive({
|
||||
openBrowser: async (url: string) => { await env.openExternal(Uri.parse(url)); },
|
||||
scopes: scopeData.scopesToSend,
|
||||
// The logic for rendering one or the other of these templates is in the
|
||||
// template itself, so we pass the same one for both.
|
||||
successTemplate: loopbackTemplate,
|
||||
errorTemplate: loopbackTemplate
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof CancellationError) {
|
||||
const yes = l10n.t('Yes');
|
||||
const result = await window.showErrorMessage(
|
||||
l10n.t('Having trouble logging in?'),
|
||||
{
|
||||
modal: true,
|
||||
detail: l10n.t('Would you like to try a different way to sign in to your Microsoft account? ({0})', 'protocol handler')
|
||||
},
|
||||
yes
|
||||
);
|
||||
if (!result) {
|
||||
let result: AuthenticationResult | undefined;
|
||||
|
||||
// Currently, the http://localhost redirect URI is only in the AzureCloud environment... even though I did make the change in the SovereignCloud environments...
|
||||
// TODO: Remove this check when the change is in all environments.
|
||||
let useLoopBack = this._env !== Environment.AzureCloud && scopeData.clientId === 'aebc6443-996d-45c2-90f0-388ff96faa56';
|
||||
if (!useLoopBack) {
|
||||
try {
|
||||
result = await cachedPca.acquireTokenInteractive({
|
||||
openBrowser: async (url: string) => { await env.openExternal(Uri.parse(url)); },
|
||||
scopes: scopeData.scopesToSend,
|
||||
// The logic for rendering one or the other of these templates is in the
|
||||
// template itself, so we pass the same one for both.
|
||||
successTemplate: loopbackTemplate,
|
||||
errorTemplate: loopbackTemplate
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof CancellationError) {
|
||||
const yes = l10n.t('Yes');
|
||||
const result = await window.showErrorMessage(
|
||||
l10n.t('Having trouble logging in?'),
|
||||
{
|
||||
modal: true,
|
||||
detail: l10n.t('Would you like to try a different way to sign in to your Microsoft account? ({0})', 'protocol handler')
|
||||
},
|
||||
yes
|
||||
);
|
||||
if (!result) {
|
||||
this._telemetryReporter.sendLoginFailedEvent();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
// This error comes from the backend and is likely not due to the user's machine
|
||||
// failing to open a port or something local that would require us to try the
|
||||
// URL handler loopback client.
|
||||
if (e instanceof ServerError) {
|
||||
this._telemetryReporter.sendLoginFailedEvent();
|
||||
throw e;
|
||||
}
|
||||
|
||||
// The user wants to try the loopback client or we got an error likely due to spinning up the server
|
||||
useLoopBack = true;
|
||||
}
|
||||
// This error comes from the backend and is likely not due to the user's machine
|
||||
// failing to open a port or something local that would require us to try the
|
||||
// URL handler loopback client.
|
||||
if (e instanceof ServerError) {
|
||||
this._telemetryReporter.sendLoginFailedEvent();
|
||||
throw e;
|
||||
}
|
||||
const loopbackClient = new UriHandlerLoopbackClient(this._uriHandler, redirectUri);
|
||||
}
|
||||
|
||||
if (useLoopBack) {
|
||||
const loopbackClient = new UriHandlerLoopbackClient(this._uriHandler, redirectUri, this._logger);
|
||||
try {
|
||||
result = await cachedPca.acquireTokenInteractive({
|
||||
openBrowser: (url: string) => loopbackClient.openBrowser(url),
|
||||
@@ -194,6 +211,11 @@ export class MsalAuthProvider implements AuthenticationProvider {
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
this._telemetryReporter.sendLoginFailedEvent();
|
||||
throw new Error('No result returned from MSAL');
|
||||
}
|
||||
|
||||
const session = this.sessionFromAuthenticationResult(result, scopeData.originalScopes);
|
||||
this._telemetryReporter.sendLoginEvent(session.scopes);
|
||||
this._logger.info('[createSession]', `[${scopeData.scopeStr}]`, 'returned session');
|
||||
|
||||
@@ -27,9 +27,10 @@ export class CachedPublicClientApplicationManager implements ICachedPublicClient
|
||||
constructor(
|
||||
private readonly _globalMemento: Memento,
|
||||
private readonly _secretStorage: SecretStorage,
|
||||
private readonly _logger: LogOutputChannel
|
||||
private readonly _logger: LogOutputChannel,
|
||||
cloudName: string
|
||||
) {
|
||||
this._pcasSecretStorage = new PublicClientApplicationsSecretStorage(_secretStorage);
|
||||
this._pcasSecretStorage = new PublicClientApplicationsSecretStorage(_secretStorage, cloudName);
|
||||
this._disposable = Disposable.from(
|
||||
this._pcasSecretStorage,
|
||||
this._registerSecretStorageHandler(),
|
||||
@@ -190,18 +191,18 @@ export class CachedPublicClientApplicationManager implements ICachedPublicClient
|
||||
}
|
||||
|
||||
class PublicClientApplicationsSecretStorage {
|
||||
private static key = 'publicClientApplications';
|
||||
|
||||
private _disposable: Disposable;
|
||||
|
||||
private readonly _onDidChangeEmitter = new EventEmitter<void>;
|
||||
readonly onDidChange: Event<void> = this._onDidChangeEmitter.event;
|
||||
|
||||
constructor(private readonly _secretStorage: SecretStorage) {
|
||||
private readonly _key = `publicClientApplications-${this._cloudName}`;
|
||||
|
||||
constructor(private readonly _secretStorage: SecretStorage, private readonly _cloudName: string) {
|
||||
this._disposable = Disposable.from(
|
||||
this._onDidChangeEmitter,
|
||||
this._secretStorage.onDidChange(e => {
|
||||
if (e.key === PublicClientApplicationsSecretStorage.key) {
|
||||
if (e.key === this._key) {
|
||||
this._onDidChangeEmitter.fire();
|
||||
}
|
||||
})
|
||||
@@ -209,7 +210,7 @@ class PublicClientApplicationsSecretStorage {
|
||||
}
|
||||
|
||||
async get(): Promise<string[] | undefined> {
|
||||
const value = await this._secretStorage.get(PublicClientApplicationsSecretStorage.key);
|
||||
const value = await this._secretStorage.get(this._key);
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -217,11 +218,11 @@ class PublicClientApplicationsSecretStorage {
|
||||
}
|
||||
|
||||
store(value: string[]): Thenable<void> {
|
||||
return this._secretStorage.store(PublicClientApplicationsSecretStorage.key, JSON.stringify(value));
|
||||
return this._secretStorage.store(this._key, JSON.stringify(value));
|
||||
}
|
||||
|
||||
delete(): Thenable<void> {
|
||||
return this._secretStorage.delete(PublicClientApplicationsSecretStorage.key);
|
||||
return this._secretStorage.delete(this._key);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
Reference in New Issue
Block a user