From 5dbed25c40c6d7c59100c4432e35e6893e7ab8b2 Mon Sep 17 00:00:00 2001 From: Alan Ren Date: Mon, 1 May 2023 10:27:00 -0700 Subject: [PATCH] change user type implementation (#2036) * change user type implementation * fix build errors --- .../ObjectTypes/Login/LoginHandler.cs | 14 +++++-- .../ObjectTypes/Login/LoginViewInfo.cs | 4 +- .../ObjectTypes/Security/UserActions.cs | 32 +++++++--------- .../ObjectTypes/Security/UserData.cs | 10 ++--- .../ObjectTypes/User/UserHandler.cs | 35 +++++++++-------- .../ObjectTypes/User/UserInfo.cs | 38 +++++++------------ .../ObjectTypes/User/UserViewInfo.cs | 8 +--- .../ObjectManagementTestUtils.cs | 1 - .../ObjectManagement/UserTests.cs | 8 ++-- 9 files changed, 68 insertions(+), 82 deletions(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Login/LoginHandler.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Login/LoginHandler.cs index c6de1ff2..3b3c4860 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Login/LoginHandler.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Login/LoginHandler.cs @@ -85,12 +85,20 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement UserMapping = new ServerLoginDatabaseUserMapping[0] }; + var supportedAuthTypes = new List(); + supportedAuthTypes.Add(LoginAuthenticationType.Sql); + if (prototype.WindowsAuthSupported) + { + supportedAuthTypes.Add(LoginAuthenticationType.Windows); + } + if (prototype.AADAuthSupported) + { + supportedAuthTypes.Add(LoginAuthenticationType.AAD); + } var viewInfo = new LoginViewInfo() { ObjectInfo = loginInfo, - SupportWindowsAuthentication = prototype.WindowsAuthSupported, - SupportAADAuthentication = prototype.AADAuthSupported, - SupportSQLAuthentication = true, // SQL Auth support for login, not necessarily mean SQL Auth support for CONNECT etc. + AuthenticationTypes = supportedAuthTypes.ToArray(), CanEditLockedOutState = !parameters.IsNewObject && prototype.IsLockedOut, Databases = databases, Languages = languages, diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Login/LoginViewInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Login/LoginViewInfo.cs index edd90d67..62678012 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Login/LoginViewInfo.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Login/LoginViewInfo.cs @@ -8,9 +8,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement { public class LoginViewInfo : SqlObjectViewInfo { - public bool SupportWindowsAuthentication { get; set; } - public bool SupportAADAuthentication { get; set; } - public bool SupportSQLAuthentication { get; set; } + public LoginAuthenticationType[] AuthenticationTypes { get; set; } public bool CanEditLockedOutState { get; set; } public string[] Databases; public string[] Languages; diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Security/UserActions.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Security/UserActions.cs index 8240fcf0..7320c156 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Security/UserActions.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Security/UserActions.cs @@ -70,23 +70,19 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement ExhaustiveUserTypes userType = ExhaustiveUserTypes.LoginMappedUser; switch (user.Type) { - case DatabaseUserType.WithLogin: + case DatabaseUserType.LoginMapped: userType = ExhaustiveUserTypes.LoginMappedUser; break; - case DatabaseUserType.WithWindowsGroupLogin: + case DatabaseUserType.WindowsUser: userType = ExhaustiveUserTypes.WindowsUser; break; - case DatabaseUserType.Contained: - if (user.AuthenticationType == ServerAuthenticationType.AzureActiveDirectory) - { - userType = ExhaustiveUserTypes.ExternalUser; - } - else - { - userType = ExhaustiveUserTypes.SqlUserWithPassword; - } + case DatabaseUserType.SqlAuthentication: + userType = ExhaustiveUserTypes.SqlUserWithPassword; break; - case DatabaseUserType.NoConnectAccess: + case DatabaseUserType.AADAuthentication: + userType = ExhaustiveUserTypes.ExternalUser; + break; + case DatabaseUserType.NoLoginAccess: userType = ExhaustiveUserTypes.SqlUserWithoutLogin; break; } @@ -95,23 +91,23 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement internal static DatabaseUserType GetDatabaseUserTypeForUserType(ExhaustiveUserTypes userType) { - DatabaseUserType databaseUserType = DatabaseUserType.WithLogin; + DatabaseUserType databaseUserType = DatabaseUserType.LoginMapped; switch (userType) { case ExhaustiveUserTypes.LoginMappedUser: - databaseUserType = DatabaseUserType.WithLogin; + databaseUserType = DatabaseUserType.LoginMapped; break; case ExhaustiveUserTypes.WindowsUser: - databaseUserType = DatabaseUserType.WithWindowsGroupLogin; + databaseUserType = DatabaseUserType.WindowsUser; break; case ExhaustiveUserTypes.SqlUserWithPassword: - databaseUserType = DatabaseUserType.Contained; + databaseUserType = DatabaseUserType.SqlAuthentication; break; case ExhaustiveUserTypes.SqlUserWithoutLogin: - databaseUserType = DatabaseUserType.NoConnectAccess; + databaseUserType = DatabaseUserType.NoLoginAccess; break; case ExhaustiveUserTypes.ExternalUser: - databaseUserType = DatabaseUserType.Contained; + databaseUserType = DatabaseUserType.AADAuthentication; break; } return databaseUserType; diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Security/UserData.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Security/UserData.cs index ee90fafa..96c5bfa7 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Security/UserData.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Security/UserData.cs @@ -142,16 +142,12 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement UserType userType = UserType.SqlLogin; switch (userInfo.Type) { - case DatabaseUserType.NoConnectAccess: + case DatabaseUserType.NoLoginAccess: userType = UserType.NoLogin; break; - case DatabaseUserType.Contained: - if (userInfo.AuthenticationType == ServerAuthenticationType.AzureActiveDirectory) - { - userType = UserType.External; - } + case DatabaseUserType.AADAuthentication: + userType = UserType.External; break; - // all the other user types are using SqlLogin } return userType; } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserHandler.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserHandler.cs index 45e7e949..ddea4709 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserHandler.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserHandler.cs @@ -78,17 +78,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement { User existingUser = dataContainer.Server.GetSmoObject(parameters.ObjectUrn) as User; userType = UserActions.GetCurrentUserTypeForExistingUser(existingUser); - DatabaseUserType databaseUserType = UserActions.GetDatabaseUserTypeForUserType(userType); - - // if contained user determine if SQL or AAD auth type - ServerAuthenticationType authenticationType = - (databaseUserType == DatabaseUserType.Contained && userType == ExhaustiveUserTypes.ExternalUser) - ? ServerAuthenticationType.AzureActiveDirectory : ServerAuthenticationType.Sql; userInfo = new UserInfo() { - Type = databaseUserType, - AuthenticationType = authenticationType, + Type = UserActions.GetDatabaseUserTypeForUserType(userType), Name = existingUser.Name, LoginName = existingUser.Login, DefaultSchema = existingUser.DefaultSchema, @@ -168,12 +161,27 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement defaultLanguage = SR.DefaultLanguagePlaceholder; } + var supportedUserTypes = new List(); + supportedUserTypes.Add(DatabaseUserType.LoginMapped); + if (currentUserPrototype.WindowsAuthSupported) + { + supportedUserTypes.Add(DatabaseUserType.WindowsUser); + } + if (supportsContainedUser) + { + supportedUserTypes.Add(DatabaseUserType.SqlAuthentication); + } + if (currentUserPrototype.AADAuthSupported) + { + supportedUserTypes.Add(DatabaseUserType.AADAuthentication); + } + supportedUserTypes.Add(DatabaseUserType.NoLoginAccess); + UserViewInfo userViewInfo = new UserViewInfo() { ObjectInfo = new UserInfo() { - Type = userInfo?.Type ?? DatabaseUserType.WithLogin, - AuthenticationType = userInfo?.AuthenticationType ?? ServerAuthenticationType.Sql, + Type = userInfo?.Type ?? DatabaseUserType.LoginMapped, Name = currentUserPrototype.Name, LoginName = loginName, Password = password, @@ -182,10 +190,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement DatabaseRoles = databaseRoles.ToArray(), DefaultLanguage = defaultLanguage }, - SupportContainedUser = supportsContainedUser, - SupportWindowsAuthentication = false, - SupportAADAuthentication = currentUserPrototype.AADAuthSupported, - SupportSQLAuthentication = true, + UserTypes = supportedUserTypes.ToArray(), Languages = languageOptionsList.ToArray(), Schemas = currentUserPrototype.SchemaNames.ToArray(), Logins = DatabaseUtils.LoadSqlLogins(dataContainer.ServerConnection), @@ -246,7 +251,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement } internal string ConfigureUser(ServerConnection serverConnection, UserInfo user, ConfigAction configAction, RunType runType, string databaseName, UserPrototypeData originalData) - { + { string sqlScript = string.Empty; CDataContainer dataContainer = CreateUserDataContainer(serverConnection, user, configAction, databaseName); using (var actions = new UserActions(dataContainer, configAction, user, originalData)) diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserInfo.cs index adf74304..10465c89 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserInfo.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserInfo.cs @@ -9,32 +9,24 @@ using Newtonsoft.Json.Converters; namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement { - [JsonConverter(typeof(StringEnumConverter))] - public enum ServerAuthenticationType - { - [EnumMember(Value = "Windows")] - Windows, - [EnumMember(Value = "Sql")] - Sql, - [EnumMember(Value = "AAD")] - AzureActiveDirectory - } - [JsonConverter(typeof(StringEnumConverter))] public enum DatabaseUserType { - // User with a server level login. - [EnumMember(Value = "WithLogin")] - WithLogin, - // User based on a Windows user/group that has no login, but can connect to the Database Engine through membership in a Windows group. - [EnumMember(Value = "WithWindowsGroupLogin")] - WithWindowsGroupLogin, - // Contained user, authentication is done within the database. - [EnumMember(Value = "Contained")] - Contained, + // Mapped to a server login. + [EnumMember(Value = "LoginMapped")] + LoginMapped, + // Mapped to a Windows user or group. + [EnumMember(Value = "WindowsUser")] + WindowsUser, + // Authenticate with password. + [EnumMember(Value = "SqlAuthentication")] + SqlAuthentication, + // Authenticate with Azure Active Directory. + [EnumMember(Value = "AADAuthentication")] + AADAuthentication, // User that cannot authenticate. - [EnumMember(Value = "NoConnectAccess")] - NoConnectAccess + [EnumMember(Value = "NoLoginAccess")] + NoLoginAccess } @@ -55,8 +47,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement public string[]? DatabaseRoles { get; set; } - public ServerAuthenticationType AuthenticationType { get; set; } - public string? DefaultLanguage { get; set; } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserViewInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserViewInfo.cs index a42ebdd4..99a4a66f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserViewInfo.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/User/UserViewInfo.cs @@ -10,13 +10,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement /// public class UserViewInfo : SqlObjectViewInfo { - public bool SupportContainedUser { get; set; } - - public bool SupportWindowsAuthentication { get; set; } - - public bool SupportAADAuthentication { get; set; } - - public bool SupportSQLAuthentication { get; set; } + public DatabaseUserType[]? UserTypes { get; set; } public string[]? Languages { get; set; } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs index 0b04c79c..b1008234 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs @@ -80,7 +80,6 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement return new UserInfo() { Type = userType, - AuthenticationType = ServerAuthenticationType.Sql, Name = userName ?? "TestUserName_" + new Random().NextInt64(10000000, 90000000).ToString(), LoginName = loginName, Password = "placeholder" + new Random().NextInt64(10000000, 90000000).ToString() + "!*PLACEHOLDER", diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/UserTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/UserTests.cs index 85251b2c..ad7e4414 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/UserTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/UserTests.cs @@ -28,7 +28,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath); var connectionUri = connectionResult.ConnectionInfo.OwnerUri; var login = await ObjectManagementTestUtils.CreateTestLogin(connectionUri); - var user = await ObjectManagementTestUtils.CreateTestUser(connectionUri, DatabaseUserType.WithLogin, null, login.Name); + var user = await ObjectManagementTestUtils.CreateTestUser(connectionUri, DatabaseUserType.LoginMapped, null, login.Name); var userUrn = ObjectManagementTestUtils.GetUserURN(connectionResult.ConnectionInfo.ConnectionDetails.DatabaseName, user.Name); var parameters = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionUri, "master", false, SqlObjectType.User, "", userUrn); await ObjectManagementTestUtils.SaveObject(parameters, user); @@ -48,7 +48,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement { var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath); var connectionUri = connectionResult.ConnectionInfo.OwnerUri; - var user = await ObjectManagementTestUtils.CreateTestUser(connectionUri, DatabaseUserType.WithWindowsGroupLogin, $"{Environment.MachineName}\\Administrator"); + var user = await ObjectManagementTestUtils.CreateTestUser(connectionUri, DatabaseUserType.WindowsUser, $"{Environment.MachineName}\\Administrator"); await ObjectManagementTestUtils.DropObject(connectionUri, ObjectManagementTestUtils.GetUserURN(connectionResult.ConnectionInfo.ConnectionDetails.DatabaseName, user.Name)); } } @@ -64,7 +64,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement string databaseName = "CRM"; var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync(databaseName, queryTempFile.FilePath); var connectionUri = connectionResult.ConnectionInfo.OwnerUri; - var user = await ObjectManagementTestUtils.CreateTestUser(connectionUri, DatabaseUserType.Contained, + var user = await ObjectManagementTestUtils.CreateTestUser(connectionUri, DatabaseUserType.SqlAuthentication, userName: null, loginName: null, databaseName: connectionResult.ConnectionInfo.ConnectionDetails.DatabaseName); @@ -84,7 +84,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath); var connectionUri = connectionResult.ConnectionInfo.OwnerUri; var login = await ObjectManagementTestUtils.CreateTestLogin(connectionUri); - var user = await ObjectManagementTestUtils.CreateTestUser(connectionUri, DatabaseUserType.WithLogin, null, login.Name); + var user = await ObjectManagementTestUtils.CreateTestUser(connectionUri, DatabaseUserType.LoginMapped, null, login.Name); var userUrn = ObjectManagementTestUtils.GetUserURN(connectionResult.ConnectionInfo.ConnectionDetails.DatabaseName, user.Name); var parameters = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionUri, "master", false, SqlObjectType.User, "", userUrn); await ObjectManagementTestUtils.ScriptObject(parameters, user);