Add support for custom endpoints (#23390)

* initial commit, add support for custom endpoints

* add template file with public azure endpoints

* add throw error, fix compile

* update description

* move custom provider to settings.json

* cleanup

* test

* wip

* try fix build error

* wip fix build issue

* add typings for package.json

* test remove default

* fix typings

* fix typing

* add object definitions

* add additional checks

* test define object

* add default

* remove default and extra checks

* Organize code well to fix integration tests (#23697)

* pr review updates

* fix custom setting checker

* fix default behavior

* add more required, change name for default cloud

* add one more required

* modify required properties to match with api

* Update extensions/azurecore/package.json

Co-authored-by: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com>

* Update extensions/azurecore/package.json

Co-authored-by: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com>

* pr review changes

* remove default value from display name

* make akv optional

* remove default name

* remove default

* update descriptions, function names

* add client ID

* small fix

* Update extensions/azurecore/package.nls.json

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>

* Update extensions/azurecore/package.json

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>

* updated names

* add custom for configkey

* providerSettingsJson -> customProviderSettings

---------

Co-authored-by: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com>
Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
This commit is contained in:
Christopher Suh 2023-07-18 14:16:53 -07:00 коммит произвёл GitHub
Родитель 04bce3f3ac
Коммит a752c84216
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 375 добавлений и 31 удалений

Просмотреть файл

@ -128,6 +128,133 @@
"Microsoft Authentication Library"
],
"deprecationMessage": "Warning: ADAL has been deprecated, and is scheduled to be removed in a future release. Please use MSAL (default option) instead."
},
"azure.customProviderSettings": {
"type": "array",
"description": "%config.customProviderSettings%",
"scope": "resource",
"items": {
"type": "object",
"description": "%config.providerSettingsTitle%",
"required": ["name", "settings"],
"properties":{
"name": {
"type": "string",
"default": "Azure Public",
"description": "%config.providerSettingsName%"
},
"settings": {
"type": "object",
"description": "%config.providerSettingsDescription%",
"required": ["metadata"],
"properties": {
"metadata": {
"type": "object",
"required": ["displayName", "id"],
"properties": {
"displayName": {
"type": "string",
"default": "Azure Public Cloud",
"description": "%config.providerSettingsMetadata%"
},
"id": {
"type": "string",
"default": "azure_publicCloud",
"description": "%config.providerSettingsId%"
},
"endpoints": {
"type": "object",
"required": ["host", "clientId", "scopes", "sqlResource", "microsoftResource", "armResource", "graphResource", "azureStorageResource"],
"properties": {
"type": "object",
"host": {
"type": "string",
"default": "https://login.microsoftonline.com/",
"description": "%config.providerSettings.endpoints.host%"
},
"clientId": {
"type": "string",
"default": "a69788c6-1d43-44ed-9ca3-b83e194da255",
"description": "%config.providerSettings.endpoints.clientId%"
},
"microsoftResource": {
"type": "string",
"default": "https://management.core.windows.net/",
"description": "%config.providerSettings.endpoints.microsoftResource%"
},
"graphResource": {
"type": "string",
"default": "https://graph.windows.net/",
"description": "%config.providerSettings.endpoints.graphResource%"
},
"msGraphResource": {
"type": "string",
"default": "https://graph.microsoft.com/",
"description": "%config.providerSettings.endpoints.msGraphResource%"
},
"armResource": {
"type": "string",
"default": "https://management.azure.com/",
"description": "%config.providerSettings.endpoints.armResource%"
},
"sqlResource": {
"type": "string",
"default": "https://database.windows.net/",
"description": "%config.providerSettings.endpoints.sqlResource%"
},
"azureKeyVaultResource": {
"type": "string",
"default": "https://vault.azure.net/",
"description": "%config.providerSettings.endpoints.azureKeyVaultResource%"
},
"azureLogAnalyticsResource": {
"type": "string",
"default": "https://api.loganalytics.io/",
"description": "%config.providerSettings.endpoints.logAnalytics%"
},
"azureStorageResource": {
"type": "object",
"properties": {
"endpoint": {
"type": "string",
"default": "",
"description": "%config.providerSettings.endpoints.azureStorageResource%"
},
"endpointSuffix": {
"type": "string",
"default": ".core.windows.net/",
"description": "%config.providerSettings.endpoints.azureStorageResourceSuffix%"
}
}
},
"azureKustoResource": {
"type": "string",
"default": "https://kusto.kusto.windows.net/",
"description": "%config.providerSettings.endpoints.azureKustoResource%"
},
"powerBiResource": {
"type": "string",
"default": "https://analysis.windows.net/powerbi/api/",
"description": "%config.providerSettings.endpoints.powerBiResource%"
},
"scopes": {
"type": "string",
"default": "https://management.azure.com/user_impersonation",
"description": "%config.providerSettings.endpoints.scopes%"
},
"portalEndpoint": {
"type": "string",
"default": "https://portal.azure.com",
"description": "%config.providerSettings.endpoints.portal%"
}
}
}
}
}
}
}
}
}
}
}
}

