mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-28 09:35:38 -05:00
Add ability to select AAD tenant when connecting (#3475)
This commit is contained in:
@@ -769,8 +769,19 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let tokens = await this._accountManagementService.getSecurityToken(account, AzureResource.Sql);
|
||||
connection.options['azureAccountToken'] = Object.values(tokens)[0].token;
|
||||
let tokensByTenant = await this._accountManagementService.getSecurityToken(account, AzureResource.Sql);
|
||||
let token: string;
|
||||
let tenantId = connection.azureTenantId;
|
||||
if (tenantId && tokensByTenant[tenantId]) {
|
||||
token = tokensByTenant[tenantId].token;
|
||||
} else {
|
||||
let tokens = Object.values(tokensByTenant);
|
||||
if (tokens.length === 0) {
|
||||
return false;
|
||||
}
|
||||
token = Object.values(tokensByTenant)[0].token;
|
||||
}
|
||||
connection.options['azureAccountToken'] = token;
|
||||
connection.options['password'] = '';
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
|
||||
this.savePassword = model.savePassword;
|
||||
this.saveProfile = model.saveProfile;
|
||||
this._id = model.id;
|
||||
this.azureTenantId = model.azureTenantId;
|
||||
} else {
|
||||
//Default for a new connection
|
||||
this.savePassword = false;
|
||||
@@ -84,6 +85,14 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
|
||||
this._id = value;
|
||||
}
|
||||
|
||||
public get azureTenantId(): string {
|
||||
return this.options['azureTenantId'];
|
||||
}
|
||||
|
||||
public set azureTenantId(value: string) {
|
||||
this.options['azureTenantId'] = value;
|
||||
}
|
||||
|
||||
public get groupFullName(): string {
|
||||
return this._groupName;
|
||||
}
|
||||
@@ -159,7 +168,8 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
|
||||
userName: this.userName,
|
||||
options: this.options,
|
||||
saveProfile: this.saveProfile,
|
||||
id: this.id
|
||||
id: this.id,
|
||||
azureTenantId: this.azureTenantId
|
||||
};
|
||||
|
||||
return result;
|
||||
|
||||
@@ -52,9 +52,11 @@ export class ConnectionWidget {
|
||||
private _password: string;
|
||||
private _rememberPasswordCheckBox: Checkbox;
|
||||
private _azureAccountDropdown: SelectBox;
|
||||
private _azureTenantDropdown: SelectBox;
|
||||
private _refreshCredentialsLinkBuilder: Builder;
|
||||
private _addAzureAccountMessage: string = localize('connectionWidget.AddAzureAccount', 'Add an account...');
|
||||
private readonly _azureProviderId = 'azurePublicCloud';
|
||||
private _azureTenantId: string;
|
||||
private _azureAccountList: sqlops.Account[];
|
||||
private _advancedButton: Button;
|
||||
private _callbacks: IConnectionComponentCallbacks;
|
||||
@@ -215,6 +217,12 @@ export class ConnectionWidget {
|
||||
let refreshCredentialsBuilder = DialogHelper.appendRow(this._tableContainer, '', 'connection-label', 'connection-input', 'azure-account-row refresh-credentials-link');
|
||||
this._refreshCredentialsLinkBuilder = refreshCredentialsBuilder.a({ href: '#' }).text(localize('connectionWidget.refreshAzureCredentials', 'Refresh account credentials'));
|
||||
|
||||
// Azure tenant picker
|
||||
let tenantLabel = localize('connection.azureTenantDropdownLabel', 'Azure AD tenant');
|
||||
let tenantDropdownBuilder = DialogHelper.appendRow(this._tableContainer, tenantLabel, 'connection-label', 'connection-input', 'azure-account-row azure-tenant-row');
|
||||
this._azureTenantDropdown = new SelectBox([], undefined, this._contextViewService, tenantDropdownBuilder.getContainer(), { ariaLabel: tenantLabel });
|
||||
DialogHelper.appendInputSelectBox(tenantDropdownBuilder, this._azureTenantDropdown);
|
||||
|
||||
// Database
|
||||
let databaseOption = this._optionsMaps[ConnectionOptionSpecialType.databaseName];
|
||||
let databaseNameBuilder = DialogHelper.appendRow(this._tableContainer, databaseOption.displayName, 'connection-label', 'connection-input');
|
||||
@@ -308,6 +316,13 @@ export class ConnectionWidget {
|
||||
}));
|
||||
}
|
||||
|
||||
if (this._azureTenantDropdown) {
|
||||
this._toDispose.push(styler.attachSelectBoxStyler(this._azureTenantDropdown, this._themeService));
|
||||
this._toDispose.push(this._azureTenantDropdown.onDidSelect((selectInfo) => {
|
||||
this.onAzureTenantSelected(selectInfo.index);
|
||||
}));
|
||||
}
|
||||
|
||||
if (this._refreshCredentialsLinkBuilder) {
|
||||
this._toDispose.push(this._refreshCredentialsLinkBuilder.on(DOM.EventType.CLICK, async () => {
|
||||
let account = this._azureAccountList.find(account => account.key.accountId === this._azureAccountDropdown.value);
|
||||
@@ -426,7 +441,7 @@ export class ConnectionWidget {
|
||||
accountDropdownOptions.push(this._addAzureAccountMessage);
|
||||
this._azureAccountDropdown.setOptions(accountDropdownOptions);
|
||||
this._azureAccountDropdown.selectWithOptionName(oldSelection);
|
||||
this.updateRefreshCredentialsLink();
|
||||
await this.onAzureAccountSelected();
|
||||
}
|
||||
|
||||
private async updateRefreshCredentialsLink(): Promise<void> {
|
||||
@@ -441,7 +456,6 @@ export class ConnectionWidget {
|
||||
private async onAzureAccountSelected(): Promise<void> {
|
||||
// Reset the dropdown's validation message if the old selection was not valid but the new one is
|
||||
this.validateAzureAccountSelection(false);
|
||||
this._refreshCredentialsLinkBuilder.display('none');
|
||||
|
||||
// Open the add account dialog if needed, then select the added account
|
||||
if (this._azureAccountDropdown.value === this._addAzureAccountMessage) {
|
||||
@@ -461,6 +475,35 @@ export class ConnectionWidget {
|
||||
}
|
||||
|
||||
this.updateRefreshCredentialsLink();
|
||||
|
||||
// Display the tenant select box if needed
|
||||
const hideTenantsClassName = 'hide-azure-tenants';
|
||||
let selectedAccount = this._azureAccountList.find(account => account.key.accountId === this._azureAccountDropdown.value);
|
||||
if (selectedAccount && selectedAccount.properties.tenants && selectedAccount.properties.tenants.length > 1) {
|
||||
// There are multiple tenants available so let the user select one
|
||||
let options = selectedAccount.properties.tenants.map(tenant => tenant.displayName);
|
||||
this._azureTenantDropdown.setOptions(options);
|
||||
this._tableContainer.getContainer().classList.remove(hideTenantsClassName);
|
||||
this.onAzureTenantSelected(0);
|
||||
} else {
|
||||
if (selectedAccount && selectedAccount.properties.tenants && selectedAccount.properties.tenants.length === 1) {
|
||||
this._azureTenantId = selectedAccount.properties.tenants[0].id;
|
||||
} else {
|
||||
this._azureTenantId = undefined;
|
||||
}
|
||||
this._tableContainer.getContainer().classList.add(hideTenantsClassName);
|
||||
}
|
||||
}
|
||||
|
||||
private onAzureTenantSelected(tenantIndex: number): void {
|
||||
this._azureTenantId = undefined;
|
||||
let account = this._azureAccountList.find(account => account.key.accountId === this._azureAccountDropdown.value);
|
||||
if (account && account.properties.tenants) {
|
||||
let tenant = account.properties.tenants[tenantIndex];
|
||||
if (tenant) {
|
||||
this._azureTenantId = tenant.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private serverNameChanged(serverName: string) {
|
||||
@@ -518,6 +561,7 @@ export class ConnectionWidget {
|
||||
this._passwordInputBox.value = connectionInfo.password ? Constants.passwordChars : '';
|
||||
this._password = this.getModelValue(connectionInfo.password);
|
||||
this._saveProfile = connectionInfo.saveProfile;
|
||||
this._azureTenantId = connectionInfo.azureTenantId;
|
||||
let groupName: string;
|
||||
if (this._saveProfile) {
|
||||
if (!connectionInfo.groupFullName) {
|
||||
@@ -551,6 +595,22 @@ export class ConnectionWidget {
|
||||
tableContainerElement.classList.add('hide-azure-accounts');
|
||||
}
|
||||
|
||||
if (this.authType === AuthenticationType.AzureMFA) {
|
||||
this.fillInAzureAccountOptions().then(async () => {
|
||||
this._azureAccountDropdown.selectWithOptionName(this.getModelValue(connectionInfo.userName));
|
||||
await this.onAzureAccountSelected();
|
||||
let tenantId = connectionInfo.azureTenantId;
|
||||
let account = this._azureAccountList.find(account => account.key.accountId === this._azureAccountDropdown.value);
|
||||
if (account && account.properties.tenants.length > 1) {
|
||||
let tenant = account.properties.tenants.find(tenant => tenant.id === tenantId);
|
||||
if (tenant) {
|
||||
this._azureTenantDropdown.selectWithOptionName(tenant.displayName);
|
||||
}
|
||||
this.onAzureTenantSelected(this._azureTenantDropdown.values.indexOf(this._azureTenantDropdown.value));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Disable connect button if -
|
||||
// 1. Authentication type is SQL Login and no username is provided
|
||||
// 2. No server name is provided
|
||||
@@ -716,6 +776,9 @@ export class ConnectionWidget {
|
||||
model.saveProfile = true;
|
||||
model.groupId = this.findGroupId(model.groupFullName);
|
||||
}
|
||||
if (this.authType === AuthenticationType.AzureMFA) {
|
||||
model.azureTenantId = this._azureTenantId;
|
||||
}
|
||||
}
|
||||
return validInputs;
|
||||
}
|
||||
|
||||
@@ -128,3 +128,7 @@
|
||||
.hide-refresh-link .azure-account-row.refresh-credentials-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hide-azure-tenants .azure-tenant-row {
|
||||
display: none;
|
||||
}
|
||||
|
||||
1
src/sql/sqlops.d.ts
vendored
1
src/sql/sqlops.d.ts
vendored
@@ -214,6 +214,7 @@ declare module 'sqlops' {
|
||||
providerName: string;
|
||||
saveProfile: boolean;
|
||||
id: string;
|
||||
azureTenantId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user