mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-13 17:23:02 -05:00
[User Management] Implement handlers for app role, db role and server role (#2030)
* contracts * more contracts * wire up * add server role and rename data classes * finish app role * finish db role * build * finish server role * register * docs and dispose * build * fix issues * fix null ref issue * fix schema not being set issue * fix password for app role --------- Co-authored-by: Alan Ren <alanren@microsoft.com>
This commit is contained in:
@@ -33,6 +33,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
this.objectTypeHandlers.Add(new LoginHandler(ConnectionService.Instance));
|
||||
this.objectTypeHandlers.Add(new UserHandler(ConnectionService.Instance));
|
||||
this.objectTypeHandlers.Add(new CredentialHandler(ConnectionService.Instance));
|
||||
this.objectTypeHandlers.Add(new AppRoleHandler(ConnectionService.Instance));
|
||||
this.objectTypeHandlers.Add(new DatabaseRoleHandler(ConnectionService.Instance));
|
||||
this.objectTypeHandlers.Add(new ServerRoleHandler(ConnectionService.Instance));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -121,7 +124,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
throw new NotSupportedException(objectType.ToString());
|
||||
throw new NotSupportedException($"No handler found for object type '{objectType.ToString()}'");
|
||||
}
|
||||
|
||||
private SqlObjectViewContext GetContext(string contextId)
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// AppRole object type handler
|
||||
/// </summary>
|
||||
public class AppRoleHandler : ObjectTypeHandler<AppRoleInfo, AppRoleViewContext>
|
||||
{
|
||||
public AppRoleHandler(ConnectionService connectionService) : base(connectionService) { }
|
||||
|
||||
public override bool CanHandleType(SqlObjectType objectType)
|
||||
{
|
||||
return objectType == SqlObjectType.ApplicationRole;
|
||||
}
|
||||
|
||||
public override async Task<InitializeViewResult> InitializeObjectView(InitializeViewRequestParams parameters)
|
||||
{
|
||||
// check input parameters
|
||||
if (string.IsNullOrWhiteSpace(parameters.Database))
|
||||
{
|
||||
throw new ArgumentNullException("parameters.Database");
|
||||
}
|
||||
|
||||
// open a connection for running the AppRole associated tasks
|
||||
ConnectionInfo originalConnInfo;
|
||||
this.ConnectionService.TryFindConnection(parameters.ConnectionUri, out originalConnInfo);
|
||||
if (originalConnInfo == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid connection URI '{0}'", parameters.ConnectionUri);
|
||||
}
|
||||
string originalDatabaseName = originalConnInfo.ConnectionDetails.DatabaseName;
|
||||
try
|
||||
{
|
||||
originalConnInfo.ConnectionDetails.DatabaseName = parameters.Database;
|
||||
ConnectParams connectParams = new ConnectParams
|
||||
{
|
||||
OwnerUri = parameters.ContextId,
|
||||
Connection = originalConnInfo.ConnectionDetails,
|
||||
Type = Connection.ConnectionType.Default
|
||||
};
|
||||
await this.ConnectionService.Connect(connectParams);
|
||||
}
|
||||
finally
|
||||
{
|
||||
originalConnInfo.ConnectionDetails.DatabaseName = originalDatabaseName;
|
||||
}
|
||||
|
||||
ConnectionInfo connInfo;
|
||||
this.ConnectionService.TryFindConnection(parameters.ContextId, out connInfo);
|
||||
|
||||
CDataContainer dataContainer = CreateAppRoleDataContainer(connInfo, null, ConfigAction.Create, parameters.Database);
|
||||
|
||||
AppRolePrototype prototype = parameters.IsNewObject
|
||||
? new AppRolePrototype(dataContainer, parameters.Database)
|
||||
: new AppRolePrototype(dataContainer, parameters.Database, dataContainer.Server.GetSmoObject(parameters.ObjectUrn) as ApplicationRole);
|
||||
|
||||
AppRoleInfo appRoleInfo = new AppRoleInfo()
|
||||
{
|
||||
Name = prototype.Name,
|
||||
DefaultSchema = prototype.DefaultSchema,
|
||||
Password = prototype.Password,
|
||||
ExtendedProperties = prototype.ExtendedProperties.Select(
|
||||
item => new ExtendedPropertyInfo()
|
||||
{
|
||||
Name = item.Key,
|
||||
Value = item.Value
|
||||
}).ToArray(),
|
||||
OwnedSchemas = prototype.SchemasOwned,
|
||||
};
|
||||
|
||||
var viewInfo = new AppRoleViewInfo()
|
||||
{
|
||||
ObjectInfo = appRoleInfo,
|
||||
Schemas = prototype.Schemas
|
||||
};
|
||||
|
||||
var context = new AppRoleViewContext(parameters, dataContainer.ServerConnection);
|
||||
return new InitializeViewResult()
|
||||
{
|
||||
ViewInfo = viewInfo,
|
||||
Context = context
|
||||
};
|
||||
}
|
||||
|
||||
public override Task Save(AppRoleViewContext context, AppRoleInfo obj)
|
||||
{
|
||||
if (context.Parameters.IsNewObject)
|
||||
{
|
||||
this.DoHandleCreateAppRoleRequest(context, obj, RunType.RunNow);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DoHandleUpdateAppRoleRequest(context, obj, RunType.RunNow);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override Task<string> Script(AppRoleViewContext context, AppRoleInfo obj)
|
||||
{
|
||||
string script;
|
||||
if (context.Parameters.IsNewObject)
|
||||
{
|
||||
script = this.DoHandleCreateAppRoleRequest(context, obj, RunType.ScriptToWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
script = this.DoHandleUpdateAppRoleRequest(context, obj, RunType.ScriptToWindow);
|
||||
}
|
||||
return Task.FromResult(script);
|
||||
}
|
||||
|
||||
private string ConfigureAppRole(CDataContainer dataContainer, ConfigAction configAction, RunType runType, AppRolePrototype prototype)
|
||||
{
|
||||
string sqlScript = string.Empty;
|
||||
using (var actions = new AppRoleActions(dataContainer, configAction, prototype))
|
||||
{
|
||||
var executionHandler = new ExecutonHandler(actions);
|
||||
executionHandler.RunNow(runType, this);
|
||||
if (executionHandler.ExecutionResult == ExecutionMode.Failure)
|
||||
{
|
||||
throw executionHandler.ExecutionFailureException;
|
||||
}
|
||||
|
||||
if (runType == RunType.ScriptToWindow)
|
||||
{
|
||||
sqlScript = executionHandler.ScriptTextFromLastRun;
|
||||
}
|
||||
}
|
||||
|
||||
return sqlScript;
|
||||
}
|
||||
|
||||
private string DoHandleUpdateAppRoleRequest(AppRoleViewContext context, AppRoleInfo appRoleInfo, RunType runType)
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
this.ConnectionService.TryFindConnection(context.Parameters.ConnectionUri, out connInfo);
|
||||
if (connInfo == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid ConnectionUri");
|
||||
}
|
||||
|
||||
CDataContainer dataContainer = CreateAppRoleDataContainer(connInfo, null, ConfigAction.Create, context.Parameters.Database);
|
||||
AppRolePrototype prototype = new AppRolePrototype(dataContainer, context.Parameters.Database, dataContainer.Server.Databases[context.Parameters.Database].ApplicationRoles[appRoleInfo.Name]);
|
||||
prototype.ApplyInfoToPrototype(appRoleInfo);
|
||||
return ConfigureAppRole(dataContainer, ConfigAction.Update, runType, prototype);
|
||||
}
|
||||
|
||||
private string DoHandleCreateAppRoleRequest(AppRoleViewContext context, AppRoleInfo appRoleInfo, RunType runType)
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
this.ConnectionService.TryFindConnection(context.Parameters.ConnectionUri, out connInfo);
|
||||
|
||||
if (connInfo == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid ConnectionUri");
|
||||
}
|
||||
|
||||
CDataContainer dataContainer = CreateAppRoleDataContainer(connInfo, null, ConfigAction.Create, context.Parameters.Database);
|
||||
|
||||
AppRolePrototype prototype = new AppRolePrototype(dataContainer, context.Parameters.Database, appRoleInfo);
|
||||
return ConfigureAppRole(dataContainer, ConfigAction.Create, runType, prototype);
|
||||
}
|
||||
|
||||
internal CDataContainer CreateAppRoleDataContainer(ConnectionInfo connInfo, AppRoleInfo role, ConfigAction configAction, string databaseName)
|
||||
{
|
||||
var serverConnection = ConnectionService.OpenServerConnection(connInfo, "DataContainer");
|
||||
var connectionInfoWithConnection = new SqlConnectionInfoWithConnection();
|
||||
connectionInfoWithConnection.ServerConnection = serverConnection;
|
||||
|
||||
string urn = (configAction == ConfigAction.Update && role != null)
|
||||
? string.Format(System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Server/Database[@Name='{0}']/ApplicationRole[@Name='{1}']",
|
||||
Urn.EscapeString(databaseName),
|
||||
Urn.EscapeString(role.Name))
|
||||
: string.Format(System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Server/Database[@Name='{0}']",
|
||||
Urn.EscapeString(databaseName));
|
||||
|
||||
ActionContext context = new ActionContext(serverConnection, "ApplicationRole", urn);
|
||||
DataContainerXmlGenerator containerXml = new DataContainerXmlGenerator(context);
|
||||
|
||||
if (configAction == ConfigAction.Create)
|
||||
{
|
||||
containerXml.AddProperty("itemtype", "ApplicationRole");
|
||||
}
|
||||
|
||||
XmlDocument xmlDoc = containerXml.GenerateXmlDocument();
|
||||
return CDataContainer.CreateDataContainer(connectionInfoWithConnection, xmlDoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// a class for storing various application role properties
|
||||
/// </summary>
|
||||
public class AppRoleInfo : SqlObject
|
||||
{
|
||||
public string? DefaultSchema { get; set; }
|
||||
public string? Password { get; set; }
|
||||
public string[]? OwnedSchemas { get; set; }
|
||||
public ExtendedPropertyInfo[]? ExtendedProperties { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// 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.Common;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
public class AppRoleViewContext : SqlObjectViewContext
|
||||
{
|
||||
public ServerConnection Connection { get; }
|
||||
|
||||
public AppRoleViewContext(Contracts.InitializeViewRequestParams parameters, ServerConnection connection) : base(parameters)
|
||||
{
|
||||
this.Connection = connection;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.Connection.Disconnect();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// a class for storing various application role view properties
|
||||
/// </summary>
|
||||
public class AppRoleViewInfo : SqlObjectViewInfo
|
||||
{
|
||||
public string[]? Schemas { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// DatabaseRole object type handler
|
||||
/// </summary>
|
||||
public class DatabaseRoleHandler : ObjectTypeHandler<DatabaseRoleInfo, DatabaseRoleViewContext>
|
||||
{
|
||||
public DatabaseRoleHandler(ConnectionService connectionService) : base(connectionService) { }
|
||||
|
||||
public override bool CanHandleType(SqlObjectType objectType)
|
||||
{
|
||||
return objectType == SqlObjectType.DatabaseRole;
|
||||
}
|
||||
|
||||
public override async Task<InitializeViewResult> InitializeObjectView(InitializeViewRequestParams parameters)
|
||||
{
|
||||
// check input parameters
|
||||
if (string.IsNullOrWhiteSpace(parameters.Database))
|
||||
{
|
||||
throw new ArgumentNullException("parameters.Database");
|
||||
}
|
||||
|
||||
// open a connection for running the DatabaseRole associated tasks
|
||||
ConnectionInfo originalConnInfo;
|
||||
this.ConnectionService.TryFindConnection(parameters.ConnectionUri, out originalConnInfo);
|
||||
if (originalConnInfo == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid connection URI '{0}'", parameters.ConnectionUri);
|
||||
}
|
||||
string originalDatabaseName = originalConnInfo.ConnectionDetails.DatabaseName;
|
||||
try
|
||||
{
|
||||
originalConnInfo.ConnectionDetails.DatabaseName = parameters.Database;
|
||||
ConnectParams connectParams = new ConnectParams
|
||||
{
|
||||
OwnerUri = parameters.ContextId,
|
||||
Connection = originalConnInfo.ConnectionDetails,
|
||||
Type = Connection.ConnectionType.Default
|
||||
};
|
||||
await this.ConnectionService.Connect(connectParams);
|
||||
}
|
||||
finally
|
||||
{
|
||||
originalConnInfo.ConnectionDetails.DatabaseName = originalDatabaseName;
|
||||
}
|
||||
|
||||
ConnectionInfo connInfo;
|
||||
this.ConnectionService.TryFindConnection(parameters.ContextId, out connInfo);
|
||||
|
||||
CDataContainer dataContainer = CreateDatabaseRoleDataContainer(connInfo, null, ConfigAction.Create, parameters.Database);
|
||||
|
||||
DatabaseRolePrototype prototype = parameters.IsNewObject
|
||||
? new DatabaseRolePrototype(dataContainer, parameters.Database)
|
||||
: new DatabaseRolePrototype(dataContainer, parameters.Database, dataContainer.Server.GetSmoObject(parameters.ObjectUrn) as DatabaseRole);
|
||||
|
||||
DatabaseRoleInfo DatabaseRoleInfo = new DatabaseRoleInfo()
|
||||
{
|
||||
Name = prototype.Name,
|
||||
Owner = prototype.Owner,
|
||||
ExtendedProperties = prototype.ExtendedProperties.Select(item => new ExtendedPropertyInfo()
|
||||
{
|
||||
Name = item.Key,
|
||||
Value = item.Value
|
||||
}).ToArray(),
|
||||
Members = prototype.Members.ToArray(),
|
||||
OwnedSchemas = prototype.SchemasOwned.ToArray(),
|
||||
};
|
||||
|
||||
var viewInfo = new DatabaseRoleViewInfo()
|
||||
{
|
||||
ObjectInfo = DatabaseRoleInfo,
|
||||
Schemas = prototype.Schemas
|
||||
};
|
||||
|
||||
var context = new DatabaseRoleViewContext(parameters, dataContainer.ServerConnection);
|
||||
return new InitializeViewResult()
|
||||
{
|
||||
ViewInfo = viewInfo,
|
||||
Context = context
|
||||
};
|
||||
}
|
||||
|
||||
public override Task Save(DatabaseRoleViewContext context, DatabaseRoleInfo obj)
|
||||
{
|
||||
if (context.Parameters.IsNewObject)
|
||||
{
|
||||
this.DoHandleCreateDatabaseRoleRequest(context, obj, RunType.RunNow);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DoHandleUpdateDatabaseRoleRequest(context, obj, RunType.RunNow);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override Task<string> Script(DatabaseRoleViewContext context, DatabaseRoleInfo obj)
|
||||
{
|
||||
string script;
|
||||
if (context.Parameters.IsNewObject)
|
||||
{
|
||||
script = this.DoHandleCreateDatabaseRoleRequest(context, obj, RunType.ScriptToWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
script = this.DoHandleUpdateDatabaseRoleRequest(context, obj, RunType.ScriptToWindow);
|
||||
}
|
||||
return Task.FromResult(script);
|
||||
}
|
||||
|
||||
private string ConfigureDatabaseRole(CDataContainer dataContainer, ConfigAction configAction, RunType runType, DatabaseRolePrototype prototype)
|
||||
{
|
||||
string sqlScript = string.Empty;
|
||||
using (var actions = new DatabaseRoleActions(dataContainer, configAction, prototype))
|
||||
{
|
||||
var executionHandler = new ExecutonHandler(actions);
|
||||
executionHandler.RunNow(runType, this);
|
||||
if (executionHandler.ExecutionResult == ExecutionMode.Failure)
|
||||
{
|
||||
throw executionHandler.ExecutionFailureException;
|
||||
}
|
||||
|
||||
if (runType == RunType.ScriptToWindow)
|
||||
{
|
||||
sqlScript = executionHandler.ScriptTextFromLastRun;
|
||||
}
|
||||
}
|
||||
|
||||
return sqlScript;
|
||||
}
|
||||
|
||||
private string DoHandleUpdateDatabaseRoleRequest(DatabaseRoleViewContext context, DatabaseRoleInfo DatabaseRoleInfo, RunType runType)
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
this.ConnectionService.TryFindConnection(context.Parameters.ConnectionUri, out connInfo);
|
||||
if (connInfo == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid ConnectionUri");
|
||||
}
|
||||
|
||||
CDataContainer dataContainer = CreateDatabaseRoleDataContainer(connInfo, null, ConfigAction.Create, context.Parameters.Database);
|
||||
DatabaseRolePrototype prototype = new DatabaseRolePrototype(dataContainer, context.Parameters.Database, dataContainer.Server.Databases[context.Parameters.Database].Roles[DatabaseRoleInfo.Name]);
|
||||
prototype.ApplyInfoToPrototype(DatabaseRoleInfo);
|
||||
return ConfigureDatabaseRole(dataContainer, ConfigAction.Update, runType, prototype);
|
||||
}
|
||||
|
||||
private string DoHandleCreateDatabaseRoleRequest(DatabaseRoleViewContext context, DatabaseRoleInfo DatabaseRoleInfo, RunType runType)
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
this.ConnectionService.TryFindConnection(context.Parameters.ConnectionUri, out connInfo);
|
||||
|
||||
if (connInfo == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid ConnectionUri");
|
||||
}
|
||||
|
||||
CDataContainer dataContainer = CreateDatabaseRoleDataContainer(connInfo, null, ConfigAction.Create, context.Parameters.Database);
|
||||
|
||||
DatabaseRolePrototype prototype = new DatabaseRolePrototype(dataContainer, context.Parameters.Database, DatabaseRoleInfo);
|
||||
return ConfigureDatabaseRole(dataContainer, ConfigAction.Create, runType, prototype);
|
||||
}
|
||||
|
||||
internal CDataContainer CreateDatabaseRoleDataContainer(ConnectionInfo connInfo, DatabaseRoleInfo role, ConfigAction configAction, string databaseName)
|
||||
{
|
||||
var serverConnection = ConnectionService.OpenServerConnection(connInfo, "DataContainer");
|
||||
var connectionInfoWithConnection = new SqlConnectionInfoWithConnection();
|
||||
connectionInfoWithConnection.ServerConnection = serverConnection;
|
||||
|
||||
string urn = (configAction == ConfigAction.Update && role != null)
|
||||
? string.Format(System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Server/Database[@Name='{0}']/Role[@Name='{1}']",
|
||||
Urn.EscapeString(databaseName),
|
||||
Urn.EscapeString(role.Name))
|
||||
: string.Format(System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Server/Database[@Name='{0}']",
|
||||
Urn.EscapeString(databaseName));
|
||||
|
||||
ActionContext context = new ActionContext(serverConnection, "Role", urn);
|
||||
DataContainerXmlGenerator containerXml = new DataContainerXmlGenerator(context);
|
||||
|
||||
if (configAction == ConfigAction.Create)
|
||||
{
|
||||
containerXml.AddProperty("itemtype", "Role");
|
||||
}
|
||||
|
||||
XmlDocument xmlDoc = containerXml.GenerateXmlDocument();
|
||||
return CDataContainer.CreateDataContainer(connectionInfoWithConnection, xmlDoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// a class for storing various database role properties
|
||||
/// </summary>
|
||||
public class DatabaseRoleInfo : SqlObject
|
||||
{
|
||||
public string? Owner { get; set; }
|
||||
public string[]? OwnedSchemas { get; set; }
|
||||
public ExtendedPropertyInfo[]? ExtendedProperties { get; set; }
|
||||
public string[]? Members { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// 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.Common;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
public class DatabaseRoleViewContext : SqlObjectViewContext
|
||||
{
|
||||
public ServerConnection Connection { get; }
|
||||
public DatabaseRoleViewContext(Contracts.InitializeViewRequestParams parameters, ServerConnection connection) : base(parameters)
|
||||
{
|
||||
this.Connection = connection;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.Connection.Disconnect();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// a class for storing various database role view properties
|
||||
/// </summary>
|
||||
public class DatabaseRoleViewInfo : SqlObjectViewInfo
|
||||
{
|
||||
public string[]? Schemas { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// 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.ServiceLayer.Management;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
internal class AppRoleActions : ManagementActionBase
|
||||
{
|
||||
private ConfigAction configAction;
|
||||
|
||||
private AppRolePrototype prototype;
|
||||
|
||||
/// <summary>
|
||||
/// Handle login create and update actions
|
||||
/// </summary>
|
||||
public AppRoleActions(CDataContainer dataContainer, ConfigAction configAction, AppRolePrototype prototype)
|
||||
{
|
||||
this.DataContainer = dataContainer;
|
||||
this.configAction = configAction;
|
||||
this.prototype = prototype;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
{
|
||||
this.prototype.SendDataToServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,636 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#nullable disable
|
||||
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using System;
|
||||
using System.Data;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// AppRoleGeneral - main app role page
|
||||
/// </summary>
|
||||
internal class AppRolePrototype
|
||||
{
|
||||
#region Members
|
||||
|
||||
/// <summary>
|
||||
/// data container member that contains data specific information like
|
||||
/// connection infor, SMO server object or an AMO server object as well
|
||||
/// as a hash table where one can manipulate custom data
|
||||
/// </summary>
|
||||
private CDataContainer dataContainer = null;
|
||||
|
||||
private bool exists;
|
||||
private AppRolePrototypeData currentState;
|
||||
private AppRolePrototypeData originalState;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Trace support
|
||||
private const string componentName = "AppRoleGeneral";
|
||||
|
||||
public string ComponentName
|
||||
{
|
||||
get
|
||||
{
|
||||
return componentName;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constants - urn fields, etc...
|
||||
private const string ownerField = "Owner";
|
||||
private const string defaultSchemaField = "DefaultSchema";
|
||||
private const string schemaNameField = "Name";
|
||||
private const string schemaOwnerField = "Owner";
|
||||
private const string memberNameField = "Name";
|
||||
private const string memberUrnField = "Urn";
|
||||
#endregion
|
||||
|
||||
#region Non-UI variables
|
||||
|
||||
// info extracted from context
|
||||
private string databaseName;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Properties: CreateNew/Properties mode
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.AppRoleName;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.AppRoleName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string DefaultSchema
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.DefaultSchema;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.DefaultSchema = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string[] Schemas
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.Schemas;
|
||||
}
|
||||
}
|
||||
|
||||
public string[] SchemasOwned
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.SchemasOwned;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.SchemasOwned = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.Password.ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.Password = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsYukonOrLater
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.IsYukonOrLater;
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, string> ExtendedProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.ExtendedProperties;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.ExtendedProperties = value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors / Dispose
|
||||
public AppRolePrototype(CDataContainer context, string database)
|
||||
{
|
||||
this.exists = false;
|
||||
this.databaseName = database;
|
||||
this.dataContainer = context;
|
||||
this.currentState = new AppRolePrototypeData(context, database);
|
||||
this.originalState = (AppRolePrototypeData)this.currentState.Clone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AppRoleData for creating a new app role
|
||||
/// </summary>
|
||||
public AppRolePrototype(CDataContainer context, string database, AppRoleInfo roleInfo)
|
||||
{
|
||||
this.exists = false;
|
||||
this.dataContainer = context;
|
||||
this.databaseName = database;
|
||||
this.currentState = new AppRolePrototypeData(context, database);
|
||||
this.originalState = (AppRolePrototypeData)this.currentState.Clone();
|
||||
|
||||
this.ApplyInfoToPrototype(roleInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AppRoleData for editing an existing app role
|
||||
/// </summary>
|
||||
public AppRolePrototype(CDataContainer context, string database, ApplicationRole role)
|
||||
{
|
||||
this.exists = true;
|
||||
this.dataContainer = context;
|
||||
this.databaseName = database;
|
||||
this.currentState = new AppRolePrototypeData(context, database, role);
|
||||
this.originalState = (AppRolePrototypeData)this.currentState.Clone();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation: SendDataToServer()
|
||||
/// <summary>
|
||||
/// SendDataToServer
|
||||
///
|
||||
/// here we talk with server via smo and do the actual data changing
|
||||
/// </summary>
|
||||
public void SendDataToServer()
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(this.databaseName), "databaseName is empty");
|
||||
|
||||
Microsoft.SqlServer.Management.Smo.Server srv = this.dataContainer.Server;
|
||||
System.Diagnostics.Debug.Assert(srv != null, "server object is null");
|
||||
|
||||
Database db = srv.Databases[this.databaseName];
|
||||
System.Diagnostics.Debug.Assert(db != null, "database object is null");
|
||||
|
||||
if (this.exists) // in properties mode -> alter role
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(this.Name), "approleName is empty");
|
||||
|
||||
ApplicationRole approle = db.ApplicationRoles[this.Name];
|
||||
System.Diagnostics.Debug.Assert(approle != null, "approle object is null");
|
||||
|
||||
bool alterRequired = false;
|
||||
|
||||
if (this.IsYukonOrLater && this.originalState.DefaultSchema != this.currentState.DefaultSchema)
|
||||
{
|
||||
approle.DefaultSchema = this.currentState.DefaultSchema;
|
||||
alterRequired = true;
|
||||
}
|
||||
|
||||
if (this.originalState.Password != this.currentState.Password)
|
||||
{
|
||||
approle.ChangePassword(this.Password);
|
||||
alterRequired = true;
|
||||
}
|
||||
|
||||
if (alterRequired == true)
|
||||
{
|
||||
approle.Alter();
|
||||
}
|
||||
|
||||
SendToServerSchemaOwnershipChanges(db, approle);
|
||||
SendToServerExtendedPropertiesChange();
|
||||
}
|
||||
else // not in properties mode -> create role
|
||||
{
|
||||
ApplicationRole approle = new ApplicationRole(db, this.Name);
|
||||
if (this.IsYukonOrLater && this.currentState.DefaultSchema.Length > 0)
|
||||
{
|
||||
approle.DefaultSchema = this.currentState.DefaultSchema;
|
||||
}
|
||||
|
||||
approle.Create(this.Password);
|
||||
|
||||
SendToServerSchemaOwnershipChanges(db, approle);
|
||||
SendToServerExtendedPropertiesChange();
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Schemas - general operations with ...
|
||||
/// <summary>
|
||||
/// sends to server changes related to schema ownership
|
||||
/// </summary>
|
||||
private void SendToServerSchemaOwnershipChanges(Database db, ApplicationRole approle)
|
||||
{
|
||||
if (this.IsYukonOrLater)
|
||||
{
|
||||
foreach (string schemaName in this.Schemas)
|
||||
{
|
||||
bool currentlyOwned = this.currentState.SchemasOwned.Contains(schemaName);
|
||||
|
||||
if (this.exists)
|
||||
{
|
||||
bool wasOwned = this.originalState.SchemasOwned.Contains(schemaName);
|
||||
|
||||
if (currentlyOwned != wasOwned)
|
||||
{
|
||||
if (currentlyOwned == true)
|
||||
{
|
||||
Schema schema = db.Schemas[schemaName];
|
||||
schema.Owner = approle.Name;
|
||||
schema.Alter();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we cannot not renounce ownership
|
||||
Schema schema = db.Schemas[name];
|
||||
schema.Owner = null;
|
||||
schema.Alter();
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentlyOwned == true)
|
||||
{
|
||||
Schema schema = db.Schemas[schemaName];
|
||||
schema.Owner = approle.Name;
|
||||
schema.Alter();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void SendToServerExtendedPropertiesChange()
|
||||
{
|
||||
// add or alter the extended properties
|
||||
foreach (var item in this.ExtendedProperties)
|
||||
{
|
||||
if (this.originalState.ExtendedProperties.ContainsKey(item.Key))
|
||||
{
|
||||
// alter the existing extended property
|
||||
ExtendedProperty ep = this.originalState.ApplicationRole.ExtendedProperties[item.Key];
|
||||
ep.Value = item.Value;
|
||||
ep.Alter();
|
||||
}
|
||||
else
|
||||
{
|
||||
// create the extended property
|
||||
ExtendedProperty ep = new ExtendedProperty(this.originalState.ApplicationRole, item.Key, item.Value);
|
||||
ep.Create();
|
||||
}
|
||||
}
|
||||
|
||||
// remove the extended properties that are not in the current list
|
||||
foreach (var item in this.originalState.ExtendedProperties)
|
||||
{
|
||||
if (!this.ExtendedProperties.ContainsKey(item.Key))
|
||||
{
|
||||
ExtendedProperty ep = this.originalState.ApplicationRole.ExtendedProperties[item.Key];
|
||||
ep.Drop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyInfoToPrototype(AppRoleInfo roleInfo)
|
||||
{
|
||||
this.Name = roleInfo.Name;
|
||||
this.DefaultSchema = roleInfo.DefaultSchema;
|
||||
this.SchemasOwned = roleInfo.OwnedSchemas.ToArray();
|
||||
this.Password = roleInfo.Password;
|
||||
this.ExtendedProperties = roleInfo.ExtendedProperties.Select(ep => new KeyValuePair<string, string>(ep.Name, ep.Value)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
}
|
||||
|
||||
private class AppRolePrototypeData : ICloneable
|
||||
{
|
||||
#region data members
|
||||
private string appRoleName = string.Empty;
|
||||
private string defaultSchema = String.Empty;
|
||||
private string password = String.Empty;
|
||||
private bool initialized = false;
|
||||
private List<string> schemaNames = new List<string>();
|
||||
private Dictionary<string, string> dictSchemas = new Dictionary<string, string>();
|
||||
private Dictionary<string, string> dictExtendedProperties = new Dictionary<string, string>();
|
||||
private ApplicationRole role = null;
|
||||
private Server server = null;
|
||||
private string database = string.Empty;
|
||||
private CDataContainer context = null;
|
||||
private bool isYukonOrLater = false;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
// General properties
|
||||
|
||||
|
||||
public string AppRoleName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
return this.appRoleName;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.appRoleName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationRole ApplicationRole
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.role;
|
||||
}
|
||||
}
|
||||
|
||||
public string DefaultSchema
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
return this.defaultSchema;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.defaultSchema = value;
|
||||
}
|
||||
}
|
||||
public string[] SchemasOwned
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
return this.dictSchemas.Keys.Where(s => dictSchemas[s] == this.appRoleName).ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
foreach (string schema in value)
|
||||
{
|
||||
// cannot renounce ownership
|
||||
this.dictSchemas[schema] = this.AppRoleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string[] Schemas
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
return this.schemaNames.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.schemaNames = value.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, string> ExtendedProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
return this.dictExtendedProperties;
|
||||
}
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.dictExtendedProperties = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Exists
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.role != null);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsYukonOrLater
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.isYukonOrLater;
|
||||
}
|
||||
}
|
||||
|
||||
public Microsoft.SqlServer.Management.Smo.Server Server
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.server;
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationRole AppRole
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.role;
|
||||
}
|
||||
}
|
||||
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
return this.password;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.password = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// private default constructor - used by Clone()
|
||||
/// </summary>
|
||||
private AppRolePrototypeData()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="context">The context in which we are creating a new appRole</param>
|
||||
/// <param name="databaseName">The database in which we are creating a new appRole</param>
|
||||
public AppRolePrototypeData(CDataContainer context, string databaseName)
|
||||
{
|
||||
this.server = context.Server;
|
||||
this.database = databaseName;
|
||||
this.context = context;
|
||||
this.isYukonOrLater = (this.server.Information.Version.Major >= 9);
|
||||
LoadData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="context">The context in which we are modifying a appRole</param>
|
||||
/// <param name="databaseName">The database in which we are modifying a appRole</param>
|
||||
/// <param name="appRole">The appRole we are modifying</param>
|
||||
public AppRolePrototypeData(CDataContainer context, string databaseName, ApplicationRole appRole)
|
||||
{
|
||||
this.server = context.Server;
|
||||
this.database = databaseName;
|
||||
this.context = context;
|
||||
this.isYukonOrLater = (this.server.Information.Version.Major >= 9);
|
||||
this.role = appRole;
|
||||
LoadData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a clone of this AppRolePrototypeData object
|
||||
/// </summary>
|
||||
/// <returns>The clone AppRolePrototypeData object</returns>
|
||||
public object Clone()
|
||||
{
|
||||
AppRolePrototypeData result = new AppRolePrototypeData();
|
||||
result.appRoleName = this.appRoleName;
|
||||
result.defaultSchema = this.defaultSchema;
|
||||
result.password = this.password;
|
||||
result.initialized = this.initialized;
|
||||
result.schemaNames = new List<string>(this.schemaNames);
|
||||
result.dictSchemas = new Dictionary<string, string>(this.dictSchemas);
|
||||
result.dictExtendedProperties = new Dictionary<string, string>(this.dictExtendedProperties);
|
||||
result.role = this.role;
|
||||
result.server = this.server;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
{
|
||||
this.initialized = true;
|
||||
|
||||
if (this.Exists)
|
||||
{
|
||||
LoadExisting();
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadNew();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadExisting()
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(server != null, "server is null");
|
||||
System.Diagnostics.Debug.Assert(role != null, "app role is null");
|
||||
this.appRoleName = role.Name;
|
||||
this.password = LoginPrototype.fakePassword;
|
||||
this.defaultSchema = role.DefaultSchema;
|
||||
LoadSchemas();
|
||||
LoadExtendProperties();
|
||||
}
|
||||
|
||||
private void LoadNew()
|
||||
{
|
||||
LoadSchemas();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// loads initial schemas from server together with information about the schema owner
|
||||
/// </summary>
|
||||
private void LoadSchemas()
|
||||
{
|
||||
if (this.isYukonOrLater)
|
||||
{
|
||||
this.dictSchemas = new Dictionary<string, string>();
|
||||
this.schemaNames = new List<string>();
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
Request req = new Request();
|
||||
req.Fields = new String[] { AppRolePrototype.schemaNameField, AppRolePrototype.schemaOwnerField };
|
||||
req.Urn = "Server/Database[@Name='" + Urn.EscapeString(this.database) + "']/Schema";
|
||||
req.OrderByList = new OrderBy[] { new OrderBy("Name", OrderBy.Direction.Asc) };
|
||||
|
||||
DataTable dt = en.Process(server.ConnectionContext, req);
|
||||
System.Diagnostics.Debug.Assert((dt != null) && (dt.Rows.Count > 0), "No rows returned from schema enumerator");
|
||||
|
||||
foreach (DataRow dr in dt.Rows)
|
||||
{
|
||||
string name = Convert.ToString(dr[AppRolePrototype.schemaNameField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
string owner = Convert.ToString(dr[AppRolePrototype.schemaOwnerField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
dictSchemas.Add(name, owner);
|
||||
schemaNames.Add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadExtendProperties()
|
||||
{
|
||||
if (this.isYukonOrLater)
|
||||
{
|
||||
foreach (ExtendedProperty ep in this.role.ExtendedProperties)
|
||||
{
|
||||
this.dictExtendedProperties.Add(ep.Name, (string)ep.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,653 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#nullable disable
|
||||
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Xml;
|
||||
using System.Data;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// AppRoleGeneral - main app role page
|
||||
/// </summary>
|
||||
internal class AppRoleGeneral
|
||||
{
|
||||
#region Members
|
||||
|
||||
/// <summary>
|
||||
/// data container member that contains data specific information like
|
||||
/// connection infor, SMO server object or an AMO server object as well
|
||||
/// as a hash table where one can manipulate custom data
|
||||
/// </summary>
|
||||
private CDataContainer dataContainer = null;
|
||||
|
||||
//SMO Server connection that MUST be used for all enumerator calls
|
||||
//We'll get this object out of CDataContainer, that must be initialized
|
||||
//property by the initialization code
|
||||
private ServerConnection serverConnection;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Trace support
|
||||
private const string componentName = "AppRoleGeneral";
|
||||
|
||||
public string ComponentName
|
||||
{
|
||||
get
|
||||
{
|
||||
return componentName;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constants - urn fields, etc...
|
||||
private const string ownerField = "Owner";
|
||||
private const string defaultSchemaField = "DefaultSchema";
|
||||
private const string schemaNameField = "Name";
|
||||
private const string schemaOwnerField = "Owner";
|
||||
private const string memberNameField = "Name";
|
||||
private const string memberUrnField = "Urn";
|
||||
#endregion
|
||||
|
||||
#region Constants - grid columns positions, etc...
|
||||
private const int colSchemasChecked = 0;
|
||||
private const int colSchemasOwnedSchemas = 1;
|
||||
|
||||
private const int colMembershipBitmap = 0;
|
||||
private const int colMembershipRoleMembers = 1;
|
||||
|
||||
private const int sizeCheckboxColumn = 20;
|
||||
private const int sizeBitmapColumn = 20;
|
||||
#endregion
|
||||
|
||||
#region Non-UI variables
|
||||
private System.Xml.XmlDocument document = null;
|
||||
|
||||
// info extracted from context
|
||||
private string serverName;
|
||||
private string databaseName;
|
||||
private string approleName;
|
||||
private bool passwordChanged = false;
|
||||
|
||||
|
||||
// initial values loaded from server
|
||||
private string initialDefaultSchema;
|
||||
|
||||
|
||||
private bool isYukonOrLater;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Properties: CreateNew/Properties mode
|
||||
private bool IsPropertiesMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return (approleName != null) && (approleName.Trim().Length != 0);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors / Dispose
|
||||
public AppRoleGeneral()
|
||||
{
|
||||
// This call is required by the Windows.Forms Form Designer.
|
||||
// InitializeComponent();
|
||||
}
|
||||
|
||||
public AppRoleGeneral(CDataContainer context)
|
||||
{
|
||||
dataContainer = context;
|
||||
|
||||
if (dataContainer != null)
|
||||
{
|
||||
document = dataContainer.Document;
|
||||
}
|
||||
else
|
||||
{
|
||||
document = null;
|
||||
}
|
||||
|
||||
this.isYukonOrLater = (9 <= context.Server.ConnectionContext.ServerVersion.Major);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
// protected override void Dispose( bool disposing )
|
||||
// {
|
||||
// if ( disposing )
|
||||
// {
|
||||
// if (components != null)
|
||||
// {
|
||||
// components.Dispose();
|
||||
// }
|
||||
// }
|
||||
// base.Dispose( disposing );
|
||||
// }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation: LoadData(), InitProp(), SendDataToServer()
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// LoadData
|
||||
///
|
||||
/// loads connection parameters from an xml
|
||||
/// </summary>
|
||||
/// <param name="doc"></param>
|
||||
private void LoadData(XmlDocument doc)
|
||||
{
|
||||
// STrace.Params(ComponentName, "LoadData", "XmlDocument doc=\"{0}\"", doc.OuterXml);
|
||||
|
||||
STParameters param;
|
||||
bool bStatus;
|
||||
|
||||
param = new STParameters();
|
||||
|
||||
param.SetDocument(doc);
|
||||
|
||||
bStatus = param.GetParam("servername", ref this.serverName);
|
||||
bStatus = param.GetParam("database", ref this.databaseName);
|
||||
bStatus = param.GetParam("applicationrole", ref this.approleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// InitProp
|
||||
///
|
||||
/// talks with enumerator an retrieves info
|
||||
/// </summary>
|
||||
private void InitProp()
|
||||
{
|
||||
// STrace.Params(ComponentName, "InitProp", "", null);
|
||||
|
||||
System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(this.serverName), "serverName is empty");
|
||||
System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(this.databaseName), "databaseName is empty");
|
||||
|
||||
passwordChanged = false;
|
||||
|
||||
// InitializeBitmapAndIcons(); // bitmapMember
|
||||
|
||||
if (this.IsPropertiesMode == true)
|
||||
{
|
||||
// initialize from enumerator in properties mode
|
||||
// STrace.Assert(!string.IsNullOrWhiteSpace(this.approleName), "approleName is empty");
|
||||
|
||||
// this.textBoxRoleName.Text = this.approleName;
|
||||
|
||||
if (this.isYukonOrLater)
|
||||
{
|
||||
// get the default schema
|
||||
|
||||
// STrace.Assert(this.DataContainer.ObjectUrn.Length != 0, "object urn is empty");
|
||||
|
||||
Enumerator enumerator = new Enumerator();
|
||||
Request request = new Request();
|
||||
request.Urn = this.dataContainer.ObjectUrn;
|
||||
request.Fields = new String[] { AppRoleGeneral.defaultSchemaField };
|
||||
|
||||
DataTable dataTable = enumerator.Process(serverConnection, request);
|
||||
// STrace.Assert(dataTable != null, "dataTable is null");
|
||||
// STrace.Assert(dataTable.Rows.Count == 1, "unexpected number of rows in dataTable");
|
||||
|
||||
if (dataTable.Rows.Count == 0)
|
||||
{
|
||||
throw new Exception("AppRoleSR.ErrorAppRoleNotFound");
|
||||
}
|
||||
|
||||
DataRow dataRow = dataTable.Rows[0];
|
||||
this.initialDefaultSchema = Convert.ToString(dataRow[AppRoleGeneral.defaultSchemaField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
// this.textBoxDefaultSchema.Text = this.initialDefaultSchema;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// initialize with empty values in create new mode
|
||||
// this.textBoxRoleName.Text = String.Empty;
|
||||
// this.textBoxDefaultSchema.Text = this.initialDefaultSchema;
|
||||
|
||||
// this.textBoxPasword.Text = String.Empty;
|
||||
// this.textBoxConfirmPassword.Text = String.Empty;
|
||||
}
|
||||
|
||||
LoadSchemas();
|
||||
// InitializeSchemasGridColumns();
|
||||
// FillSchemasGrid();
|
||||
|
||||
LoadMembership();
|
||||
// InitializeMembershipGridColumns();
|
||||
// FillMembershipGrid();
|
||||
|
||||
// dont display the membership controls - app roles dont support members
|
||||
// HideMembership();
|
||||
|
||||
// update UI enable/disable controls
|
||||
// EnableDisableControls();
|
||||
}
|
||||
|
||||
// private void HideMembership()
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// this.SuspendLayout();
|
||||
// this.panelSchema.SuspendLayout();
|
||||
|
||||
// this.panelSchema.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right | AnchorStyles.Left;
|
||||
// this.panelSchema.Size = new Size
|
||||
// (
|
||||
// this.panelSchema.Size.Width
|
||||
// ,
|
||||
// this.panelMembership.Location.Y + this.panelMembership.Size.Height -
|
||||
// this.panelSchema.Location.Y
|
||||
// );
|
||||
|
||||
// this.panelMembership.Visible = false;
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// this.panelSchema.ResumeLayout();
|
||||
// this.ResumeLayout();
|
||||
|
||||
// this.gridSchemasOwned.Refresh();
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
private string _selectedDefaultSchema;
|
||||
// private SqlSecureString _textBoxPaswordText;
|
||||
// private SqlSecureString _textBoxConfirmPasswordText;
|
||||
private string _textBoxRoleNameText;
|
||||
|
||||
/// <summary>
|
||||
/// Called to validate all date in controls and save them in
|
||||
/// temproary storage to be used when OnRunNow is called
|
||||
/// </summary>
|
||||
// public override void OnGatherUiInformation(RunType runType)
|
||||
// {
|
||||
// base.OnGatherUiInformation(runType);
|
||||
|
||||
// try
|
||||
// {
|
||||
// base.ExecutionMode = ExecutionMode.Success;
|
||||
|
||||
// _selectedDefaultSchema = this.textBoxDefaultSchema.Text;
|
||||
// _textBoxPaswordText = textBoxPasword.Text;
|
||||
// _textBoxConfirmPasswordText = textBoxConfirmPassword.Text;
|
||||
// _textBoxRoleNameText = textBoxRoleName.Text;
|
||||
// }
|
||||
// catch (Exception exception)
|
||||
// {
|
||||
// DisplayExceptionMessage(exception);
|
||||
// base.ExecutionMode = ExecutionMode.Failure;
|
||||
// }
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// SendDataToServer
|
||||
///
|
||||
/// here we talk with server via smo and do the actual data changing
|
||||
/// </summary>
|
||||
private void SendDataToServer()
|
||||
{
|
||||
// STrace.Params(ComponentName, "SendDataToServer", "", null);
|
||||
|
||||
System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(this.databaseName), "databaseName is empty");
|
||||
|
||||
Microsoft.SqlServer.Management.Smo.Server srv = this.dataContainer.Server;
|
||||
System.Diagnostics.Debug.Assert(srv != null, "server object is null");
|
||||
|
||||
Database db = srv.Databases[this.databaseName];
|
||||
System.Diagnostics.Debug.Assert(db != null, "database object is null");
|
||||
|
||||
if (this.IsPropertiesMode == true) // in properties mode -> alter role
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(this.approleName), "approleName is empty");
|
||||
|
||||
ApplicationRole approle = db.ApplicationRoles[this.approleName];
|
||||
System.Diagnostics.Debug.Assert(approle != null, "approle object is null");
|
||||
|
||||
bool alterRequired = false;
|
||||
|
||||
if (this.isYukonOrLater && _selectedDefaultSchema != this.initialDefaultSchema)
|
||||
{
|
||||
approle.DefaultSchema = _selectedDefaultSchema;
|
||||
alterRequired = true;
|
||||
}
|
||||
|
||||
if (passwordChanged == true)
|
||||
{
|
||||
approle.ChangePassword((string)"_textBoxPaswordText");
|
||||
}
|
||||
|
||||
if (alterRequired == true)
|
||||
{
|
||||
approle.Alter();
|
||||
}
|
||||
|
||||
SendToServerSchemaOwnershipChanges(db, approle);
|
||||
SendToServerMembershipChanges(db, approle);
|
||||
}
|
||||
else // not in properties mode -> create role
|
||||
{
|
||||
ApplicationRole approle = new ApplicationRole(db, _textBoxRoleNameText);
|
||||
if (this.isYukonOrLater && _selectedDefaultSchema.Length > 0)
|
||||
{
|
||||
approle.DefaultSchema = _selectedDefaultSchema;
|
||||
}
|
||||
|
||||
approle.Create((string)"_textBoxPaswordText");
|
||||
|
||||
SendToServerSchemaOwnershipChanges(db, approle);
|
||||
SendToServerMembershipChanges(db, approle);
|
||||
|
||||
this.dataContainer.SqlDialogSubject = approle; // needed by extended properties page
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Schemas - general operations with ...
|
||||
HybridDictionary dictSchemas = null;
|
||||
StringCollection schemaNames = null;
|
||||
/// <summary>
|
||||
/// loads initial schemas from server together with information about the schema owner
|
||||
/// </summary>
|
||||
private void LoadSchemas()
|
||||
{
|
||||
if (this.isYukonOrLater)
|
||||
{
|
||||
this.dictSchemas = new HybridDictionary();
|
||||
this.schemaNames = new StringCollection();
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
Request req = new Request();
|
||||
req.Fields = new String[] { AppRoleGeneral.schemaNameField, AppRoleGeneral.schemaOwnerField };
|
||||
req.Urn = "Server/Database[@Name='" + Urn.EscapeString(this.databaseName) + "']/Schema";
|
||||
req.OrderByList = new OrderBy[] { new OrderBy("Name", OrderBy.Direction.Asc) };
|
||||
|
||||
DataTable dt = en.Process(serverConnection, req);
|
||||
// STrace.Assert((dt != null) && (dt.Rows.Count > 0), "No rows returned from schema enumerator");
|
||||
|
||||
foreach (DataRow dr in dt.Rows)
|
||||
{
|
||||
string name = Convert.ToString(dr[AppRoleGeneral.schemaNameField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
string owner = Convert.ToString(dr[AppRoleGeneral.schemaOwnerField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
dictSchemas.Add(name, owner);
|
||||
schemaNames.Add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sends to server changes related to schema ownership
|
||||
/// </summary>
|
||||
private void SendToServerSchemaOwnershipChanges(Database db, ApplicationRole approle)
|
||||
{
|
||||
if (this.isYukonOrLater)
|
||||
{
|
||||
// DlgGridControl grid = this.gridSchemasOwned;
|
||||
|
||||
for (int i = 0; i < 1; ++i)
|
||||
{
|
||||
string name = "grid.GetCellInfo(i, colSchemasOwnedSchemas).CellData.ToString()";
|
||||
object o = dictSchemas[name];
|
||||
|
||||
System.Diagnostics.Debug.Assert(o != null, "schema object is null");
|
||||
|
||||
// bool currentlyOwned = IsEmbeededCheckboxChecked(grid, i, colSchemasChecked);
|
||||
bool currentlyOwned = false;
|
||||
|
||||
if (IsPropertiesMode == true)
|
||||
{
|
||||
bool wasOwned = (o.ToString() == approleName);
|
||||
|
||||
if (currentlyOwned != wasOwned)
|
||||
{
|
||||
if (currentlyOwned == true)
|
||||
{
|
||||
Schema schema = db.Schemas[name];
|
||||
schema.Owner = approle.Name;
|
||||
schema.Alter();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we cannot not renounce ownership
|
||||
Schema schema = db.Schemas[name];
|
||||
schema.Owner = null;
|
||||
schema.Alter();
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentlyOwned == true)
|
||||
{
|
||||
Schema schema = db.Schemas[name];
|
||||
schema.Owner = approle.Name;
|
||||
schema.Alter();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private void gridSchemasOwned_MouseButtonClicked(object sender, Microsoft.SqlServer.Management.UI.Grid.MouseButtonClickedEventArgs args)
|
||||
// {
|
||||
// if (args.Button != MouseButtons.Left)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// int rowno = Convert.ToInt32(args.RowIndex);
|
||||
// int colno = Convert.ToInt32(args.ColumnIndex);
|
||||
|
||||
// switch (colno)
|
||||
// {
|
||||
// case colSchemasChecked:
|
||||
// FlipCheckbox(gridSchemasOwned, rowno, colno);
|
||||
// break;
|
||||
// default: // else do default action: e.g. edit - open combo - etc ...
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Membership - general operations with ...
|
||||
System.Collections.Specialized.HybridDictionary dictMembership = null;
|
||||
|
||||
/// <summary>
|
||||
/// loads from server initial membership information
|
||||
/// </summary>
|
||||
private void LoadMembership()
|
||||
{
|
||||
dictMembership = new System.Collections.Specialized.HybridDictionary();
|
||||
if (IsPropertiesMode == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
Request req = new Request();
|
||||
req.Fields = new String[] { AppRoleGeneral.memberNameField, AppRoleGeneral.memberUrnField };
|
||||
req.Urn = "Server/Database[@Name='" + Urn.EscapeString(this.databaseName) + "']/ApplicationRole[@Name='" + Urn.EscapeString(this.approleName) + "']/Member";
|
||||
|
||||
try
|
||||
{
|
||||
DataTable dt = en.Process(serverConnection, req);
|
||||
System.Diagnostics.Debug.Assert(dt != null, "No results returned from membership query");
|
||||
|
||||
foreach (DataRow dr in dt.Rows)
|
||||
{
|
||||
string name = Convert.ToString(dr[AppRoleGeneral.memberNameField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
string urn = Convert.ToString(dr[AppRoleGeneral.memberUrnField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
dictMembership.Add(name, urn);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// initialize grid column headers, but not the content
|
||||
/// </summary>
|
||||
// private void InitializeMembershipGridColumns()
|
||||
// {
|
||||
// Microsoft.SqlServer.Management.UI.Grid.DlgGridControl grid = this.gridRoleMembership;
|
||||
|
||||
// if (grid.RowsNumber != 0)
|
||||
// {
|
||||
// grid.DeleteAllRows();
|
||||
// }
|
||||
|
||||
// while (grid.ColumnsNumber != 0)
|
||||
// {
|
||||
// grid.DeleteColumn(0);
|
||||
// }
|
||||
|
||||
// GridColumnInfo colInfo = null;
|
||||
|
||||
// // bitmap member type
|
||||
// colInfo = new GridColumnInfo();
|
||||
// colInfo.ColumnWidth = sizeBitmapColumn;
|
||||
// colInfo.WidthType = GridColumnWidthType.InPixels;
|
||||
// colInfo.ColumnType = GridColumnType.Bitmap;
|
||||
// grid.AddColumn(colInfo);
|
||||
|
||||
// // member name
|
||||
// colInfo = new GridColumnInfo();
|
||||
// colInfo.ColumnWidth = grid.Width - sizeBitmapColumn - 2;
|
||||
// colInfo.WidthType = GridColumnWidthType.InPixels;
|
||||
// grid.AddColumn(colInfo);
|
||||
|
||||
// grid.SetHeaderInfo(colMembershipRoleMembers, AppRoleSR.HeaderRoleMembers, null);
|
||||
|
||||
// grid.SelectionType = GridSelectionType.SingleRow;
|
||||
// grid.UpdateGrid();
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// fills the membership grid with data (bitmaps, names, etc)
|
||||
/// </summary>
|
||||
// private void FillMembershipGrid()
|
||||
// {
|
||||
// Microsoft.SqlServer.Management.UI.Grid.DlgGridControl grid = this.gridRoleMembership;
|
||||
|
||||
// grid.DeleteAllRows();
|
||||
// foreach (DictionaryEntry de in dictMembership)
|
||||
// {
|
||||
// GridCellCollection row = new GridCellCollection();
|
||||
// GridCell cell = null;
|
||||
|
||||
// string name = de.Key.ToString();
|
||||
|
||||
// cell = new GridCell(bitmapMember); row.Add(cell); // compute type based on urn
|
||||
// cell = new GridCell(name); row.Add(cell);
|
||||
|
||||
// // row.Tag = urn == de.Value.ToString();
|
||||
|
||||
// grid.AddRow(row);
|
||||
// }
|
||||
|
||||
// if (grid.RowsNumber > 0)
|
||||
// {
|
||||
// grid.SelectedRow = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// sends to server user changes related to membership
|
||||
/// </summary>
|
||||
private void SendToServerMembershipChanges(Database db, ApplicationRole approle)
|
||||
{
|
||||
// DlgGridControl grid = this.gridRoleMembership;
|
||||
|
||||
if (IsPropertiesMode == true)
|
||||
{
|
||||
// members to add
|
||||
for (int i = 0; i < 1; ++i)
|
||||
{
|
||||
string name = "grid.GetCellInfo(i, colMembershipRoleMembers).CellData.ToString()";
|
||||
bool nameExistedInitially = dictMembership.Contains(name);
|
||||
|
||||
if (nameExistedInitially == false)
|
||||
{
|
||||
// need SMO for: role.Members.Add();
|
||||
}
|
||||
}
|
||||
// members to drop
|
||||
foreach (DictionaryEntry de in dictMembership)
|
||||
{
|
||||
if (FoundInMembershipGrid(de.Key.ToString(), de.Value.ToString()) == false)
|
||||
{
|
||||
// need SMO for: role.Members.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// add only
|
||||
for (int i = 0; i < 1; ++i)
|
||||
{
|
||||
string name = "grid.GetCellInfo(i, colMembershipRoleMembers).CellData.ToString()";
|
||||
// need SMO for: role.Members.Add();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// lookup in membership grid to see if user added a name
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="urn"></param>
|
||||
/// <returns></returns>
|
||||
private bool FoundInMembershipGrid(string name, string urn)
|
||||
{
|
||||
// DlgGridControl grid = this.gridRoleMembership;
|
||||
|
||||
// for (int i = 0; i < grid.RowsNumber; ++i)
|
||||
// {
|
||||
// string currentName = grid.GetCellInfo(i, colMembershipRoleMembers).CellData.ToString();
|
||||
// if (name == currentName)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// 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.ServiceLayer.Management;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
internal class DatabaseRoleActions : ManagementActionBase
|
||||
{
|
||||
private ConfigAction configAction;
|
||||
|
||||
private DatabaseRolePrototype prototype;
|
||||
|
||||
/// <summary>
|
||||
/// Handle database role create and update actions
|
||||
/// </summary>
|
||||
public DatabaseRoleActions(CDataContainer dataContainer, ConfigAction configAction, DatabaseRolePrototype prototype)
|
||||
{
|
||||
this.DataContainer = dataContainer;
|
||||
this.configAction = configAction;
|
||||
this.prototype = prototype;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
{
|
||||
this.prototype.SendDataToServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,662 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#nullable disable
|
||||
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using System;
|
||||
using System.Data;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// DatabaseRoleGeneral - main app role page
|
||||
/// </summary>
|
||||
internal class DatabaseRolePrototype
|
||||
{
|
||||
#region Members
|
||||
|
||||
/// <summary>
|
||||
/// data container member that contains data specific information like
|
||||
/// connection infor, SMO server object or an AMO server object as well
|
||||
/// as a hash table where one can manipulate custom data
|
||||
/// </summary>
|
||||
private CDataContainer dataContainer = null;
|
||||
|
||||
private bool exists;
|
||||
private DatabaseRolePrototypeData currentState;
|
||||
private DatabaseRolePrototypeData originalState;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Trace support
|
||||
private const string componentName = "DatabaseRoleGeneral";
|
||||
|
||||
public string ComponentName
|
||||
{
|
||||
get
|
||||
{
|
||||
return componentName;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constants - urn fields, etc...
|
||||
private const string ownerField = "Owner";
|
||||
private const string schemaOwnerField = "Owner";
|
||||
private const string schemaNameField = "Name";
|
||||
private const string memberNameField = "Name";
|
||||
private const string memberUrnField = "Urn";
|
||||
#endregion
|
||||
|
||||
#region Non-UI variables
|
||||
|
||||
// info extracted from context
|
||||
private string databaseName;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Properties: CreateNew/Properties mode
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.DatabaseRoleName;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.DatabaseRoleName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Owner
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.Owner;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.Owner = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string[] Schemas
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.Schemas;
|
||||
}
|
||||
}
|
||||
|
||||
public string[] SchemasOwned
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.SchemasOwned;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.SchemasOwned = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, string> ExtendedProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.ExtendedProperties;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.ExtendedProperties = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> Members
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.Members;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.Members = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsYukonOrLater
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.dataContainer.Server.VersionMajor >= 9;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors / Dispose
|
||||
public DatabaseRolePrototype(CDataContainer context, string database)
|
||||
{
|
||||
this.exists = false;
|
||||
this.databaseName = database;
|
||||
this.dataContainer = context;
|
||||
this.currentState = new DatabaseRolePrototypeData(context, database);
|
||||
this.originalState = (DatabaseRolePrototypeData)this.currentState.Clone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DatabaseRoleData for creating a new app role
|
||||
/// </summary>
|
||||
public DatabaseRolePrototype(CDataContainer context, string database, DatabaseRoleInfo roleInfo)
|
||||
{
|
||||
this.exists = false;
|
||||
this.databaseName = database;
|
||||
this.dataContainer = context;
|
||||
this.currentState = new DatabaseRolePrototypeData(context, database);
|
||||
this.originalState = (DatabaseRolePrototypeData)this.currentState.Clone();
|
||||
|
||||
this.ApplyInfoToPrototype(roleInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DatabaseRoleData for editing an existing app role
|
||||
/// </summary>
|
||||
public DatabaseRolePrototype(CDataContainer context, string database, DatabaseRole role)
|
||||
{
|
||||
this.exists = true;
|
||||
this.databaseName = database;
|
||||
this.dataContainer = context;
|
||||
this.currentState = new DatabaseRolePrototypeData(context, database, role);
|
||||
this.originalState = (DatabaseRolePrototypeData)this.currentState.Clone();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation: SendDataToServer()
|
||||
/// <summary>
|
||||
/// SendDataToServer
|
||||
///
|
||||
/// here we talk with server via smo and do the actual data changing
|
||||
/// </summary>
|
||||
public void SendDataToServer()
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(this.databaseName), "databaseName is empty");
|
||||
|
||||
Microsoft.SqlServer.Management.Smo.Server srv = this.dataContainer.Server;
|
||||
System.Diagnostics.Debug.Assert(srv != null, "server object is null");
|
||||
|
||||
Database db = srv.Databases[this.databaseName];
|
||||
System.Diagnostics.Debug.Assert(db != null, "database object is null");
|
||||
|
||||
DatabaseRole databaseRole = null;
|
||||
if (this.exists) // in properties mode -> alter role
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(this.Name), "databaseRoleName is empty");
|
||||
|
||||
databaseRole = db.Roles[this.Name];
|
||||
System.Diagnostics.Debug.Assert(databaseRole != null, "databaseRole object is null");
|
||||
|
||||
if (0 != String.Compare(this.currentState.Owner, this.originalState.Owner, StringComparison.Ordinal))
|
||||
{
|
||||
databaseRole.Owner = this.Owner;
|
||||
databaseRole.Alter();
|
||||
}
|
||||
}
|
||||
else // not in properties mode -> create role
|
||||
{
|
||||
databaseRole = new DatabaseRole(db, this.Name);
|
||||
if (this.Owner.Length != 0)
|
||||
{
|
||||
databaseRole.Owner = this.Owner;
|
||||
}
|
||||
databaseRole.Create();
|
||||
}
|
||||
SendToServerSchemaOwnershipChanges(db, databaseRole);
|
||||
SendToServerExtendedPropertiesChange();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Schemas - general operations with ...
|
||||
/// <summary>
|
||||
/// sends to server changes related to schema ownership
|
||||
/// </summary>
|
||||
private void SendToServerSchemaOwnershipChanges(Database db, DatabaseRole databaseRole)
|
||||
{
|
||||
if (this.IsYukonOrLater)
|
||||
{
|
||||
foreach (string schemaName in this.Schemas)
|
||||
{
|
||||
bool currentlyOwned = this.currentState.SchemasOwned.Contains(schemaName);
|
||||
|
||||
if (this.exists)
|
||||
{
|
||||
bool wasOwned = this.originalState.SchemasOwned.Contains(schemaName);
|
||||
|
||||
if (currentlyOwned != wasOwned)
|
||||
{
|
||||
if (currentlyOwned == true)
|
||||
{
|
||||
Schema schema = db.Schemas[schemaName];
|
||||
schema.Owner = databaseRole.Name;
|
||||
schema.Alter();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we cannot not renounce ownership
|
||||
Schema schema = db.Schemas[name];
|
||||
schema.Owner = null;
|
||||
schema.Alter();
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentlyOwned == true)
|
||||
{
|
||||
Schema schema = db.Schemas[schemaName];
|
||||
schema.Owner = databaseRole.Name;
|
||||
schema.Alter();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void SendToServerExtendedPropertiesChange()
|
||||
{
|
||||
// add or alter the extended properties
|
||||
foreach (var item in this.ExtendedProperties)
|
||||
{
|
||||
if (this.originalState.ExtendedProperties.ContainsKey(item.Key))
|
||||
{
|
||||
// alter the existing extended property
|
||||
ExtendedProperty ep = this.originalState.DatabaseRole.ExtendedProperties[item.Key];
|
||||
ep.Value = item.Value;
|
||||
ep.Alter();
|
||||
}
|
||||
else
|
||||
{
|
||||
// create the extended property
|
||||
ExtendedProperty ep = new ExtendedProperty(this.originalState.DatabaseRole, item.Key, item.Value);
|
||||
ep.Create();
|
||||
}
|
||||
}
|
||||
|
||||
// remove the extended properties that are not in the current list
|
||||
foreach (var item in this.originalState.ExtendedProperties)
|
||||
{
|
||||
if (!this.ExtendedProperties.ContainsKey(item.Key))
|
||||
{
|
||||
ExtendedProperty ep = this.originalState.DatabaseRole.ExtendedProperties[item.Key];
|
||||
ep.Drop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sends to server user changes related to membership
|
||||
/// </summary>
|
||||
private void SendToServerMembershipChanges(Database db, DatabaseRole dbrole)
|
||||
{
|
||||
if (!this.exists)
|
||||
{
|
||||
foreach (string member in this.Members)
|
||||
{
|
||||
dbrole.AddMember(member);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string member in this.Members)
|
||||
{
|
||||
if (!this.originalState.Members.Contains(member))
|
||||
{
|
||||
dbrole.AddMember(member);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string member in this.originalState.Members)
|
||||
{
|
||||
if (!this.Members.Contains(member))
|
||||
{
|
||||
dbrole.DropMember(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ApplyInfoToPrototype(DatabaseRoleInfo roleInfo)
|
||||
{
|
||||
this.Name = roleInfo.Name;
|
||||
this.Owner = roleInfo.Owner;
|
||||
this.Members = roleInfo.Members.ToList();
|
||||
this.SchemasOwned = roleInfo.OwnedSchemas.ToArray();
|
||||
this.ExtendedProperties = roleInfo.ExtendedProperties.Select(ep => new KeyValuePair<string, string>(ep.Name, ep.Value)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
}
|
||||
|
||||
private class DatabaseRolePrototypeData : ICloneable
|
||||
{
|
||||
#region data members
|
||||
private string databaseRoleName = string.Empty;
|
||||
private string owner = String.Empty;
|
||||
private bool initialized = false;
|
||||
private List<string> schemaNames = null;
|
||||
private Dictionary<string, string> dictSchemas = new Dictionary<string, string>();
|
||||
private Dictionary<string, string> dictExtendedProperties = new Dictionary<string, string>();
|
||||
private List<string> members = new List<string>();
|
||||
private DatabaseRole role = null;
|
||||
private Server server = null;
|
||||
private string database = string.Empty;
|
||||
private CDataContainer context = null;
|
||||
private bool isYukonOrLater = false;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
// General properties
|
||||
|
||||
|
||||
public string DatabaseRoleName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
return this.databaseRoleName;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.databaseRoleName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public DatabaseRole DatabaseRole
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.role;
|
||||
}
|
||||
}
|
||||
|
||||
public string Owner
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.owner = value;
|
||||
}
|
||||
}
|
||||
public string[] SchemasOwned
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
return this.dictSchemas.Keys.Where(s => dictSchemas[s] == this.databaseRoleName).ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
foreach (string schema in value)
|
||||
{
|
||||
// cannot renounce ownership
|
||||
this.dictSchemas[schema] = this.DatabaseRoleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string[] Schemas
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
return this.schemaNames.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.schemaNames = value.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, string> ExtendedProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
return this.dictExtendedProperties;
|
||||
}
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.dictExtendedProperties = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> Members
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
return this.members;
|
||||
}
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.members = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Exists
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.role != null);
|
||||
}
|
||||
}
|
||||
|
||||
public Microsoft.SqlServer.Management.Smo.Server Server
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.server;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsYukonOrLater
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.isYukonOrLater;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// private default constructor - used by Clone()
|
||||
/// </summary>
|
||||
private DatabaseRolePrototypeData()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="server">The server on which we are creating a new databaseRole</param>
|
||||
/// <param name="databaseName">The database on which we are creating a new databaseRole</param>
|
||||
public DatabaseRolePrototypeData(CDataContainer context, string databaseName)
|
||||
{
|
||||
this.server = context.Server;
|
||||
this.database = databaseName;
|
||||
this.context = context;
|
||||
this.isYukonOrLater = (this.server.Information.Version.Major >= 9);
|
||||
LoadData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="server">The server on which we are modifying a databaseRole</param>
|
||||
/// <param name="databaseName">The database on which we are modifying a databaseRole</param>
|
||||
/// <param name="databaseRole">The databaseRole we are modifying</param>
|
||||
public DatabaseRolePrototypeData(CDataContainer context, string databaseName, DatabaseRole databaseRole)
|
||||
{
|
||||
this.server = context.Server;
|
||||
this.database = databaseName;
|
||||
this.context = context;
|
||||
this.isYukonOrLater = (this.server.Information.Version.Major >= 9);
|
||||
this.role = databaseRole;
|
||||
LoadData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a clone of this DatabaseRolePrototypeData object
|
||||
/// </summary>
|
||||
/// <returns>The clone DatabaseRolePrototypeData object</returns>
|
||||
public object Clone()
|
||||
{
|
||||
DatabaseRolePrototypeData result = new DatabaseRolePrototypeData();
|
||||
result.databaseRoleName = this.databaseRoleName;
|
||||
result.initialized = this.initialized;
|
||||
result.schemaNames = new List<string>(this.schemaNames);
|
||||
result.dictSchemas = new Dictionary<string, string>(this.dictSchemas);
|
||||
result.dictExtendedProperties = new Dictionary<string, string>(this.dictExtendedProperties);
|
||||
result.members = new List<string>(this.members);
|
||||
result.owner = this.owner;
|
||||
result.role = this.role;
|
||||
result.server = this.server;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
{
|
||||
this.initialized = true;
|
||||
|
||||
if (this.Exists)
|
||||
{
|
||||
LoadExisting();
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadNew();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadExisting()
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(server != null, "server is null");
|
||||
System.Diagnostics.Debug.Assert(role != null, "app role is null");
|
||||
this.databaseRoleName = role.Name;
|
||||
this.owner = role.Owner;
|
||||
LoadSchemas();
|
||||
LoadMembership();
|
||||
LoadExtendProperties();
|
||||
}
|
||||
|
||||
private void LoadNew()
|
||||
{
|
||||
LoadSchemas();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// loads initial schemas from server together with information about the schema owner
|
||||
/// </summary>
|
||||
private void LoadSchemas()
|
||||
{
|
||||
if (this.isYukonOrLater)
|
||||
{
|
||||
this.dictSchemas = new Dictionary<string, string>();
|
||||
this.schemaNames = new List<string>();
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
Request req = new Request();
|
||||
req.Fields = new String[] { DatabaseRolePrototype.schemaNameField, DatabaseRolePrototype.schemaOwnerField };
|
||||
req.Urn = "Server/Database[@Name='" + Urn.EscapeString(this.database) + "']/Schema";
|
||||
req.OrderByList = new OrderBy[] { new OrderBy("Name", OrderBy.Direction.Asc) };
|
||||
|
||||
DataTable dt = en.Process(server.ConnectionContext, req);
|
||||
System.Diagnostics.Debug.Assert((dt != null) && (dt.Rows.Count > 0), "No rows returned from schema enumerator");
|
||||
|
||||
foreach (DataRow dr in dt.Rows)
|
||||
{
|
||||
string name = Convert.ToString(dr[DatabaseRolePrototype.schemaNameField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
string owner = Convert.ToString(dr[DatabaseRolePrototype.schemaOwnerField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
dictSchemas.Add(name, owner);
|
||||
schemaNames.Add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadMembership()
|
||||
{
|
||||
if (this.Exists)
|
||||
{
|
||||
this.members = new List<string>();
|
||||
Enumerator enumerator = new Enumerator();
|
||||
Urn urn = String.Format(System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Server/Database[@Name='{0}']/Role[@Name='{1}']/Member",
|
||||
Urn.EscapeString(this.database),
|
||||
Urn.EscapeString(this.databaseRoleName));
|
||||
string[] fields = new string[] { DatabaseRolePrototype.memberNameField };
|
||||
OrderBy[] orderBy = new OrderBy[] { new OrderBy(DatabaseRolePrototype.memberNameField, OrderBy.Direction.Asc) };
|
||||
Request request = new Request(urn, fields, orderBy);
|
||||
DataTable dt = enumerator.Process(this.server.ConnectionContext, request);
|
||||
foreach (DataRow dr in dt.Rows)
|
||||
{
|
||||
string memberName = dr[DatabaseRolePrototype.memberNameField].ToString();
|
||||
this.members.Add(memberName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadExtendProperties()
|
||||
{
|
||||
if (this.isYukonOrLater)
|
||||
{
|
||||
foreach (ExtendedProperty ep in this.role.ExtendedProperties)
|
||||
{
|
||||
this.dictExtendedProperties.Add(ep.Name, (string)ep.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,890 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#nullable disable
|
||||
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Xml;
|
||||
using System.Data;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// DatabaseRoleGeneral - main panel for database role
|
||||
/// </summary>
|
||||
internal class DatabaseRoleGeneral
|
||||
{
|
||||
#region Members
|
||||
/// <summary>
|
||||
/// data container member that contains data specific information like
|
||||
/// connection infor, SMO server object or an AMO server object as well
|
||||
/// as a hash table where one can manipulate custom data
|
||||
/// </summary>
|
||||
private CDataContainer dataContainer = null;
|
||||
|
||||
//SMO Server connection that MUST be used for all enumerator calls
|
||||
//We'll get this object out of CDataContainer, that must be initialized
|
||||
//property by the initialization code
|
||||
private ServerConnection serverConnection;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Trace support
|
||||
private const string componentName = "DatabaseRoleGeneral";
|
||||
|
||||
public string ComponentName
|
||||
{
|
||||
get
|
||||
{
|
||||
return componentName;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Constants - urn fields, etc...
|
||||
private const string ownerField = "Owner";
|
||||
private const string schemaOwnerField = "Owner";
|
||||
private const string schemaNameField = "Name";
|
||||
private const string memberNameField = "Name";
|
||||
private const string memberUrnField = "Urn";
|
||||
#endregion
|
||||
|
||||
#region Constants - grid columns positions, etc...
|
||||
private const int colSchemasChecked = 0;
|
||||
private const int colSchemasOwnedSchemas = 1;
|
||||
|
||||
private const int colMembershipBitmap = 0;
|
||||
private const int colMembershipRoleMembers = 1;
|
||||
|
||||
private const int sizeCheckboxColumn = 20;
|
||||
private const int sizeBitmapColumn = 20;
|
||||
#endregion
|
||||
|
||||
#region Non-UI variables
|
||||
|
||||
private System.Xml.XmlDocument document = null;
|
||||
|
||||
// info extracted from context
|
||||
private string serverName;
|
||||
private string databaseName;
|
||||
private string dbroleName;
|
||||
private string dbroleUrn;
|
||||
|
||||
// initial values loaded from server
|
||||
private string initialOwner;
|
||||
|
||||
private string ownerName = String.Empty;
|
||||
private string roleName = String.Empty;
|
||||
private HybridDictionary schemaOwnership = null;
|
||||
private HybridDictionary roleMembers = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties: CreateNew/Properties mode
|
||||
private bool IsPropertiesMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return (dbroleName != null) && (dbroleName.Trim().Length != 0);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors / Dispose
|
||||
public DatabaseRoleGeneral()
|
||||
{
|
||||
// This call is required by the Windows.Forms Form Designer.
|
||||
// InitializeComponent();
|
||||
}
|
||||
|
||||
public DatabaseRoleGeneral(CDataContainer context)
|
||||
{
|
||||
// InitializeComponent();
|
||||
dataContainer = context;
|
||||
|
||||
if (dataContainer != null)
|
||||
{
|
||||
document = dataContainer.Document;
|
||||
}
|
||||
else
|
||||
{
|
||||
document = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation: LoadData(), InitProp(), SendDataToServer()
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// LoadData
|
||||
///
|
||||
/// loads connection parameters from an xml
|
||||
/// </summary>
|
||||
/// <param name="doc"></param>
|
||||
private void LoadData(XmlDocument doc)
|
||||
{
|
||||
// STrace.Params(ComponentName, "LoadData", "XmlDocument doc=\"{0}\"", doc.OuterXml);
|
||||
|
||||
STParameters param;
|
||||
bool bStatus;
|
||||
|
||||
param = new STParameters();
|
||||
|
||||
param.SetDocument(doc);
|
||||
|
||||
bStatus = param.GetParam("servername", ref this.serverName);
|
||||
bStatus = param.GetParam("database", ref this.databaseName);
|
||||
|
||||
bStatus = param.GetParam("role", ref this.dbroleName);
|
||||
bStatus = param.GetParam("urn", ref this.dbroleUrn);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// InitProp
|
||||
///
|
||||
/// talks with enumerator an retrievives info
|
||||
/// </summary>
|
||||
private void InitProp()
|
||||
{
|
||||
// STrace.Params(ComponentName, "InitProp", "", null);
|
||||
|
||||
System.Diagnostics.Debug.Assert(this.serverName != null);
|
||||
System.Diagnostics.Debug.Assert((this.databaseName != null) && (this.databaseName.Trim().Length != 0));
|
||||
|
||||
|
||||
// InitializeSchemasGridColumns();
|
||||
if (this.dataContainer.Server.Information.Version.Major >= 9)
|
||||
{
|
||||
LoadSchemas();
|
||||
// FillSchemasGrid();
|
||||
}
|
||||
else
|
||||
{
|
||||
// panelSchema.Enabled = false;
|
||||
}
|
||||
|
||||
LoadMembership();
|
||||
// InitializeMembershipGridColumns();
|
||||
// FillMembershipGrid();
|
||||
|
||||
if (this.IsPropertiesMode == true)
|
||||
{
|
||||
// initialize from enumerator in properties mode
|
||||
System.Diagnostics.Debug.Assert(this.dbroleName != null);
|
||||
System.Diagnostics.Debug.Assert(this.dbroleName.Trim().Length != 0);
|
||||
System.Diagnostics.Debug.Assert(this.dbroleUrn != null);
|
||||
System.Diagnostics.Debug.Assert(this.dbroleUrn.Trim().Length != 0);
|
||||
|
||||
// this.textBoxDbRoleName.Text = this.dbroleName;
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
Request req = new Request();
|
||||
req.Fields = new String[] { DatabaseRoleGeneral.ownerField };
|
||||
|
||||
if ((this.dbroleUrn != null) && (this.dbroleUrn.Trim().Length != 0))
|
||||
{
|
||||
req.Urn = this.dbroleUrn;
|
||||
}
|
||||
else
|
||||
{
|
||||
req.Urn = "Server/Database[@Name='" + Urn.EscapeString(this.databaseName) + "']/Role[@Name='" + Urn.EscapeString(this.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;
|
||||
}
|
||||
else
|
||||
{
|
||||
// initialize with empty values in create new mode
|
||||
// this.textBoxDbRoleName.Text = String.Empty;
|
||||
// this.textBoxOwner.Text = String.Empty;
|
||||
}
|
||||
|
||||
// update UI enable/disable controls
|
||||
// EnableDisableControls();
|
||||
}
|
||||
|
||||
|
||||
// public override void OnGatherUiInformation(RunType runType)
|
||||
// {
|
||||
// base.OnGatherUiInformation(runType);
|
||||
|
||||
// this.ownerName = this.textBoxOwner.Text;
|
||||
// this.roleName = this.textBoxDbRoleName.Text;
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// SendDataToServer
|
||||
///
|
||||
/// here we talk with server via smo and do the actual data changing
|
||||
/// </summary>
|
||||
private void SendDataToServer()
|
||||
{
|
||||
// STrace.Params(ComponentName, "SendDataToServer", "", null);
|
||||
|
||||
// STrace.Assert(this.databaseName != null && this.databaseName.Trim().Length != 0, "database name is empty");
|
||||
// STrace.Assert(this.DataContainer.Server != null, "server is null");
|
||||
|
||||
Database database = this.dataContainer.Server.Databases[this.databaseName];
|
||||
// STrace.Assert(database!= null, "database is null");
|
||||
|
||||
DatabaseRole role = null;
|
||||
|
||||
if (this.IsPropertiesMode == true) // in properties mode -> alter role
|
||||
{
|
||||
// STrace.Assert(this.dbroleName != null && this.dbroleName.Trim().Length != 0, "role name is empty");
|
||||
|
||||
role = database.Roles[this.dbroleName];
|
||||
// STrace.Assert(role != null, "role is null");
|
||||
|
||||
if (0 != String.Compare(this.ownerName, this.initialOwner, StringComparison.Ordinal))
|
||||
{
|
||||
role.Owner = this.ownerName;
|
||||
role.Alter();
|
||||
}
|
||||
}
|
||||
else // not in properties mode -> create role
|
||||
{
|
||||
role = new DatabaseRole(database, this.roleName);
|
||||
if (this.ownerName.Length != 0)
|
||||
{
|
||||
role.Owner = this.ownerName;
|
||||
}
|
||||
|
||||
role.Create();
|
||||
}
|
||||
|
||||
SendToServerSchemaOwnershipChanges(database, role);
|
||||
SendToServerMembershipChanges(database, role);
|
||||
|
||||
this.dataContainer.ObjectName = role.Name;
|
||||
this.dataContainer.SqlDialogSubject = role; // needed by extended properties page
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// #region Update UI enable/disable controls
|
||||
// private void EnableDisableControls()
|
||||
// {
|
||||
// if (this.DataContainer.Server.Information.Version.Major<9)
|
||||
// {
|
||||
// panelSchema.Enabled = false;
|
||||
// }
|
||||
|
||||
// if (this.IsPropertiesMode == true)
|
||||
// {
|
||||
// this.textBoxDbRoleName.Enabled = false;
|
||||
|
||||
// this.AllUIEnabled = true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// this.textBoxDbRoleName.Enabled = true;
|
||||
|
||||
// this.AllUIEnabled = (this.textBoxDbRoleName.Text.Trim().Length!=0);
|
||||
// }
|
||||
|
||||
// buttonRemove.Enabled = (gridRoleMembership.SelectedRow>=0);
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
// #region ISupportValidation Members
|
||||
|
||||
// bool ISupportValidation.Validate()
|
||||
// {
|
||||
// if (IsPropertiesMode == false)
|
||||
// {
|
||||
// if (this.textBoxDbRoleName.Text.Trim().Length==0)
|
||||
// {
|
||||
// System.Exception e = new System.Exception(DatabaseRoleSR.Error_SpecifyAName);
|
||||
// this.DisplayExceptionMessage(e);
|
||||
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Component Designer generated code
|
||||
// /// <summary>
|
||||
// /// Required method for Designer support - do not modify
|
||||
// /// the contents of this method with the code editor.
|
||||
// /// </summary>
|
||||
// private void InitializeComponent()
|
||||
// {
|
||||
// System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DatabaseRoleGeneral));
|
||||
// this.panelEntireUserControl = new System.Windows.Forms.Panel();
|
||||
// this.panelSchema = new System.Windows.Forms.Panel();
|
||||
// this.gridSchemasOwned = new Microsoft.SqlServer.Management.SqlManagerUI.SqlManagerUIDlgGrid();
|
||||
// this.labelSchemasOwnedByDbRole = new System.Windows.Forms.Label();
|
||||
// this.panelMembership = new System.Windows.Forms.Panel();
|
||||
// this.buttonRemove = new System.Windows.Forms.Button();
|
||||
// this.buttonAdd = new System.Windows.Forms.Button();
|
||||
// this.gridRoleMembership = new Microsoft.SqlServer.Management.SqlManagerUI.SqlManagerUIDlgGrid();
|
||||
// this.labelMembersOfDbRole = new System.Windows.Forms.Label();
|
||||
// this.panelDbRoleGeneralInfo = new System.Windows.Forms.Panel();
|
||||
// this.buttonSearchOwner = new System.Windows.Forms.Button();
|
||||
// this.textBoxOwner = new System.Windows.Forms.TextBox();
|
||||
// this.labelDbRoleOwner = new System.Windows.Forms.Label();
|
||||
// this.textBoxDbRoleName = new System.Windows.Forms.TextBox();
|
||||
// this.labelDbRoleName = new System.Windows.Forms.Label();
|
||||
// this.panelEntireUserControl.SuspendLayout();
|
||||
// this.panelSchema.SuspendLayout();
|
||||
// ((System.ComponentModel.ISupportInitialize)(this.gridSchemasOwned)).BeginInit();
|
||||
// this.panelMembership.SuspendLayout();
|
||||
// ((System.ComponentModel.ISupportInitialize)(this.gridRoleMembership)).BeginInit();
|
||||
// this.panelDbRoleGeneralInfo.SuspendLayout();
|
||||
// this.SuspendLayout();
|
||||
// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
// this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
// //
|
||||
// // panelEntireUserControl
|
||||
// //
|
||||
// this.panelEntireUserControl.Controls.Add(this.panelSchema);
|
||||
// this.panelEntireUserControl.Controls.Add(this.panelMembership);
|
||||
// this.panelEntireUserControl.Controls.Add(this.panelDbRoleGeneralInfo);
|
||||
// resources.ApplyResources(this.panelEntireUserControl, "panelEntireUserControl");
|
||||
// this.panelEntireUserControl.Name = "panelEntireUserControl";
|
||||
// //
|
||||
// // panelSchema
|
||||
// //
|
||||
// resources.ApplyResources(this.panelSchema, "panelSchema");
|
||||
// this.panelSchema.Controls.Add(this.gridSchemasOwned);
|
||||
// this.panelSchema.Controls.Add(this.labelSchemasOwnedByDbRole);
|
||||
// this.panelSchema.Name = "panelSchema";
|
||||
// //
|
||||
// // gridSchemasOwned
|
||||
// //
|
||||
// resources.ApplyResources(this.gridSchemasOwned, "gridSchemasOwned");
|
||||
// this.gridSchemasOwned.BackColor = System.Drawing.SystemColors.Window;
|
||||
// this.gridSchemasOwned.ForceEnabled = false;
|
||||
// this.gridSchemasOwned.Name = "gridSchemasOwned";
|
||||
// this.gridSchemasOwned.MouseButtonClicked += new Microsoft.SqlServer.Management.UI.Grid.MouseButtonClickedEventHandler(this.gridSchemasOwned_MouseButtonClicked);
|
||||
// //
|
||||
// // labelSchemasOwnedByDbRole
|
||||
// //
|
||||
// resources.ApplyResources(this.labelSchemasOwnedByDbRole, "labelSchemasOwnedByDbRole");
|
||||
// this.labelSchemasOwnedByDbRole.Name = "labelSchemasOwnedByDbRole";
|
||||
// //
|
||||
// // panelMembership
|
||||
// //
|
||||
// resources.ApplyResources(this.panelMembership, "panelMembership");
|
||||
// this.panelMembership.Controls.Add(this.buttonRemove);
|
||||
// this.panelMembership.Controls.Add(this.buttonAdd);
|
||||
// this.panelMembership.Controls.Add(this.gridRoleMembership);
|
||||
// this.panelMembership.Controls.Add(this.labelMembersOfDbRole);
|
||||
// this.panelMembership.Name = "panelMembership";
|
||||
// //
|
||||
// // buttonRemove
|
||||
// //
|
||||
// resources.ApplyResources(this.buttonRemove, "buttonRemove");
|
||||
// this.buttonRemove.Name = "buttonRemove";
|
||||
// this.buttonRemove.Click += new System.EventHandler(this.buttonRemove_Click);
|
||||
// //
|
||||
// // buttonAdd
|
||||
// //
|
||||
// resources.ApplyResources(this.buttonAdd, "buttonAdd");
|
||||
// this.buttonAdd.Name = "buttonAdd";
|
||||
// this.buttonAdd.Click += new System.EventHandler(this.buttonAdd_Click);
|
||||
// //
|
||||
// // gridRoleMembership
|
||||
// //
|
||||
// resources.ApplyResources(this.gridRoleMembership, "gridRoleMembership");
|
||||
// this.gridRoleMembership.BackColor = System.Drawing.SystemColors.Window;
|
||||
// this.gridRoleMembership.ForceEnabled = false;
|
||||
// this.gridRoleMembership.Name = "gridRoleMembership";
|
||||
// this.gridRoleMembership.SelectionChanged += new Microsoft.SqlServer.Management.UI.Grid.SelectionChangedEventHandler(this.gridRoleMembership_SelectionChanged);
|
||||
// //
|
||||
// // labelMembersOfDbRole
|
||||
// //
|
||||
// resources.ApplyResources(this.labelMembersOfDbRole, "labelMembersOfDbRole");
|
||||
// this.labelMembersOfDbRole.Name = "labelMembersOfDbRole";
|
||||
// //
|
||||
// // panelDbRoleGeneralInfo
|
||||
// //
|
||||
// resources.ApplyResources(this.panelDbRoleGeneralInfo, "panelDbRoleGeneralInfo");
|
||||
// this.panelDbRoleGeneralInfo.Controls.Add(this.buttonSearchOwner);
|
||||
// this.panelDbRoleGeneralInfo.Controls.Add(this.textBoxOwner);
|
||||
// this.panelDbRoleGeneralInfo.Controls.Add(this.labelDbRoleOwner);
|
||||
// this.panelDbRoleGeneralInfo.Controls.Add(this.textBoxDbRoleName);
|
||||
// this.panelDbRoleGeneralInfo.Controls.Add(this.labelDbRoleName);
|
||||
// this.panelDbRoleGeneralInfo.Name = "panelDbRoleGeneralInfo";
|
||||
// //
|
||||
// // buttonSearchOwner
|
||||
// //
|
||||
// resources.ApplyResources(this.buttonSearchOwner, "buttonSearchOwner");
|
||||
// this.buttonSearchOwner.Name = "buttonSearchOwner";
|
||||
// this.buttonSearchOwner.Click += new System.EventHandler(this.buttonSearchOwner_Click);
|
||||
// //
|
||||
// // textBoxOwner
|
||||
// //
|
||||
// resources.ApplyResources(this.textBoxOwner, "textBoxOwner");
|
||||
// this.textBoxOwner.Name = "textBoxOwner";
|
||||
// //
|
||||
// // labelDbRoleOwner
|
||||
// //
|
||||
// resources.ApplyResources(this.labelDbRoleOwner, "labelDbRoleOwner");
|
||||
// this.labelDbRoleOwner.Name = "labelDbRoleOwner";
|
||||
// //
|
||||
// // textBoxDbRoleName
|
||||
// //
|
||||
// resources.ApplyResources(this.textBoxDbRoleName, "textBoxDbRoleName");
|
||||
// this.textBoxDbRoleName.Name = "textBoxDbRoleName";
|
||||
// //
|
||||
// // labelDbRoleName
|
||||
// //
|
||||
// resources.ApplyResources(this.labelDbRoleName, "labelDbRoleName");
|
||||
// this.labelDbRoleName.Name = "labelDbRoleName";
|
||||
// //
|
||||
// // DatabaseRoleGeneral
|
||||
// //
|
||||
// this.Controls.Add(this.panelEntireUserControl);
|
||||
// this.Name = "DatabaseRoleGeneral";
|
||||
// resources.ApplyResources(this, "$this");
|
||||
// this.panelEntireUserControl.ResumeLayout(false);
|
||||
// this.panelSchema.ResumeLayout(false);
|
||||
// ((System.ComponentModel.ISupportInitialize)(this.gridSchemasOwned)).EndInit();
|
||||
// this.panelMembership.ResumeLayout(false);
|
||||
// ((System.ComponentModel.ISupportInitialize)(this.gridRoleMembership)).EndInit();
|
||||
// this.panelDbRoleGeneralInfo.ResumeLayout(false);
|
||||
// this.panelDbRoleGeneralInfo.PerformLayout();
|
||||
// this.ResumeLayout(false);
|
||||
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
#region Schemas - general operations with ...
|
||||
/// <summary>
|
||||
/// loads initial schemas from server together with information about the schema owner
|
||||
/// </summary>
|
||||
private void LoadSchemas()
|
||||
{
|
||||
this.schemaOwnership = new HybridDictionary();
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
Request req = new Request();
|
||||
req.Fields = new String[] { DatabaseRoleGeneral.schemaNameField, DatabaseRoleGeneral.schemaOwnerField };
|
||||
req.Urn = "Server/Database[@Name='" + Urn.EscapeString(this.databaseName) + "']/Schema";
|
||||
|
||||
DataTable dt = en.Process(serverConnection, req);
|
||||
// STrace.Assert((dt != null) && (0 < dt.Rows.Count), "enumerator did not return schemas");
|
||||
// STrace.Assert(!this.IsPropertiesMode || (this.dbroleName.Length != 0), "role name is not known");
|
||||
|
||||
foreach (DataRow dr in dt.Rows)
|
||||
{
|
||||
string schemaName = Convert.ToString(dr[DatabaseRoleGeneral.schemaNameField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
string schemaOwner = Convert.ToString(dr[DatabaseRoleGeneral.schemaOwnerField], System.Globalization.CultureInfo.InvariantCulture);
|
||||
bool roleOwnsSchema =
|
||||
this.IsPropertiesMode &&
|
||||
(0 == String.Compare(this.dbroleName, schemaOwner, StringComparison.Ordinal));
|
||||
|
||||
this.schemaOwnership[schemaName] = new SchemaOwnership(roleOwnsSchema);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// initializes the columns and headers of schema grid - but doesnt populate grid with any data
|
||||
/// </summary>
|
||||
// private void InitializeSchemasGridColumns()
|
||||
// {
|
||||
// Microsoft.SqlServer.Management.UI.Grid.DlgGridControl grid = this.gridSchemasOwned;
|
||||
|
||||
// if (grid.RowsNumber != 0)
|
||||
// {
|
||||
// grid.DeleteAllRows();
|
||||
// }
|
||||
|
||||
// while (grid.ColumnsNumber != 0)
|
||||
// {
|
||||
// grid.DeleteColumn(0);
|
||||
// }
|
||||
|
||||
// GridColumnInfo colInfo = null;
|
||||
|
||||
// // checkbox owned/not-owned
|
||||
// colInfo = new GridColumnInfo();
|
||||
// colInfo.ColumnWidth = sizeCheckboxColumn;
|
||||
// colInfo.WidthType = GridColumnWidthType.InPixels;
|
||||
// colInfo.ColumnType = GridColumnType.Checkbox;
|
||||
// grid.AddColumn(colInfo);
|
||||
|
||||
// // schema name
|
||||
// colInfo = new GridColumnInfo();
|
||||
// colInfo.ColumnWidth = grid.Width - sizeCheckboxColumn - 2;
|
||||
// colInfo.WidthType = GridColumnWidthType.InPixels;
|
||||
// grid.AddColumn(colInfo);
|
||||
|
||||
// grid.SetHeaderInfo(colSchemasOwnedSchemas, DatabaseRoleSR.HeaderOwnedSchemas, null);
|
||||
|
||||
// grid.SelectionType = GridSelectionType.SingleRow;
|
||||
// grid.UpdateGrid();
|
||||
// }
|
||||
|
||||
// private void FillSchemasGrid()
|
||||
// {
|
||||
// Microsoft.SqlServer.Management.UI.Grid.DlgGridControl grid = this.gridSchemasOwned;
|
||||
|
||||
// grid.BeginInit();
|
||||
// grid.DeleteAllRows();
|
||||
|
||||
// IDictionaryEnumerator enumerator = this.schemaOwnership.GetEnumerator();
|
||||
// enumerator.Reset();
|
||||
// while (enumerator.MoveNext())
|
||||
// {
|
||||
// DictionaryEntry entry = enumerator.Entry;
|
||||
// GridCellCollection row = new GridCellCollection();
|
||||
// GridCell cell = null;
|
||||
|
||||
// string schemaName = entry.Key.ToString();
|
||||
// bool roleCurrentlyOwnsSchema = ((SchemaOwnership)entry.Value).currentlyOwned;
|
||||
|
||||
// // grid is filled either
|
||||
// // a) disabled-checked checkboxes: Indeterminate - if already owning schema - we cannot renounce ownership
|
||||
// // b) enabled-unchecked checkboxes: Unchecked - user can check / uncheck them and we read final state
|
||||
// cell = new GridCell(roleCurrentlyOwnsSchema ? GridCheckBoxState.Indeterminate : GridCheckBoxState.Unchecked);
|
||||
// row.Add(cell);
|
||||
|
||||
// cell = new GridCell(schemaName);
|
||||
// row.Add(cell);
|
||||
|
||||
// grid.AddRow(row);
|
||||
// }
|
||||
|
||||
// grid.EndInit();
|
||||
|
||||
// if (grid.RowsNumber > 0)
|
||||
// {
|
||||
// grid.SelectedRow = 0;
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// sends to server changes related to schema ownership
|
||||
/// </summary>
|
||||
private void SendToServerSchemaOwnershipChanges(Database db, DatabaseRole dbrole)
|
||||
{
|
||||
if (9 <= this.dataContainer.Server.Information.Version.Major)
|
||||
{
|
||||
IDictionaryEnumerator enumerator = this.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.currentlyOwned && !ownership.initiallyOwned)
|
||||
{
|
||||
Schema schema = db.Schemas[schemaName];
|
||||
schema.Owner = dbrole.Name;
|
||||
schema.Alter();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private void gridSchemasOwned_MouseButtonClicked(object sender, Microsoft.SqlServer.Management.UI.Grid.MouseButtonClickedEventArgs args)
|
||||
// {
|
||||
// if ((args.Button == MouseButtons.Left) &&
|
||||
// (colSchemasChecked == args.ColumnIndex))
|
||||
// {
|
||||
// int row = (int) args.RowIndex;
|
||||
// string schemaName = this.gridSchemasOwned.GetCellInfo(row, colSchemasOwnedSchemas).CellData.ToString();
|
||||
// GridCheckBoxState newState = this.FlipCheckbox(this.gridSchemasOwned, row, colSchemasChecked);
|
||||
// bool nowOwned = ((GridCheckBoxState.Checked == newState) || (GridCheckBoxState.Indeterminate == newState));
|
||||
|
||||
// ((SchemaOwnership) this.schemaOwnership[schemaName]).currentlyOwned = nowOwned;
|
||||
// }
|
||||
// }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Membership - general operations with ...
|
||||
|
||||
/// <summary>
|
||||
/// loads from server initial membership information
|
||||
/// </summary>
|
||||
private void LoadMembership()
|
||||
{
|
||||
this.roleMembers = new HybridDictionary();
|
||||
|
||||
if (this.IsPropertiesMode)
|
||||
{
|
||||
Enumerator enumerator = new Enumerator();
|
||||
Urn urn = String.Format(System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Server/Database[@Name='{0}']/Role[@Name='{1}']/Member",
|
||||
Urn.EscapeString(this.databaseName),
|
||||
Urn.EscapeString(this.dbroleName));
|
||||
string[] fields = new string[] { DatabaseRoleGeneral.memberNameField };
|
||||
OrderBy[] orderBy = new OrderBy[] { new OrderBy(DatabaseRoleGeneral.memberNameField, OrderBy.Direction.Asc) };
|
||||
Request request = new Request(urn, fields, orderBy);
|
||||
DataTable dt = enumerator.Process(this.serverConnection, request);
|
||||
|
||||
foreach (DataRow dr in dt.Rows)
|
||||
{
|
||||
string memberName = dr[DatabaseRoleGeneral.memberNameField].ToString();
|
||||
this.roleMembers[memberName] = new RoleMembership(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// initialize grid column headers, but not the content
|
||||
/// </summary>
|
||||
// private void InitializeMembershipGridColumns()
|
||||
// {
|
||||
// Microsoft.SqlServer.Management.UI.Grid.DlgGridControl grid = this.gridRoleMembership;
|
||||
|
||||
// if (grid.RowsNumber != 0)
|
||||
// {
|
||||
// grid.DeleteAllRows();
|
||||
// }
|
||||
|
||||
// while (grid.ColumnsNumber != 0)
|
||||
// {
|
||||
// grid.DeleteColumn(0);
|
||||
// }
|
||||
|
||||
// GridColumnInfo colInfo = null;
|
||||
|
||||
// // bitmap member type
|
||||
// colInfo = new GridColumnInfo();
|
||||
// colInfo.ColumnWidth = sizeBitmapColumn;
|
||||
// colInfo.WidthType = GridColumnWidthType.InPixels;
|
||||
// colInfo.ColumnType = GridColumnType.Bitmap;
|
||||
// grid.AddColumn(colInfo);
|
||||
|
||||
// // member name
|
||||
// colInfo = new GridColumnInfo();
|
||||
// colInfo.ColumnWidth = grid.Width - sizeBitmapColumn - 2;
|
||||
// colInfo.WidthType = GridColumnWidthType.InPixels;
|
||||
// grid.AddColumn(colInfo);
|
||||
|
||||
// grid.SetHeaderInfo(colMembershipRoleMembers, DatabaseRoleSR.HeaderRoleMembers, null);
|
||||
|
||||
// grid.SelectionType = GridSelectionType.SingleRow;
|
||||
// grid.UpdateGrid();
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// fills the membership grid with data (bitmaps, names, etc)
|
||||
/// </summary>
|
||||
// private void FillMembershipGrid()
|
||||
// {
|
||||
// Microsoft.SqlServer.Management.UI.Grid.DlgGridControl grid = this.gridRoleMembership;
|
||||
|
||||
// grid.BeginInit();
|
||||
// grid.DeleteAllRows();
|
||||
|
||||
// IDictionaryEnumerator enumerator = this.roleMembers.GetEnumerator();
|
||||
// enumerator.Reset();
|
||||
// while (enumerator.MoveNext())
|
||||
// {
|
||||
// DictionaryEntry entry = enumerator.Entry;
|
||||
// string memberName = entry.Key.ToString();
|
||||
// RoleMembership membership = (RoleMembership) entry.Value;
|
||||
|
||||
// if (membership.currentlyAMember)
|
||||
// {
|
||||
// GridCellCollection row = new GridCellCollection();
|
||||
// GridCell cell = null;
|
||||
|
||||
// cell = new GridCell(bitmapMember);
|
||||
// row.Add(cell);
|
||||
|
||||
// cell = new GridCell(memberName);
|
||||
// row.Add(cell);
|
||||
|
||||
// grid.AddRow(row);
|
||||
// }
|
||||
// }
|
||||
|
||||
// grid.EndInit();
|
||||
|
||||
// if (grid.RowsNumber > 0)
|
||||
// {
|
||||
// grid.SelectedRow = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// sends to server user changes related to membership
|
||||
/// </summary>
|
||||
private void SendToServerMembershipChanges(Database db, DatabaseRole dbrole)
|
||||
{
|
||||
IDictionaryEnumerator enumerator = this.roleMembers.GetEnumerator();
|
||||
enumerator.Reset();
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
DictionaryEntry entry = enumerator.Entry;
|
||||
string memberName = entry.Key.ToString();
|
||||
RoleMembership membership = (RoleMembership)entry.Value;
|
||||
|
||||
if (!membership.initiallyAMember && membership.currentlyAMember)
|
||||
{
|
||||
dbrole.AddMember(memberName);
|
||||
}
|
||||
else if (membership.initiallyAMember && !membership.currentlyAMember)
|
||||
{
|
||||
dbrole.DropMember(memberName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private void gridRoleMembership_SelectionChanged(object sender, Microsoft.SqlServer.Management.UI.Grid.SelectionChangedEventArgs args)
|
||||
// {
|
||||
// EnableDisableControls();
|
||||
// }
|
||||
|
||||
// private void buttonAdd_Click(object sender, System.EventArgs e)
|
||||
// {
|
||||
|
||||
// using (SqlObjectSearch dlg = new SqlObjectSearch(
|
||||
// this.Font,
|
||||
// iconSearchRolesAndUsers,
|
||||
// this.HelpProvider,
|
||||
// DatabaseRoleSR.Add_DialogTitle,
|
||||
// this.DataContainer.ConnectionInfo,
|
||||
// this.databaseName,
|
||||
// new SearchableObjectTypeCollection(SearchableObjectType.User, SearchableObjectType.DatabaseRole),
|
||||
// new SearchableObjectTypeCollection(SearchableObjectType.User, SearchableObjectType.DatabaseRole),
|
||||
// false))
|
||||
// {
|
||||
// if (DialogResult.OK == dlg.ShowDialog(this.FindForm()))
|
||||
// {
|
||||
// bool memberAdded = false;
|
||||
|
||||
// this.gridRoleMembership.BeginInit();
|
||||
|
||||
// foreach (SearchableObject principal in dlg.SearchResults)
|
||||
// {
|
||||
// if (!this.roleMembers.Contains(principal.Name))
|
||||
// {
|
||||
// this.roleMembers[principal.Name] = new RoleMembership(false, true);
|
||||
// memberAdded = true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// RoleMembership membership = (RoleMembership) this.roleMembers[principal.Name];
|
||||
|
||||
// if (!membership.currentlyAMember)
|
||||
// {
|
||||
// membership.currentlyAMember = true;
|
||||
// memberAdded = true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (memberAdded)
|
||||
// {
|
||||
// GridCellCollection row = new GridCellCollection();
|
||||
// GridCell cell = null;
|
||||
|
||||
// cell = new GridCell(bitmapMember);
|
||||
// row.Add(cell);
|
||||
|
||||
// cell = new GridCell(principal.Name);
|
||||
// row.Add(cell);
|
||||
|
||||
// this.gridRoleMembership.AddRow(row);
|
||||
// }
|
||||
// }
|
||||
|
||||
// this.gridRoleMembership.EndInit();
|
||||
|
||||
// if (memberAdded)
|
||||
// {
|
||||
// this.gridRoleMembership.SelectedRow = this.gridRoleMembership.RowsNumber - 1;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// private void buttonRemove_Click(object sender, System.EventArgs e)
|
||||
// {
|
||||
// DlgGridControl grid = this.gridRoleMembership;
|
||||
|
||||
// int row = this.gridRoleMembership.SelectedRow;
|
||||
// STrace.Assert(0 <= row, "unexpected row number");
|
||||
|
||||
// if (0 <= row)
|
||||
// {
|
||||
// string memberName = this.gridRoleMembership.GetCellInfo(row, colMembershipRoleMembers).CellData.ToString();
|
||||
// RoleMembership membership = (RoleMembership) this.roleMembers[memberName];
|
||||
|
||||
// if (membership.initiallyAMember)
|
||||
// {
|
||||
// membership.currentlyAMember = false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// this.roleMembers.Remove(memberName);
|
||||
// }
|
||||
|
||||
// this.gridRoleMembership.DeleteRow(row);
|
||||
// }
|
||||
// }
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// a class for storing various application role properties
|
||||
/// </summary>
|
||||
public class ExtendedPropertyInfo
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
public string? Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// 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.ServiceLayer.Management;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
internal class ServerRoleActions : ManagementActionBase
|
||||
{
|
||||
private ConfigAction configAction;
|
||||
|
||||
private ServerRolePrototype prototype;
|
||||
|
||||
/// <summary>
|
||||
/// Handle login create and update actions
|
||||
/// </summary>
|
||||
public ServerRoleActions(CDataContainer dataContainer, ConfigAction configAction, ServerRolePrototype prototype)
|
||||
{
|
||||
this.DataContainer = dataContainer;
|
||||
this.configAction = configAction;
|
||||
this.prototype = prototype;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
{
|
||||
prototype.SendDataToServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,499 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// ServerRoleGeneral - main app role page
|
||||
/// </summary>
|
||||
internal class ServerRolePrototype
|
||||
{
|
||||
#region Members
|
||||
|
||||
/// <summary>
|
||||
/// data container member that contains data specific information like
|
||||
/// connection infor, SMO server object or an AMO server object as well
|
||||
/// as a hash table where one can manipulate custom data
|
||||
/// </summary>
|
||||
private CDataContainer dataContainer = null;
|
||||
|
||||
private bool exists;
|
||||
private ServerRolePrototypeData currentState;
|
||||
private ServerRolePrototypeData originalState;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Trace support
|
||||
private const string componentName = "ServerRoleGeneral";
|
||||
|
||||
public string ComponentName
|
||||
{
|
||||
get
|
||||
{
|
||||
return componentName;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Properties: CreateNew/Properties mode
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.ServerRoleName;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.ServerRoleName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Owner
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.Owner;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.Owner = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> Members
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.Members;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.Members = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> Memberships
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.Memberships;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.currentState.Memberships = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsYukonOrLater
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.dataContainer.Server.VersionMajor >= 9;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFixedRole
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentState.IsFixedRole;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors / Dispose
|
||||
public ServerRolePrototype(CDataContainer context)
|
||||
{
|
||||
this.exists = false;
|
||||
this.dataContainer = context;
|
||||
this.currentState = new ServerRolePrototypeData(context);
|
||||
this.originalState = (ServerRolePrototypeData)this.currentState.Clone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ServerRoleData for creating a new app role
|
||||
/// </summary>
|
||||
public ServerRolePrototype(CDataContainer context, ServerRoleInfo roleInfo)
|
||||
{
|
||||
this.exists = false;
|
||||
this.dataContainer = context;
|
||||
this.currentState = new ServerRolePrototypeData(context);
|
||||
this.originalState = (ServerRolePrototypeData)this.currentState.Clone();
|
||||
|
||||
this.ApplyInfoToPrototype(roleInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ServerRoleData for editing an existing app role
|
||||
/// </summary>
|
||||
public ServerRolePrototype(CDataContainer context, ServerRole role)
|
||||
{
|
||||
this.exists = true;
|
||||
this.dataContainer = context;
|
||||
this.currentState = new ServerRolePrototypeData(context, role);
|
||||
this.originalState = (ServerRolePrototypeData)this.currentState.Clone();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation: SendDataToServer()
|
||||
/// <summary>
|
||||
/// SendDataToServer
|
||||
///
|
||||
/// here we talk with server via smo and do the actual data changing
|
||||
/// </summary>
|
||||
public void SendDataToServer()
|
||||
{
|
||||
Microsoft.SqlServer.Management.Smo.Server srv = this.dataContainer.Server;
|
||||
System.Diagnostics.Debug.Assert(srv != null, "server object is null");
|
||||
|
||||
ServerRole serverRole = null;
|
||||
if (this.exists) // in properties mode -> alter role
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(this.Name), "serverRoleName is empty");
|
||||
|
||||
serverRole = srv.Roles[this.Name];
|
||||
System.Diagnostics.Debug.Assert(serverRole != null, "serverRole object is null");
|
||||
|
||||
if (0 != String.Compare(this.currentState.Owner, this.originalState.Owner, StringComparison.Ordinal))
|
||||
{
|
||||
serverRole.Owner = this.Owner;
|
||||
serverRole.Alter();
|
||||
}
|
||||
}
|
||||
else // not in properties mode -> create role
|
||||
{
|
||||
serverRole = new ServerRole(srv, this.Name);
|
||||
if (this.Owner.Length != 0)
|
||||
{
|
||||
serverRole.Owner = this.Owner;
|
||||
}
|
||||
serverRole.Create();
|
||||
}
|
||||
|
||||
SendToServerMemberChanges(serverRole);
|
||||
SendToServerMembershipChanges(serverRole);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// sends to server user changes related to members
|
||||
/// </summary>
|
||||
private void SendToServerMemberChanges(ServerRole serverRole)
|
||||
{
|
||||
if (!this.exists)
|
||||
{
|
||||
foreach (string member in this.Members)
|
||||
{
|
||||
serverRole.AddMember(member);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string member in this.Members)
|
||||
{
|
||||
if (!this.originalState.Members.Contains(member))
|
||||
{
|
||||
serverRole.AddMember(member);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string member in this.originalState.Members)
|
||||
{
|
||||
if (!this.Members.Contains(member))
|
||||
{
|
||||
serverRole.DropMember(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sends to server user changes related to memberships
|
||||
/// </summary>
|
||||
private void SendToServerMembershipChanges(ServerRole serverRole)
|
||||
{
|
||||
if (!this.exists)
|
||||
{
|
||||
foreach (string role in this.Memberships)
|
||||
{
|
||||
serverRole.AddMembershipToRole(this.dataContainer.Server.Roles[role].Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string role in this.Memberships)
|
||||
{
|
||||
if (!this.originalState.Memberships.Contains(role))
|
||||
{
|
||||
serverRole.AddMembershipToRole(this.dataContainer.Server.Roles[role].Name);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string role in this.originalState.Memberships)
|
||||
{
|
||||
if (!this.Memberships.Contains(role))
|
||||
{
|
||||
serverRole.DropMembershipFromRole(this.dataContainer.Server.Roles[role].Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ApplyInfoToPrototype(ServerRoleInfo roleInfo)
|
||||
{
|
||||
this.Name = roleInfo.Name;
|
||||
this.Owner = roleInfo.Owner;
|
||||
this.Members = roleInfo.Members.ToList();
|
||||
this.Memberships = roleInfo.Memberships.ToList();
|
||||
}
|
||||
|
||||
private class ServerRolePrototypeData : ICloneable
|
||||
{
|
||||
#region data members
|
||||
private string serverRoleName = string.Empty;
|
||||
private string owner = String.Empty;
|
||||
private bool initialized = false;
|
||||
private List<string> members = new List<string>();
|
||||
private List<string> memberships = new List<string>();
|
||||
private ServerRole role = null;
|
||||
private ServerRoleExtender extender = null;
|
||||
private Server server = null;
|
||||
private CDataContainer context = null;
|
||||
private bool isYukonOrLater = false;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
// General properties
|
||||
|
||||
|
||||
public string ServerRoleName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
return this.serverRoleName;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.serverRoleName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ServerRole ServerRole
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.role;
|
||||
}
|
||||
}
|
||||
|
||||
public string Owner
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.owner = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> Members
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
return this.members;
|
||||
}
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.members = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> Memberships
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
return this.memberships;
|
||||
}
|
||||
set
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(this.initialized, "unexpected property set before initialization");
|
||||
this.memberships = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Exists
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.role != null);
|
||||
}
|
||||
}
|
||||
|
||||
public Microsoft.SqlServer.Management.Smo.Server Server
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.server;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsYukonOrLater
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.isYukonOrLater;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFixedRole
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.role != null && this.role.IsFixedRole;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// private default constructor - used by Clone()
|
||||
/// </summary>
|
||||
private ServerRolePrototypeData()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="context">The context in which we are creating a new serverRole</param>
|
||||
public ServerRolePrototypeData(CDataContainer context)
|
||||
{
|
||||
this.server = context.Server;
|
||||
this.context = context;
|
||||
this.isYukonOrLater = (this.server.Information.Version.Major >= 9);
|
||||
LoadData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="context">The context in which we are modifying an existing serverRole</param>
|
||||
/// <param name="serverRole">The serverRole we are modifying</param>
|
||||
public ServerRolePrototypeData(CDataContainer context, ServerRole serverRole)
|
||||
{
|
||||
this.server = context.Server;
|
||||
this.context = context;
|
||||
this.isYukonOrLater = (this.server.Information.Version.Major >= 9);
|
||||
this.role = serverRole;
|
||||
this.extender = new ServerRoleExtender(this.role);
|
||||
LoadData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a clone of this ServerRolePrototypeData object
|
||||
/// </summary>
|
||||
/// <returns>The clone ServerRolePrototypeData object</returns>
|
||||
public object Clone()
|
||||
{
|
||||
ServerRolePrototypeData result = new ServerRolePrototypeData();
|
||||
result.serverRoleName = this.serverRoleName;
|
||||
result.initialized = this.initialized;
|
||||
result.members = new List<string>(this.members);
|
||||
result.memberships = new List<string>(this.memberships);
|
||||
result.role = this.role;
|
||||
result.extender = this.extender;
|
||||
result.owner = this.owner;
|
||||
result.server = this.server;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
{
|
||||
this.initialized = true;
|
||||
|
||||
if (this.Exists)
|
||||
{
|
||||
LoadExisting();
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadNew();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadExisting()
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(server != null, "server is null");
|
||||
System.Diagnostics.Debug.Assert(role != null, "app role is null");
|
||||
this.serverRoleName = role.Name;
|
||||
this.owner = role.Owner;
|
||||
LoadMembers();
|
||||
LoadMemberships();
|
||||
}
|
||||
|
||||
private void LoadNew()
|
||||
{
|
||||
}
|
||||
|
||||
private void LoadMembers()
|
||||
{
|
||||
if (this.Exists)
|
||||
{
|
||||
foreach (string memberName in this.role.EnumMemberNames())
|
||||
{
|
||||
this.members.Add(memberName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadMemberships()
|
||||
{
|
||||
foreach (ServerRole srvRole in this.server.Roles)
|
||||
{
|
||||
if (srvRole.EnumMemberNames().Contains(this.role.Name))
|
||||
{
|
||||
this.memberships.Add(srvRole.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,327 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Specialized;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
public class ServerRoleManageTaskFormComponent
|
||||
{
|
||||
protected ServerRole serverRole;
|
||||
ServerRoleExtender extender;
|
||||
|
||||
ServerRole instance;
|
||||
Server server;
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
}
|
||||
|
||||
public ServerRoleManageTaskFormComponent()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public ServerRoleManageTaskFormComponent(IContainer container)
|
||||
{
|
||||
// container.Add(this);
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected string MethodName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Alter";
|
||||
}
|
||||
}
|
||||
|
||||
protected ServerRole Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
#pragma warning disable IDE0074 // Use compound assignment
|
||||
if (this.instance == null)
|
||||
{
|
||||
this.instance = CreateSmoObjectInstance();
|
||||
}
|
||||
#pragma warning restore IDE0074 // Use compound assignment
|
||||
return this.instance;
|
||||
}
|
||||
}
|
||||
|
||||
protected Server Server
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.server;
|
||||
}
|
||||
}
|
||||
|
||||
protected Microsoft.SqlServer.Management.Sdk.Sfc.ISfcPropertyProvider CreatePropertyProvider()
|
||||
{
|
||||
#pragma warning disable IDE0074 // Use compound assignment
|
||||
if (extender == null)
|
||||
{
|
||||
extender = new ServerRoleExtender(this.Instance);
|
||||
}
|
||||
#pragma warning restore IDE0074 // Use compound assignment
|
||||
return extender;
|
||||
}
|
||||
|
||||
protected ServerRole CreateSmoObjectInstance()
|
||||
{
|
||||
if (this.serverRole == null)
|
||||
{
|
||||
Urn urn;
|
||||
// if (!SmoTaskHelper.TryGetUrn(this.TaskManager.Context, out urn))
|
||||
if (true) // TODO new server role
|
||||
{
|
||||
this.serverRole = new ServerRole(this.Server, GetServerRoleName());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.serverRole = this.Server.GetSmoObject(urn) as ServerRole;
|
||||
}
|
||||
}
|
||||
return this.serverRole;
|
||||
}
|
||||
|
||||
protected void PerformTask()
|
||||
{
|
||||
this.CreateOrManage();
|
||||
|
||||
//General Page Permissions Related actions
|
||||
EventHandler tempEventHandler = (EventHandler)this.extender.GeneralPageOnRunNow;
|
||||
if (tempEventHandler != null)
|
||||
{
|
||||
tempEventHandler(this, new EventArgs());
|
||||
}
|
||||
|
||||
//Disposing DataContainer object as it has a dedicated server connection.
|
||||
if (this.extender.GeneralPageDataContainer != null)
|
||||
{
|
||||
((CDataContainer)this.extender.GeneralPageDataContainer).Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateOrManage()
|
||||
{
|
||||
//General Page Actions
|
||||
if (Utils.IsSql11OrLater(this.Instance.ServerVersion.Major))
|
||||
{
|
||||
if (this.Instance.State == SqlSmoState.Creating)
|
||||
{
|
||||
if (this.extender.OwnerForUI == string.Empty) //In order to avoid scripting Authorization part of ddl.
|
||||
{
|
||||
this.extender.OwnerForUI = null;
|
||||
}
|
||||
this.Instance.Create();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Instance.Alter();
|
||||
}
|
||||
}
|
||||
|
||||
//Members Page Related actions
|
||||
this.extender.RefreshRoleMembersHash();
|
||||
Dictionary<string, bool> memberNameIsMemberHash = this.extender.MemberNameIsMemberHash;
|
||||
|
||||
StringCollection membersToBeDropped = new StringCollection();
|
||||
StringCollection membersToBeAdded = new StringCollection();
|
||||
|
||||
StringCollection membershipsToBeDropped = new StringCollection();
|
||||
StringCollection membershipsToBeAdded = new StringCollection();
|
||||
|
||||
foreach (string memberName in memberNameIsMemberHash.Keys)
|
||||
{
|
||||
if (memberNameIsMemberHash[memberName]) //if added as member
|
||||
{
|
||||
membersToBeAdded.Add(memberName);
|
||||
}
|
||||
else //if dropped from members
|
||||
{
|
||||
membersToBeDropped.Add(memberName);
|
||||
}
|
||||
}
|
||||
|
||||
//Membership page Related actions
|
||||
this.extender.RefreshServerRoleNameHasMembershipHash();
|
||||
Dictionary<string, bool> membershipInfoHash = this.extender.ServerRoleNameHasMembershipHash;
|
||||
|
||||
foreach (string serverRoleName in membershipInfoHash.Keys)
|
||||
{
|
||||
if (membershipInfoHash[serverRoleName]) //If new membership added
|
||||
{
|
||||
membershipsToBeAdded.Add(serverRoleName);
|
||||
}
|
||||
else //If now not a member of
|
||||
{
|
||||
membershipsToBeDropped.Add(serverRoleName);
|
||||
}
|
||||
}
|
||||
|
||||
//First dropping members and memberships
|
||||
foreach (string member in membersToBeDropped)
|
||||
{
|
||||
this.serverRole.DropMember(member);
|
||||
}
|
||||
|
||||
foreach (string containingRole in membershipsToBeDropped)
|
||||
{
|
||||
this.serverRole.DropMembershipFromRole(containingRole);
|
||||
}
|
||||
|
||||
//Now adding members and memberships.
|
||||
foreach (string member in membersToBeAdded)
|
||||
{
|
||||
this.serverRole.AddMember(member);
|
||||
}
|
||||
|
||||
foreach (string containingRole in membershipsToBeAdded)
|
||||
{
|
||||
this.serverRole.AddMembershipToRole(containingRole);
|
||||
}
|
||||
}
|
||||
|
||||
// protected System.Collections.Specialized.StringCollection GetScriptStrings(ITaskExecutionContext context)
|
||||
// {
|
||||
// StringCollection script = this.GetScriptForCreateOrManage();
|
||||
|
||||
// StringCollection permissionScript = this.GetPermissionRelatedScripts();
|
||||
|
||||
// foreach (string str in permissionScript)
|
||||
// {
|
||||
// script.Add(str);
|
||||
// }
|
||||
|
||||
// if (script.Count == 0)
|
||||
// {
|
||||
// //When the user tries to script and no changes have been made.
|
||||
// // throw new SsmsException(SR.NoActionToBeScripted);
|
||||
// }
|
||||
// return script;
|
||||
// }
|
||||
|
||||
private StringCollection GetPermissionRelatedScripts()
|
||||
{
|
||||
StringCollection script = new StringCollection();
|
||||
|
||||
if (this.extender.GeneralPageDataContainer != null) //Permission controls have been initialized.
|
||||
{
|
||||
//For General Page permissions
|
||||
ServerConnection permControlConn = ((CDataContainer)this.extender.GeneralPageDataContainer).ServerConnection;
|
||||
SqlExecutionModes em = permControlConn.SqlExecutionModes;
|
||||
|
||||
//PermissionUI has a cloned connection.
|
||||
permControlConn.CapturedSql.Clear();
|
||||
permControlConn.SqlExecutionModes = SqlExecutionModes.CaptureSql;
|
||||
|
||||
//This will run General page's permission related actions.
|
||||
EventHandler tempEventHandler = (EventHandler)this.extender.GeneralPageOnRunNow;
|
||||
if (tempEventHandler != null)
|
||||
{
|
||||
tempEventHandler(this, new EventArgs());
|
||||
}
|
||||
|
||||
script = permControlConn.CapturedSql.Text;
|
||||
permControlConn.SqlExecutionModes = em;
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates script for Create and Properties.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private StringCollection GetScriptForCreateOrManage()
|
||||
{
|
||||
StringCollection script = new StringCollection();
|
||||
|
||||
Server svr = this.Instance.Parent;
|
||||
svr.ConnectionContext.CapturedSql.Clear();
|
||||
SqlExecutionModes em = svr.ConnectionContext.SqlExecutionModes;
|
||||
|
||||
svr.ConnectionContext.SqlExecutionModes = SqlExecutionModes.CaptureSql;
|
||||
|
||||
//T-SQL Capturing starts.
|
||||
|
||||
this.CreateOrManage();
|
||||
|
||||
//T-SQL capturing ends
|
||||
script = svr.ConnectionContext.CapturedSql.Text;
|
||||
svr.ConnectionContext.SqlExecutionModes = em;
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
protected string GetServerRoleName()
|
||||
{
|
||||
return "ServerRole-" + DateTime.Now.ToString("yyyyMMdd-HHmmss",SmoApplication.DefaultCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
// if (disposing && (components != null))
|
||||
// {
|
||||
// components.Dispose();
|
||||
// }
|
||||
// base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerRoleCreateTaskFormComponent : ServerRoleManageTaskFormComponent
|
||||
{
|
||||
public ServerRoleCreateTaskFormComponent()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public ServerRoleCreateTaskFormComponent(IContainer container)
|
||||
: base(container)
|
||||
{
|
||||
}
|
||||
|
||||
protected ServerRole CreateSmoObjectInstance()
|
||||
{
|
||||
#pragma warning disable IDE0074 // Use compound assignment
|
||||
if (this.serverRole == null)
|
||||
{
|
||||
this.serverRole = new ServerRole(this.Server, GetServerRoleName());
|
||||
}
|
||||
#pragma warning restore IDE0074 // Use compound assignment
|
||||
return this.serverRole;
|
||||
}
|
||||
|
||||
protected string MethodName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Create";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// ServerRole object type handler
|
||||
/// </summary>
|
||||
public class ServerRoleHandler : ObjectTypeHandler<ServerRoleInfo, ServerRoleViewContext>
|
||||
{
|
||||
public ServerRoleHandler(ConnectionService connectionService) : base(connectionService) { }
|
||||
|
||||
public override bool CanHandleType(SqlObjectType objectType)
|
||||
{
|
||||
return objectType == SqlObjectType.ServerRole;
|
||||
}
|
||||
|
||||
public override Task<InitializeViewResult> InitializeObjectView(InitializeViewRequestParams parameters)
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
this.ConnectionService.TryFindConnection(parameters.ConnectionUri, out connInfo);
|
||||
if (connInfo == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid ConnectionUri");
|
||||
}
|
||||
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
|
||||
|
||||
ServerRolePrototype prototype = parameters.IsNewObject
|
||||
? new ServerRolePrototype(dataContainer)
|
||||
: new ServerRolePrototype(dataContainer, dataContainer.Server.GetSmoObject(parameters.ObjectUrn) as ServerRole);
|
||||
|
||||
List<string> serverRoles = new List<string>();
|
||||
for (int i = 0; i < dataContainer.Server.Roles.Count; i++)
|
||||
{
|
||||
var role = dataContainer.Server.Roles[i].Name;
|
||||
// Cannot add member to public, sysadmin and self
|
||||
if (role != "public" && role != "sysadmin" && role != prototype.Name)
|
||||
{
|
||||
serverRoles.Add(role);
|
||||
}
|
||||
}
|
||||
|
||||
ServerRoleInfo ServerRoleInfo = new ServerRoleInfo()
|
||||
{
|
||||
Name = prototype.Name,
|
||||
Owner = prototype.Owner,
|
||||
Members = prototype.Members.ToArray(),
|
||||
Memberships = prototype.Memberships.ToArray()
|
||||
};
|
||||
|
||||
var viewInfo = new ServerRoleViewInfo()
|
||||
{
|
||||
ObjectInfo = ServerRoleInfo,
|
||||
IsFixedRole = prototype.IsFixedRole,
|
||||
ServerRoles = serverRoles.ToArray()
|
||||
};
|
||||
|
||||
var context = new ServerRoleViewContext(parameters);
|
||||
return Task.FromResult(new InitializeViewResult()
|
||||
{
|
||||
ViewInfo = viewInfo,
|
||||
Context = context
|
||||
});
|
||||
}
|
||||
|
||||
public override Task Save(ServerRoleViewContext context, ServerRoleInfo obj)
|
||||
{
|
||||
if (context.Parameters.IsNewObject)
|
||||
{
|
||||
this.DoHandleCreateServerRoleRequest(context, obj, RunType.RunNow);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DoHandleUpdateServerRoleRequest(context, obj, RunType.RunNow);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override Task<string> Script(ServerRoleViewContext context, ServerRoleInfo obj)
|
||||
{
|
||||
string script;
|
||||
if (context.Parameters.IsNewObject)
|
||||
{
|
||||
script = this.DoHandleCreateServerRoleRequest(context, obj, RunType.ScriptToWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
script = this.DoHandleUpdateServerRoleRequest(context, obj, RunType.ScriptToWindow);
|
||||
}
|
||||
return Task.FromResult(script);
|
||||
}
|
||||
|
||||
private string ConfigureServerRole(CDataContainer dataContainer, ConfigAction configAction, RunType runType, ServerRolePrototype prototype)
|
||||
{
|
||||
string sqlScript = string.Empty;
|
||||
using (var actions = new ServerRoleActions(dataContainer, configAction, prototype))
|
||||
{
|
||||
var executionHandler = new ExecutonHandler(actions);
|
||||
executionHandler.RunNow(runType, this);
|
||||
if (executionHandler.ExecutionResult == ExecutionMode.Failure)
|
||||
{
|
||||
throw executionHandler.ExecutionFailureException;
|
||||
}
|
||||
|
||||
if (runType == RunType.ScriptToWindow)
|
||||
{
|
||||
sqlScript = executionHandler.ScriptTextFromLastRun;
|
||||
}
|
||||
}
|
||||
|
||||
return sqlScript;
|
||||
}
|
||||
|
||||
private string DoHandleUpdateServerRoleRequest(ServerRoleViewContext context, ServerRoleInfo serverRoleInfo, RunType runType)
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
this.ConnectionService.TryFindConnection(context.Parameters.ConnectionUri, out connInfo);
|
||||
if (connInfo == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid ConnectionUri");
|
||||
}
|
||||
|
||||
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
|
||||
ServerRolePrototype prototype = new ServerRolePrototype(dataContainer, dataContainer.Server.Roles[serverRoleInfo.Name]);
|
||||
prototype.ApplyInfoToPrototype(serverRoleInfo);
|
||||
return ConfigureServerRole(dataContainer, ConfigAction.Update, runType, prototype);
|
||||
|
||||
}
|
||||
|
||||
private string DoHandleCreateServerRoleRequest(ServerRoleViewContext context, ServerRoleInfo serverRoleInfo, RunType runType)
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
this.ConnectionService.TryFindConnection(context.Parameters.ConnectionUri, out connInfo);
|
||||
|
||||
if (connInfo == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid ConnectionUri");
|
||||
}
|
||||
|
||||
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
|
||||
|
||||
ServerRolePrototype prototype = new ServerRolePrototype(dataContainer, serverRoleInfo);
|
||||
return ConfigureServerRole(dataContainer, ConfigAction.Create, runType, prototype);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// a class for storing various server role properties
|
||||
/// </summary>
|
||||
public class ServerRoleInfo : SqlObject
|
||||
{
|
||||
public string? Owner { get; set; }
|
||||
public string[]? Members { get; set; }
|
||||
public string[]? Memberships { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
public class ServerRoleViewContext : SqlObjectViewContext
|
||||
{
|
||||
public ServerRoleViewContext(Contracts.InitializeViewRequestParams parameters) : base(parameters)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// a class for storing various server role view properties
|
||||
/// </summary>
|
||||
public class ServerRoleViewInfo : SqlObjectViewInfo
|
||||
{
|
||||
public bool IsFixedRole { get; set; }
|
||||
public string[]? ServerRoles { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,18 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum SqlObjectType
|
||||
{
|
||||
[EnumMember(Value = "ApplicationRole")]
|
||||
ApplicationRole,
|
||||
[EnumMember(Value = "Column")]
|
||||
Column,
|
||||
[EnumMember(Value = "Credential")]
|
||||
Credential,
|
||||
[EnumMember(Value = "DatabaseRole")]
|
||||
DatabaseRole,
|
||||
[EnumMember(Value = "ServerLevelLogin")]
|
||||
ServerLevelLogin,
|
||||
[EnumMember(Value = "ServerLevelServerRole")]
|
||||
ServerRole,
|
||||
[EnumMember(Value = "Table")]
|
||||
Table,
|
||||
[EnumMember(Value = "User")]
|
||||
|
||||
Reference in New Issue
Block a user