Просмотреть файл

@ -20,14 +20,33 @@
"config.azureAccountConfigurationSection": "Azure Account Configuration",
"config.enablePublicCloudDescription": "Should Azure public cloud integration be enabled",
"config.enableUsGovCloudDescription": "Should US Government Azure cloud (Fairfax) integration be enabled",
"config.enableUsNatCloudDescription": "Should US National Azure cloud integration be enabled",
"config.enableChinaCloudDescription": "Should Azure China integration be enabled",
"config.enableGermanyCloudDescription": "Should Azure Germany integration be enabled",
"config.azureAuthMethodConfigurationSection": "Azure Authentication Method",
"config.azureCodeGrantMethod": "Code Grant Method",
"config.azureDeviceCodeMethod": "Device Code Method",
"config.noSystemKeychain": "Disable system keychain integration. Credentials will be stored in a flat file in the user's home directory.",
"config.piiLogging": "Should Personally Identifiable Information (PII) be logged in the Azure Accounts output channel and the output channel log file.",
"config.loggingLevel": "[Optional] The verbosity of logging for the Azure Accounts extension.",
"config.authenticationLibrary": "The library used for the AAD auth flow. Please restart ADS after changing this option."
"config.authenticationLibrary": "The library used for the AAD auth flow. Please restart ADS after changing this option.",
"config.customProviderSettings": "Setting containing custom Azure authentication endpoints. Changes to this setting require a restart to take effect.",
"config.providerSettingsTitle": "Provider Settings",
"config.providerSettingsName": "Cloud Name",
"config.providerSettingsDescription": "Cloud Settings",
"config.providerSettingsMetadata": "Cloud Display Name",
"config.providerSettingsId": "Cloud ID",
"config.providerSettings.endpoints.host": "Host Endpoint",
"config.providerSettings.endpoints.clientId": "Client ID for Azure Data Studio",
"config.providerSettings.endpoints.microsoftResource": "Microsoft Resource Endpoint",
"config.providerSettings.endpoints.graphResource": "Graph Resource Endpoint",
"config.providerSettings.endpoints.msGraphResource": "Microsoft Graph Resource Endpoint",
"config.providerSettings.endpoints.armResource": "ARM Resource Endpoint",
"config.providerSettings.endpoints.sqlResource": "SQL Resource Endpoint",
"config.providerSettings.endpoints.azureKeyVaultResource": "Azure KeyVault Resource Endpoint",
"config.providerSettings.endpoints.logAnalytics": "Azure Log Analytics Endpoint",
"config.providerSettings.endpoints.azureStorageResource": "Azure Storage Resource Endpoint",
"config.providerSettings.endpoints.azureStorageResourceSuffix": "Azure Storage Resource Endpoint Suffix",
"config.providerSettings.endpoints.azureKustoResource": "Azure Kusto Resource Endpoint",
"config.providerSettings.endpoints.powerBiResource": "Power BI Resource Endpoint",
"config.providerSettings.endpoints.scopes": "Scopes Endpoint",
"config.providerSettings.endpoints.portal": "Azure Portal Endpoint"
}

Просмотреть файл

