remove auth type from user (#22905)

* remove auth type from user

* vbump sts
This commit is contained in:
Alan Ren
2023-05-01 13:29:55 -07:00
committed by GitHub
parent af6f9089f7
commit 6a7899281a
10 changed files with 157 additions and 217 deletions

View File

@@ -1,6 +1,6 @@
{ {
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
"version": "4.7.0.23", "version": "4.7.0.24",
"downloadFileNames": { "downloadFileNames": {
"Windows_86": "win-x86-net7.0.zip", "Windows_86": "win-x86-net7.0.zip",
"Windows_64": "win-x64-net7.0.zip", "Windows_64": "win-x64-net7.0.zip",

View File

@@ -1027,17 +1027,9 @@ declare module 'mssql' {
*/ */
export interface LoginViewInfo extends ObjectViewInfo<Login> { export interface LoginViewInfo extends ObjectViewInfo<Login> {
/** /**
* Whether Windows Authentication is supported. * The authentication types supported by the server.
*/ */
supportWindowsAuthentication: boolean; authenticationTypes: AuthenticationType[];
/**
* Whether Azure Active Directory Authentication is supported.
*/
supportAADAuthentication: boolean;
/**
* Whether SQL Authentication is supported.
*/
supportSQLAuthentication: boolean;
/** /**
* Whether the locked out state can be changed. * Whether the locked out state can be changed.
*/ */
@@ -1119,21 +1111,25 @@ declare module 'mssql' {
*/ */
export const enum UserType { export const enum UserType {
/** /**
* User with a server level login. * Mapped to a server login.
*/ */
WithLogin = 'WithLogin', LoginMapped = 'LoginMapped',
/** /**
* User based on a Windows user/group that has no login, but can connect to the Database Engine through membership in a Windows group. * Mapped to a Windows user or group.
*/ */
WithWindowsGroupLogin = 'WithWindowsGroupLogin', WindowsUser = 'WindowsUser',
/** /**
* Contained user, authentication is done within the database. * Authenticate with password.
*/ */
Contained = 'Contained', SqlAuthentication = 'SqlAuthentication',
/**
* Authenticate with Azure Active Directory.
*/
AADAuthentication = 'AADAuthentication',
/** /**
* User that cannot authenticate. * User that cannot authenticate.
*/ */
NoConnectAccess = 'NoConnectAccess' NoLoginAccess = 'NoLoginAccess'
} }
/** /**
@@ -1166,11 +1162,6 @@ declare module 'mssql' {
* Only applicable when the user type is 'Contained'. * Only applicable when the user type is 'Contained'.
*/ */
defaultLanguage: string | undefined; defaultLanguage: string | undefined;
/**
* Authentication type.
* Only applicable when user type is 'Contained'.
*/
authenticationType: AuthenticationType | undefined;
/** /**
* Password of the user. * Password of the user.
* Only applicable when the user type is 'Contained' and the authentication type is 'Sql'. * Only applicable when the user type is 'Contained' and the authentication type is 'Sql'.
@@ -1183,21 +1174,9 @@ declare module 'mssql' {
*/ */
export interface UserViewInfo extends ObjectViewInfo<User> { export interface UserViewInfo extends ObjectViewInfo<User> {
/** /**
* Whether contained user is supported. * All user types supported by the database.
*/ */
supportContainedUser: boolean; userTypes: UserType[];
/**
* Whether Windows authentication is supported.
*/
supportWindowsAuthentication: boolean;
/**
* Whether Azure Active Directory authentication is supported.
*/
supportAADAuthentication: boolean;
/**
* Whether SQL Authentication is supported.
*/
supportSQLAuthentication: boolean;
/** /**
* All languages supported by the database. * All languages supported by the database.
*/ */

View File

@@ -14,7 +14,7 @@ import * as localizedConstants from './localizedConstants';
import { UserDialog } from './ui/userDialog'; import { UserDialog } from './ui/userDialog';
import { IObjectManagementService, ObjectManagement } from 'mssql'; import { IObjectManagementService, ObjectManagement } from 'mssql';
import * as constants from '../constants'; import * as constants from '../constants';
import { getNodeTypeDisplayName, refreshParentNode } from './utils'; import { refreshParentNode } from './utils';
import { TelemetryReporter } from '../telemetry'; import { TelemetryReporter } from '../telemetry';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './ui/objectManagementDialogBase'; import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './ui/objectManagementDialogBase';
import { ServerRoleDialog } from './ui/serverRoleDialog'; import { ServerRoleDialog } from './ui/serverRoleDialog';
@@ -91,7 +91,7 @@ async function handleNewObjectDialogCommand(context: azdata.ObjectExplorerContex
objectType: context.nodeInfo!.nodeType objectType: context.nodeInfo!.nodeType
}).send(); }).send();
console.error(err); console.error(err);
await vscode.window.showErrorMessage(localizedConstants.OpenNewObjectDialogError(getNodeTypeDisplayName(objectType), getErrorMessage(err))); await vscode.window.showErrorMessage(localizedConstants.OpenNewObjectDialogError(localizedConstants.getNodeTypeDisplayName(objectType), getErrorMessage(err)));
} }
} }
@@ -120,7 +120,7 @@ async function handleObjectPropertiesDialogCommand(context: azdata.ObjectExplore
objectType: context.nodeInfo!.nodeType objectType: context.nodeInfo!.nodeType
}).send(); }).send();
console.error(err); console.error(err);
await vscode.window.showErrorMessage(localizedConstants.OpenObjectPropertiesDialogError(getNodeTypeDisplayName(context.nodeInfo!.nodeType), context.nodeInfo!.label, getErrorMessage(err))); await vscode.window.showErrorMessage(localizedConstants.OpenObjectPropertiesDialogError(localizedConstants.getNodeTypeDisplayName(context.nodeInfo!.nodeType), context.nodeInfo!.label, getErrorMessage(err)));
} }
} }
@@ -137,7 +137,7 @@ async function handleDeleteObjectCommand(context: azdata.ObjectExplorerContext,
default: default:
break; break;
} }
const nodeTypeDisplayName = getNodeTypeDisplayName(context.nodeInfo!.nodeType); const nodeTypeDisplayName = localizedConstants.getNodeTypeDisplayName(context.nodeInfo!.nodeType);
let confirmMessage = localizedConstants.DeleteObjectConfirmationText(nodeTypeDisplayName, context.nodeInfo!.label); let confirmMessage = localizedConstants.DeleteObjectConfirmationText(nodeTypeDisplayName, context.nodeInfo!.label);
if (additionalConfirmationMessage) { if (additionalConfirmationMessage) {
confirmMessage = `${additionalConfirmationMessage} ${confirmMessage}`; confirmMessage = `${additionalConfirmationMessage} ${confirmMessage}`;
@@ -179,7 +179,7 @@ async function handleRenameObjectCommand(context: azdata.ObjectExplorerContext,
if (!connectionUri) { if (!connectionUri) {
return; return;
} }
const nodeTypeDisplayName = getNodeTypeDisplayName(context.nodeInfo!.nodeType); const nodeTypeDisplayName = localizedConstants.getNodeTypeDisplayName(context.nodeInfo!.nodeType);
const originalName = context.nodeInfo!.metadata!.name; const originalName = context.nodeInfo!.metadata!.name;
const newName = await vscode.window.showInputBox({ const newName = await vscode.window.showInputBox({
title: localizedConstants.RenameObjectDialogTitle, title: localizedConstants.RenameObjectDialogTitle,

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { ObjectManagement } from 'mssql';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
// Object Types // Object Types
@@ -167,10 +168,11 @@ export const OldPasswordCannotBeEmptyError = localize('objectManagement.login.ol
// User // User
export const UserTypeText = localize('objectManagement.user.type', "Type"); export const UserTypeText = localize('objectManagement.user.type', "Type");
export const UserWithLoginText = localize('objectManagement.user.userWithLogin', "User with login"); export const UserType_LoginMapped = localize('objectManagement.user.loginMapped', "Mapped to a server login");
export const UserWithWindowsGroupLoginText = localize('objectManagement.user.userWithGroupLogin', "User with Windows group login"); export const UserType_WindowsUser = localize('objectManagement.user.windowsUser', "Mapped to a Windows user/group");
export const ContainedUserText = localize('objectManagement.user.containedUser', "Contained user"); export const UserType_SqlAuthentication = localize('objectManagement.user.sqlAuth', "Authenticate with password");
export const UserWithNoConnectAccess = localize('objectManagement.user.userWithNoConnectAccess', "User with no connect access"); export const UserType_AADAuthentication = localize('objectManagement.user.aadAuth', "Authenticate with Azure Active Directory");
export const UserType_NoLoginAccess = localize('objectManagement.user.noLogin', "No Login Access");
export const DefaultSchemaText = localize('objectManagement.user.defaultSchemaLabel', "Default schema"); export const DefaultSchemaText = localize('objectManagement.user.defaultSchemaLabel', "Default schema");
export const LoginText = localize('objectManagement.user.loginLabel', "Login"); export const LoginText = localize('objectManagement.user.loginLabel', "Login");
export const OwnedSchemaSectionHeader = localize('objectManagement.user.ownedSchemasLabel', "Owned Schemas"); export const OwnedSchemaSectionHeader = localize('objectManagement.user.ownedSchemasLabel', "Owned Schemas");
@@ -193,3 +195,72 @@ export const LoadingObjectsText = localize('objectManagement.loadingObjectsLabel
export function LoadingObjectsCompletedText(count: number): string { export function LoadingObjectsCompletedText(count: number): string {
return localize('objectManagement.loadingObjectsCompletedLabel', "Loading objects completed, {0} objects found", count); return localize('objectManagement.loadingObjectsCompletedLabel', "Loading objects completed, {0} objects found", count);
} }
// Util functions
export function getNodeTypeDisplayName(type: string, inTitle: boolean = false): string {
switch (type) {
case ObjectManagement.NodeType.ApplicationRole:
return inTitle ? ApplicationRoleTypeDisplayNameInTitle : ApplicationRoleTypeDisplayName;
case ObjectManagement.NodeType.DatabaseRole:
return inTitle ? DatabaseRoleTypeDisplayNameInTitle : DatabaseRoleTypeDisplayName;
case ObjectManagement.NodeType.ServerLevelLogin:
return inTitle ? LoginTypeDisplayNameInTitle : LoginTypeDisplayName;
case ObjectManagement.NodeType.ServerLevelServerRole:
return inTitle ? ServerRoleTypeDisplayNameInTitle : ServerRoleTypeDisplayName;
case ObjectManagement.NodeType.User:
return inTitle ? UserTypeDisplayNameInTitle : UserTypeDisplayName;
case ObjectManagement.NodeType.Table:
return TableTypeDisplayName;
case ObjectManagement.NodeType.View:
return ViewTypeDisplayName;
case ObjectManagement.NodeType.Column:
return ColumnTypeDisplayName;
case ObjectManagement.NodeType.Database:
return DatabaseTypeDisplayName;
default:
throw new Error(`Unknown node type: ${type}`);
}
}
const AuthencationTypeDisplayNameMap = new Map<ObjectManagement.AuthenticationType, string>();
AuthencationTypeDisplayNameMap.set(ObjectManagement.AuthenticationType.Windows, WindowsAuthenticationTypeDisplayText);
AuthencationTypeDisplayNameMap.set(ObjectManagement.AuthenticationType.Sql, SQLAuthenticationTypeDisplayText);
AuthencationTypeDisplayNameMap.set(ObjectManagement.AuthenticationType.AzureActiveDirectory, AADAuthenticationTypeDisplayText);
export function getAuthenticationTypeDisplayName(authType: ObjectManagement.AuthenticationType): string {
if (AuthencationTypeDisplayNameMap.has(authType)) {
return AuthencationTypeDisplayNameMap.get(authType);
}
throw new Error(`Unknown authentication type: ${authType}`);
}
export function getAuthenticationTypeByDisplayName(displayName: string): ObjectManagement.AuthenticationType {
for (let [key, value] of AuthencationTypeDisplayNameMap.entries()) {
if (value === displayName)
return key;
}
throw new Error(`Unknown authentication type display name: ${displayName}`);
}
const UserTypeDisplayNameMap = new Map<ObjectManagement.UserType, string>();
UserTypeDisplayNameMap.set(ObjectManagement.UserType.LoginMapped, UserType_LoginMapped);
UserTypeDisplayNameMap.set(ObjectManagement.UserType.WindowsUser, UserType_WindowsUser);
UserTypeDisplayNameMap.set(ObjectManagement.UserType.SqlAuthentication, UserType_SqlAuthentication);
UserTypeDisplayNameMap.set(ObjectManagement.UserType.AADAuthentication, UserType_AADAuthentication);
UserTypeDisplayNameMap.set(ObjectManagement.UserType.NoLoginAccess, UserType_NoLoginAccess);
export function getUserTypeDisplayName(userType: ObjectManagement.UserType): string {
if (UserTypeDisplayNameMap.has(userType)) {
return UserTypeDisplayNameMap.get(userType);
}
throw new Error(`Unknown user type: ${userType}`);
}
export function getUserTypeByDisplayName(displayName: string): ObjectManagement.UserType {
for (let [key, value] of UserTypeDisplayNameMap.entries()) {
if (value === displayName)
return key;
}
throw new Error(`Unknown user type display name: ${displayName}`);
}

View File

@@ -138,9 +138,7 @@ export class TestObjectManagementService implements IObjectManagementService {
isEnabled: true, isEnabled: true,
isLockedOut: false isLockedOut: false
}, },
supportAADAuthentication: true, authenticationTypes: [ObjectManagement.AuthenticationType.Sql, ObjectManagement.AuthenticationType.Windows],
supportSQLAuthentication: true,
supportWindowsAuthentication: true,
supportAdvancedOptions: true, supportAdvancedOptions: true,
supportAdvancedPasswordOptions: true, supportAdvancedPasswordOptions: true,
canEditLockedOutState: false, canEditLockedOutState: false,
@@ -164,9 +162,7 @@ export class TestObjectManagementService implements IObjectManagementService {
isLockedOut: false, isLockedOut: false,
password: '******************' password: '******************'
}, },
supportAADAuthentication: true, authenticationTypes: [ObjectManagement.AuthenticationType.Sql, ObjectManagement.AuthenticationType.Windows],
supportSQLAuthentication: true,
supportWindowsAuthentication: true,
supportAdvancedOptions: true, supportAdvancedOptions: true,
supportAdvancedPasswordOptions: true, supportAdvancedPasswordOptions: true,
canEditLockedOutState: false, canEditLockedOutState: false,
@@ -189,7 +185,7 @@ export class TestObjectManagementService implements IObjectManagementService {
viewInfo = { viewInfo = {
objectInfo: <ObjectManagement.User>{ objectInfo: <ObjectManagement.User>{
name: '', name: '',
type: ObjectManagement.UserType.WithLogin, type: ObjectManagement.UserType.LoginMapped,
defaultSchema: 'dbo', defaultSchema: 'dbo',
defaultLanguage: '<default>', defaultLanguage: '<default>',
authenticationType: ObjectManagement.AuthenticationType.Sql, authenticationType: ObjectManagement.AuthenticationType.Sql,
@@ -202,20 +198,21 @@ export class TestObjectManagementService implements IObjectManagementService {
schemas: schemas, schemas: schemas,
logins: logins, logins: logins,
databaseRoles: databaseRoles, databaseRoles: databaseRoles,
supportContainedUser: true, userTypes: [
supportAADAuthentication: true, ObjectManagement.UserType.LoginMapped,
supportSQLAuthentication: true, ObjectManagement.UserType.AADAuthentication,
supportWindowsAuthentication: true ObjectManagement.UserType.SqlAuthentication,
ObjectManagement.UserType.NoLoginAccess
]
}; };
} else { } else {
viewInfo = { viewInfo = {
objectInfo: <ObjectManagement.User>{ objectInfo: <ObjectManagement.User>{
name: name, name: name,
type: ObjectManagement.UserType.WithLogin, type: ObjectManagement.UserType.LoginMapped,
defaultSchema: 'dbo', defaultSchema: 'dbo',
defaultLanguage: '<default>', defaultLanguage: '<default>',
loginName: 'sa', loginName: 'sa',
authenticationType: ObjectManagement.AuthenticationType.Sql,
ownedSchemas: ['dbo'], ownedSchemas: ['dbo'],
databaseRoles: ['dbmanager', 'bulkadmin'] databaseRoles: ['dbmanager', 'bulkadmin']
}, },
@@ -223,10 +220,12 @@ export class TestObjectManagementService implements IObjectManagementService {
schemas: schemas, schemas: schemas,
logins: logins, logins: logins,
databaseRoles: databaseRoles, databaseRoles: databaseRoles,
supportContainedUser: true, userTypes: [
supportAADAuthentication: true, ObjectManagement.UserType.LoginMapped,
supportSQLAuthentication: true, ObjectManagement.UserType.AADAuthentication,
supportWindowsAuthentication: true ObjectManagement.UserType.SqlAuthentication,
ObjectManagement.UserType.NoLoginAccess
]
}; };
} }
return viewInfo; return viewInfo;

View File

@@ -7,7 +7,6 @@ import * as azdata from 'azdata';
import * as mssql from 'mssql'; import * as mssql from 'mssql';
import { DefaultTableListItemEnabledStateGetter, DefaultMaxTableHeight, DialogBase, TableListItemComparer, TableListItemValueGetter } from './dialogBase'; import { DefaultTableListItemEnabledStateGetter, DefaultMaxTableHeight, DialogBase, TableListItemComparer, TableListItemValueGetter } from './dialogBase';
import * as localizedConstants from '../localizedConstants'; import * as localizedConstants from '../localizedConstants';
import { getNodeTypeDisplayName } from '../utils';
import { getErrorMessage } from '../../utils'; import { getErrorMessage } from '../../utils';
export interface FindObjectDialogOptions { export interface FindObjectDialogOptions {
@@ -28,7 +27,7 @@ const ObjectComparer: TableListItemComparer<mssql.ObjectManagement.SearchResultI
const ObjectRowValueGetter: TableListItemValueGetter<mssql.ObjectManagement.SearchResultItem> = const ObjectRowValueGetter: TableListItemValueGetter<mssql.ObjectManagement.SearchResultItem> =
(item) => { (item) => {
return [item.name, getNodeTypeDisplayName(item.type, true)]; return [item.name, localizedConstants.getNodeTypeDisplayName(item.type, true)];
}; };
const ObjectsTableMaxHeight = 700; const ObjectsTableMaxHeight = 700;
@@ -59,7 +58,7 @@ export class FindObjectDialog extends DialogBase<FindObjectDialogResult> {
this.selectedObjectTypes, this.selectedObjectTypes,
DefaultMaxTableHeight, DefaultMaxTableHeight,
DefaultTableListItemEnabledStateGetter, (item) => { DefaultTableListItemEnabledStateGetter, (item) => {
return [getNodeTypeDisplayName(item, true)]; return [localizedConstants.getNodeTypeDisplayName(item, true)];
}); });
this.findButton = this.createButton(localizedConstants.FindText, localizedConstants.FindText, async () => { this.findButton = this.createButton(localizedConstants.FindText, localizedConstants.FindText, async () => {
await this.onFindObjectButtonClick(); await this.onFindObjectButtonClick();

View File

@@ -8,7 +8,7 @@ import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './obj
import { IObjectManagementService, ObjectManagement } from 'mssql'; import { IObjectManagementService, ObjectManagement } from 'mssql';
import * as localizedConstants from '../localizedConstants'; import * as localizedConstants from '../localizedConstants';
import { AlterLoginDocUrl, CreateLoginDocUrl, PublicServerRoleName } from '../constants'; import { AlterLoginDocUrl, CreateLoginDocUrl, PublicServerRoleName } from '../constants';
import { getAuthenticationTypeByDisplayName, getAuthenticationTypeDisplayName, isValidSQLPassword } from '../utils'; import { isValidSQLPassword } from '../utils';
import { DefaultMaxTableHeight } from './dialogBase'; import { DefaultMaxTableHeight } from './dialogBase';
export class LoginDialog extends ObjectManagementDialogBase<ObjectManagement.Login, ObjectManagement.LoginViewInfo> { export class LoginDialog extends ObjectManagementDialogBase<ObjectManagement.Login, ObjectManagement.LoginViewInfo> {
@@ -107,20 +107,14 @@ export class LoginDialog extends ObjectManagementDialogBase<ObjectManagement.Log
}, this.objectInfo.name, this.options.isNewObject); }, this.objectInfo.name, this.options.isNewObject);
const nameContainer = this.createLabelInputContainer(localizedConstants.NameText, this.nameInput); const nameContainer = this.createLabelInputContainer(localizedConstants.NameText, this.nameInput);
const authTypes = []; this.authTypeDropdown = this.createDropdown(localizedConstants.AuthTypeText,
if (this.viewInfo.supportWindowsAuthentication) { async (newValue) => {
authTypes.push(localizedConstants.WindowsAuthenticationTypeDisplayText); this.objectInfo.authenticationType = localizedConstants.getAuthenticationTypeByDisplayName(newValue);
} this.setViewByAuthenticationType();
if (this.viewInfo.supportSQLAuthentication) { },
authTypes.push(localizedConstants.SQLAuthenticationTypeDisplayText); this.viewInfo.authenticationTypes.map(authType => localizedConstants.getAuthenticationTypeDisplayName(authType)),
} localizedConstants.getAuthenticationTypeDisplayName(this.objectInfo.authenticationType),
if (this.viewInfo.supportAADAuthentication) { this.options.isNewObject);
authTypes.push(localizedConstants.AADAuthenticationTypeDisplayText);
}
this.authTypeDropdown = this.createDropdown(localizedConstants.AuthTypeText, async (newValue) => {
this.objectInfo.authenticationType = getAuthenticationTypeByDisplayName(newValue);
this.setViewByAuthenticationType();
}, authTypes, getAuthenticationTypeDisplayName(this.objectInfo.authenticationType), this.options.isNewObject);
const authTypeContainer = this.createLabelInputContainer(localizedConstants.AuthTypeText, this.authTypeDropdown); const authTypeContainer = this.createLabelInputContainer(localizedConstants.AuthTypeText, this.authTypeDropdown);

View File

@@ -8,7 +8,7 @@ import { IObjectManagementService, ObjectManagement } from 'mssql';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { generateUuid } from 'vscode-languageclient/lib/utils/uuid'; import { generateUuid } from 'vscode-languageclient/lib/utils/uuid';
import * as localizedConstants from '../localizedConstants'; import * as localizedConstants from '../localizedConstants';
import { deepClone, getNodeTypeDisplayName, refreshNode, refreshParentNode } from '../utils'; import { deepClone, refreshNode, refreshParentNode } from '../utils';
import { DialogBase } from './dialogBase'; import { DialogBase } from './dialogBase';
import { ObjectManagementViewName, TelemetryActions } from '../constants'; import { ObjectManagementViewName, TelemetryActions } from '../constants';
import { TelemetryReporter } from '../../telemetry'; import { TelemetryReporter } from '../../telemetry';
@@ -41,8 +41,8 @@ export abstract class ObjectManagementDialogBase<ObjectInfoType extends ObjectMa
private _scriptButton: azdata.window.Button; private _scriptButton: azdata.window.Button;
constructor(protected readonly objectManagementService: IObjectManagementService, protected readonly options: ObjectManagementDialogOptions) { constructor(protected readonly objectManagementService: IObjectManagementService, protected readonly options: ObjectManagementDialogOptions) {
super(options.isNewObject ? localizedConstants.NewObjectDialogTitle(getNodeTypeDisplayName(options.objectType, true)) : super(options.isNewObject ? localizedConstants.NewObjectDialogTitle(localizedConstants.getNodeTypeDisplayName(options.objectType, true)) :
localizedConstants.ObjectPropertiesDialogTitle(getNodeTypeDisplayName(options.objectType, true), options.objectName), localizedConstants.ObjectPropertiesDialogTitle(localizedConstants.getNodeTypeDisplayName(options.objectType, true), options.objectName),
getDialogName(options.objectType, options.isNewObject), getDialogName(options.objectType, options.isNewObject),
options.width || 'narrow', 'flyout' options.width || 'narrow', 'flyout'
); );
@@ -78,7 +78,7 @@ export abstract class ObjectManagementDialogBase<ObjectInfoType extends ObjectMa
protected override async initialize(): Promise<void> { protected override async initialize(): Promise<void> {
await this.initializeData(); await this.initializeData();
await this.initializeUI(); await this.initializeUI();
const typeDisplayName = getNodeTypeDisplayName(this.options.objectType); const typeDisplayName = localizedConstants.getNodeTypeDisplayName(this.options.objectType);
this.dialogObject.registerOperation({ this.dialogObject.registerOperation({
displayName: this.options.isNewObject ? localizedConstants.CreateObjectOperationDisplayName(typeDisplayName) displayName: this.options.isNewObject ? localizedConstants.CreateObjectOperationDisplayName(typeDisplayName)
: localizedConstants.UpdateObjectOperationDisplayName(typeDisplayName, this.options.objectName), : localizedConstants.UpdateObjectOperationDisplayName(typeDisplayName, this.options.objectName),

View File

@@ -7,7 +7,7 @@ import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './obj
import { IObjectManagementService, ObjectManagement } from 'mssql'; import { IObjectManagementService, ObjectManagement } from 'mssql';
import * as localizedConstants from '../localizedConstants'; import * as localizedConstants from '../localizedConstants';
import { AlterUserDocUrl, CreateUserDocUrl } from '../constants'; import { AlterUserDocUrl, CreateUserDocUrl } from '../constants';
import { getAuthenticationTypeByDisplayName, getAuthenticationTypeDisplayName, getUserTypeByDisplayName, getUserTypeDisplayName, isValidSQLPassword } from '../utils'; import { isValidSQLPassword } from '../utils';
import { DefaultMaxTableHeight } from './dialogBase'; import { DefaultMaxTableHeight } from './dialogBase';
export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User, ObjectManagement.UserViewInfo> { export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User, ObjectManagement.UserViewInfo> {
@@ -18,8 +18,6 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
private nameInput: azdata.InputBoxComponent; private nameInput: azdata.InputBoxComponent;
private typeDropdown: azdata.DropDownComponent; private typeDropdown: azdata.DropDownComponent;
private typeContainer: azdata.FlexContainer; private typeContainer: azdata.FlexContainer;
private authTypeDropdown: azdata.DropDownComponent;
private authTypeContainer: azdata.FlexContainer;
private loginDropdown: azdata.DropDownComponent; private loginDropdown: azdata.DropDownComponent;
private loginContainer: azdata.FlexContainer; private loginContainer: azdata.FlexContainer;
private passwordInput: azdata.InputBoxComponent; private passwordInput: azdata.InputBoxComponent;
@@ -46,7 +44,7 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
protected override async validateInput(): Promise<string[]> { protected override async validateInput(): Promise<string[]> {
const errors = await super.validateInput(); const errors = await super.validateInput();
if (this.objectInfo.type === ObjectManagement.UserType.Contained && this.objectInfo.authenticationType === ObjectManagement.AuthenticationType.Sql) { if (this.objectInfo.type === ObjectManagement.UserType.SqlAuthentication) {
if (!this.objectInfo.password) { if (!this.objectInfo.password) {
errors.push(localizedConstants.PasswordCannotBeEmptyError); errors.push(localizedConstants.PasswordCannotBeEmptyError);
} }
@@ -57,10 +55,8 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
&& (this.options.isNewObject || this.objectInfo.password !== this.originalObjectInfo.password)) { && (this.options.isNewObject || this.objectInfo.password !== this.originalObjectInfo.password)) {
errors.push(localizedConstants.InvalidPasswordError); errors.push(localizedConstants.InvalidPasswordError);
} }
} else if (this.objectInfo.type === ObjectManagement.UserType.WithLogin) { } else if (this.objectInfo.type === ObjectManagement.UserType.LoginMapped && !this.objectInfo.loginName) {
if (!this.objectInfo.loginName) { errors.push(localizedConstants.LoginNotSelectedError);
errors.push(localizedConstants.LoginNotSelectedError);
}
} }
return errors; return errors;
} }
@@ -86,13 +82,14 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
this.objectInfo.defaultSchema = newValue; this.objectInfo.defaultSchema = newValue;
}, this.viewInfo.schemas, this.objectInfo.defaultSchema!); }, this.viewInfo.schemas, this.objectInfo.defaultSchema!);
this.defaultSchemaContainer = this.createLabelInputContainer(localizedConstants.DefaultSchemaText, this.defaultSchemaDropdown); this.defaultSchemaContainer = this.createLabelInputContainer(localizedConstants.DefaultSchemaText, this.defaultSchemaDropdown);
this.typeDropdown = this.createDropdown(localizedConstants.UserTypeText,
// only supporting user with login for initial preview async (newValue) => {
const userTypes = [localizedConstants.UserWithLoginText, localizedConstants.UserWithWindowsGroupLoginText, localizedConstants.ContainedUserText, localizedConstants.UserWithNoConnectAccess]; this.objectInfo.type = localizedConstants.getUserTypeByDisplayName(newValue);
this.typeDropdown = this.createDropdown(localizedConstants.UserTypeText, async (newValue) => { this.setViewByUserType();
this.objectInfo.type = getUserTypeByDisplayName(newValue); },
this.setViewByUserType(); this.viewInfo.userTypes.map(userType => localizedConstants.getUserTypeDisplayName(userType)),
}, userTypes, getUserTypeDisplayName(this.objectInfo.type), this.options.isNewObject); localizedConstants.getUserTypeDisplayName(this.objectInfo.type),
this.options.isNewObject);
this.typeContainer = this.createLabelInputContainer(localizedConstants.UserTypeText, this.typeDropdown); this.typeContainer = this.createLabelInputContainer(localizedConstants.UserTypeText, this.typeDropdown);
this.loginDropdown = this.createDropdown(localizedConstants.LoginText, async (newValue) => { this.loginDropdown = this.createDropdown(localizedConstants.LoginText, async (newValue) => {
@@ -100,22 +97,6 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
}, this.viewInfo.logins, this.objectInfo.loginName, this.options.isNewObject); }, this.viewInfo.logins, this.objectInfo.loginName, this.options.isNewObject);
this.loginContainer = this.createLabelInputContainer(localizedConstants.LoginText, this.loginDropdown); this.loginContainer = this.createLabelInputContainer(localizedConstants.LoginText, this.loginDropdown);
const authTypes = [];
if (this.viewInfo.supportWindowsAuthentication) {
authTypes.push(localizedConstants.WindowsAuthenticationTypeDisplayText);
}
if (this.viewInfo.supportSQLAuthentication) {
authTypes.push(localizedConstants.SQLAuthenticationTypeDisplayText);
}
if (this.viewInfo.supportAADAuthentication) {
authTypes.push(localizedConstants.AADAuthenticationTypeDisplayText);
}
this.authTypeDropdown = this.createDropdown(localizedConstants.AuthTypeText, async (newValue) => {
this.objectInfo.authenticationType = getAuthenticationTypeByDisplayName(newValue);
this.setViewByAuthenticationType();
}, authTypes, getAuthenticationTypeDisplayName(this.objectInfo.authenticationType), this.options.isNewObject);
this.authTypeContainer = this.createLabelInputContainer(localizedConstants.AuthTypeText, this.authTypeDropdown);
this.passwordInput = this.createPasswordInputBox(localizedConstants.PasswordText, async (newValue) => { this.passwordInput = this.createPasswordInputBox(localizedConstants.PasswordText, async (newValue) => {
this.objectInfo.password = newValue; this.objectInfo.password = newValue;
}, this.objectInfo.password ?? ''); }, this.objectInfo.password ?? '');
@@ -128,7 +109,6 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
this.defaultSchemaContainer, this.defaultSchemaContainer,
this.typeContainer, this.typeContainer,
this.loginContainer, this.loginContainer,
this.authTypeContainer,
this.passwordContainer, this.passwordContainer,
this.confirmPasswordContainer this.confirmPasswordContainer
], false); ], false);
@@ -161,30 +141,24 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
} }
private setViewByUserType(): void { private setViewByUserType(): void {
if (this.typeDropdown.value === localizedConstants.UserWithLoginText) { this.removeItem(this.generalSection, this.loginContainer);
this.removeItem(this.generalSection, this.authTypeContainer); this.removeItem(this.generalSection, this.passwordContainer);
this.removeItem(this.formContainer, this.advancedSection); this.removeItem(this.generalSection, this.confirmPasswordContainer);
this.addItem(this.generalSection, this.loginContainer); this.removeItem(this.formContainer, this.advancedSection);
} else if (this.typeDropdown.value === localizedConstants.ContainedUserText) { switch (this.objectInfo.type) {
this.removeItem(this.generalSection, this.loginContainer); case ObjectManagement.UserType.LoginMapped:
this.addItem(this.generalSection, this.authTypeContainer); this.addItem(this.generalSection, this.loginContainer);
this.addItem(this.formContainer, this.advancedSection); break;
} else { case ObjectManagement.UserType.AADAuthentication:
this.removeItem(this.generalSection, this.loginContainer); this.addItem(this.formContainer, this.advancedSection);
this.removeItem(this.generalSection, this.authTypeContainer); break;
this.removeItem(this.formContainer, this.advancedSection); case ObjectManagement.UserType.SqlAuthentication:
} this.addItem(this.generalSection, this.passwordContainer);
this.setViewByAuthenticationType(); this.addItem(this.generalSection, this.confirmPasswordContainer);
} this.addItem(this.formContainer, this.advancedSection);
break;
private setViewByAuthenticationType(): void { default:
const showPassword = this.typeDropdown.value === localizedConstants.ContainedUserText && this.authTypeDropdown.value === localizedConstants.SQLAuthenticationTypeDisplayText; break;
if (showPassword) {
this.addItem(this.generalSection, this.passwordContainer);
this.addItem(this.generalSection, this.confirmPasswordContainer);
} else {
this.removeItem(this.generalSection, this.passwordContainer);
this.removeItem(this.generalSection, this.confirmPasswordContainer);
} }
} }
} }

View File

@@ -6,7 +6,6 @@
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { getErrorMessage } from '../utils'; import { getErrorMessage } from '../utils';
import { ObjectManagement } from 'mssql';
import * as localizedConstants from './localizedConstants'; import * as localizedConstants from './localizedConstants';
export function deepClone<T>(obj: T): T { export function deepClone<T>(obj: T): T {
@@ -53,81 +52,6 @@ export async function refreshNode(context: azdata.ObjectExplorerContext): Promis
} }
} }
export function getNodeTypeDisplayName(type: string, inTitle: boolean = false): string {
switch (type) {
case ObjectManagement.NodeType.ApplicationRole:
return inTitle ? localizedConstants.ApplicationRoleTypeDisplayNameInTitle : localizedConstants.ApplicationRoleTypeDisplayName;
case ObjectManagement.NodeType.DatabaseRole:
return inTitle ? localizedConstants.DatabaseRoleTypeDisplayNameInTitle : localizedConstants.DatabaseRoleTypeDisplayName;
case ObjectManagement.NodeType.ServerLevelLogin:
return inTitle ? localizedConstants.LoginTypeDisplayNameInTitle : localizedConstants.LoginTypeDisplayName;
case ObjectManagement.NodeType.ServerLevelServerRole:
return inTitle ? localizedConstants.ServerRoleTypeDisplayNameInTitle : localizedConstants.ServerRoleTypeDisplayName;
case ObjectManagement.NodeType.User:
return inTitle ? localizedConstants.UserTypeDisplayNameInTitle : localizedConstants.UserTypeDisplayName;
case ObjectManagement.NodeType.Table:
return localizedConstants.TableTypeDisplayName;
case ObjectManagement.NodeType.View:
return localizedConstants.ViewTypeDisplayName;
case ObjectManagement.NodeType.Column:
return localizedConstants.ColumnTypeDisplayName;
case ObjectManagement.NodeType.Database:
return localizedConstants.DatabaseTypeDisplayName;
default:
throw new Error(`Unknown node type: ${type}`);
}
}
export function getAuthenticationTypeDisplayName(authType: ObjectManagement.AuthenticationType | undefined): string | undefined {
if (authType === undefined) { return undefined; }
switch (authType) {
case ObjectManagement.AuthenticationType.Windows:
return localizedConstants.WindowsAuthenticationTypeDisplayText;
case ObjectManagement.AuthenticationType.AzureActiveDirectory:
return localizedConstants.AADAuthenticationTypeDisplayText;
default:
return localizedConstants.SQLAuthenticationTypeDisplayText;
}
}
export function getAuthenticationTypeByDisplayName(displayValue: string): ObjectManagement.AuthenticationType {
switch (displayValue) {
case localizedConstants.WindowsAuthenticationTypeDisplayText:
return ObjectManagement.AuthenticationType.Windows;
case localizedConstants.AADAuthenticationTypeDisplayText:
return ObjectManagement.AuthenticationType.AzureActiveDirectory;
default:
return ObjectManagement.AuthenticationType.Sql;
}
}
export function getUserTypeDisplayName(userType: ObjectManagement.UserType): string {
switch (userType) {
case ObjectManagement.UserType.WithLogin:
return localizedConstants.UserWithLoginText;
case ObjectManagement.UserType.WithWindowsGroupLogin:
return localizedConstants.UserWithWindowsGroupLoginText;
case ObjectManagement.UserType.Contained:
return localizedConstants.ContainedUserText;
default:
return localizedConstants.UserWithNoConnectAccess;
}
}
export function getUserTypeByDisplayName(userTypeDisplayName: string): ObjectManagement.UserType {
switch (userTypeDisplayName) {
case localizedConstants.UserWithLoginText:
return ObjectManagement.UserType.WithLogin;
case localizedConstants.UserWithWindowsGroupLoginText:
return ObjectManagement.UserType.WithWindowsGroupLogin;
case localizedConstants.ContainedUserText:
return ObjectManagement.UserType.Contained;
default:
return ObjectManagement.UserType.NoConnectAccess;
}
}
// https://docs.microsoft.com/sql/relational-databases/security/password-policy // https://docs.microsoft.com/sql/relational-databases/security/password-policy
export function isValidSQLPassword(password: string, userName: string = 'sa'): boolean { export function isValidSQLPassword(password: string, userName: string = 'sa'): boolean {
const containsUserName = password && userName && password.toUpperCase().includes(userName.toUpperCase()); const containsUserName = password && userName && password.toUpperCase().includes(userName.toUpperCase());