diff --git a/src/Microsoft.SqlTools.ServiceLayer/Security/LoginActions.cs b/src/Microsoft.SqlTools.ServiceLayer/Security/LoginActions.cs new file mode 100644 index 00000000..e34fc05f --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Security/LoginActions.cs @@ -0,0 +1,258 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.SqlServer.Management.Common; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.SqlTools.ServiceLayer.Connection; +using Microsoft.SqlTools.ServiceLayer.Management; +using Microsoft.SqlTools.ServiceLayer.Security.Contracts; +using Microsoft.SqlTools.ServiceLayer.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.Security +{ + internal class LoginServiceHandlerImpl + { + private Dictionary contextIdToConnectionUriMap = new Dictionary(); + + private ConnectionService? connectionService; + + /// + /// Internal for testing purposes only + /// + internal ConnectionService ConnectionServiceInstance + { + get + { + connectionService ??= ConnectionService.Instance; + return connectionService; + } + + set + { + connectionService = value; + } + } + + /// + /// Handle request to create a login + /// + internal async Task HandleCreateLoginRequest(CreateLoginParams parameters, RequestContext requestContext) + { + ConnectionInfo connInfo; + string ownerUri; + contextIdToConnectionUriMap.TryGetValue(parameters.ContextId, out ownerUri); + ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo); + + if (connInfo == null) + { + throw new ArgumentException("Invalid ConnectionUri"); + } + + CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); + LoginPrototype prototype = new LoginPrototype(dataContainer.Server, parameters.Login); + + if (prototype.LoginType == SqlServer.Management.Smo.LoginType.SqlLogin) + { + // check that there is a password + // this check is made if policy enforcement is off + // with policy turned on we do not display this message, instead we let server + // return the error associated with null password (coming from policy) - see bug 124377 + if (prototype.SqlPassword.Length == 0 && prototype.EnforcePolicy == false) + { + // raise error here + } + + // check that password and confirm password controls' text matches + if (0 != string.Compare(prototype.SqlPassword, prototype.SqlPasswordConfirm, StringComparison.Ordinal)) + { + // raise error here + } + } + + prototype.ApplyGeneralChanges(dataContainer.Server); + + // TODO move this to LoginData + // TODO support role assignment for Azure + LoginPrototype newPrototype = new LoginPrototype(dataContainer.Server, dataContainer.Server.Logins[parameters.Login.Name]); + var _ =newPrototype.ServerRoles.ServerRoleNames; + + foreach (string role in parameters.Login.ServerRoles ?? Enumerable.Empty()) + { + newPrototype.ServerRoles.SetMember(role, true); + } + + newPrototype.ApplyServerRoleChanges(dataContainer.Server); + await requestContext.SendResult(new object()); + } + + internal async Task HandleUpdateLoginRequest(UpdateLoginParams parameters, RequestContext requestContext) + { + ConnectionInfo connInfo; + string ownerUri; + contextIdToConnectionUriMap.TryGetValue(parameters.ContextId, out ownerUri); + ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo); + if (connInfo == null) + { + throw new ArgumentException("Invalid ConnectionUri"); + } + + CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); + LoginPrototype prototype = new LoginPrototype(dataContainer.Server, dataContainer.Server.Logins[parameters.Login.Name]); + + var login = parameters.Login; + prototype.SqlPassword = login.Password; + if (0 != String.Compare(login.DefaultLanguage, SR.DefaultLanguagePlaceholder, StringComparison.Ordinal)) + { + string[] arr = login.DefaultLanguage?.Split(" - "); + if (arr != null && arr.Length > 1) + { + prototype.DefaultLanguage = arr[1]; + } + } + prototype.DefaultDatabase = login.DefaultDatabase; + prototype.EnforcePolicy = login.EnforcePasswordPolicy; + prototype.EnforceExpiration = login.EnforcePasswordPolicy ? login.EnforcePasswordExpiration : false; + prototype.IsLockedOut = login.IsLockedOut; + prototype.IsDisabled = !login.IsEnabled; + prototype.MustChange = login.EnforcePasswordPolicy ? login.MustChangePassword : false; + prototype.WindowsGrantAccess = login.ConnectPermission; + + if (prototype.LoginType == SqlServer.Management.Smo.LoginType.SqlLogin) + { + // check that there is a password + // this check is made if policy enforcement is off + // with policy turned on we do not display this message, instead we let server + // return the error associated with null password (coming from policy) - see bug 124377 + if (prototype.SqlPassword.Length == 0 && prototype.EnforcePolicy == false) + { + // raise error here + } + + // check that password and confirm password controls' text matches + if (0 != string.Compare(prototype.SqlPassword, prototype.SqlPasswordConfirm, StringComparison.Ordinal)) + { + // raise error here + } + } + + var _ = prototype.ServerRoles.ServerRoleNames; + + foreach (string role in prototype.ServerRoles.ServerRoleNames) + { + prototype.ServerRoles.SetMember(role, false); + } + + foreach (string role in login.ServerRoles) + { + prototype.ServerRoles.SetMember(role, true); + } + + prototype.ApplyGeneralChanges(dataContainer.Server); + prototype.ApplyServerRoleChanges(dataContainer.Server); + prototype.ApplyDatabaseRoleChanges(dataContainer.Server); + await requestContext.SendResult(new object()); + } + + internal async Task HandleInitializeLoginViewRequest(InitializeLoginViewRequestParams parameters, RequestContext requestContext) + { + contextIdToConnectionUriMap.Add(parameters.ContextId, parameters.ConnectionUri); + ConnectionInfo connInfo; + ConnectionServiceInstance.TryFindConnection(parameters.ConnectionUri, out connInfo); + if (connInfo == null) + { + throw new ArgumentException("Invalid ConnectionUri"); + } + CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); + LoginViewInfo loginViewInfo = new LoginViewInfo(); + + // TODO cache databases and languages + string[] databases = new string[dataContainer.Server.Databases.Count]; + for (int i = 0; i < dataContainer.Server.Databases.Count; i++) + { + databases[i] = dataContainer.Server.Databases[i].Name; + } + + var languageOptions = LanguageUtils.GetDefaultLanguageOptions(dataContainer); + var languageOptionsList = languageOptions.Select(LanguageUtils.FormatLanguageDisplay).ToList(); + if (parameters.IsNewObject) + { + languageOptionsList.Insert(0, SR.DefaultLanguagePlaceholder); + } + string[] languages = languageOptionsList.ToArray(); + LoginPrototype prototype = parameters.IsNewObject + ? new LoginPrototype(dataContainer.Server) + : new LoginPrototype(dataContainer.Server, dataContainer.Server.Logins[parameters.Name]); + + List loginServerRoles = new List(); + foreach(string role in prototype.ServerRoles.ServerRoleNames) + { + if (prototype.ServerRoles.IsMember(role)) + { + loginServerRoles.Add(role); + } + } + + LoginInfo loginInfo = new LoginInfo() + { + Name = prototype.LoginName, + Password = prototype.SqlPassword, + OldPassword = prototype.OldPassword, + AuthenticationType = LoginTypeToAuthenticationType(prototype.LoginType), + EnforcePasswordExpiration = prototype.EnforceExpiration, + EnforcePasswordPolicy = prototype.EnforcePolicy, + MustChangePassword = prototype.MustChange, + DefaultDatabase = prototype.DefaultDatabase, + DefaultLanguage = parameters.IsNewObject ? SR.DefaultLanguagePlaceholder : LanguageUtils.FormatLanguageDisplay(languageOptions.FirstOrDefault(o => o?.Language.Name == prototype.DefaultLanguage || o?.Language.Alias == prototype.DefaultLanguage, null)), + ServerRoles = loginServerRoles.ToArray(), + ConnectPermission = prototype.WindowsGrantAccess, + IsEnabled = !prototype.IsDisabled, + IsLockedOut = prototype.IsLockedOut, + UserMapping = new ServerLoginDatabaseUserMapping[0] + }; + + await requestContext.SendResult(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. + CanEditLockedOutState = !parameters.IsNewObject && prototype.IsLockedOut, + Databases = databases, + Languages = languages, + ServerRoles = prototype.ServerRoles.ServerRoleNames, + SupportAdvancedPasswordOptions = dataContainer.Server.DatabaseEngineType == DatabaseEngineType.Standalone || dataContainer.Server.DatabaseEngineEdition == DatabaseEngineEdition.SqlDataWarehouse, + SupportAdvancedOptions = dataContainer.Server.DatabaseEngineType == DatabaseEngineType.Standalone || dataContainer.Server.DatabaseEngineEdition == DatabaseEngineEdition.SqlManagedInstance + }); + } + + private LoginAuthenticationType LoginTypeToAuthenticationType(LoginType loginType) + { + switch (loginType) + { + case LoginType.WindowsUser: + case LoginType.WindowsGroup: + return LoginAuthenticationType.Windows; + case LoginType.SqlLogin: + return LoginAuthenticationType.Sql; + case LoginType.ExternalUser: + case LoginType.ExternalGroup: + return LoginAuthenticationType.AAD; + default: + return LoginAuthenticationType.Others; + } + } + + internal async Task HandleDisposeLoginViewRequest(DisposeLoginViewRequestParams parameters, RequestContext requestContext) + { + await requestContext.SendResult(new object()); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Security/SecurityService.cs b/src/Microsoft.SqlTools.ServiceLayer/Security/SecurityService.cs index 88063706..671f4704 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Security/SecurityService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Security/SecurityService.cs @@ -4,18 +4,12 @@ // using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; using System.Threading.Tasks; -using Microsoft.SqlServer.Management.Common; -using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlTools.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Hosting; using Microsoft.SqlTools.ServiceLayer.Management; using Microsoft.SqlTools.ServiceLayer.Security.Contracts; -using Microsoft.SqlTools.ServiceLayer.Utility; namespace Microsoft.SqlTools.ServiceLayer.Security { @@ -30,9 +24,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Security private UserServiceHandlerImpl userServiceHandler; + private LoginServiceHandlerImpl loginServiceHandler; + private static readonly Lazy instance = new Lazy(() => new SecurityService()); - private Dictionary contextIdToConnectionUriMap = new Dictionary(); /// /// Construct a new SecurityService instance with default parameters @@ -40,6 +35,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security public SecurityService() { userServiceHandler = new UserServiceHandlerImpl(); + loginServiceHandler = new LoginServiceHandlerImpl(); } /// @@ -90,10 +86,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Security this.ServiceHost.SetRequestHandler(GetCredentialsRequest.Type, HandleGetCredentialsRequest, true); // Login request handlers - this.ServiceHost.SetRequestHandler(CreateLoginRequest.Type, HandleCreateLoginRequest, true); - this.ServiceHost.SetRequestHandler(UpdateLoginRequest.Type, HandleUpdateLoginRequest, true); - this.ServiceHost.SetRequestHandler(InitializeLoginViewRequest.Type, HandleInitializeLoginViewRequest, true); - this.ServiceHost.SetRequestHandler(DisposeLoginViewRequest.Type, HandleDisposeLoginViewRequest, true); + this.ServiceHost.SetRequestHandler(CreateLoginRequest.Type, this.loginServiceHandler.HandleCreateLoginRequest, true); + this.ServiceHost.SetRequestHandler(UpdateLoginRequest.Type, this.loginServiceHandler.HandleUpdateLoginRequest, true); + this.ServiceHost.SetRequestHandler(InitializeLoginViewRequest.Type, this.loginServiceHandler.HandleInitializeLoginViewRequest, true); + this.ServiceHost.SetRequestHandler(DisposeLoginViewRequest.Type, this.loginServiceHandler.HandleDisposeLoginViewRequest, true); // User request handlers this.ServiceHost.SetRequestHandler(InitializeUserViewRequest.Type, this.userServiceHandler.HandleInitializeUserViewRequest, true); @@ -102,231 +98,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Security this.ServiceHost.SetRequestHandler(DisposeUserViewRequest.Type, this.userServiceHandler.HandleDisposeUserViewRequest, true); } - - #region "Login Handlers" - - /// - /// Handle request to create a login - /// - internal async Task HandleCreateLoginRequest(CreateLoginParams parameters, RequestContext requestContext) - { - ConnectionInfo connInfo; - string ownerUri; - contextIdToConnectionUriMap.TryGetValue(parameters.ContextId, out ownerUri); - ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo); - - if (connInfo == null) - { - throw new ArgumentException("Invalid ConnectionUri"); - } - - CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); - LoginPrototype prototype = new LoginPrototype(dataContainer.Server, parameters.Login); - - if (prototype.LoginType == SqlServer.Management.Smo.LoginType.SqlLogin) - { - // check that there is a password - // this check is made if policy enforcement is off - // with policy turned on we do not display this message, instead we let server - // return the error associated with null password (coming from policy) - see bug 124377 - if (prototype.SqlPassword.Length == 0 && prototype.EnforcePolicy == false) - { - // raise error here - } - - // check that password and confirm password controls' text matches - if (0 != string.Compare(prototype.SqlPassword, prototype.SqlPasswordConfirm, StringComparison.Ordinal)) - { - // raise error here - } - } - - prototype.ApplyGeneralChanges(dataContainer.Server); - - // TODO move this to LoginData - // TODO support role assignment for Azure - LoginPrototype newPrototype = new LoginPrototype(dataContainer.Server, dataContainer.Server.Logins[parameters.Login.Name]); - var _ =newPrototype.ServerRoles.ServerRoleNames; - - foreach (string role in parameters.Login.ServerRoles ?? Enumerable.Empty()) - { - newPrototype.ServerRoles.SetMember(role, true); - } - - newPrototype.ApplyServerRoleChanges(dataContainer.Server); - await requestContext.SendResult(new object()); - } - - internal async Task HandleUpdateLoginRequest(UpdateLoginParams parameters, RequestContext requestContext) - { - ConnectionInfo connInfo; - string ownerUri; - contextIdToConnectionUriMap.TryGetValue(parameters.ContextId, out ownerUri); - ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo); - if (connInfo == null) - { - throw new ArgumentException("Invalid ConnectionUri"); - } - - CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); - LoginPrototype prototype = new LoginPrototype(dataContainer.Server, dataContainer.Server.Logins[parameters.Login.Name]); - - var login = parameters.Login; - prototype.SqlPassword = login.Password; - if (0 != String.Compare(login.DefaultLanguage, SR.DefaultLanguagePlaceholder, StringComparison.Ordinal)) - { - string[] arr = login.DefaultLanguage?.Split(" - "); - if (arr != null && arr.Length > 1) - { - prototype.DefaultLanguage = arr[1]; - } - } - prototype.DefaultDatabase = login.DefaultDatabase; - prototype.EnforcePolicy = login.EnforcePasswordPolicy; - prototype.EnforceExpiration = login.EnforcePasswordPolicy ? login.EnforcePasswordExpiration : false; - prototype.IsLockedOut = login.IsLockedOut; - prototype.IsDisabled = !login.IsEnabled; - prototype.MustChange = login.EnforcePasswordPolicy ? login.MustChangePassword : false; - prototype.WindowsGrantAccess = login.ConnectPermission; - - if (prototype.LoginType == SqlServer.Management.Smo.LoginType.SqlLogin) - { - // check that there is a password - // this check is made if policy enforcement is off - // with policy turned on we do not display this message, instead we let server - // return the error associated with null password (coming from policy) - see bug 124377 - if (prototype.SqlPassword.Length == 0 && prototype.EnforcePolicy == false) - { - // raise error here - } - - // check that password and confirm password controls' text matches - if (0 != string.Compare(prototype.SqlPassword, prototype.SqlPasswordConfirm, StringComparison.Ordinal)) - { - // raise error here - } - } - - var _ = prototype.ServerRoles.ServerRoleNames; - - foreach (string role in prototype.ServerRoles.ServerRoleNames) - { - prototype.ServerRoles.SetMember(role, false); - } - - foreach (string role in login.ServerRoles) - { - prototype.ServerRoles.SetMember(role, true); - } - - prototype.ApplyGeneralChanges(dataContainer.Server); - prototype.ApplyServerRoleChanges(dataContainer.Server); - prototype.ApplyDatabaseRoleChanges(dataContainer.Server); - await requestContext.SendResult(new object()); - } - - internal async Task HandleInitializeLoginViewRequest(InitializeLoginViewRequestParams parameters, RequestContext requestContext) - { - contextIdToConnectionUriMap.Add(parameters.ContextId, parameters.ConnectionUri); - ConnectionInfo connInfo; - ConnectionServiceInstance.TryFindConnection(parameters.ConnectionUri, out connInfo); - if (connInfo == null) - { - throw new ArgumentException("Invalid ConnectionUri"); - } - CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); - LoginViewInfo loginViewInfo = new LoginViewInfo(); - - // TODO cache databases and languages - string[] databases = new string[dataContainer.Server.Databases.Count]; - for (int i = 0; i < dataContainer.Server.Databases.Count; i++) - { - databases[i] = dataContainer.Server.Databases[i].Name; - } - - var languageOptions = LanguageUtils.GetDefaultLanguageOptions(dataContainer); - var languageOptionsList = languageOptions.Select(SecurityService.FormatLanguageDisplay).ToList(); - if (parameters.IsNewObject) - { - languageOptionsList.Insert(0, SR.DefaultLanguagePlaceholder); - } - string[] languages = languageOptionsList.ToArray(); - LoginPrototype prototype = parameters.IsNewObject - ? new LoginPrototype(dataContainer.Server) - : new LoginPrototype(dataContainer.Server, dataContainer.Server.Logins[parameters.Name]); - - List loginServerRoles = new List(); - foreach(string role in prototype.ServerRoles.ServerRoleNames) - { - if (prototype.ServerRoles.IsMember(role)) - { - loginServerRoles.Add(role); - } - } - - LoginInfo loginInfo = new LoginInfo() - { - Name = prototype.LoginName, - Password = prototype.SqlPassword, - OldPassword = prototype.OldPassword, - AuthenticationType = LoginTypeToAuthenticationType(prototype.LoginType), - EnforcePasswordExpiration = prototype.EnforceExpiration, - EnforcePasswordPolicy = prototype.EnforcePolicy, - MustChangePassword = prototype.MustChange, - DefaultDatabase = prototype.DefaultDatabase, - DefaultLanguage = parameters.IsNewObject ? SR.DefaultLanguagePlaceholder : FormatLanguageDisplay(languageOptions.FirstOrDefault(o => o?.Language.Name == prototype.DefaultLanguage || o?.Language.Alias == prototype.DefaultLanguage, null)), - ServerRoles = loginServerRoles.ToArray(), - ConnectPermission = prototype.WindowsGrantAccess, - IsEnabled = !prototype.IsDisabled, - IsLockedOut = prototype.IsLockedOut, - UserMapping = new ServerLoginDatabaseUserMapping[0] - }; - - await requestContext.SendResult(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. - CanEditLockedOutState = !parameters.IsNewObject && prototype.IsLockedOut, - Databases = databases, - Languages = languages, - ServerRoles = prototype.ServerRoles.ServerRoleNames, - SupportAdvancedPasswordOptions = dataContainer.Server.DatabaseEngineType == DatabaseEngineType.Standalone || dataContainer.Server.DatabaseEngineEdition == DatabaseEngineEdition.SqlDataWarehouse, - SupportAdvancedOptions = dataContainer.Server.DatabaseEngineType == DatabaseEngineType.Standalone || dataContainer.Server.DatabaseEngineEdition == DatabaseEngineEdition.SqlManagedInstance - }); - } - - private LoginAuthenticationType LoginTypeToAuthenticationType(LoginType loginType) - { - switch (loginType) - { - case LoginType.WindowsUser: - case LoginType.WindowsGroup: - return LoginAuthenticationType.Windows; - case LoginType.SqlLogin: - return LoginAuthenticationType.Sql; - case LoginType.ExternalUser: - case LoginType.ExternalGroup: - return LoginAuthenticationType.AAD; - default: - return LoginAuthenticationType.Others; - } - } - - internal async Task HandleDisposeLoginViewRequest(DisposeLoginViewRequestParams parameters, RequestContext requestContext) - { - await requestContext.SendResult(new object()); - } - - internal static string FormatLanguageDisplay(LanguageDisplay? l) - { - if (l == null) return null; - return string.Format("{0} - {1}", l.Language.Alias, l.Language.Name); - } - - #endregion - #region "Credential Handlers" /// @@ -416,10 +187,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Security } } - #endregion - - #region "Helpers" - internal Task> ConfigureCredential( string ownerUri, CredentialInfo credential, @@ -449,215 +216,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Security }); } - #endregion // "Helpers" - - // some potentially useful code for working with server & db roles to be refactored later - #region "Roles" - private class SchemaOwnership - { - public bool initiallyOwned; - public bool currentlyOwned; - - public SchemaOwnership(bool initiallyOwned) - { - this.initiallyOwned = initiallyOwned; - this.currentlyOwned = initiallyOwned; - } - } - - private class RoleMembership - { - public bool initiallyAMember; - public bool currentlyAMember; - - public RoleMembership(bool initiallyAMember) - { - this.initiallyAMember = initiallyAMember; - this.currentlyAMember = initiallyAMember; - } - - public RoleMembership(bool initiallyAMember, bool currentlyAMember) - { - this.initiallyAMember = initiallyAMember; - this.currentlyAMember = currentlyAMember; - } - } - - // private void DbRole_LoadMembership(string databaseName, string dbroleName, ServerConnection serverConnection) - // { - // var roleMembers = new HybridDictionary(); - // bool isPropertiesMode = false; - // if (isPropertiesMode) - // { - // Enumerator enumerator = new Enumerator(); - // Urn urn = String.Format(System.Globalization.CultureInfo.InvariantCulture, - // "Server/Database[@Name='{0}']/Role[@Name='{1}']/Member", - // Urn.EscapeString(databaseName), - // Urn.EscapeString(dbroleName)); - // string[] fields = new string[] { "Name" }; - // OrderBy[] orderBy = new OrderBy[] { new OrderBy("Name", OrderBy.Direction.Asc)}; - // Request request = new Request(urn, fields, orderBy); - // DataTable dt = enumerator.Process(serverConnection, request); - - // foreach (DataRow dr in dt.Rows) - // { - // string memberName = dr["Name"].ToString(); - // if (memberName != null) - // { - // roleMembers[memberName] = new RoleMembership(true); - // } - // } - // } - // } - - // /// - // /// sends to server user changes related to membership - // /// - // private void DbRole_SendToServerMembershipChanges(Database db, DatabaseRole dbrole) - // { - // var roleMembers = new HybridDictionary(); - // IDictionaryEnumerator enumerator = roleMembers.GetEnumerator(); - // enumerator.Reset(); - - // while (enumerator.MoveNext()) - // { - // DictionaryEntry entry = enumerator.Entry; - // string memberName = entry.Key.ToString(); - // RoleMembership membership = (RoleMembership) entry.Value; - // if (membership != null) - // { - // if (!membership.initiallyAMember && membership.currentlyAMember) - // { - // dbrole.AddMember(memberName); - // } - // else if (membership.initiallyAMember && !membership.currentlyAMember) - // { - // dbrole.DropMember(memberName); - // } - // } - // } - // } - - // private void InitProp(ServerConnection serverConnection, string serverName, string databaseName, - // string dbroleName, string dbroleUrn, bool isPropertiesMode) - // { - // System.Diagnostics.Debug.Assert(serverName!=null); - // System.Diagnostics.Debug.Assert((databaseName!=null) && (databaseName.Trim().Length!=0)); - - // // LoadSchemas(); - // // LoadMembership(); - - // if (isPropertiesMode == true) - // { - // // initialize from enumerator in properties mode - // System.Diagnostics.Debug.Assert(dbroleName!=null); - // System.Diagnostics.Debug.Assert(dbroleName.Trim().Length !=0); - // System.Diagnostics.Debug.Assert(dbroleUrn!=null); - // System.Diagnostics.Debug.Assert(dbroleUrn.Trim().Length != 0); - - // Enumerator en = new Enumerator(); - // Request req = new Request(); - // req.Fields = new String [] { "Owner" }; - - // if ((dbroleUrn!=null) && (dbroleUrn.Trim().Length != 0)) - // { - // req.Urn = dbroleUrn; - // } - // else - // { - // req.Urn = "Server/Database[@Name='" + Urn.EscapeString(databaseName) + "']/Role[@Name='" + Urn.EscapeString(dbroleName) + "]"; - // } - - // DataTable dt = en.Process(serverConnection, req); - // System.Diagnostics.Debug.Assert(dt!=null); - // System.Diagnostics.Debug.Assert(dt.Rows.Count==1); - - // if (dt.Rows.Count==0) - // { - // throw new Exception("DatabaseRoleSR.ErrorDbRoleNotFound"); - // } - - // // DataRow dr = dt.Rows[0]; - // // this.initialOwner = Convert.ToString(dr[DatabaseRoleGeneral.ownerField],System.Globalization.CultureInfo.InvariantCulture); - // // this.textBoxOwner.Text = this.initialOwner; - // } - // } - - // private void DbRole_SendDataToServer(CDataContainer dataContainer, string databaseName, - // string dbroleName, string ownerName, string initialOwner, string roleName, bool isPropertiesMode) - // { - // System.Diagnostics.Debug.Assert(databaseName != null && databaseName.Trim().Length != 0, "database name is empty"); - // System.Diagnostics.Debug.Assert(dataContainer.Server != null, "server is null"); - - // Database database = dataContainer.Server.Databases[databaseName]; - // System.Diagnostics.Debug.Assert(database!= null, "database is null"); - - // DatabaseRole role; - - // if (isPropertiesMode == true) // in properties mode -> alter role - // { - // System.Diagnostics.Debug.Assert(dbroleName != null && dbroleName.Trim().Length != 0, "role name is empty"); - - // role = database.Roles[dbroleName]; - // System.Diagnostics.Debug.Assert(role != null, "role is null"); - - // if (0 != String.Compare(ownerName, initialOwner, StringComparison.Ordinal)) - // { - // role.Owner = ownerName; - // role.Alter(); - // } - // } - // else // not in properties mode -> create role - // { - // role = new DatabaseRole(database, roleName); - // if (ownerName.Length != 0) - // { - // role.Owner = ownerName; - // } - - // role.Create(); - // } - - // // SendToServerSchemaOwnershipChanges(database, role); - // // SendToServerMembershipChanges(database, role); - // } - - - // /// - // /// sends to server changes related to schema ownership - // /// - // private void DbRole_SendToServerSchemaOwnershipChanges(CDataContainer dataContainer, Database db, DatabaseRole dbrole) - // { - // if (dataContainer.Server == null) - // { - // return; - // } - - // HybridDictionary schemaOwnership = new HybridDictionary(); - // if (9 <= dataContainer.Server.Information.Version.Major) - // { - // IDictionaryEnumerator enumerator = schemaOwnership.GetEnumerator(); - // enumerator.Reset(); - // while (enumerator.MoveNext()) - // { - // DictionaryEntry de = enumerator.Entry; - // string schemaName = de.Key.ToString(); - // SchemaOwnership ownership = (SchemaOwnership)de.Value; - - // // If we are creating a new role, then no schema will have been initially owned by this role. - // // If we are modifying an existing role, we can only take ownership of roles. (Ownership can't - // // be renounced, it can only be positively assigned to a principal.) - // if (ownership != null && (ownership.currentlyOwned && !ownership.initiallyOwned)) - // { - // Schema schema = db.Schemas[schemaName]; - // schema.Owner = dbrole.Name; - // schema.Alter(); - // } - // } - // } - // } - - #endregion - + #endregion // "Credential Handlers" } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Security/UserActions.cs b/src/Microsoft.SqlTools.ServiceLayer/Security/UserActions.cs index 1f387301..5eb62935 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Security/UserActions.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Security/UserActions.cs @@ -105,7 +105,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security Database? parentDb = dataContainer.Server.GetSmoObject(databaseUrn) as Database; var languageOptions = LanguageUtils.GetDefaultLanguageOptions(dataContainer); - var languageOptionsList = languageOptions.Select(SecurityService.FormatLanguageDisplay).ToList(); + var languageOptionsList = languageOptions.Select(LanguageUtils.FormatLanguageDisplay).ToList(); languageOptionsList.Insert(0, SR.DefaultLanguagePlaceholder); // if viewing an exisitng user then populate some properties @@ -214,7 +214,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security DefaultSchema = defaultSchema, OwnedSchemas = schemaNames.ToArray(), DatabaseRoles = databaseRoles.ToArray(), - DefaultLanguage = SecurityService.FormatLanguageDisplay( + DefaultLanguage = LanguageUtils.FormatLanguageDisplay( languageOptions.FirstOrDefault(o => o?.Language.Name == defaultLanguageAlias || o?.Language.Alias == defaultLanguageAlias, null)), }, SupportContainedUser = supportsContainedUser, diff --git a/src/Microsoft.SqlTools.ServiceLayer/Utility/LanguageUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/Utility/LanguageUtils.cs index ec9c6033..9ffe21bf 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Utility/LanguageUtils.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Utility/LanguageUtils.cs @@ -191,6 +191,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility && server.ServerType != DatabaseEngineType.SqlAzureDatabase; } + public static string FormatLanguageDisplay(LanguageDisplay? l) + { + if (l == null) + { + return null; + } + return string.Format("{0} - {1}", l.Language.Alias, l.Language.Name); + } } internal class LanguageChoice diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/LoginTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/LoginTests.cs index 0068b4d1..a9e5d2d7 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/LoginTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/LoginTests.cs @@ -54,7 +54,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security .Returns(Task.FromResult(new LoginViewInfo())); // call the create login method - SecurityService service = new SecurityService(); + LoginServiceHandlerImpl service = new LoginServiceHandlerImpl(); await service.HandleInitializeLoginViewRequest(initializeLoginViewRequestParams, initializeLoginViewContext.Object); await service.HandleCreateLoginRequest(loginParams, createLoginContext.Object); diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/SecurityTestUtils.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/SecurityTestUtils.cs index c322ea10..9d9b8a5a 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/SecurityTestUtils.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/SecurityTestUtils.cs @@ -129,7 +129,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security await SecurityTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, SecurityTestUtils.GetCredentialURN(credential.Name)); } - internal static async Task CreateLogin(SecurityService service, TestConnectionResult connectionResult) + internal static async Task CreateLogin(LoginServiceHandlerImpl service, TestConnectionResult connectionResult) { string contextId = System.Guid.NewGuid().ToString(); var initializeLoginViewRequestParams = new InitializeLoginViewRequestParams diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/UserTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/UserTests.cs index 780bc69e..7a37884c 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/UserTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Security/UserTests.cs @@ -27,11 +27,11 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) { // setup - SecurityService service = new SecurityService(); UserServiceHandlerImpl userService = new UserServiceHandlerImpl(); + LoginServiceHandlerImpl loginService = new LoginServiceHandlerImpl(); var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath); - var login = await SecurityTestUtils.CreateLogin(service, connectionResult); + var login = await SecurityTestUtils.CreateLogin(loginService, connectionResult); var user = await SecurityTestUtils.CreateUser(userService, connectionResult, DatabaseUserType.WithLogin, null, login.Name); @@ -50,7 +50,6 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) { // setup - SecurityService service = new SecurityService(); UserServiceHandlerImpl userService = new UserServiceHandlerImpl(); var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath); @@ -73,7 +72,6 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) { // setup - SecurityService service = new SecurityService(); UserServiceHandlerImpl userService = new UserServiceHandlerImpl(); string databaseName = "CRM"; var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync(databaseName, queryTempFile.FilePath); @@ -99,11 +97,11 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) { // setup - SecurityService service = new SecurityService(); UserServiceHandlerImpl userService = new UserServiceHandlerImpl(); + LoginServiceHandlerImpl loginService = new LoginServiceHandlerImpl(); var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath); - var login = await SecurityTestUtils.CreateLogin(service, connectionResult); + var login = await SecurityTestUtils.CreateLogin(loginService, connectionResult); var user = await SecurityTestUtils.CreateUser(userService, connectionResult, DatabaseUserType.WithLogin, null, login.Name);