[Azure Arc] Update MIAA model to include encryption properties (#21702)

This commit is contained in:
Cheena Malhotra
2023-01-24 16:20:35 -08:00
committed by GitHub
parent 427a859c63
commit ef240a9a63
6 changed files with 107 additions and 12 deletions

View File

@@ -8,11 +8,15 @@ import * as vscode from 'vscode';
import { Deferred } from '../../common/promise';
import * as loc from '../../localizedConstants';
import { createCredentialId } from '../../common/utils';
import { credentialNamespace } from '../../constants';
import * as constants from '../../constants';
import { InitializingComponent } from '../components/initializingComponent';
import { ResourceModel } from '../../models/resourceModel';
import { ControllerModel } from '../../models/controllerModel';
export interface IReconnectAction {
(profile: azdata.IConnectionProfile): Promise<boolean>;
}
export abstract class ConnectToSqlDialog extends InitializingComponent {
protected modelBuilder!: azdata.ModelBuilder;
@@ -20,6 +24,9 @@ export abstract class ConnectToSqlDialog extends InitializingComponent {
protected usernameInputBox!: azdata.InputBoxComponent;
protected passwordInputBox!: azdata.InputBoxComponent;
protected rememberPwCheckBox!: azdata.CheckBoxComponent;
protected encryptSelectBox!: azdata.DropDownComponent;
protected trustServerCertificateSelectBox!: azdata.DropDownComponent;
private options: { [name: string]: any } = {};
protected _completionPromise = new Deferred<azdata.IConnectionProfile | undefined>();
@@ -29,7 +36,11 @@ export abstract class ConnectToSqlDialog extends InitializingComponent {
}
public showDialog(dialogTitle: string, connectionProfile?: azdata.IConnectionProfile): azdata.window.Dialog {
const dialog = azdata.window.createModelViewDialog(dialogTitle);
const dialog = azdata.window.createModelViewDialog(dialogTitle, undefined, 'narrow');
const trueCategory: azdata.CategoryValue = { displayName: loc.booleantrue, name: 'true' }
const falseCategory: azdata.CategoryValue = { displayName: loc.booleanfalse, name: 'false' }
const booleanCategoryValues: azdata.CategoryValue[] = [trueCategory, falseCategory];
dialog.cancelButton.onClick(() => this.handleCancel());
dialog.registerContent(async view => {
this.modelBuilder = view.modelBuilder;
@@ -47,13 +58,22 @@ export abstract class ConnectToSqlDialog extends InitializingComponent {
.withProps({
inputType: 'password',
value: connectionProfile?.password
})
.component();
}).component();
this.rememberPwCheckBox = this.modelBuilder.checkBox()
.withProps({
label: loc.rememberPassword,
checked: connectionProfile?.savePassword
}).component();
this.encryptSelectBox = this.modelBuilder.dropDown()
.withProps({
values: booleanCategoryValues,
value: connectionProfile?.options[constants.encryptOption] ? trueCategory : falseCategory
}).component();
this.trustServerCertificateSelectBox = this.modelBuilder.dropDown()
.withProps({
values: booleanCategoryValues,
value: connectionProfile?.options[constants.trustServerCertificateOption] ? trueCategory : falseCategory
}).component();
let formModel = this.modelBuilder.formContainer()
.withFormItems([{
@@ -73,6 +93,18 @@ export abstract class ConnectToSqlDialog extends InitializingComponent {
}, {
component: this.rememberPwCheckBox,
title: ''
}, {
component: this.encryptSelectBox,
title: loc.encrypt,
layout: {
info: loc.encryptDescription,
}
}, {
component: this.trustServerCertificateSelectBox,
title: loc.trustServerCertificate,
layout: {
info: loc.trustServerCertDescription,
}
}
],
title: ''
@@ -94,6 +126,10 @@ export abstract class ConnectToSqlDialog extends InitializingComponent {
if (!this.serverNameInputBox.value || !this.usernameInputBox.value || !this.passwordInputBox.value) {
return false;
}
this.options.encrypt = this.encryptSelectBox.value;
this.options.trustServerCertificate = this.trustServerCertificateSelectBox.value;
const connectionProfile: azdata.IConnectionProfile = {
serverName: this.serverNameInputBox.value,
databaseName: '',
@@ -109,10 +145,15 @@ export abstract class ConnectToSqlDialog extends InitializingComponent {
groupId: undefined,
options: this.options
};
return await this.connect(connectionProfile);
}
private async connect(connectionProfile: azdata.IConnectionProfile): Promise<boolean> {
const result = await azdata.connection.connect(connectionProfile, false, false);
if (result.connected) {
connectionProfile.id = result.connectionId!;
const credentialProvider = await azdata.credentials.getProvider(credentialNamespace);
const credentialProvider = await azdata.credentials.getProvider(constants.credentialNamespace);
if (connectionProfile.savePassword) {
await credentialProvider.saveCredential(createCredentialId(this._controllerModel.info.id, this._model.info.resourceType, this._model.info.name), connectionProfile.password);
} else {
@@ -123,10 +164,40 @@ export abstract class ConnectToSqlDialog extends InitializingComponent {
}
else {
vscode.window.showErrorMessage(this.connectionFailedMessage(result.errorMessage));
return false;
// Show error with instructions for MSSQL Provider Encryption error code -2146893019 thrown by SqlClient when certificate validation fails.
if (result.errorCode === -2146893019) {
return this.showInstructionTextAsWarning(connectionProfile, async updatedConnection => {
return await this.connect(updatedConnection);
});
} else {
return false;
}
}
}
private async showInstructionTextAsWarning(profile: azdata.IConnectionProfile, reconnectAction: IReconnectAction): Promise<boolean> {
while (true) {
const selection = await vscode.window.showWarningMessage(
loc.msgPromptSSLCertificateValidationFailed,
{ modal: false },
...[
loc.enableTrustServerCert,
loc.readMore,
loc.cancel
]);
if (selection === loc.enableTrustServerCert) {
profile.options.encrypt = true;
profile.options.trustServerCertificate = true;
return await reconnectAction(profile);
} else if (selection === loc.readMore) {
vscode.env.openExternal(vscode.Uri.parse(constants.encryptReadMoreLink));
// Show the dialog again so the user can still pick yes or no after they've read the docs
continue;
} else {
return false;
}
}
}
protected abstract get providerName(): string;
protected abstract connectionFailedMessage(error: any): string;