mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-22 09:35:38 -05:00
User management support classes (#1856)
* WIP * Fix nullable warnings in UserData class * WIP2 * WIP * Refresh database prototype classes * Fix some typos & merge issues * WIP * WIP * WIP * Additional updates * Remove unneded using
This commit is contained in:
@@ -58,7 +58,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
||||
/// </summary>
|
||||
public class UserInfo
|
||||
{
|
||||
DatabaseUserType? Type { get; set; }
|
||||
public DatabaseUserType? Type { get; set; }
|
||||
|
||||
public string UserName { get; set; }
|
||||
|
||||
public string LoginName { get; set; }
|
||||
|
||||
@@ -72,9 +74,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
||||
|
||||
public bool isAAD { get; set; }
|
||||
|
||||
public ExtendedProperty[] ExtendedProperties { get; set; }
|
||||
public ExtendedProperty[]? ExtendedProperties { get; set; }
|
||||
|
||||
public SecurablePermissions[] SecurablePermissions { get; set; }
|
||||
public SecurablePermissions[]? SecurablePermissions { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Create User parameters
|
||||
/// </summary>
|
||||
public class CreateUserParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public UserInfo User { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create User result
|
||||
/// </summary>
|
||||
public class CreateUserResult : ResultStatus
|
||||
{
|
||||
public UserInfo User { get; set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create User request type
|
||||
/// </summary>
|
||||
public class CreateUserRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<CreateUserParams, CreateUserResult> Type =
|
||||
RequestType<CreateUserParams, CreateUserResult>.Create("objectmanagement/createuser");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete User params
|
||||
/// </summary>
|
||||
public class DeleteUserParams : GeneralRequestDetails
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public string UserName { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete User request type
|
||||
/// </summary>
|
||||
public class DeleteUserRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Request definition
|
||||
/// </summary>
|
||||
public static readonly
|
||||
RequestType<DeleteUserParams, ResultStatus> Type =
|
||||
RequestType<DeleteUserParams, ResultStatus>.Create("objectmanagement/deleteuser");
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data;
|
||||
using System.Security;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Dmf;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
@@ -31,7 +31,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
{
|
||||
private bool disposed;
|
||||
|
||||
private ConnectionService connectionService = null;
|
||||
private ConnectionService connectionService;
|
||||
|
||||
private static readonly Lazy<SecurityService> instance = new Lazy<SecurityService>(() => new SecurityService());
|
||||
|
||||
@@ -93,6 +93,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
// Login request handlers
|
||||
this.ServiceHost.SetRequestHandler(CreateLoginRequest.Type, HandleCreateLoginRequest, true);
|
||||
this.ServiceHost.SetRequestHandler(DeleteLoginRequest.Type, HandleDeleteLoginRequest, true);
|
||||
|
||||
// User request handlers
|
||||
this.ServiceHost.SetRequestHandler(CreateUserRequest.Type, HandleCreateUserRequest, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -170,112 +173,73 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
|
||||
#region "User Handlers"
|
||||
|
||||
private UserPrototype InitUserNew(CDataContainer dataContainer)
|
||||
internal Task<Tuple<bool, string>> ConfigureUser(
|
||||
string ownerUri,
|
||||
UserInfo user,
|
||||
ConfigAction configAction,
|
||||
RunType runType)
|
||||
{
|
||||
// this.DataContainer = context;
|
||||
// this.parentDbUrn = new Urn(this.DataContainer.ParentUrn);
|
||||
// this.objectUrn = new Urn(this.DataContainer.ObjectUrn);
|
||||
ExhaustiveUserTypes currentUserType;
|
||||
UserPrototypeFactory userPrototypeFactory = UserPrototypeFactory.GetInstance(dataContainer);
|
||||
|
||||
if (dataContainer.IsNewObject)
|
||||
return Task<Tuple<bool, string>>.Run(() =>
|
||||
{
|
||||
if (IsParentDatabaseContained(dataContainer.ParentUrn, dataContainer))
|
||||
try
|
||||
{
|
||||
currentUserType = ExhaustiveUserTypes.SqlUserWithPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentUserType = ExhaustiveUserTypes.LoginMappedUser;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
currentUserType = this.GetCurrentUserTypeForExistingUser(
|
||||
dataContainer.Server.GetSmoObject(dataContainer.ObjectUrn) as User);
|
||||
}
|
||||
|
||||
UserPrototype currentUserPrototype = userPrototypeFactory.GetUserPrototype(currentUserType);
|
||||
return currentUserPrototype;
|
||||
}
|
||||
|
||||
private ExhaustiveUserTypes GetCurrentUserTypeForExistingUser(User user)
|
||||
{
|
||||
switch (user.UserType)
|
||||
{
|
||||
case UserType.SqlUser:
|
||||
if (user.IsSupportedProperty("AuthenticationType"))
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo);
|
||||
if (connInfo == null)
|
||||
{
|
||||
if (user.AuthenticationType == AuthenticationType.Windows)
|
||||
{
|
||||
return ExhaustiveUserTypes.WindowsUser;
|
||||
}
|
||||
else if (user.AuthenticationType == AuthenticationType.Database)
|
||||
{
|
||||
return ExhaustiveUserTypes.SqlUserWithPassword;
|
||||
}
|
||||
throw new ArgumentException("Invalid connection URI '{0}'", ownerUri);
|
||||
}
|
||||
|
||||
return ExhaustiveUserTypes.LoginMappedUser;
|
||||
|
||||
case UserType.NoLogin:
|
||||
return ExhaustiveUserTypes.SqlUserWithoutLogin;
|
||||
|
||||
case UserType.Certificate:
|
||||
return ExhaustiveUserTypes.CertificateMappedUser;
|
||||
|
||||
case UserType.AsymmetricKey:
|
||||
return ExhaustiveUserTypes.AsymmetricKeyMappedUser;
|
||||
|
||||
default:
|
||||
return ExhaustiveUserTypes.Unknown;
|
||||
}
|
||||
var serverConnection = ConnectionService.OpenServerConnection(connInfo, "DataContainer");
|
||||
var connectionInfoWithConnection = new SqlConnectionInfoWithConnection();
|
||||
connectionInfoWithConnection.ServerConnection = serverConnection;
|
||||
|
||||
string urn = string.Format(System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Server/Database[@Name='{0}']",
|
||||
Urn.EscapeString(serverConnection.DatabaseName));
|
||||
|
||||
ActionContext context = new ActionContext(serverConnection, "new_user", urn);
|
||||
DataContainerXmlGenerator containerXml = new DataContainerXmlGenerator(context);
|
||||
containerXml.AddProperty("itemtype", "User");
|
||||
|
||||
XmlDocument xmlDoc = containerXml.GenerateXmlDocument();
|
||||
bool objectExists = configAction != ConfigAction.Create;
|
||||
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connectionInfoWithConnection, xmlDoc);
|
||||
|
||||
using (var actions = new UserActions(dataContainer, user, configAction))
|
||||
{
|
||||
var executionHandler = new ExecutonHandler(actions);
|
||||
executionHandler.RunNow(runType, this);
|
||||
}
|
||||
|
||||
return new Tuple<bool, string>(true, string.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Tuple<bool, string>(false, ex.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private bool IsParentDatabaseContained(Urn parentDbUrn, CDataContainer dataContainer)
|
||||
/// <summary>
|
||||
/// Handle request to create a user
|
||||
/// </summary>
|
||||
internal async Task HandleCreateUserRequest(CreateUserParams parameters, RequestContext<CreateUserResult> requestContext)
|
||||
{
|
||||
string parentDbName = parentDbUrn.GetNameForType("Database");
|
||||
Database parentDatabase = dataContainer.Server.Databases[parentDbName];
|
||||
var result = await ConfigureUser(parameters.OwnerUri,
|
||||
parameters.User,
|
||||
ConfigAction.Create,
|
||||
RunType.RunNow);
|
||||
|
||||
if (parentDatabase.IsSupportedProperty("ContainmentType")
|
||||
&& parentDatabase.ContainmentType == ContainmentType.Partial)
|
||||
await requestContext.SendResult(new CreateUserResult()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
User = parameters.User,
|
||||
Success = result.Item1,
|
||||
ErrorMessage = result.Item2
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void GetUserTypeOptions(CDataContainer dataContainer)
|
||||
{
|
||||
if (SqlMgmtUtils.IsSql11OrLater(dataContainer.Server.ServerVersion)
|
||||
&& IsParentDatabaseContained(dataContainer.ParentUrn, dataContainer))
|
||||
{
|
||||
// this.userTypeComboBox.Items.AddRange(
|
||||
// new string[]{
|
||||
// UserSR.SqlUserWithPasswordUserTypeText
|
||||
// }
|
||||
//);
|
||||
}
|
||||
if (SqlMgmtUtils.IsYukonOrAbove(dataContainer.Server))
|
||||
{
|
||||
// this.userTypeComboBox.Items.AddRange(
|
||||
// new string[]{
|
||||
// UserSR.AsymmetricKeyUserTypeText,
|
||||
// UserSR.CertificateUserTypeText,
|
||||
// UserSR.WithoutLoginSqlUserTypeText,
|
||||
// UserSR.WindowsUserTypeText
|
||||
// }
|
||||
// );
|
||||
}
|
||||
// this.userTypeComboBox.Items.AddRange(
|
||||
// new string[]{
|
||||
// UserSR.LoginMappedSqlUserTypeText
|
||||
// }
|
||||
// );
|
||||
}
|
||||
|
||||
private void GetDefaultLanguageOptions(CDataContainer dataContainer)
|
||||
{
|
||||
// this.defaultLanguageComboBox.Items.Clear();
|
||||
@@ -298,65 +262,54 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
}
|
||||
}
|
||||
|
||||
private SecureString GetReadOnlySecureString(string secret)
|
||||
{
|
||||
SecureString ss = new SecureString();
|
||||
foreach (char c in secret.ToCharArray())
|
||||
{
|
||||
ss.AppendChar(c);
|
||||
}
|
||||
ss.MakeReadOnly();
|
||||
// code needs to be ported into the useraction class
|
||||
// public void UserMemberships_OnRunNow(object sender, CDataContainer dataContainer)
|
||||
// {
|
||||
// UserPrototype currentPrototype = UserPrototypeFactory.GetInstance(dataContainer).CurrentPrototype;
|
||||
|
||||
return ss;
|
||||
}
|
||||
// //In case the UserGeneral/OwnedSchemas pages are loaded,
|
||||
// //those will takes care of applying membership changes also.
|
||||
// //Hence, we only need to apply changes in this method when those are not loaded.
|
||||
// if (!currentPrototype.IsRoleMembershipChangesApplied)
|
||||
// {
|
||||
// //base.OnRunNow(sender);
|
||||
|
||||
public void UserMemberships_OnRunNow(object sender, CDataContainer dataContainer)
|
||||
{
|
||||
UserPrototype currentPrototype = UserPrototypeFactory.GetInstance(dataContainer).CurrentPrototype;
|
||||
// User user = currentPrototype.ApplyChanges();
|
||||
|
||||
//In case the UserGeneral/OwnedSchemas pages are loaded,
|
||||
//those will takes care of applying membership changes also.
|
||||
//Hence, we only need to apply changes in this method when those are not loaded.
|
||||
if (!currentPrototype.IsRoleMembershipChangesApplied)
|
||||
{
|
||||
//base.OnRunNow(sender);
|
||||
// //this.ExecutionMode = ExecutionMode.Success;
|
||||
// dataContainer.ObjectName = currentPrototype.Name;
|
||||
// dataContainer.SqlDialogSubject = user;
|
||||
// }
|
||||
|
||||
User user = currentPrototype.ApplyChanges();
|
||||
// //setting back to original after changes are applied
|
||||
// currentPrototype.IsRoleMembershipChangesApplied = false;
|
||||
// }
|
||||
|
||||
//this.ExecutionMode = ExecutionMode.Success;
|
||||
dataContainer.ObjectName = currentPrototype.Name;
|
||||
dataContainer.SqlDialogSubject = user;
|
||||
}
|
||||
// /// <summary>
|
||||
// /// implementation of OnPanelRunNow
|
||||
// /// </summary>
|
||||
// /// <param name="node"></param>
|
||||
// public void UserOwnedSchemas_OnRunNow(object sender, CDataContainer dataContainer)
|
||||
// {
|
||||
// UserPrototype currentPrototype = UserPrototypeFactory.GetInstance(dataContainer).CurrentPrototype;
|
||||
|
||||
//setting back to original after changes are applied
|
||||
currentPrototype.IsRoleMembershipChangesApplied = false;
|
||||
}
|
||||
// //In case the UserGeneral/Membership pages are loaded,
|
||||
// //those will takes care of applying schema ownership changes also.
|
||||
// //Hence, we only need to apply changes in this method when those are not loaded.
|
||||
// if (!currentPrototype.IsSchemaOwnershipChangesApplied)
|
||||
// {
|
||||
// //base.OnRunNow(sender);
|
||||
|
||||
/// <summary>
|
||||
/// implementation of OnPanelRunNow
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
public void UserOwnedSchemas_OnRunNow(object sender, CDataContainer dataContainer)
|
||||
{
|
||||
UserPrototype currentPrototype = UserPrototypeFactory.GetInstance(dataContainer).CurrentPrototype;
|
||||
// User user = currentPrototype.ApplyChanges();
|
||||
|
||||
//In case the UserGeneral/Membership pages are loaded,
|
||||
//those will takes care of applying schema ownership changes also.
|
||||
//Hence, we only need to apply changes in this method when those are not loaded.
|
||||
if (!currentPrototype.IsSchemaOwnershipChangesApplied)
|
||||
{
|
||||
//base.OnRunNow(sender);
|
||||
// //this.ExecutionMode = ExecutionMode.Success;
|
||||
// dataContainer.ObjectName = currentPrototype.Name;
|
||||
// dataContainer.SqlDialogSubject = user;
|
||||
// }
|
||||
|
||||
User user = currentPrototype.ApplyChanges();
|
||||
|
||||
//this.ExecutionMode = ExecutionMode.Success;
|
||||
dataContainer.ObjectName = currentPrototype.Name;
|
||||
dataContainer.SqlDialogSubject = user;
|
||||
}
|
||||
|
||||
//setting back to original after changes are applied
|
||||
currentPrototype.IsSchemaOwnershipChangesApplied = false;
|
||||
}
|
||||
// //setting back to original after changes are applied
|
||||
// currentPrototype.IsSchemaOwnershipChangesApplied = false;
|
||||
// }
|
||||
|
||||
// how to populate defaults from prototype, will delete once refactored
|
||||
// private void InitializeValuesInUiControls()
|
||||
@@ -855,7 +808,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
Database database = dataContainer.Server.Databases[databaseName];
|
||||
System.Diagnostics.Debug.Assert(database!= null, "database is null");
|
||||
|
||||
DatabaseRole role = null;
|
||||
DatabaseRole role;
|
||||
|
||||
if (isPropertiesMode == true) // in properties mode -> alter role
|
||||
{
|
||||
@@ -888,7 +841,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
private void DbRole_LoadSchemas(string databaseName, string dbroleName, ServerConnection serverConnection)
|
||||
{
|
||||
bool isPropertiesMode = false;
|
||||
HybridDictionary schemaOwnership = null;
|
||||
HybridDictionary schemaOwnership;
|
||||
schemaOwnership = new HybridDictionary();
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
|
||||
144
src/Microsoft.SqlTools.ServiceLayer/Security/UserActions.cs
Normal file
144
src/Microsoft.SqlTools.ServiceLayer/Security/UserActions.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using Microsoft.SqlTools.ServiceLayer.Security.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
{
|
||||
internal class UserActions : ManagementActionBase
|
||||
{
|
||||
#region Variables
|
||||
//private UserPrototypeData userData;
|
||||
private UserPrototype userPrototype;
|
||||
private UserInfo user;
|
||||
private ConfigAction configAction;
|
||||
#endregion
|
||||
|
||||
#region Constructors / Dispose
|
||||
/// <summary>
|
||||
/// required when loading from Object Explorer context
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public UserActions(
|
||||
CDataContainer context,
|
||||
UserInfo user,
|
||||
ConfigAction configAction)
|
||||
{
|
||||
this.DataContainer = context;
|
||||
this.user = user;
|
||||
this.configAction = configAction;
|
||||
|
||||
this.userPrototype = InitUserNew(context, user);
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// Clean up any resources being used.
|
||||
// /// </summary>
|
||||
// protected override void Dispose(bool disposing)
|
||||
// {
|
||||
// base.Dispose(disposing);
|
||||
// }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// called on background thread by the framework to execute the action
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
public override void OnRunNow(object sender)
|
||||
{
|
||||
if (this.configAction == ConfigAction.Drop)
|
||||
{
|
||||
// if (this.credentialData.Credential != null)
|
||||
// {
|
||||
// this.credentialData.Credential.DropIfExists();
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
this.userPrototype.ApplyChanges();
|
||||
}
|
||||
}
|
||||
|
||||
private UserPrototype InitUserNew(CDataContainer dataContainer, UserInfo user)
|
||||
{
|
||||
// this.DataContainer = context;
|
||||
// this.parentDbUrn = new Urn(this.DataContainer.ParentUrn);
|
||||
// this.objectUrn = new Urn(this.DataContainer.ObjectUrn);
|
||||
ExhaustiveUserTypes currentUserType;
|
||||
UserPrototypeFactory userPrototypeFactory = UserPrototypeFactory.GetInstance(dataContainer, user);
|
||||
|
||||
if (dataContainer.IsNewObject)
|
||||
{
|
||||
if (IsParentDatabaseContained(dataContainer.ParentUrn, dataContainer))
|
||||
{
|
||||
currentUserType = ExhaustiveUserTypes.SqlUserWithPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentUserType = ExhaustiveUserTypes.LoginMappedUser;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
currentUserType = this.GetCurrentUserTypeForExistingUser(
|
||||
dataContainer.Server.GetSmoObject(dataContainer.ObjectUrn) as User);
|
||||
}
|
||||
|
||||
UserPrototype currentUserPrototype = userPrototypeFactory.GetUserPrototype(currentUserType);
|
||||
return currentUserPrototype;
|
||||
}
|
||||
|
||||
private ExhaustiveUserTypes GetCurrentUserTypeForExistingUser(User user)
|
||||
{
|
||||
switch (user.UserType)
|
||||
{
|
||||
case UserType.SqlUser:
|
||||
if (user.IsSupportedProperty("AuthenticationType"))
|
||||
{
|
||||
if (user.AuthenticationType == AuthenticationType.Windows)
|
||||
{
|
||||
return ExhaustiveUserTypes.WindowsUser;
|
||||
}
|
||||
else if (user.AuthenticationType == AuthenticationType.Database)
|
||||
{
|
||||
return ExhaustiveUserTypes.SqlUserWithPassword;
|
||||
}
|
||||
}
|
||||
|
||||
return ExhaustiveUserTypes.LoginMappedUser;
|
||||
|
||||
case UserType.NoLogin:
|
||||
return ExhaustiveUserTypes.SqlUserWithoutLogin;
|
||||
|
||||
case UserType.Certificate:
|
||||
return ExhaustiveUserTypes.CertificateMappedUser;
|
||||
|
||||
case UserType.AsymmetricKey:
|
||||
return ExhaustiveUserTypes.AsymmetricKeyMappedUser;
|
||||
|
||||
default:
|
||||
return ExhaustiveUserTypes.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsParentDatabaseContained(Urn parentDbUrn, CDataContainer dataContainer)
|
||||
{
|
||||
string parentDbName = parentDbUrn.GetNameForType("Database");
|
||||
Database parentDatabase = dataContainer.Server.Databases[parentDbName];
|
||||
|
||||
if (parentDatabase.IsSupportedProperty("ContainmentType")
|
||||
&& parentDatabase.ContainmentType == ContainmentType.Partial)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,13 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using System.Linq;
|
||||
using Microsoft.SqlTools.ServiceLayer.Security.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
{
|
||||
@@ -101,7 +103,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
this.isMember = new Dictionary<string, bool>();
|
||||
}
|
||||
|
||||
public UserPrototypeData(CDataContainer context)
|
||||
public UserPrototypeData(CDataContainer context, UserInfo userInfo)
|
||||
{
|
||||
this.isSchemaOwned = new Dictionary<string, bool>();
|
||||
this.isMember = new Dictionary<string, bool>();
|
||||
@@ -110,10 +112,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
{
|
||||
this.LoadUserData(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.name = userInfo.UserName;
|
||||
this.mappedLoginName = userInfo.LoginName;
|
||||
this.defaultSchemaName = userInfo.DefaultSchema;
|
||||
this.password = DatabaseUtils.GetReadOnlySecureString(userInfo.Password);
|
||||
}
|
||||
|
||||
this.LoadRoleMembership(context);
|
||||
|
||||
this.LoadSchemaData(context);
|
||||
this.LoadSchemaData(context);
|
||||
}
|
||||
|
||||
public UserPrototypeData Clone()
|
||||
@@ -465,7 +474,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
var comparer = this.parent.GetStringComparer();
|
||||
if (comparer.Compare(dbRole.Name, "public") != 0)
|
||||
{
|
||||
this.roleNames.Add(dbRole.Name);
|
||||
roleNames.Add(dbRole.Name);
|
||||
}
|
||||
}
|
||||
return roleNames;
|
||||
@@ -483,7 +492,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
|
||||
foreach (Schema sch in this.parent.Schemas)
|
||||
{
|
||||
this.schemaNames.Add(sch.Name);
|
||||
schemaNames.Add(sch.Name);
|
||||
}
|
||||
return schemaNames;
|
||||
}
|
||||
@@ -539,7 +548,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
{
|
||||
enumerator.Reset();
|
||||
|
||||
String? nullString = null;
|
||||
string? nullString = null;
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
@@ -597,15 +606,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
}
|
||||
|
||||
if ((this.currentState.userType == UserType.Certificate)
|
||||
&&(!this.Exists || (user.Certificate != this.currentState.certificateName))
|
||||
)
|
||||
&&(!this.Exists || (user.Certificate != this.currentState.certificateName)))
|
||||
{
|
||||
user.Certificate = this.currentState.certificateName;
|
||||
}
|
||||
|
||||
if ((this.currentState.userType == UserType.AsymmetricKey)
|
||||
&& (!this.Exists || (user.AsymmetricKey != this.currentState.asymmetricKeyName))
|
||||
)
|
||||
&& (!this.Exists || (user.AsymmetricKey != this.currentState.asymmetricKeyName)))
|
||||
{
|
||||
user.AsymmetricKey = this.currentState.asymmetricKeyName;
|
||||
}
|
||||
@@ -621,7 +628,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
result = this.parent.Users[this.originalState.name];
|
||||
result?.Refresh();
|
||||
|
||||
System.Diagnostics.Debug.Assert(0 == String.Compare(this.originalState.name, this.currentState.name, StringComparison.Ordinal), "name of existing user has changed");
|
||||
System.Diagnostics.Debug.Assert(0 == string.Compare(this.originalState.name, this.currentState.name, StringComparison.Ordinal), "name of existing user has changed");
|
||||
if (result == null)
|
||||
{
|
||||
throw new Exception();
|
||||
@@ -756,7 +763,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
{
|
||||
//Default Schema was not supported before Denali for windows group.
|
||||
User user = this.GetUser();
|
||||
if (this.Exists && user.LoginType == LoginType.WindowsGroup)
|
||||
if (this.Exists && user.LoginType == Microsoft.SqlServer.Management.Smo.LoginType.WindowsGroup)
|
||||
{
|
||||
return SqlMgmtUtils.IsSql11OrLater(this.context.Server.ConnectionContext.ServerVersion);
|
||||
}
|
||||
@@ -993,15 +1000,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
}
|
||||
}
|
||||
|
||||
private UserPrototypeFactory(CDataContainer context)
|
||||
private UserPrototypeFactory(CDataContainer context, UserInfo user)
|
||||
{
|
||||
this.context = context;
|
||||
|
||||
this.originalData = new UserPrototypeData(this.context);
|
||||
this.originalData = new UserPrototypeData(this.context, user);
|
||||
this.currentData = this.originalData.Clone();
|
||||
}
|
||||
|
||||
public static UserPrototypeFactory GetInstance(CDataContainer context)
|
||||
public static UserPrototypeFactory GetInstance(CDataContainer context, UserInfo user)
|
||||
{
|
||||
if (singletonInstance != null
|
||||
&& singletonInstance.context != context)
|
||||
@@ -1009,7 +1016,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
singletonInstance = null;
|
||||
}
|
||||
|
||||
singletonInstance ??= new UserPrototypeFactory(context);
|
||||
singletonInstance ??= new UserPrototypeFactory(context, user);
|
||||
|
||||
return singletonInstance;
|
||||
}
|
||||
@@ -1076,87 +1083,4 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
||||
CertificateMappedUser,
|
||||
AsymmetricKeyMappedUser
|
||||
};
|
||||
|
||||
internal class LanguageUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets alias for a language name.
|
||||
/// </summary>
|
||||
/// <param name="connectedServer"></param>
|
||||
/// <param name="languageName"></param>
|
||||
/// <returns>Returns string.Empty in case it doesn't find a matching languageName on the server</returns>
|
||||
public static string GetLanguageAliasFromName(Server connectedServer,
|
||||
string languageName)
|
||||
{
|
||||
string languageAlias = string.Empty;
|
||||
|
||||
SetLanguageDefaultInitFieldsForDefaultLanguages(connectedServer);
|
||||
|
||||
foreach (Language lang in connectedServer.Languages)
|
||||
{
|
||||
if (lang.Name == languageName)
|
||||
{
|
||||
languageAlias = lang.Alias;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return languageAlias;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets name for a language alias.
|
||||
/// </summary>
|
||||
/// <param name="connectedServer"></param>
|
||||
/// <param name="languageAlias"></param>
|
||||
/// <returns>Returns string.Empty in case it doesn't find a matching languageAlias on the server</returns>
|
||||
public static string GetLanguageNameFromAlias(Server connectedServer,
|
||||
string languageAlias)
|
||||
{
|
||||
string languageName = string.Empty;
|
||||
|
||||
SetLanguageDefaultInitFieldsForDefaultLanguages(connectedServer);
|
||||
|
||||
foreach (Language lang in connectedServer.Languages)
|
||||
{
|
||||
if (lang.Alias == languageAlias)
|
||||
{
|
||||
languageName = lang.Name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return languageName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets exhaustive fields required for displaying and working with default languages in server,
|
||||
/// database and user dialogs as default init fields so that queries are not sent again and again.
|
||||
/// </summary>
|
||||
/// <param name="connectedServer">server on which languages will be enumerated</param>
|
||||
public static void SetLanguageDefaultInitFieldsForDefaultLanguages(Server connectedServer)
|
||||
{
|
||||
string[] fieldsNeeded = new string[] { "Alias", "Name", "LocaleID", "LangID" };
|
||||
connectedServer.SetDefaultInitFields(typeof(Language), fieldsNeeded);
|
||||
}
|
||||
}
|
||||
|
||||
internal class ObjectNoLongerExistsException : Exception
|
||||
{
|
||||
private static string ExceptionMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Object no longer exists";
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectNoLongerExistsException()
|
||||
: base(ExceptionMessage)
|
||||
{
|
||||
//
|
||||
// TODO: Add constructor logic here
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user