diff --git a/extensions/import/src/common/utils.ts b/extensions/import/src/common/utils.ts new file mode 100644 index 0000000000..6ac533e0b1 --- /dev/null +++ b/extensions/import/src/common/utils.ts @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +const mssqlExtensionConfigName = 'mssql'; +const enableSqlAuthenticationProviderConfig = 'enableSqlAuthenticationProvider'; + +const azureExtensionConfigName = 'azure'; +const azureAuthenticationLibraryConfig = 'authenticationLibrary'; +const MSAL = 'MSAL'; + +/** + * @returns 'True' if MSAL auth library is in use and SQL Auth provider is enabled. + */ +export function isMssqlAuthProviderEnabled(): boolean { + return getAzureAuthenticationLibraryConfig() === MSAL && getEnableSqlAuthenticationProviderConfig(); +} + +export function getConfiguration(config: string): vscode.WorkspaceConfiguration { + return vscode.workspace.getConfiguration(config); +} + +/** + * Reads setting 'azure.AuthenticationLibrary' and returns the library name enabled. + * @returns MSAL | ADAL + */ +export function getAzureAuthenticationLibraryConfig(): string { + const config = getConfiguration(azureExtensionConfigName); + if (config) { + return config.get(azureAuthenticationLibraryConfig, MSAL); // default Auth library + } + else { + return MSAL; // default Auth library + } +} + +/** + * Reads setting 'mssql.enableSqlAuthenticationProvider' and returns true if it's enabled. + * @returns True Sql Auth provider is enabled for MSSQL provider. + */ +export function getEnableSqlAuthenticationProviderConfig(): boolean { + const config = getConfiguration(mssqlExtensionConfigName); + if (config) { + return config.get(enableSqlAuthenticationProviderConfig, true); // enabled by default + } + else { + return true; // enabled by default + } +} diff --git a/extensions/import/src/wizard/pages/summaryPage.ts b/extensions/import/src/wizard/pages/summaryPage.ts index 183d9e0034..560578dba3 100644 --- a/extensions/import/src/wizard/pages/summaryPage.ts +++ b/extensions/import/src/wizard/pages/summaryPage.ts @@ -9,6 +9,7 @@ import { ImportPage } from '../api/importPage'; import { InsertDataResponse } from '../../services/contracts'; import * as constants from '../../common/constants'; import { EOL } from 'os'; +import { isMssqlAuthProviderEnabled } from '../../common/utils'; export class SummaryPage extends ImportPage { private _table: azdata.TableComponent; @@ -137,10 +138,14 @@ export class SummaryPage extends ImportPage { const currentServer = this.model.server; const includePasswordInConnectionString = (currentServer.options.authenticationType === azdata.connection.AuthenticationType.Integrated) ? false : true; - const connectionString = await azdata.connection.getConnectionString(currentServer.connectionId, includePasswordInConnectionString); + let connectionString = await azdata.connection.getConnectionString(currentServer.connectionId, includePasswordInConnectionString); let accessToken = undefined; if (currentServer.options.authenticationType === azdata.connection.AuthenticationType.AzureMFA) { + // Remove authentication properties from connection string if SQL Authentication Provider is enabled + if (isMssqlAuthProviderEnabled()) { + connectionString = this.updateConnectionStringForAccessToken(connectionString); + } const azureAccount = (await azdata.accounts.getAllAccounts()).filter(v => v.key.accountId === currentServer.options.azureAccount)[0]; accessToken = (await azdata.accounts.getAccountSecurityToken(azureAccount, currentServer.options.azureTenantId, azdata.AzureResource.Sql)).token; } @@ -178,6 +183,21 @@ export class SummaryPage extends ImportPage { }); } + /** + * Removes authentication related properties from connection string as SQL Tools Service now supports + * 'EnableSqlAuthenticationProvider' which sets the below properties on connection string that conflict with access token: + * 1. User Id + * 2. Authentication + * Since we need to set access token, we cannot use the same connection string as is. + * @param connString Connection string to fix + * @returns Updated connection string + */ + private updateConnectionStringForAccessToken(connString: string): string { + return connString ? connString.split(';').filter(prop => + !['user', 'uid', 'password', 'pwd', 'authentication'].some(prefix => prop.toLocaleLowerCase().startsWith(prefix)) + ).join(';') : connString; + } + // private async getCountRowsInserted(): Promise { // let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId); // let queryProvider = azdata.dataprotocol.getProvider(this.model.server.providerName, azdata.DataProviderType.QueryProvider);