Add security tab for server properties (#24209)

Co-authored-by: Cory Rivera <corivera@microsoft.com>
This commit is contained in:
Barbara Valdez
2023-08-29 13:28:17 -07:00
committed by GitHub
parent a21aa840c9
commit 362290f8ec
4 changed files with 108 additions and 3 deletions

View File

@@ -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'

View File

@@ -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 {

View File

@@ -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");

View File

@@ -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<Server, ServerViewInfo> {
private generalTab: azdata.Tab;
@@ -46,6 +47,19 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
private processorsSection: azdata.GroupContainer;
private autoSetProcessorAffinityMaskForAllCheckbox: azdata.CheckBoxComponent;
private autoSetProcessorIOAffinityMaskForAllCheckbox: azdata.CheckBoxComponent;
private securityTab: azdata.Tab;
private readonly securityTabId: string = 'securityId';
private securitySection: azdata.GroupContainer;
// Server authentication radio buttons
private onlyWindowsAuthRadioButton: azdata.RadioButtonComponent;
private sqlServerAndWindowsAuthRadioButton: azdata.RadioButtonComponent;
// Login auditing radio buttons
private noneRadioButton: azdata.RadioButtonComponent;
private failedLoginsOnlyRadioButton: azdata.RadioButtonComponent;
private successfulLoginsOnlyRadioButton: azdata.RadioButtonComponent;
private bothFailedAndSuccessfulLoginsRadioButton: azdata.RadioButtonComponent;
private activeTabId: string;
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
@@ -62,6 +76,8 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
helpUrl = ViewMemoryServerPropertiesDocUrl;
case this.processorsTabId:
helpUrl = ViewProcessorsServerPropertiesDocUrl;
case this.securityTabId:
helpUrl = ViewSecurityServerPropertiesDocUrl;
default:
break;
}
@@ -74,7 +90,8 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
this.initializeGeneralSection();
this.initializeMemorySection();
this.initializeProcessorsSection();
const serverPropertiesTabGroup = { title: '', tabs: [this.generalTab, this.memoryTab, this.processorsTab] };
this.initializeSecuritySection();
const serverPropertiesTabGroup = { title: '', tabs: [this.generalTab, this.memoryTab, this.processorsTab, this.securityTab] };
const serverPropertiesTabbedPannel = this.modelView.modelBuilder.tabbedPanel()
.withTabs([serverPropertiesTabGroup])
.withProps({
@@ -425,4 +442,61 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
}
}
}
private initializeSecuritySection(): void {
// cannot change auth mode in sql managed instance or non windows instances
const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance && this.objectInfo.platform !== 'Windows';
const radioServerGroupName = 'serverAuthenticationRadioGroup';
this.onlyWindowsAuthRadioButton = this.createRadioButton(localizedConstants.onlyWindowsAuthModeText, radioServerGroupName, this.objectInfo.authenticationMode === ServerLoginMode.Integrated, async () => { 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<void> {
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<void> {
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;
}
}
}