Add support for Encrypt=Strict for TDS 8.0 connections with SQL Server 2022 (#21256)

This commit is contained in:
Cheena Malhotra
2023-02-10 10:34:36 -08:00
committed by GitHub
parent c75628639c
commit 3fb8d57d25
13 changed files with 256 additions and 24 deletions

View File

@@ -35,9 +35,11 @@ import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMess
import Severity from 'vs/base/common/severity';
import { ConnectionStringOptions } from 'sql/platform/capabilities/common/capabilitiesService';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { AuthenticationType } from 'sql/platform/connection/common/constants';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { AuthLibrary, filterAccounts } from 'sql/workbench/services/accountManagement/browser/accountDialog';
import { AuthenticationType, Actions } from 'sql/platform/connection/common/constants';
import { AdsWidget } from 'sql/base/browser/ui/adsWidget';
import { createCSSRule } from 'vs/base/browser/dom';
const ConnectionStringText = localize('connectionWidget.connectionString', "Connection string");
@@ -78,7 +80,7 @@ export class ConnectionWidget extends lifecycle.Disposable {
protected _providerName: string;
protected _connectionNameInputBox: InputBox;
protected _databaseNameInputBox: Dropdown;
protected _customOptionWidgets: (InputBox | SelectBox)[];
protected _customOptionWidgets: AdsWidget[];
protected _advancedButton: Button;
private static readonly _authTypes: AuthenticationType[] =
[AuthenticationType.AzureMFA, AuthenticationType.AzureMFAAndUser, AuthenticationType.Integrated, AuthenticationType.SqlLogin, AuthenticationType.DSTSAuth, AuthenticationType.None];
@@ -192,6 +194,7 @@ export class ConnectionWidget extends lifecycle.Disposable {
this.addConnectionNameOptions();
this.addAdvancedOptions();
this.updateRequiredStateForOptions();
this.registerOnSelectionChangeEvents();
if (this._connectionStringOptions.isEnabled) {
// update the UI based on connection string setting after initialization
this.handleConnectionStringOptionChange();
@@ -255,7 +258,8 @@ export class ConnectionWidget extends lifecycle.Disposable {
protected addAuthenticationTypeOption(authTypeChanged: boolean = false): void {
if (this._optionsMaps[ConnectionOptionSpecialType.authType]) {
let authType = DialogHelper.appendRow(this._tableContainer, this._optionsMaps[ConnectionOptionSpecialType.authType].displayName, 'connection-label', 'connection-input', 'auth-type-row');
let authType = DialogHelper.appendRow(this._tableContainer, this._optionsMaps[ConnectionOptionSpecialType.authType].displayName,
'connection-label', 'connection-input', 'auth-type-row');
DialogHelper.appendInputSelectBox(authType, this._authTypeSelectBox);
}
}
@@ -264,10 +268,12 @@ export class ConnectionWidget extends lifecycle.Disposable {
if (this._customOptions.length > 0) {
this._customOptionWidgets = [];
this._customOptions.forEach((option, i) => {
let customOptionsContainer = DialogHelper.appendRow(this._tableContainer, option.displayName, 'connection-label', 'connection-input', 'custom-connection-options', false, option.description, 100);
let customOptionsContainer = DialogHelper.appendRow(this._tableContainer, option.displayName, 'connection-label', 'connection-input',
['custom-connection-options', `option-${option.name}`], false, option.description, 100);
switch (option.valueType) {
case ServiceOptionType.boolean:
case ServiceOptionType.category:
let selectedValue = option.defaultValue;
let options = option.valueType === ServiceOptionType.category
@@ -282,7 +288,7 @@ export class ConnectionWidget extends lifecycle.Disposable {
return { text: v.displayName, value: v.value } as SelectOptionItemSQL;
});
this._customOptionWidgets[i] = new SelectBox(options, selectedValue, this._contextViewService, customOptionsContainer, { ariaLabel: option.displayName });
this._customOptionWidgets[i] = new SelectBox(options, selectedValue, this._contextViewService, customOptionsContainer, { ariaLabel: option.displayName }, option.name);
DialogHelper.appendInputSelectBox(customOptionsContainer, this._customOptionWidgets[i] as SelectBox);
this._register(styler.attachSelectBoxStyler(this._customOptionWidgets[i] as SelectBox, this._themeService));
break;
@@ -296,6 +302,70 @@ export class ConnectionWidget extends lifecycle.Disposable {
}
}
/**
* Registers on selection change event for connection options configured with 'onSelectionChange' property.
* TODO extend this to include collection of other main and advanced option widgets here.
*/
protected registerOnSelectionChangeEvents(): void {
//Register on selection change event for custom options
this._customOptionWidgets.forEach((widget, i) => {
if (widget instanceof SelectBox) {
this._registerSelectionChangeEvents([this._customOptionWidgets], this._customOptions[i], widget);
}
});
}
private _registerSelectionChangeEvents(collections: AdsWidget[][], option: azdata.ConnectionOption, widget: SelectBox) {
if (option.onSelectionChange) {
option.onSelectionChange.forEach((event) => {
this._register(widget.onDidSelect(value => {
let selectedValue = value.selected;
event?.dependentOptionActions?.forEach((optionAction) => {
let defaultValue: string | undefined = this._customOptions.find(o => o.name === optionAction.optionName)?.defaultValue;
let widget: AdsWidget | undefined = this._findWidget(collections, optionAction.optionName);
if (widget) {
createCSSRule(`.hide-${widget.id} .option-${widget.id}`, `display: none;`);
this._onValueChangeEvent(selectedValue, event.values, widget, defaultValue, optionAction.action);
}
});
}));
});
}
}
/**
* Finds Widget from provided collection of widgets using option name.
* @param collections collections of widgets to search for the widget with the widget Id
* @param id Widget Id
* @returns Widget if found, undefined otherwise
*/
private _findWidget(collections: AdsWidget[][], id: string): AdsWidget | undefined {
let foundWidget: AdsWidget | undefined;
collections.forEach((collection) => {
if (!foundWidget) {
foundWidget = collection.find(widget => widget.id === id);
}
});
return foundWidget;
}
private _onValueChangeEvent(selectedValue: string, acceptedValues: string[],
widget: AdsWidget, defaultValue: string, action: string): void {
if ((acceptedValues.includes(selectedValue.toLocaleLowerCase()) && action === Actions.Show)
|| (!acceptedValues.includes(selectedValue.toLocaleLowerCase()) && action === Actions.Hide)) {
this._tableContainer.classList.remove(`hide-${widget.id}`);
} else {
// Support more Widget classes here as needed.
if (widget instanceof SelectBox) {
widget.select(widget.values.indexOf(defaultValue));
} else if (widget instanceof InputBox) {
widget.value = defaultValue;
}
this._tableContainer.classList.add(`hide-${widget.id}`);
widget.hideMessage();
}
}
protected addServerNameOption(): void {
// Server name
let serverNameOption = this._optionsMaps[ConnectionOptionSpecialType.serverName];
@@ -832,7 +902,7 @@ export class ConnectionWidget extends lifecycle.Disposable {
if (value !== '') {
if (widget instanceof SelectBox) {
widget.selectWithOptionName(value);
} else {
} else if (widget instanceof InputBox) {
widget.value = value;
}
}