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:
Karl Burtram
2023-02-08 18:02:08 -08:00
committed by GitHub
parent ee086e2067
commit 2ef5f0918a
24 changed files with 3584 additions and 1336 deletions

View File

@@ -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
//
}
}
}