Initial commit for dSTS Auth (#13802)

* Initial commit for dSTS Auth

* Removed getDstsToken from accountManagementService. Renamed azureAccount to token.

* Renamed dstsToken to _token in connectionWidget

* Code Review Feedback. Renamed token to authToken in onFetchDatabases.

* Removed dsts options from Kusto package.json
This commit is contained in:
Justin M
2021-02-01 10:48:16 -08:00
committed by GitHub
parent 1c0259f4c5
commit 8f5dc1526a
6 changed files with 63 additions and 23 deletions

View File

@@ -47,8 +47,8 @@ export class ConnectionController implements IConnectionComponentController {
onCreateNewServerGroup: () => this.onCreateNewServerGroup(),
onAdvancedProperties: () => this.handleOnAdvancedProperties(),
onSetAzureTimeOut: () => this.handleonSetAzureTimeOut(),
onFetchDatabases: (serverName: string, authenticationType: string, userName?: string, password?: string, azureAccount?: string) => this.onFetchDatabases(
serverName, authenticationType, userName, password, azureAccount).then(result => {
onFetchDatabases: (serverName: string, authenticationType: string, userName?: string, password?: string, authToken?: string) => this.onFetchDatabases(
serverName, authenticationType, userName, password, authToken).then(result => {
return result;
}),
onAzureTenantSelection: (azureTenantId?: string) => this.onAzureTenantSelection(azureTenantId),
@@ -56,7 +56,7 @@ export class ConnectionController implements IConnectionComponentController {
this._providerName = providerName;
}
protected async onFetchDatabases(serverName: string, authenticationType: string, userName?: string, password?: string, azureAccount?: string): Promise<string[]> {
protected async onFetchDatabases(serverName: string, authenticationType: string, userName?: string, password?: string, authToken?: string): Promise<string[]> {
let tempProfile = this._model;
tempProfile.serverName = serverName;
tempProfile.authenticationType = authenticationType;
@@ -64,7 +64,7 @@ export class ConnectionController implements IConnectionComponentController {
tempProfile.password = password;
tempProfile.groupFullName = '';
tempProfile.saveProfile = false;
tempProfile.azureAccount = azureAccount;
tempProfile.azureAccount = authToken;
let uri = this._connectionManagementService.getConnectionUri(tempProfile);
if (this._databaseCache.has(uri)) {
let cachedDatabases: string[] = this._databaseCache.get(uri);

View File

@@ -42,7 +42,7 @@ export interface IConnectionComponentCallbacks {
onCreateNewServerGroup?: () => void;
onAdvancedProperties?: () => void;
onSetAzureTimeOut?: () => void;
onFetchDatabases?: (serverName: string, authenticationType: string, userName?: string, password?: string, azureAccount?: string) => Promise<string[]>;
onFetchDatabases?: (serverName: string, authenticationType: string, userName?: string, password?: string, token?: string) => Promise<string[]>;
onAzureTenantSelection?: (azureTenantId?: string) => void;
}

View File

@@ -251,7 +251,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
* @param connectionProfile Connection Profile
*/
public async addSavedPassword(connectionProfile: interfaces.IConnectionProfile): Promise<interfaces.IConnectionProfile> {
await this.fillInOrClearAzureToken(connectionProfile);
await this.fillInOrClearToken(connectionProfile);
return this._connectionStore.addSavedPassword(connectionProfile).then(result => result.profile);
}
@@ -310,7 +310,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
}
// Fill in the Azure account token if needed and open the connection dialog if it fails
let tokenFillSuccess = await this.fillInOrClearAzureToken(newConnection);
let tokenFillSuccess = await this.fillInOrClearToken(newConnection);
// If the password is required and still not loaded show the dialog
if ((!foundPassword && this._connectionStore.isPasswordRequired(newConnection) && !newConnection.password) || !tokenFillSuccess) {
@@ -468,7 +468,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
if (callbacks.onConnectStart) {
callbacks.onConnectStart();
}
let tokenFillSuccess = await this.fillInOrClearAzureToken(connection);
let tokenFillSuccess = await this.fillInOrClearToken(connection);
if (!tokenFillSuccess) {
throw new Error(nls.localize('connection.noAzureAccount', "Failed to get Azure account token for connection"));
}
@@ -803,17 +803,38 @@ export class ConnectionManagementService extends Disposable implements IConnecti
}
/**
* Fills in the Azure account token if it's needed for this connection and doesn't already have one
* 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.
* @param connection The connection to fill in or update
*/
private async fillInOrClearAzureToken(connection: interfaces.IConnectionProfile): Promise<boolean> {
if (connection.authenticationType !== Constants.azureMFA && connection.authenticationType !== Constants.azureMFAAndUser) {
private async fillInOrClearToken(connection: interfaces.IConnectionProfile): Promise<boolean> {
if (connection.authenticationType !== Constants.azureMFA
&& connection.authenticationType !== Constants.azureMFAAndUser
&& connection.authenticationType !== Constants.dstsAuth) {
connection.options['azureAccountToken'] = undefined;
return true;
}
let azureResource = this.getAzureResourceForConnection(connection);
const accounts = await this._accountManagementService.getAccounts();
if (connection.authenticationType === Constants.dstsAuth) {
let dstsAccounts = accounts.filter(a => a.key.providerId.startsWith('dstsAuth'));
if (dstsAccounts.length <= 0) {
connection.options['azureAccountToken'] = undefined;
return false;
}
dstsAccounts[0].key.providerArgs = {
serverName: connection.serverName,
databaseName: connection.databaseName
};
let tokenPromise = await this._accountManagementService.getAccountSecurityToken(dstsAccounts[0], undefined, undefined);
connection.options['azureAccountToken'] = tokenPromise.token;
return true;
}
const azureAccounts = accounts.filter(a => a.key.providerId.startsWith('azure'));
if (azureAccounts && azureAccounts.length > 0) {
let accountId = (connection.authenticationType === Constants.azureMFA || connection.authenticationType === Constants.azureMFAAndUser) ? connection.azureAccount : connection.userName;

View File

@@ -40,7 +40,8 @@ export enum AuthenticationType {
SqlLogin = 'SqlLogin',
Integrated = 'Integrated',
AzureMFA = 'AzureMFA',
AzureMFAAndUser = 'AzureMFAAndUser'
AzureMFAAndUser = 'AzureMFAAndUser',
dSTSAuth = 'dstsAuth'
}
export class ConnectionWidget extends lifecycle.Disposable {
@@ -65,6 +66,7 @@ export class ConnectionWidget extends lifecycle.Disposable {
private _defaultDatabaseName: string = localize('defaultDatabaseOption', "<Default>");
private _loadingDatabaseName: string = localize('loadingDatabaseOption', "Loading...");
private _serverGroupDisplayString: string = localize('serverGroup', "Server group");
private _token: string;
protected _container: HTMLElement;
protected _serverGroupSelectBox: SelectBox;
protected _authTypeSelectBox: SelectBox;
@@ -75,7 +77,7 @@ export class ConnectionWidget extends lifecycle.Disposable {
protected _databaseNameInputBox: Dropdown;
protected _advancedButton: Button;
private static readonly _authTypes: AuthenticationType[] =
[AuthenticationType.AzureMFA, AuthenticationType.AzureMFAAndUser, AuthenticationType.Integrated, AuthenticationType.SqlLogin];
[AuthenticationType.AzureMFA, AuthenticationType.AzureMFAAndUser, AuthenticationType.Integrated, AuthenticationType.SqlLogin, AuthenticationType.dSTSAuth];
private static readonly _osByName = {
Windows: OperatingSystem.Windows,
Macintosh: OperatingSystem.Macintosh,
@@ -364,7 +366,7 @@ export class ConnectionWidget extends lifecycle.Disposable {
this._databaseDropdownExpanded = true;
if (this.serverName) {
this._databaseNameInputBox.values = [this._loadingDatabaseName];
this._callbacks.onFetchDatabases(this.serverName, this.authenticationType, this.userName, this._password, this.azureAccount).then(databases => {
this._callbacks.onFetchDatabases(this.serverName, this.authenticationType, this.userName, this._password, this.authToken).then(databases => {
if (databases) {
this._databaseNameInputBox.values = databases.sort((a, b) => a.localeCompare(b));
} else {
@@ -504,6 +506,22 @@ export class ConnectionWidget extends lifecycle.Disposable {
this._tableContainer.classList.remove('hide-username');
this._tableContainer.classList.add('hide-password');
this._tableContainer.classList.remove('hide-azure-accounts');
} else if (currentAuthType === AuthenticationType.dSTSAuth) {
this._accountManagementService.getAccountsForProvider('dstsAuth').then(accounts => {
if (accounts && accounts.length > 0) {
accounts[0].key.providerArgs = {
serverName: this.serverName,
databaseName: this.databaseName
};
this._accountManagementService.getAccountSecurityToken(accounts[0], undefined, undefined).then(securityToken => {
this._token = securityToken.token;
});
}
});
this._tableContainer.classList.add('hide-username');
this._tableContainer.classList.add('hide-password');
this._tableContainer.classList.add('hide-azure-accounts');
} else {
this._azureAccountDropdown.disable();
this._azureAccountDropdown.hideMessage();
@@ -826,8 +844,14 @@ export class ConnectionWidget extends lifecycle.Disposable {
return this._authTypeSelectBox ? this.getAuthTypeName(this._authTypeSelectBox.value) : undefined;
}
public get azureAccount(): string {
return this.authenticationType === AuthenticationType.AzureMFAAndUser || this.authenticationType === AuthenticationType.AzureMFA ? this._azureAccountDropdown.value : undefined;
public get authToken(): string | undefined {
if (this.authenticationType === AuthenticationType.AzureMFAAndUser || this.authenticationType === AuthenticationType.AzureMFA) {
return this._azureAccountDropdown.value;
}
if (this.authenticationType === AuthenticationType.dSTSAuth) {
return this._token;
}
return undefined;
}
private validateAzureAccountSelection(showMessage: boolean = true): boolean {
@@ -883,7 +907,7 @@ export class ConnectionWidget extends lifecycle.Disposable {
model.userName = this.userName;
model.password = this.password;
model.authenticationType = this.authenticationType;
model.azureAccount = this.azureAccount;
model.azureAccount = this.authToken;
model.savePassword = this._rememberPasswordCheckBox.checked;
model.connectionName = this.connectionName;
model.databaseName = this.databaseName;