@ -72,9 +72,7 @@ export abstract class AzureAuth implements vscode.Disposable {
this.resources = [
this.metadata.settings.armResource,
this.metadata.settings.graphResource,
this.metadata.settings.azureKeyVaultResource
];
if (this.metadata.settings.sqlResource) {
this.resources.push(this.metadata.settings.sqlResource);
}
@ -90,6 +88,9 @@ export abstract class AzureAuth implements vscode.Disposable {
if (this.metadata.settings.azureLogAnalyticsResource) {
this.resources.push(this.metadata.settings.azureLogAnalyticsResource);
}
if (this.metadata.settings.azureKeyVaultResource) {
this.resources.push(this.metadata.settings.azureKeyVaultResource);
}
if (this.metadata.settings.azureKustoResource) {
this.resources.push(this.metadata.settings.azureKustoResource);
}

Просмотреть файл

@ -150,6 +150,11 @@ export class AzureAccountProviderService implements vscode.Disposable {
if (!oldConfigValue && newConfigValue) {
providerChanges.push(this.registerAccountProvider(provider));
}
// Case 4: Provider was added from JSON - register provider
if (provider.configKey !== 'enablePublicCloud' && provider.configKey !== 'enableUsGovCloud' && provider.configKey !== 'enableChinaCloud') {
providerChanges.push(this.registerAccountProvider(provider));
}
}
// Process all the changes before continuing

Просмотреть файл

@ -5,6 +5,21 @@
import * as azurecore from 'azurecore';
export const enum SettingIds {
marm = 'marm',
graph = 'graph',
msgraph = 'msgraph',
arm = 'arm',
sql = 'sql',
ossrdbms = 'ossrdbms',
vault = 'vault',
ado = 'ado',
ala = 'ala',
storage = 'storage',
kusto = 'kusto',
powerbi = 'powerbi'
}
/**
* Mapping of configuration key with the metadata to instantiate the account provider
*/
@ -20,6 +35,39 @@ export interface ProviderSettings {
metadata: azurecore.AzureAccountProviderMetadata;
}
/**
* Custom Provider settings mapping
*/
export type ProviderSettingsJson = {
name: string,
settings: {
configKey: string,
metadata: {
displayName: string,
id: string,
endpoints: {
host: string,
clientId: string,
microsoftResource: string,
graphResource: string,
msGraphResource?: string,
armResource: string,
sqlResource: string,
azureKeyVaultResource: string,
azureLogAnalyticsResource?: string,
azureStorageResource: {
endpoint: string,
endpointSuffix: string
}
azureKustoResource?: string,
powerBiResource?: string,
scopes: string,
portalEndpoint?: string
}
}
}
}
export interface Subscription {
id: string,
tenantId: string,

Просмотреть файл

@ -4,26 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vscode-nls';
import { ProviderSettings } from './interfaces';
import { ProviderSettings, SettingIds } from './interfaces';
import { AzureResource } from 'azdata';
import { updateCustomCloudProviderSettings } from '../utils';
const localize = nls.loadMessageBundle();
const enum SettingIds {
marm = 'marm',
graph = 'graph',
msgraph = 'msgraph',
arm = 'arm',
sql = 'sql',
ossrdbms = 'ossrdbms',
vault = 'vault',
ado = 'ado',
ala = 'ala',
storage = 'storage',
kusto = 'kusto',
powerbi = 'powerbi'
}
const publicAzureSettings: ProviderSettings = {
configKey: 'enablePublicCloud',
metadata: {
@ -246,5 +232,7 @@ const chinaAzureSettings: ProviderSettings = {
}
}
};
const allSettings = [publicAzureSettings, usGovAzureSettings, chinaAzureSettings];
let allSettings = [publicAzureSettings, usGovAzureSettings, chinaAzureSettings];
allSettings = updateCustomCloudProviderSettings(allSettings);
export default allSettings;

Просмотреть файл

@ -0,0 +1,32 @@
{
"clouds": [
{
"name": "Azure Public",
"settings": {
"configKey": "enablePublicCloud",
"metadata": {
"displayName": "Azure Public Cloud",
"id": "azure_publicCloud",
"endpoints": {
"host": "https://login.microsoftonline.com/",
"microsoftResource": "https://management.core.windows.net/",
"graphResource": "https://graph.windows.net/",
"msGraphResource": "https://graph.microsoft.com/",
"armResource": "https://management.azure.com/",
"sqlResource": "https://database.windows.net/",
"azureKeyVaultResource": "https://vault.azure.net/",
"azureLogAnalyticsResource": "https://api.loganalytics.io/",
"azureStorageResource": {
"endpoint": "",
"endpointSuffix": ".core.windows.net/"
},
"azureKustoResource": "https://kusto.kusto.windows.net/",
"powerBiResource": "https://analysis.windows.net/powerbi/api/",
"scopes": "https://management.azure.com/user_impersonation",
"portalEndpoint": "https://portal.azure.com"
}
}
}
}
]
}

4
extensions/azurecore/src/azurecore.d.ts поставляемый
Просмотреть файл

@ -91,7 +91,7 @@ declare module 'azurecore' {
/**
* Information that describes the Microsoft resource management resource
*/
microsoftResource?: Resource
microsoftResource: Resource
/**
* Information that describes the AAD graph resource
@ -121,7 +121,7 @@ declare module 'azurecore' {
/**
* Information that describes the Azure Key Vault resource
*/
azureKeyVaultResource: Resource;
azureKeyVaultResource?: Resource;
/**
* Information that describes the Azure Dev Ops resource

Просмотреть файл

@ -47,6 +47,10 @@ export const oldMsalCacheFileName = 'azureTokenCacheMsal-azure_publicCloud';
export const piiLogging = 'piiLogging';
export const CustomProviderSettings = 'customProviderSettings';
export const CustomProviderSettingsSection = AzureSection + '.' + CustomProviderSettings;
/** MSAL Account version */
export const AccountVersion = '2.0';

Просмотреть файл

@ -293,7 +293,7 @@ async function onDidChangeConfiguration(e: vscode.ConfigurationChangeEvent): Pro
if (vscode.workspace.getConfiguration(Constants.AzureSection).get('authenticationLibrary') === 'ADAL') {
void vscode.window.showInformationMessage(loc.deprecatedOption);
}
await utils.displayReloadAds(loc.reloadPrompt);
await utils.displayReloadAds('authenticationLibrary');
}
}

Просмотреть файл

@ -63,7 +63,9 @@ export const location = localize('azurecore.location', "Location");
export const subscription = localize('azurecore.subscription', "Subscription");
export const typeIcon = localize('azurecore.typeIcon', "Type Icon");
export const reloadPrompt = localize('azurecore.reloadPrompt', "Authentication Library has changed, please reload Azure Data Studio.");
export function reloadPrompt(sectionName: string): string {
return localize('azurecore.reloadPrompt', "{0} setting changed, please reload Azure Data Studio.", sectionName);
}
export const reloadPromptCacheClear = localize('azurecore.reloadPromptCacheClear', "Token cache has been cleared successfully, please reload Azure Data Studio.");
export const reloadChoice = localize('azurecore.reloadChoice', "Reload Azure Data Studio");

Просмотреть файл

@ -5,6 +5,7 @@
import * as loc from './localizedConstants';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import * as constants from './constants';
import { AzureRegion, azureResource } from 'azurecore';
@ -13,7 +14,11 @@ import { HttpClient } from './account-provider/auths/httpClient';
import { parse } from 'url';
import { getProxyAgentOptions } from './proxy';
import { HttpsProxyAgentOptions } from 'https-proxy-agent';
import { ProviderSettings, ProviderSettingsJson, SettingIds } from './account-provider/interfaces';
import { AzureResource } from 'azdata';
import { Logger } from './utils/Logger';
const localize = nls.loadMessageBundle();
const configProxy = 'proxy';
const configProxyStrictSSL = 'proxyStrictSSL';
const configProxyAuthorization = 'proxyAuthorization';
@ -161,6 +166,118 @@ export async function updateTenantIgnoreList(tenantIgnoreList: string[]): Promis
await configuration.update(constants.Filter, tenantIgnoreList, vscode.ConfigurationTarget.Global);
}
export function updateCustomCloudProviderSettings(defaultSettings: ProviderSettings[]): ProviderSettings[] {
let providerSettingsJson: ProviderSettingsJson[] | undefined = vscode.workspace.getConfiguration(constants.AzureSection).get(constants.CustomProviderSettings) as ProviderSettingsJson[];
vscode.workspace.onDidChangeConfiguration(async (changeEvent) => {
const impactProvider = changeEvent.affectsConfiguration(constants.CustomProviderSettingsSection);
if (impactProvider === true) {
await displayReloadAds(constants.CustomProviderSettingsSection);
}
});
if (providerSettingsJson && providerSettingsJson.length > 0) {
try {
for (let cloudProvider of providerSettingsJson) {
// build provider setting
let newSettings = buildCustomCloudProviderSettings(cloudProvider);
defaultSettings.push(newSettings)
Logger.info(`Custom provider settings loaded for ${cloudProvider.settings.metadata.displayName}`);
}
void vscode.window.showInformationMessage(localize('providerSettings.success', 'Successfully loaded custom endpoints from settings'));
} catch (error) {
void vscode.window.showErrorMessage(localize('providerSettings.error', 'Could not load endpoints from settings, please check the logs for more details.'));
console.error(error.message);
throw Error(error.message);
}
}
return defaultSettings;
}
function buildCustomCloudProviderSettings(customProvider: ProviderSettingsJson): ProviderSettings {
// build provider setting
let newSettings: ProviderSettings = {
configKey: 'enableCustom' + customProvider.settings.metadata.id,
metadata: {
displayName: customProvider.settings.metadata.displayName,
id: customProvider.settings.metadata.id,
settings: {
host: customProvider.settings.metadata.endpoints.host,
clientId: customProvider.settings.metadata.endpoints.clientId,
microsoftResource: {
id: SettingIds.marm,
endpoint: customProvider.settings.metadata.endpoints.microsoftResource,
azureResourceId: AzureResource.MicrosoftResourceManagement
},
armResource: {
id: SettingIds.arm,
endpoint: customProvider.settings.metadata.endpoints.armResource,
azureResourceId: AzureResource.ResourceManagement
},
graphResource: {
id: SettingIds.graph,
endpoint: customProvider.settings.metadata.endpoints.graphResource,
azureResourceId: AzureResource.Graph
},
azureStorageResource: {
id: SettingIds.storage,
endpoint: customProvider.settings.metadata.endpoints.azureStorageResource.endpoint,
endpointSuffix: customProvider.settings.metadata.endpoints.azureStorageResource.endpointSuffix,
azureResourceId: AzureResource.AzureStorage
},
sqlResource: {
id: SettingIds.sql,
endpoint: customProvider.settings.metadata.endpoints.sqlResource,
azureResourceId: AzureResource.Sql
},
redirectUri: 'http://localhost',
scopes: [
'openid', 'email', 'profile', 'offline_access',
customProvider.settings.metadata.endpoints.scopes
],
}
}
};
if (customProvider.settings.metadata.endpoints.msGraphResource) {
newSettings.metadata.settings.msGraphResource = {
id: SettingIds.msgraph,
endpoint: customProvider.settings.metadata.endpoints.msGraphResource,
azureResourceId: AzureResource.MsGraph
};
}
if (customProvider.settings.metadata.endpoints.azureLogAnalyticsResource) {
newSettings.metadata.settings.azureLogAnalyticsResource = {
id: SettingIds.ala,
endpoint: customProvider.settings.metadata.endpoints.azureLogAnalyticsResource,
azureResourceId: AzureResource.AzureLogAnalytics
};
}
if (customProvider.settings.metadata.endpoints.azureKustoResource) {
newSettings.metadata.settings.azureKustoResource = {
id: SettingIds.kusto,
endpoint: customProvider.settings.metadata.endpoints.azureKustoResource,
azureResourceId: AzureResource.AzureKusto
};
}
if (customProvider.settings.metadata.endpoints.azureKeyVaultResource) {
newSettings.metadata.settings.azureKeyVaultResource = {
id: SettingIds.vault,
endpoint: customProvider.settings.metadata.endpoints.azureKeyVaultResource,
azureResourceId: AzureResource.AzureKeyVault
};
}
if (customProvider.settings.metadata.endpoints.powerBiResource) {
newSettings.metadata.settings.powerBiResource = {
id: SettingIds.powerbi,
endpoint: customProvider.settings.metadata.endpoints.powerBiResource,
azureResourceId: AzureResource.PowerBi
};
}
if (customProvider.settings.metadata.endpoints.portalEndpoint) {
newSettings.metadata.settings.portalEndpoint = customProvider.settings.metadata.endpoints.portalEndpoint;
}
return newSettings;
}
export function getResourceTypeIcon(appContext: AppContext, type: string): string {
switch (type) {
case azureResource.AzureResourceType.sqlServer:
@ -201,12 +318,13 @@ export function getProxyEnabledHttpClient(): HttpClient {
return new HttpClient(proxy, agentOptions);
}
/* Display notification with button to reload
* return true if button clicked
* return false if button not clicked
/**
* Display notification with button to reload
* @param sectionName Name of section to reload
* @returns true if reload clicked, false otherwise.
*/
export async function displayReloadAds(message: string): Promise<boolean> {
const result = await vscode.window.showInformationMessage(message, loc.reloadChoice);
export async function displayReloadAds(sectionName: string): Promise<boolean> {
const result = await vscode.window.showInformationMessage(loc.reloadPrompt(sectionName), loc.reloadChoice);
if (result === loc.reloadChoice) {
await vscode.commands.executeCommand('workbench.action.reloadWindow');
return true;