mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 01:25:40 -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 LoginHandler(ConnectionService.Instance));
|
||||||
this.objectTypeHandlers.Add(new UserHandler(ConnectionService.Instance));
|
this.objectTypeHandlers.Add(new UserHandler(ConnectionService.Instance));
|
||||||
this.objectTypeHandlers.Add(new CredentialHandler(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>
|
/// <summary>
|
||||||
@@ -121,7 +124,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new NotSupportedException(objectType.ToString());
|
throw new NotSupportedException($"No handler found for object type '{objectType.ToString()}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
private SqlObjectViewContext GetContext(string contextId)
|
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))]
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
public enum SqlObjectType
|
public enum SqlObjectType
|
||||||
{
|
{
|
||||||
|
[EnumMember(Value = "ApplicationRole")]
|
||||||
|
ApplicationRole,
|
||||||
[EnumMember(Value = "Column")]
|
[EnumMember(Value = "Column")]
|
||||||
Column,
|
Column,
|
||||||
[EnumMember(Value = "Credential")]
|
[EnumMember(Value = "Credential")]
|
||||||
Credential,
|
Credential,
|
||||||
|
[EnumMember(Value = "DatabaseRole")]
|
||||||
|
DatabaseRole,
|
||||||
[EnumMember(Value = "ServerLevelLogin")]
|
[EnumMember(Value = "ServerLevelLogin")]
|
||||||
ServerLevelLogin,
|
ServerLevelLogin,
|
||||||
|
[EnumMember(Value = "ServerLevelServerRole")]
|
||||||
|
ServerRole,
|
||||||
[EnumMember(Value = "Table")]
|
[EnumMember(Value = "Table")]
|
||||||
Table,
|
Table,
|
||||||
[EnumMember(Value = "User")]
|
[EnumMember(Value = "User")]
|
||||||
|
|||||||
Reference in New Issue
Block a user