From 362290f8ecaac319df51601472ccab473910b2e9 Mon Sep 17 00:00:00 2001 From: Barbara Valdez <34872381+barbaravaldez@users.noreply.github.com> Date: Tue, 29 Aug 2023 13:28:17 -0700 Subject: [PATCH] Add security tab for server properties (#24209) Co-authored-by: Cory Rivera --- .../mssql/src/objectManagement/constants.ts | 1 + .../mssql/src/objectManagement/interfaces.ts | 20 +++++ .../objectManagement/localizedConstants.ts | 10 +++ .../ui/serverPropertiesDialog.ts | 80 ++++++++++++++++++- 4 files changed, 108 insertions(+), 3 deletions(-) diff --git a/extensions/mssql/src/objectManagement/constants.ts b/extensions/mssql/src/objectManagement/constants.ts index 159a8f07fb..0cc9cfd267 100644 --- a/extensions/mssql/src/objectManagement/constants.ts +++ b/extensions/mssql/src/objectManagement/constants.ts @@ -31,6 +31,7 @@ export const CreateDatabaseDocUrl = 'https://learn.microsoft.com/sql/t-sql/state export const ViewGeneralServerPropertiesDocUrl = 'https://learn.microsoft.com/sql/t-sql/functions/serverproperty-transact-sql'; export const ViewMemoryServerPropertiesDocUrl = 'https://learn.microsoft.com/sql/database-engine/configure-windows/server-properties-memory-page'; export const ViewProcessorsServerPropertiesDocUrl = 'https://learn.microsoft.com/sql/database-engine/configure-windows/server-properties-processors-page'; +export const ViewSecurityServerPropertiesDocUrl = 'https://learn.microsoft.com/sql/database-engine/configure-windows/server-properties-security-page'; export const DetachDatabaseDocUrl = 'https://go.microsoft.com/fwlink/?linkid=2240322'; export const DatabaseGeneralPropertiesDocUrl = 'https://learn.microsoft.com/sql/relational-databases/databases/database-properties-general-page'; export const DatabaseOptionsPropertiesDocUrl = 'https://learn.microsoft.com/sql/relational-databases/databases/database-properties-options-page' diff --git a/extensions/mssql/src/objectManagement/interfaces.ts b/extensions/mssql/src/objectManagement/interfaces.ts index bae4b5e08b..43d04e954f 100644 --- a/extensions/mssql/src/objectManagement/interfaces.ts +++ b/extensions/mssql/src/objectManagement/interfaces.ts @@ -538,6 +538,26 @@ export interface Server extends ObjectManagement.SqlObject { autoProcessorAffinityMaskForAll: boolean; autoProcessorAffinityIOMaskForAll: boolean; numaNodes: NumaNode[]; + authenticationMode: ServerLoginMode; + loginAuditing: AuditLevel; +} + +/** + * The server login types. + */ +export const enum ServerLoginMode { + Integrated, //windows auth only + Mixed // both sql server and windows auth +} + +/** + * The server audit levels. + */ +export const enum AuditLevel { + None, + Success, + Failure, + All } export interface NumericServerProperty { diff --git a/extensions/mssql/src/objectManagement/localizedConstants.ts b/extensions/mssql/src/objectManagement/localizedConstants.ts index 3e4dcc012f..b8f5a21219 100644 --- a/extensions/mssql/src/objectManagement/localizedConstants.ts +++ b/extensions/mssql/src/objectManagement/localizedConstants.ts @@ -287,6 +287,16 @@ export const processorLabel = localize('objectManagement.processorLabel', "Proce export const serverMemoryMaxLowerThanMinInputError: string = localize('objectManagement.serverMemoryMaxLowerThanMinInputError', "Maximum server memory cannot be lower than minimum server memory"); export const serverNumaNodeLabel = (value: string) => localize('objectManagement.serverNumaNodeLabel', "Numa Node {0}", value); export const serverCPULabel = (value: string) => localize('objectManagement.serverCPULabel', "CPU {0}", value); +export const securityText = localize('objectManagement.security', "Security"); +export const serverAuthenticationText = localize('objectManagement.serverAuthenticationText', "Server authentication"); +export const onlyWindowsAuthModeText = localize('objectManagement.onlyWindowsAuthModeText', "Windows Authentication mode"); +export const sqlServerAndWindowsAuthText = localize('objectManagement.sqlServerAndWindowsAuthText', "SQL Server and Windows Authentication mode"); +export const loginAuditingText = localize('objectManagement.loginAuditingText', "Login auditing"); +export const noLoginAuditingText = localize('objectManagement.noLoginAuditingText', "None"); +export const failedLoginsOnlyText = localize('objectManagement.failedLoginsOnlyText', "Failed logins only"); +export const successfulLoginsOnlyText = localize('objectManagement.successfulLoginsOnlyText', "Successful logins only"); +export const bothFailedAndSuccessfulLoginsText = localize('objectManagement.bothFailedAndSuccessfulLoginsText', "Both failed and successful logins"); +export const needToRestartServer = localize('objectManagement.needToRestartServer', "Changes require server restart in order to be effective"); //Database properties Dialog export const LastDatabaseBackupText = localize('objectManagement.lastDatabaseBackup', "Last Database Backup"); diff --git a/extensions/mssql/src/objectManagement/ui/serverPropertiesDialog.ts b/extensions/mssql/src/objectManagement/ui/serverPropertiesDialog.ts index 95f10d0791..3863688eef 100644 --- a/extensions/mssql/src/objectManagement/ui/serverPropertiesDialog.ts +++ b/extensions/mssql/src/objectManagement/ui/serverPropertiesDialog.ts @@ -3,12 +3,13 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as azdata from 'azdata'; +import * as vscode from 'vscode'; import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase'; import { DefaultColumnCheckboxWidth } from '../../ui/dialogBase'; import { IObjectManagementService } from 'mssql'; import * as localizedConstants from '../localizedConstants'; -import { ViewGeneralServerPropertiesDocUrl, ViewMemoryServerPropertiesDocUrl, ViewProcessorsServerPropertiesDocUrl } from '../constants'; -import { Server, ServerViewInfo, NumaNode, AffinityType } from '../interfaces'; +import { ViewGeneralServerPropertiesDocUrl, ViewMemoryServerPropertiesDocUrl, ViewProcessorsServerPropertiesDocUrl, ViewSecurityServerPropertiesDocUrl } from '../constants'; +import { Server, ServerViewInfo, NumaNode, AffinityType, ServerLoginMode, AuditLevel } from '../interfaces'; export class ServerPropertiesDialog extends ObjectManagementDialogBase { private generalTab: azdata.Tab; @@ -46,6 +47,19 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase { await this.handleAuthModeChange(); }); + this.sqlServerAndWindowsAuthRadioButton = this.createRadioButton(localizedConstants.sqlServerAndWindowsAuthText, radioServerGroupName, this.objectInfo.authenticationMode === ServerLoginMode.Mixed, async () => { await this.handleAuthModeChange(); }); + this.onlyWindowsAuthRadioButton.enabled = isEnabled; + this.sqlServerAndWindowsAuthRadioButton.enabled = isEnabled; + const serverAuthSection = this.createGroup(localizedConstants.serverAuthenticationText, [ + this.onlyWindowsAuthRadioButton, + this.sqlServerAndWindowsAuthRadioButton + ], true); + + const radioLoginsGroupName = 'serverLoginsRadioGroup'; + this.noneRadioButton = this.createRadioButton(localizedConstants.noLoginAuditingText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.None, async () => { await this.handleAuditLevelChange(); }); + this.failedLoginsOnlyRadioButton = this.createRadioButton(localizedConstants.failedLoginsOnlyText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.Failure, async () => { await this.handleAuditLevelChange(); }); + this.successfulLoginsOnlyRadioButton = this.createRadioButton(localizedConstants.successfulLoginsOnlyText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.Success, async () => { await this.handleAuditLevelChange(); }); + this.bothFailedAndSuccessfulLoginsRadioButton = this.createRadioButton(localizedConstants.bothFailedAndSuccessfulLoginsText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.All, async () => { await this.handleAuditLevelChange(); }); + const serverLoginSection = this.createGroup(localizedConstants.loginAuditingText, [ + this.noneRadioButton, + this.failedLoginsOnlyRadioButton, + this.successfulLoginsOnlyRadioButton, + this.bothFailedAndSuccessfulLoginsRadioButton + ], true); + this.securitySection = this.createGroup('', [ + serverAuthSection, + serverLoginSection + ], true); + + this.securityTab = this.createTab(this.securityTabId, localizedConstants.securityText, this.securitySection); + } + + private async handleAuthModeChange(): Promise { + if (this.onlyWindowsAuthRadioButton.checked) { + this.objectInfo.authenticationMode = ServerLoginMode.Integrated; + } + if (this.sqlServerAndWindowsAuthRadioButton.checked) { + this.objectInfo.authenticationMode = ServerLoginMode.Mixed; + } + await vscode.window.showInformationMessage(localizedConstants.needToRestartServer, { modal: true }); + } + + private async handleAuditLevelChange(): Promise { + if (this.noneRadioButton.checked) { + this.objectInfo.loginAuditing = AuditLevel.None; + } + if (this.failedLoginsOnlyRadioButton.checked) { + this.objectInfo.loginAuditing = AuditLevel.Failure; + } + if (this.successfulLoginsOnlyRadioButton.checked) { + this.objectInfo.loginAuditing = AuditLevel.Success; + } + if (this.bothFailedAndSuccessfulLoginsRadioButton.checked) { + this.objectInfo.loginAuditing = AuditLevel.All; + } + } }