Enable support for Windows users (#1957)

* WIP

* Update for Windows user
This commit is contained in:
Karl Burtram
2023-03-21 19:00:11 -07:00
committed by GitHub
parent d46bb2ce53
commit a104251885
4 changed files with 110 additions and 141 deletions

View File

@@ -60,6 +60,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
/// </summary>
internal async Task HandleInitializeUserViewRequest(InitializeUserViewParams parameters, RequestContext<UserViewInfo> requestContext)
{
// check input parameters
if (string.IsNullOrWhiteSpace(parameters.Database))
{
throw new ArgumentNullException("parameters.Database");
@@ -70,13 +71,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
throw new ArgumentNullException("parameters.ContextId");
}
// open a connection for running the user dialog and associated task
ConnectionInfo originalConnInfo;
ConnectionServiceInstance.TryFindConnection(parameters.ConnectionUri, out originalConnInfo);
if (originalConnInfo == null)
{
throw new ArgumentException("Invalid connection URI '{0}'", parameters.ConnectionUri);
}
string originalDatabaseName = originalConnInfo.ConnectionDetails.DatabaseName;
try
{
@@ -93,26 +94,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
{
originalConnInfo.ConnectionDetails.DatabaseName = originalDatabaseName;
}
ConnectionInfo connInfo;
this.ConnectionServiceInstance.TryFindConnection(parameters.ContextId, out connInfo);
CDataContainer dataContainer = CreateUserDataContainer(connInfo, null, ConfigAction.Create, parameters.Database);
// create a default user data context and database object
CDataContainer dataContainer = CreateUserDataContainer(connInfo, null, ConfigAction.Create, parameters.Database);
string databaseUrn = string.Format(System.Globalization.CultureInfo.InvariantCulture,
"Server/Database[@Name='{0}']", Urn.EscapeString(parameters.Database));
Database? parentDb = dataContainer.Server.GetSmoObject(databaseUrn) as Database;
// if viewing an exisitng user then populate some properties
UserInfo? userInfo = null;
ExhaustiveUserTypes userType = ExhaustiveUserTypes.LoginMappedUser;
if (!parameters.IsNewObject)
{
User? existingUser = null;
string databaseUrn = string.Format(System.Globalization.CultureInfo.InvariantCulture,
"Server/Database[@Name='{0}']",
Urn.EscapeString(parameters.Database));
Database? parentDb = dataContainer.Server.GetSmoObject(databaseUrn) as Database;
existingUser = dataContainer.Server.Databases[parentDb.Name].Users[parameters.Name];
if (string.IsNullOrWhiteSpace(existingUser.Login))
{
throw new ApplicationException("Only 'User with Login' user type supported");
}
User? existingUser = dataContainer.Server.Databases[parentDb.Name].Users[parameters.Name];
userType = UserActions.GetCurrentUserTypeForExistingUser(existingUser);
userInfo = new UserInfo()
{
Name = parameters.Name,
@@ -121,9 +118,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
};
}
UserPrototypeFactory userPrototypeFactory = UserPrototypeFactory.GetInstance(dataContainer, userInfo, originalData: null);
UserPrototype currentUserPrototype = userPrototypeFactory.GetUserPrototype(ExhaustiveUserTypes.LoginMappedUser);
// generate a user prototype
UserPrototype currentUserPrototype = UserPrototypeFactory.GetUserPrototype(dataContainer, userInfo, originalData: null, userType);
// get the default language if available
IUserPrototypeWithDefaultLanguage defaultLanguagePrototype = currentUserPrototype as IUserPrototypeWithDefaultLanguage;
string? defaultLanguageAlias = null;
if (defaultLanguagePrototype != null && defaultLanguagePrototype.IsDefaultLanguageSupported)
@@ -140,12 +138,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
}
}
// get the default schema if available
string? defaultSchema = null;
IUserPrototypeWithDefaultSchema defaultSchemaPrototype = currentUserPrototype as IUserPrototypeWithDefaultSchema;
if (defaultSchemaPrototype != null && defaultSchemaPrototype.IsDefaultSchemaSupported)
{
defaultSchema = defaultSchemaPrototype.DefaultSchema;
}
// IUserPrototypeWithPassword userWithPwdPrototype = currentUserPrototype as IUserPrototypeWithPassword;
// if (userWithPwdPrototype != null && !this.DataContainer.IsNewObject)
// {
@@ -153,6 +153,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
// this.confirmPwdTextBox.Text = FAKE_PASSWORD;
// }
// get the login name if it exists
string? loginName = null;
IUserPrototypeWithMappedLogin mappedLoginPrototype = currentUserPrototype as IUserPrototypeWithMappedLogin;
if (mappedLoginPrototype != null)
@@ -160,6 +161,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
loginName = mappedLoginPrototype.LoginName;
}
// populate user's role assignments
List<string> databaseRoles = new List<string>();
foreach (string role in currentUserPrototype.DatabaseRoleNames)
{
@@ -169,6 +171,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
}
}
// populate user's schema ownerships
List<string> schemaNames = new List<string>();
foreach (string schema in currentUserPrototype.SchemaNames)
{
@@ -178,12 +181,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
}
}
// default to dbo schema, if there isn't already a default
if (string.IsNullOrWhiteSpace(defaultSchema) && currentUserPrototype.SchemaNames.Contains("dbo"))
{
defaultSchema = "dbo";
}
ServerConnection serverConnection = dataContainer.ServerConnection;
UserViewInfo userViewInfo = new UserViewInfo()
{
@@ -198,7 +195,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
DatabaseRoles = databaseRoles.ToArray(),
DefaultLanguage = defaultLanguageAlias
},
SupportContainedUser = false, // support for these will be added later
SupportContainedUser = UserActions.IsParentDatabaseContained(parentDb), // support for these will be added later
SupportWindowsAuthentication = false,
SupportAADAuthentication = false,
SupportSQLAuthentication = true,
@@ -349,7 +346,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
}
CDataContainer dataContainer = CreateUserDataContainer(connInfo, user, configAction, databaseName);
using (var actions = new UserActions(dataContainer, user, configAction, originalData))
using (var actions = new UserActions(dataContainer, configAction, user, originalData))
{
var executionHandler = new ExecutonHandler(actions);
executionHandler.RunNow(runType, this);
@@ -379,8 +376,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
/// <param name="context"></param>
public UserActions(
CDataContainer context,
UserInfo? user,
ConfigAction configAction,
UserInfo? user,
UserPrototypeData? originalData)
{
this.DataContainer = context;
@@ -401,19 +398,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
#endregion
/// <summary>
/// called on background thread by the framework to execute the action
/// called by the management actions 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
if (this.configAction != ConfigAction.Drop)
{
this.userPrototype.ApplyChanges();
}
@@ -422,30 +412,42 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
private UserPrototype InitUserPrototype(CDataContainer dataContainer, UserInfo user, UserPrototypeData? originalData)
{
ExhaustiveUserTypes currentUserType;
UserPrototypeFactory userPrototypeFactory = UserPrototypeFactory.GetInstance(dataContainer, user, originalData);
if (dataContainer.IsNewObject)
{
if (dataContainer.Server != null && IsParentDatabaseContained(dataContainer.ParentUrn, dataContainer.Server))
{
currentUserType = ExhaustiveUserTypes.SqlUserWithPassword;
}
else
{
currentUserType = ExhaustiveUserTypes.LoginMappedUser;
}
currentUserType = GetUserTypeForUserInfo(user);
}
else
{
currentUserType = this.GetCurrentUserTypeForExistingUser(
currentUserType = UserActions.GetCurrentUserTypeForExistingUser(
dataContainer.Server.GetSmoObject(dataContainer.ObjectUrn) as User);
}
UserPrototype currentUserPrototype = userPrototypeFactory.GetUserPrototype(currentUserType);
return currentUserPrototype;
UserPrototype currentUserPrototype = UserPrototypeFactory.GetUserPrototype(dataContainer, user, originalData, currentUserType);
return currentUserPrototype;
}
private ExhaustiveUserTypes GetCurrentUserTypeForExistingUser(User? user)
private ExhaustiveUserTypes GetUserTypeForUserInfo(UserInfo user)
{
ExhaustiveUserTypes userType = ExhaustiveUserTypes.LoginMappedUser;
switch (user.Type)
{
case DatabaseUserType.WithLogin:
userType = ExhaustiveUserTypes.LoginMappedUser;
break;
case DatabaseUserType.WithWindowsGroupLogin:
userType = ExhaustiveUserTypes.WindowsUser;
break;
case DatabaseUserType.Contained:
userType = ExhaustiveUserTypes.SqlUserWithPassword;
break;
case DatabaseUserType.NoConnectAccess:
userType = ExhaustiveUserTypes.SqlUserWithoutLogin;
break;
}
return userType;
}
internal static ExhaustiveUserTypes GetCurrentUserTypeForExistingUser(User? user)
{
if (user == null)
{
@@ -478,18 +480,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
}
}
private static bool IsParentDatabaseContained(Urn parentDbUrn, Server server)
internal static bool IsParentDatabaseContained(Urn parentDbUrn, Server server)
{
string parentDbName = parentDbUrn.GetNameForType("Database");
Database parentDatabase = server.Databases[parentDbName];
return IsParentDatabaseContained(server.Databases[parentDbName]);
}
if (parentDatabase.IsSupportedProperty("ContainmentType")
&& parentDatabase.ContainmentType == ContainmentType.Partial)
{
return true;
}
return false;
internal static bool IsParentDatabaseContained(Database parentDatabase)
{
return parentDatabase.IsSupportedProperty("ContainmentType")
&& parentDatabase.ContainmentType == ContainmentType.Partial;
}
}
}