diff --git a/extensions/azurecore/src/account-provider/auths/azureAuth.ts b/extensions/azurecore/src/account-provider/auths/azureAuth.ts index 7ff77f8318..0728c46e75 100644 --- a/extensions/azurecore/src/account-provider/auths/azureAuth.ts +++ b/extensions/azurecore/src/account-provider/auths/azureAuth.ts @@ -81,6 +81,10 @@ export abstract class AzureAuth implements vscode.Disposable { this.resources = this.resources.concat(this.metadata.settings.azureKustoResource); } + if (this.metadata.settings.powerBiResource) { + this.resources = this.resources.concat(this.metadata.settings.powerBiResource); + } + this.scopes = [...this.metadata.settings.scopes]; this.scopesString = this.scopes.join(' '); } diff --git a/extensions/azurecore/src/account-provider/providerSettings.ts b/extensions/azurecore/src/account-provider/providerSettings.ts index 5865ef550b..1fb2242fe1 100644 --- a/extensions/azurecore/src/account-provider/providerSettings.ts +++ b/extensions/azurecore/src/account-provider/providerSettings.ts @@ -20,7 +20,8 @@ const enum SettingIds { ado = 'ado', ala = 'ala', storage = 'storage', - kusto = 'kusto' + kusto = 'kusto', + powerbi = 'powerbi' } const publicAzureSettings: ProviderSettings = { @@ -87,6 +88,11 @@ const publicAzureSettings: ProviderSettings = { endpoint: 'https://kusto.kusto.windows.net', azureResourceId: AzureResource.AzureKusto, }, + powerBiResource: { + id: SettingIds.powerbi, + endpoint: 'https://analysis.windows.net/powerbi/api', + azureResourceId: AzureResource.PowerBi + }, redirectUri: 'https://vscode-redirect.azurewebsites.net/', scopes: [ 'openid', 'email', 'profile', 'offline_access', @@ -147,6 +153,11 @@ const usGovAzureSettings: ProviderSettings = { endpointSuffix: '.core.usgovcloudapi.net', azureResourceId: AzureResource.AzureStorage }, + powerBiResource: { + id: SettingIds.powerbi, + endpoint: 'https://analysis.windows.net/powerbi/api', + azureResourceId: AzureResource.PowerBi + }, redirectUri: 'https://vscode-redirect.azurewebsites.net/', scopes: [ 'openid', 'email', 'profile', 'offline_access', @@ -251,6 +262,11 @@ const germanyAzureSettings: ProviderSettings = { endpointSuffix: '.core.cloudapi.de', azureResourceId: AzureResource.AzureStorage }, + powerBiResource: { + id: SettingIds.powerbi, + endpoint: 'https://analysis.windows.net/powerbi/api', + azureResourceId: AzureResource.PowerBi + }, redirectUri: 'https://vscode-redirect.azurewebsites.net/', scopes: [ 'openid', 'email', 'profile', 'offline_access', @@ -310,6 +326,11 @@ const chinaAzureSettings: ProviderSettings = { endpointSuffix: '.core.chinacloudapi.cn', azureResourceId: AzureResource.AzureStorage }, + powerBiResource: { + id: SettingIds.powerbi, + endpoint: 'https://analysis.windows.net/powerbi/api', + azureResourceId: AzureResource.PowerBi + }, redirectUri: 'https://vscode-redirect.azurewebsites.net/', scopes: [ 'openid', 'email', 'profile', 'offline_access', diff --git a/extensions/azurecore/src/azurecore.d.ts b/extensions/azurecore/src/azurecore.d.ts index 6c1d7df944..97de711686 100644 --- a/extensions/azurecore/src/azurecore.d.ts +++ b/extensions/azurecore/src/azurecore.d.ts @@ -130,10 +130,15 @@ declare module 'azurecore' { azureLogAnalyticsResource?: Resource; /** - * Information that describes the Azure Storage resourceI + * Information that describes the Azure Storage resource */ azureStorageResource?: Resource; + /** + * Information that describes the Power BI resource + */ + powerBiResource?: Resource; + /** * A list of tenant IDs to authenticate against. If defined, then these IDs will be used * instead of querying the tenants endpoint of the armResource diff --git a/src/sql/azdata.d.ts b/src/sql/azdata.d.ts index c10def27dd..57ec099533 100644 --- a/src/sql/azdata.d.ts +++ b/src/sql/azdata.d.ts @@ -2354,7 +2354,11 @@ declare module 'azdata' { /** * Kusto */ - AzureKusto = 10 + AzureKusto = 10, + /** + * Power BI + */ + PowerBi = 11 } export interface DidChangeAccountsParams { diff --git a/src/sql/workbench/api/common/sqlExtHostTypes.ts b/src/sql/workbench/api/common/sqlExtHostTypes.ts index 17b6d6654d..82ebf727a9 100644 --- a/src/sql/workbench/api/common/sqlExtHostTypes.ts +++ b/src/sql/workbench/api/common/sqlExtHostTypes.ts @@ -443,7 +443,8 @@ export enum AzureResource { MsGraph = 7, AzureLogAnalytics = 8, AzureStorage = 9, - AzureKusto = 10 + AzureKusto = 10, + PowerBi = 11 } export class TreeItem extends vsExtTypes.TreeItem { diff --git a/src/sql/workbench/services/connection/browser/connectionManagementService.ts b/src/sql/workbench/services/connection/browser/connectionManagementService.ts index 3f43f9f177..c43b791126 100644 --- a/src/sql/workbench/services/connection/browser/connectionManagementService.ts +++ b/src/sql/workbench/services/connection/browser/connectionManagementService.ts @@ -809,15 +809,45 @@ export class ConnectionManagementService extends Disposable implements IConnecti * @param connection The connection to fill in or update */ private getAzureResourceForConnection(connection: interfaces.IConnectionProfile): azdata.AzureResource { + // check if this is a PowerBI connection which is determined based on connection domain address + if (this.isPowerBiConnection(connection)) { + return AzureResource.PowerBi; + } + + // default to SQL if there are no provides or registered resources let provider = this._providers.get(connection.providerName); if (!provider || !provider.properties || !provider.properties.azureResource) { + this._logService.warn('Connection providers incorrectly registered. Defaulting to SQL Azure resource,'); return AzureResource.Sql; } + // lookup the Azure resource based on the provider azureResource properties let result = ConnectionManagementService._azureResources.find(r => AzureResource[r] === provider.properties.azureResource); return result ? result : AzureResource.Sql; } + /** + * Determine if a connection is to PowerBI based on the servers domain name. + * PowerBi servers will be in one of the hard-coded domains listed in this method, based on the + * Azure cloud being used. This method can be removed once the connection/AAD service is updated + * to parse the server endpoint using TDS prior to connecting. But that will need to be part of a + * larger refactoring of the connection & auth functionality. + * @param connection The connection profile that is to be checked. + */ + private isPowerBiConnection(connection: interfaces.IConnectionProfile): boolean { + if (!connection || !connection.serverName || connection.serverName.length === 0) { + return false; + } + let powerBiDomains = [ + 'pbidedicated.windows.net', + 'pbidedicated.cloudapi.de', + 'pbidedicated.usgovcloudapi.net', + 'pbidedicated.chinacloudapi.cn' + ]; + let serverName = connection.serverName.toLowerCase(); + return !!powerBiDomains.find(d => serverName.indexOf(d) >= 0); + } + /** * Fills in the account token if it's needed for this connection and doesn't already have one * and clears it if it isn't.