[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:
Hai Cao
2023-04-28 07:56:15 -07:00
committed by GitHub
parent ccad4e1f8f
commit 35aa8d42de
24 changed files with 2687 additions and 1871 deletions

View File

@@ -33,6 +33,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
this.objectTypeHandlers.Add(new LoginHandler(ConnectionService.Instance));
this.objectTypeHandlers.Add(new UserHandler(ConnectionService.Instance));
this.objectTypeHandlers.Add(new CredentialHandler(ConnectionService.Instance));
this.objectTypeHandlers.Add(new AppRoleHandler(ConnectionService.Instance));
this.objectTypeHandlers.Add(new DatabaseRoleHandler(ConnectionService.Instance));
this.objectTypeHandlers.Add(new ServerRoleHandler(ConnectionService.Instance));
}
/// <summary>
@@ -121,7 +124,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
return handler;
}
}
throw new NotSupportedException(objectType.ToString());
throw new NotSupportedException($"No handler found for object type '{objectType.ToString()}'");
}
private SqlObjectViewContext GetContext(string contextId)

View File

@@ -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);
}
}
}

View File

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

View File

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

View File

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

View File

@@ -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);
}
}
}

View File

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

View File

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

View File

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

View File

@@ -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();
}
}
}
}

View File

@@ -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);
}
}
}
}
}
}

View File

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

View File

@@ -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();
}
}
}
}

View File

@@ -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);
}
}
}
}
}
}

View File

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

View File

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

View File

@@ -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();
}
}
}
}

View File

@@ -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);
}
}
}
}
}
}

View File

@@ -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";
}
}
}
}

View File

@@ -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);
}
}
}

View File

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

View File

@@ -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()
{
}
}
}

View File

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

View File

@@ -12,12 +12,18 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
[JsonConverter(typeof(StringEnumConverter))]
public enum SqlObjectType
{
[EnumMember(Value = "ApplicationRole")]
ApplicationRole,
[EnumMember(Value = "Column")]
Column,
[EnumMember(Value = "Credential")]
Credential,
[EnumMember(Value = "DatabaseRole")]
DatabaseRole,
[EnumMember(Value = "ServerLevelLogin")]
ServerLevelLogin,
[EnumMember(Value = "ServerLevelServerRole")]
ServerRole,
[EnumMember(Value = "Table")]
Table,
[EnumMember(Value = "User")]