From 9b08993753c3aecb9701ef1dfa48b13bef3a3d4b Mon Sep 17 00:00:00 2001 From: Hai Cao Date: Thu, 6 Apr 2023 10:17:46 -0700 Subject: [PATCH] Port code for Application Role, Database Role, Permission Data and Securable search (#1992) * port code for db role and app role * port permissionData (wip) * port securable search data --- .../Localization/sr.cs | 1210 ++ .../Localization/sr.resx | 440 + .../Localization/sr.strings | 116 + .../Localization/sr.xlf | 550 + .../Security/AppRoleGeneral.cs | 1191 ++ .../Security/DatabaseRoleGeneral.cs | 925 ++ .../Security/NetStandardUtils.cs | 212 + .../Security/PermissionsData.cs | 10876 ++++++++++++++++ .../Security/PermissionsDataExtensions.cs | 50 + .../SchemaScopedSecurableAttribute.cs | 88 + .../Security/SqlObjectSearchData.cs | 2328 ++++ 11 files changed, 17986 insertions(+) create mode 100644 src/Microsoft.SqlTools.ServiceLayer/Security/AppRoleGeneral.cs create mode 100644 src/Microsoft.SqlTools.ServiceLayer/Security/DatabaseRoleGeneral.cs create mode 100644 src/Microsoft.SqlTools.ServiceLayer/Security/NetStandardUtils.cs create mode 100644 src/Microsoft.SqlTools.ServiceLayer/Security/PermissionsData.cs create mode 100644 src/Microsoft.SqlTools.ServiceLayer/Security/PermissionsDataExtensions.cs create mode 100644 src/Microsoft.SqlTools.ServiceLayer/Security/SchemaScopedSecurableAttribute.cs create mode 100644 src/Microsoft.SqlTools.ServiceLayer/Security/SqlObjectSearchData.cs diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs index 5e4eef0f..4f2e1a24 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs @@ -9733,6 +9733,886 @@ namespace Microsoft.SqlTools.ServiceLayer } } + public static string Permission_Alter + { + get + { + return Keys.GetString(Keys.Permission_Alter); + } + } + + public static string Permission_Connect + { + get + { + return Keys.GetString(Keys.Permission_Connect); + } + } + + public static string Permission_Control + { + get + { + return Keys.GetString(Keys.Permission_Control); + } + } + + public static string Permission_Delete + { + get + { + return Keys.GetString(Keys.Permission_Delete); + } + } + + public static string Permission_Execute + { + get + { + return Keys.GetString(Keys.Permission_Execute); + } + } + + public static string Permission_Impersonate + { + get + { + return Keys.GetString(Keys.Permission_Impersonate); + } + } + + public static string Permission_Insert + { + get + { + return Keys.GetString(Keys.Permission_Insert); + } + } + + public static string Permission_Receive + { + get + { + return Keys.GetString(Keys.Permission_Receive); + } + } + + public static string Permission_References + { + get + { + return Keys.GetString(Keys.Permission_References); + } + } + + public static string Permission_Select + { + get + { + return Keys.GetString(Keys.Permission_Select); + } + } + + public static string Permission_Send + { + get + { + return Keys.GetString(Keys.Permission_Send); + } + } + + public static string Permission_TakeOwnership + { + get + { + return Keys.GetString(Keys.Permission_TakeOwnership); + } + } + + public static string Permission_Update + { + get + { + return Keys.GetString(Keys.Permission_Update); + } + } + + public static string Permission_ViewDefinition + { + get + { + return Keys.GetString(Keys.Permission_ViewDefinition); + } + } + + public static string Permission_ViewChangeTracking + { + get + { + return Keys.GetString(Keys.Permission_ViewChangeTracking); + } + } + + public static string Permission_AlterAnyApplicationRole + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyApplicationRole); + } + } + + public static string Permission_AlterAnyAssembly + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyAssembly); + } + } + + public static string Permission_AlterAnyAsymmetricKey + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyAsymmetricKey); + } + } + + public static string Permission_AlterAnyCertificate + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyCertificate); + } + } + + public static string Permission_AlterAnyDatabaseAudit + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyDatabaseAudit); + } + } + + public static string Permission_AlterAnyContract + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyContract); + } + } + + public static string Permission_AlterAnyDatabaseDdlTrigger + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyDatabaseDdlTrigger); + } + } + + public static string Permission_AlterAnyDatabaseEventNotification + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyDatabaseEventNotification); + } + } + + public static string Permission_AlterAnyDataspace + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyDataspace); + } + } + + public static string Permission_AlterAnyExternalDataSource + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyExternalDataSource); + } + } + + public static string Permission_AlterAnyExternalFileFormat + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyExternalFileFormat); + } + } + + public static string Permission_AlterAnyFulltextCatalog + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyFulltextCatalog); + } + } + + public static string Permission_AlterAnyMask + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyMask); + } + } + + public static string Permission_AlterAnyMessageType + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyMessageType); + } + } + + public static string Permission_AlterAnyRemoteServiceBinding + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyRemoteServiceBinding); + } + } + + public static string Permission_AlterAnyRole + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyRole); + } + } + + public static string Permission_AlterAnyRoute + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyRoute); + } + } + + public static string Permission_AlterAnySchema + { + get + { + return Keys.GetString(Keys.Permission_AlterAnySchema); + } + } + + public static string Permission_AlterAnySecurityPolicy + { + get + { + return Keys.GetString(Keys.Permission_AlterAnySecurityPolicy); + } + } + + public static string Permission_AlterAnySensitivityClassification + { + get + { + return Keys.GetString(Keys.Permission_AlterAnySensitivityClassification); + } + } + + public static string Permission_AlterAnyService + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyService); + } + } + + public static string Permission_AlterAnyUser + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyUser); + } + } + + public static string Permission_AlterAnySymmetricKey + { + get + { + return Keys.GetString(Keys.Permission_AlterAnySymmetricKey); + } + } + + public static string Permission_Authenticate + { + get + { + return Keys.GetString(Keys.Permission_Authenticate); + } + } + + public static string Permission_BackupDatabase + { + get + { + return Keys.GetString(Keys.Permission_BackupDatabase); + } + } + + public static string Permission_BackupLog + { + get + { + return Keys.GetString(Keys.Permission_BackupLog); + } + } + + public static string Permission_Checkpoint + { + get + { + return Keys.GetString(Keys.Permission_Checkpoint); + } + } + + public static string Permission_ConnectReplication + { + get + { + return Keys.GetString(Keys.Permission_ConnectReplication); + } + } + + public static string Permission_CreateAggregate + { + get + { + return Keys.GetString(Keys.Permission_CreateAggregate); + } + } + + public static string Permission_CreateAssembly + { + get + { + return Keys.GetString(Keys.Permission_CreateAssembly); + } + } + + public static string Permission_CreateAsymmetricKey + { + get + { + return Keys.GetString(Keys.Permission_CreateAsymmetricKey); + } + } + + public static string Permission_CreateCertificate + { + get + { + return Keys.GetString(Keys.Permission_CreateCertificate); + } + } + + public static string Permission_CreateContract + { + get + { + return Keys.GetString(Keys.Permission_CreateContract); + } + } + + public static string Permission_CreateDatabase + { + get + { + return Keys.GetString(Keys.Permission_CreateDatabase); + } + } + + public static string Permission_CreateDatabaseDdlEventNotification + { + get + { + return Keys.GetString(Keys.Permission_CreateDatabaseDdlEventNotification); + } + } + + public static string Permission_CreateDefault + { + get + { + return Keys.GetString(Keys.Permission_CreateDefault); + } + } + + public static string Permission_CreateFulltextCatalog + { + get + { + return Keys.GetString(Keys.Permission_CreateFulltextCatalog); + } + } + + public static string Permission_CreateFunction + { + get + { + return Keys.GetString(Keys.Permission_CreateFunction); + } + } + + public static string Permission_CreateMessageType + { + get + { + return Keys.GetString(Keys.Permission_CreateMessageType); + } + } + + public static string Permission_CreateProcedure + { + get + { + return Keys.GetString(Keys.Permission_CreateProcedure); + } + } + + public static string Permission_CreateQueue + { + get + { + return Keys.GetString(Keys.Permission_CreateQueue); + } + } + + public static string Permission_CreateRemoteServiceBinding + { + get + { + return Keys.GetString(Keys.Permission_CreateRemoteServiceBinding); + } + } + + public static string Permission_CreateRole + { + get + { + return Keys.GetString(Keys.Permission_CreateRole); + } + } + + public static string Permission_CreateRoute + { + get + { + return Keys.GetString(Keys.Permission_CreateRoute); + } + } + + public static string Permission_CreateRule + { + get + { + return Keys.GetString(Keys.Permission_CreateRule); + } + } + + public static string Permission_CreateSchema + { + get + { + return Keys.GetString(Keys.Permission_CreateSchema); + } + } + + public static string Permission_CreateService + { + get + { + return Keys.GetString(Keys.Permission_CreateService); + } + } + + public static string Permission_CreateSymmetricKey + { + get + { + return Keys.GetString(Keys.Permission_CreateSymmetricKey); + } + } + + public static string Permission_CreateSynonym + { + get + { + return Keys.GetString(Keys.Permission_CreateSynonym); + } + } + + public static string Permission_CreateSequence + { + get + { + return Keys.GetString(Keys.Permission_CreateSequence); + } + } + + public static string Permission_CreateTable + { + get + { + return Keys.GetString(Keys.Permission_CreateTable); + } + } + + public static string Permission_CreateType + { + get + { + return Keys.GetString(Keys.Permission_CreateType); + } + } + + public static string Permission_CreateView + { + get + { + return Keys.GetString(Keys.Permission_CreateView); + } + } + + public static string Permission_CreateXmlSchemaCollection + { + get + { + return Keys.GetString(Keys.Permission_CreateXmlSchemaCollection); + } + } + + public static string Permission_Showplan + { + get + { + return Keys.GetString(Keys.Permission_Showplan); + } + } + + public static string Permission_SubscribeQueryNotifications + { + get + { + return Keys.GetString(Keys.Permission_SubscribeQueryNotifications); + } + } + + public static string Permission_Unmask + { + get + { + return Keys.GetString(Keys.Permission_Unmask); + } + } + + public static string Permission_ViewAnyColumnEncryptionKeyDefinition + { + get + { + return Keys.GetString(Keys.Permission_ViewAnyColumnEncryptionKeyDefinition); + } + } + + public static string Permission_ViewAnyColumnMasterKeyDefinition + { + get + { + return Keys.GetString(Keys.Permission_ViewAnyColumnMasterKeyDefinition); + } + } + + public static string Permission_ViewAnySensitivityClassification + { + get + { + return Keys.GetString(Keys.Permission_ViewAnySensitivityClassification); + } + } + + public static string Permission_ViewDatabaseState + { + get + { + return Keys.GetString(Keys.Permission_ViewDatabaseState); + } + } + + public static string Permission_AdministerBulkOperations + { + get + { + return Keys.GetString(Keys.Permission_AdministerBulkOperations); + } + } + + public static string Permission_AlterAnyServerAudit + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyServerAudit); + } + } + + public static string Permission_AlterAnyConnection + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyConnection); + } + } + + public static string Permission_AlterAnyCredential + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyCredential); + } + } + + public static string Permission_AlterAnyDatabase + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyDatabase); + } + } + + public static string Permission_AlterAnyEndpoint + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyEndpoint); + } + } + + public static string Permission_AlterAnyEventNotification + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyEventNotification); + } + } + + public static string Permission_AlterAnyEventSession + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyEventSession); + } + } + + public static string Permission_AlterAnyLinkedServer + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyLinkedServer); + } + } + + public static string Permission_AlterAnyLogin + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyLogin); + } + } + + public static string Permission_AlterAnyServerRole + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyServerRole); + } + } + + public static string Permission_AlterResources + { + get + { + return Keys.GetString(Keys.Permission_AlterResources); + } + } + + public static string Permission_AlterServerState + { + get + { + return Keys.GetString(Keys.Permission_AlterServerState); + } + } + + public static string Permission_AlterSettings + { + get + { + return Keys.GetString(Keys.Permission_AlterSettings); + } + } + + public static string Permission_AlterTrace + { + get + { + return Keys.GetString(Keys.Permission_AlterTrace); + } + } + + public static string Permission_AuthenticateServer + { + get + { + return Keys.GetString(Keys.Permission_AuthenticateServer); + } + } + + public static string Permission_ConnectSql + { + get + { + return Keys.GetString(Keys.Permission_ConnectSql); + } + } + + public static string Permission_ControlServer + { + get + { + return Keys.GetString(Keys.Permission_ControlServer); + } + } + + public static string Permission_CreateAnyDatabase + { + get + { + return Keys.GetString(Keys.Permission_CreateAnyDatabase); + } + } + + public static string Permission_CreateDdlEventNotification + { + get + { + return Keys.GetString(Keys.Permission_CreateDdlEventNotification); + } + } + + public static string Permission_CreateEndpoint + { + get + { + return Keys.GetString(Keys.Permission_CreateEndpoint); + } + } + + public static string Permission_CreateTraceEventNotification + { + get + { + return Keys.GetString(Keys.Permission_CreateTraceEventNotification); + } + } + + public static string Permission_CreateServerRole + { + get + { + return Keys.GetString(Keys.Permission_CreateServerRole); + } + } + + public static string Permission_ExternalAccessAssembly + { + get + { + return Keys.GetString(Keys.Permission_ExternalAccessAssembly); + } + } + + public static string Permission_Shutdown + { + get + { + return Keys.GetString(Keys.Permission_Shutdown); + } + } + + public static string Permission_UnsafeAssembly + { + get + { + return Keys.GetString(Keys.Permission_UnsafeAssembly); + } + } + + public static string Permission_ViewAnyDatabase + { + get + { + return Keys.GetString(Keys.Permission_ViewAnyDatabase); + } + } + + public static string Permission_ViewAnyDefinition + { + get + { + return Keys.GetString(Keys.Permission_ViewAnyDefinition); + } + } + + public static string Permission_ViewServerState + { + get + { + return Keys.GetString(Keys.Permission_ViewServerState); + } + } + + public static string Permission_AlterAnyAvailabilityGroup + { + get + { + return Keys.GetString(Keys.Permission_AlterAnyAvailabilityGroup); + } + } + + public static string Permission_CreateAvailabilityGroup + { + get + { + return Keys.GetString(Keys.Permission_CreateAvailabilityGroup); + } + } + + public static string Permission_SelectAllUserSecurables + { + get + { + return Keys.GetString(Keys.Permission_SelectAllUserSecurables); + } + } + + public static string Permission_ConnectAnyDatabase + { + get + { + return Keys.GetString(Keys.Permission_ConnectAnyDatabase); + } + } + + public static string Permission_ImpersonateAnyLogin + { + get + { + return Keys.GetString(Keys.Permission_ImpersonateAnyLogin); + } + } + public static string ConnectionServiceListDbErrorNotConnected(string uri) { return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri); @@ -14068,6 +14948,336 @@ namespace Microsoft.SqlTools.ServiceLayer public const string ResetPasswordWhileUnlocking = "ResetPasswordWhileUnlocking"; + public const string Permission_Alter = "Permission_Alter"; + + + public const string Permission_Connect = "Permission_Connect"; + + + public const string Permission_Control = "Permission_Control"; + + + public const string Permission_Delete = "Permission_Delete"; + + + public const string Permission_Execute = "Permission_Execute"; + + + public const string Permission_Impersonate = "Permission_Impersonate"; + + + public const string Permission_Insert = "Permission_Insert"; + + + public const string Permission_Receive = "Permission_Receive"; + + + public const string Permission_References = "Permission_References"; + + + public const string Permission_Select = "Permission_Select"; + + + public const string Permission_Send = "Permission_Send"; + + + public const string Permission_TakeOwnership = "Permission_TakeOwnership"; + + + public const string Permission_Update = "Permission_Update"; + + + public const string Permission_ViewDefinition = "Permission_ViewDefinition"; + + + public const string Permission_ViewChangeTracking = "Permission_ViewChangeTracking"; + + + public const string Permission_AlterAnyApplicationRole = "Permission_AlterAnyApplicationRole"; + + + public const string Permission_AlterAnyAssembly = "Permission_AlterAnyAssembly"; + + + public const string Permission_AlterAnyAsymmetricKey = "Permission_AlterAnyAsymmetricKey"; + + + public const string Permission_AlterAnyCertificate = "Permission_AlterAnyCertificate"; + + + public const string Permission_AlterAnyDatabaseAudit = "Permission_AlterAnyDatabaseAudit"; + + + public const string Permission_AlterAnyContract = "Permission_AlterAnyContract"; + + + public const string Permission_AlterAnyDatabaseDdlTrigger = "Permission_AlterAnyDatabaseDdlTrigger"; + + + public const string Permission_AlterAnyDatabaseEventNotification = "Permission_AlterAnyDatabaseEventNotification"; + + + public const string Permission_AlterAnyDataspace = "Permission_AlterAnyDataspace"; + + + public const string Permission_AlterAnyExternalDataSource = "Permission_AlterAnyExternalDataSource"; + + + public const string Permission_AlterAnyExternalFileFormat = "Permission_AlterAnyExternalFileFormat"; + + + public const string Permission_AlterAnyFulltextCatalog = "Permission_AlterAnyFulltextCatalog"; + + + public const string Permission_AlterAnyMask = "Permission_AlterAnyMask"; + + + public const string Permission_AlterAnyMessageType = "Permission_AlterAnyMessageType"; + + + public const string Permission_AlterAnyRemoteServiceBinding = "Permission_AlterAnyRemoteServiceBinding"; + + + public const string Permission_AlterAnyRole = "Permission_AlterAnyRole"; + + + public const string Permission_AlterAnyRoute = "Permission_AlterAnyRoute"; + + + public const string Permission_AlterAnySchema = "Permission_AlterAnySchema"; + + + public const string Permission_AlterAnySecurityPolicy = "Permission_AlterAnySecurityPolicy"; + + + public const string Permission_AlterAnySensitivityClassification = "Permission_AlterAnySensitivityClassification"; + + + public const string Permission_AlterAnyService = "Permission_AlterAnyService"; + + + public const string Permission_AlterAnyUser = "Permission_AlterAnyUser"; + + + public const string Permission_AlterAnySymmetricKey = "Permission_AlterAnySymmetricKey"; + + + public const string Permission_Authenticate = "Permission_Authenticate"; + + + public const string Permission_BackupDatabase = "Permission_BackupDatabase"; + + + public const string Permission_BackupLog = "Permission_BackupLog"; + + + public const string Permission_Checkpoint = "Permission_Checkpoint"; + + + public const string Permission_ConnectReplication = "Permission_ConnectReplication"; + + + public const string Permission_CreateAggregate = "Permission_CreateAggregate"; + + + public const string Permission_CreateAssembly = "Permission_CreateAssembly"; + + + public const string Permission_CreateAsymmetricKey = "Permission_CreateAsymmetricKey"; + + + public const string Permission_CreateCertificate = "Permission_CreateCertificate"; + + + public const string Permission_CreateContract = "Permission_CreateContract"; + + + public const string Permission_CreateDatabase = "Permission_CreateDatabase"; + + + public const string Permission_CreateDatabaseDdlEventNotification = "Permission_CreateDatabaseDdlEventNotification"; + + + public const string Permission_CreateDefault = "Permission_CreateDefault"; + + + public const string Permission_CreateFulltextCatalog = "Permission_CreateFulltextCatalog"; + + + public const string Permission_CreateFunction = "Permission_CreateFunction"; + + + public const string Permission_CreateMessageType = "Permission_CreateMessageType"; + + + public const string Permission_CreateProcedure = "Permission_CreateProcedure"; + + + public const string Permission_CreateQueue = "Permission_CreateQueue"; + + + public const string Permission_CreateRemoteServiceBinding = "Permission_CreateRemoteServiceBinding"; + + + public const string Permission_CreateRole = "Permission_CreateRole"; + + + public const string Permission_CreateRoute = "Permission_CreateRoute"; + + + public const string Permission_CreateRule = "Permission_CreateRule"; + + + public const string Permission_CreateSchema = "Permission_CreateSchema"; + + + public const string Permission_CreateService = "Permission_CreateService"; + + + public const string Permission_CreateSymmetricKey = "Permission_CreateSymmetricKey"; + + + public const string Permission_CreateSynonym = "Permission_CreateSynonym"; + + + public const string Permission_CreateSequence = "Permission_CreateSequence"; + + + public const string Permission_CreateTable = "Permission_CreateTable"; + + + public const string Permission_CreateType = "Permission_CreateType"; + + + public const string Permission_CreateView = "Permission_CreateView"; + + + public const string Permission_CreateXmlSchemaCollection = "Permission_CreateXmlSchemaCollection"; + + + public const string Permission_Showplan = "Permission_Showplan"; + + + public const string Permission_SubscribeQueryNotifications = "Permission_SubscribeQueryNotifications"; + + + public const string Permission_Unmask = "Permission_Unmask"; + + + public const string Permission_ViewAnyColumnEncryptionKeyDefinition = "Permission_ViewAnyColumnEncryptionKeyDefinition"; + + + public const string Permission_ViewAnyColumnMasterKeyDefinition = "Permission_ViewAnyColumnMasterKeyDefinition"; + + + public const string Permission_ViewAnySensitivityClassification = "Permission_ViewAnySensitivityClassification"; + + + public const string Permission_ViewDatabaseState = "Permission_ViewDatabaseState"; + + + public const string Permission_AdministerBulkOperations = "Permission_AdministerBulkOperations"; + + + public const string Permission_AlterAnyServerAudit = "Permission_AlterAnyServerAudit"; + + + public const string Permission_AlterAnyConnection = "Permission_AlterAnyConnection"; + + + public const string Permission_AlterAnyCredential = "Permission_AlterAnyCredential"; + + + public const string Permission_AlterAnyDatabase = "Permission_AlterAnyDatabase"; + + + public const string Permission_AlterAnyEndpoint = "Permission_AlterAnyEndpoint"; + + + public const string Permission_AlterAnyEventNotification = "Permission_AlterAnyEventNotification"; + + + public const string Permission_AlterAnyEventSession = "Permission_AlterAnyEventSession"; + + + public const string Permission_AlterAnyLinkedServer = "Permission_AlterAnyLinkedServer"; + + + public const string Permission_AlterAnyLogin = "Permission_AlterAnyLogin"; + + + public const string Permission_AlterAnyServerRole = "Permission_AlterAnyServerRole"; + + + public const string Permission_AlterResources = "Permission_AlterResources"; + + + public const string Permission_AlterServerState = "Permission_AlterServerState"; + + + public const string Permission_AlterSettings = "Permission_AlterSettings"; + + + public const string Permission_AlterTrace = "Permission_AlterTrace"; + + + public const string Permission_AuthenticateServer = "Permission_AuthenticateServer"; + + + public const string Permission_ConnectSql = "Permission_ConnectSql"; + + + public const string Permission_ControlServer = "Permission_ControlServer"; + + + public const string Permission_CreateAnyDatabase = "Permission_CreateAnyDatabase"; + + + public const string Permission_CreateDdlEventNotification = "Permission_CreateDdlEventNotification"; + + + public const string Permission_CreateEndpoint = "Permission_CreateEndpoint"; + + + public const string Permission_CreateTraceEventNotification = "Permission_CreateTraceEventNotification"; + + + public const string Permission_CreateServerRole = "Permission_CreateServerRole"; + + + public const string Permission_ExternalAccessAssembly = "Permission_ExternalAccessAssembly"; + + + public const string Permission_Shutdown = "Permission_Shutdown"; + + + public const string Permission_UnsafeAssembly = "Permission_UnsafeAssembly"; + + + public const string Permission_ViewAnyDatabase = "Permission_ViewAnyDatabase"; + + + public const string Permission_ViewAnyDefinition = "Permission_ViewAnyDefinition"; + + + public const string Permission_ViewServerState = "Permission_ViewServerState"; + + + public const string Permission_AlterAnyAvailabilityGroup = "Permission_AlterAnyAvailabilityGroup"; + + + public const string Permission_CreateAvailabilityGroup = "Permission_CreateAvailabilityGroup"; + + + public const string Permission_SelectAllUserSecurables = "Permission_SelectAllUserSecurables"; + + + public const string Permission_ConnectAnyDatabase = "Permission_ConnectAnyDatabase"; + + + public const string Permission_ImpersonateAnyLogin = "Permission_ImpersonateAnyLogin"; + + private Keys() { } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx index e5e6653f..920de080 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx @@ -5403,4 +5403,444 @@ The Query Processor estimates that implementing the following index could improv Reset password for the login while unlocking. + + Alter + + + + Connect + + + + Control + + + + Delete + + + + Execute + + + + Impersonate + + + + Insert + + + + Receive + + + + References + + + + Select + + + + Send + + + + Take ownership + + + + Update + + + + View definition + + + + View change tracking + + + + Alter any application role + + + + Alter any assembly + + + + Alter any asymmetric key + + + + Alter any certificate + + + + Alter any database audit + + + + Alter any contract + + + + Alter any database DDL trigger + + + + Alter any database event notification + + + + Alter any dataspace + + + + Alter any external data source + + + + Alter any external file format + + + + Alter any fulltext catalog + + + + Alter any mask + + + + Alter any message type + + + + Alter any remote service binding + + + + Alter any role + + + + Alter any route + + + + Alter any schema + + + + Alter any security policy + + + + Alter any sensitivity classification + + + + Alter any service + + + + Alter any user + + + + Alter any symmetric key + + + + Authenticate + + + + Backup database + + + + Backup log + + + + Checkpoint + + + + Connect replication + + + + Create aggregate + + + + Create assembly + + + + Create asymmetric key + + + + Create certificate + + + + Create contract + + + + Create database + + + + Create database DDL event notification + + + + Create default + + + + Create fulltext catalog + + + + Create function + + + + Create message type + + + + Create procedure + + + + Create queue + + + + Create remote service binding + + + + Create role + + + + Create route + + + + Create rule + + + + Create schema + + + + Create service + + + + Create symmetric key + + + + Create synonym + + + + Create sequence + + + + Create table + + + + Create type + + + + Create view + + + + Create XML schema collection + + + + Show plan + + + + Subscribe query notifications + + + + Unmask + + + + View any column encryption key definition + + + + View any column master key definition + + + + View any sensitivity classification + + + + View database state + + + + Administer bulk operations + + + + Alter any server audit + + + + Alter any connection + + + + Alter any credential + + + + Alter any database + + + + Alter any endpoint + + + + Alter any event notification + + + + Alter any event session + + + + Alter any linked server + + + + Alter any login + + + + Alter any server role + + + + Alter resources + + + + Alter server state + + + + Alter settings + + + + Alter trace + + + + Authenticate server + + + + Connect SQL + + + + Control server + + + + Create any database + + + + Create DDL event notification + + + + Create endpoint + + + + Create trace event notification + + + + Create server role + + + + External access assembly + + + + Shutdown + + + + Unsafe assembly + + + + View any database + + + + View any definition + + + + View server state + + + + Alter any availability group + + + + Create availability group + + + + Select All User Securables + + + + Connect Any Database + + + + Impersonate Any Login + + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings index c2875174..3ae8955c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings @@ -2451,3 +2451,119 @@ ObjectNotRenamable(string urn) = The object could not be renamed. URN: '{0}'. # Security Service DefaultLanguagePlaceholder = ResetPasswordWhileUnlocking = Reset password for the login while unlocking. + +#Object permission names +Permission_Alter = Alter +Permission_Connect = Connect +Permission_Control = Control +Permission_Delete = Delete +Permission_Execute = Execute +Permission_Impersonate = Impersonate +Permission_Insert = Insert +Permission_Receive = Receive +Permission_References = References +Permission_Select = Select +Permission_Send = Send +Permission_TakeOwnership = Take ownership +Permission_Update = Update +Permission_ViewDefinition = View definition +Permission_ViewChangeTracking = View change tracking + +#Database permission names +Permission_AlterAnyApplicationRole = Alter any application role +Permission_AlterAnyAssembly = Alter any assembly +Permission_AlterAnyAsymmetricKey = Alter any asymmetric key +Permission_AlterAnyCertificate = Alter any certificate +Permission_AlterAnyDatabaseAudit = Alter any database audit +Permission_AlterAnyContract = Alter any contract +Permission_AlterAnyDatabaseDdlTrigger = Alter any database DDL trigger +Permission_AlterAnyDatabaseEventNotification = Alter any database event notification +Permission_AlterAnyDataspace = Alter any dataspace +Permission_AlterAnyExternalDataSource = Alter any external data source +Permission_AlterAnyExternalFileFormat = Alter any external file format +Permission_AlterAnyFulltextCatalog = Alter any fulltext catalog +Permission_AlterAnyMask = Alter any mask +Permission_AlterAnyMessageType = Alter any message type +Permission_AlterAnyRemoteServiceBinding = Alter any remote service binding +Permission_AlterAnyRole = Alter any role +Permission_AlterAnyRoute = Alter any route +Permission_AlterAnySchema = Alter any schema +Permission_AlterAnySecurityPolicy = Alter any security policy +Permission_AlterAnySensitivityClassification = Alter any sensitivity classification +Permission_AlterAnyService = Alter any service +Permission_AlterAnyUser = Alter any user +Permission_AlterAnySymmetricKey = Alter any symmetric key +Permission_Authenticate = Authenticate +Permission_BackupDatabase = Backup database +Permission_BackupLog = Backup log +Permission_Checkpoint = Checkpoint +Permission_ConnectReplication = Connect replication +Permission_CreateAggregate = Create aggregate +Permission_CreateAssembly = Create assembly +Permission_CreateAsymmetricKey = Create asymmetric key +Permission_CreateCertificate = Create certificate +Permission_CreateContract = Create contract +Permission_CreateDatabase = Create database +Permission_CreateDatabaseDdlEventNotification = Create database DDL event notification +Permission_CreateDefault = Create default +Permission_CreateFulltextCatalog = Create fulltext catalog +Permission_CreateFunction = Create function +Permission_CreateMessageType = Create message type +Permission_CreateProcedure = Create procedure +Permission_CreateQueue = Create queue +Permission_CreateRemoteServiceBinding = Create remote service binding +Permission_CreateRole = Create role +Permission_CreateRoute = Create route +Permission_CreateRule = Create rule +Permission_CreateSchema = Create schema +Permission_CreateService = Create service +Permission_CreateSymmetricKey = Create symmetric key +Permission_CreateSynonym = Create synonym +Permission_CreateSequence = Create sequence +Permission_CreateTable = Create table +Permission_CreateType = Create type +Permission_CreateView = Create view +Permission_CreateXmlSchemaCollection = Create XML schema collection +Permission_Showplan = Show plan +Permission_SubscribeQueryNotifications = Subscribe query notifications +Permission_Unmask = Unmask +Permission_ViewAnyColumnEncryptionKeyDefinition = View any column encryption key definition +Permission_ViewAnyColumnMasterKeyDefinition = View any column master key definition +Permission_ViewAnySensitivityClassification = View any sensitivity classification +Permission_ViewDatabaseState = View database state + +#Server permissions names +Permission_AdministerBulkOperations = Administer bulk operations +Permission_AlterAnyServerAudit = Alter any server audit +Permission_AlterAnyConnection = Alter any connection +Permission_AlterAnyCredential = Alter any credential +Permission_AlterAnyDatabase = Alter any database +Permission_AlterAnyEndpoint = Alter any endpoint +Permission_AlterAnyEventNotification = Alter any event notification +Permission_AlterAnyEventSession = Alter any event session +Permission_AlterAnyLinkedServer = Alter any linked server +Permission_AlterAnyLogin = Alter any login +Permission_AlterAnyServerRole = Alter any server role +Permission_AlterResources = Alter resources +Permission_AlterServerState = Alter server state +Permission_AlterSettings = Alter settings +Permission_AlterTrace = Alter trace +Permission_AuthenticateServer = Authenticate server +Permission_ConnectSql = Connect SQL +Permission_ControlServer = Control server +Permission_CreateAnyDatabase = Create any database +Permission_CreateDdlEventNotification = Create DDL event notification +Permission_CreateEndpoint = Create endpoint +Permission_CreateTraceEventNotification = Create trace event notification +Permission_CreateServerRole = Create server role +Permission_ExternalAccessAssembly = External access assembly +Permission_Shutdown = Shutdown +Permission_UnsafeAssembly = Unsafe assembly +Permission_ViewAnyDatabase = View any database +Permission_ViewAnyDefinition = View any definition +Permission_ViewServerState = View server state +Permission_AlterAnyAvailabilityGroup = Alter any availability group +Permission_CreateAvailabilityGroup = Create availability group +Permission_SelectAllUserSecurables = Select All User Securables +Permission_ConnectAnyDatabase = Connect Any Database +Permission_ImpersonateAnyLogin = Impersonate Any Login diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf index 3ed72691..b6338bfb 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf @@ -6587,6 +6587,556 @@ The Query Processor estimates that implementing the following index could improv Attestation protocol cannot be empty with Secure enclaves enabled. + + Alter + Alter + + + + Connect + Connect + + + + Control + Control + + + + Delete + Delete + + + + Execute + Execute + + + + Impersonate + Impersonate + + + + Insert + Insert + + + + Receive + Receive + + + + References + References + + + + Select + Select + + + + Send + Send + + + + Take ownership + Take ownership + + + + Update + Update + + + + View definition + View definition + + + + View change tracking + View change tracking + + + + Alter any application role + Alter any application role + + + + Alter any assembly + Alter any assembly + + + + Alter any asymmetric key + Alter any asymmetric key + + + + Alter any certificate + Alter any certificate + + + + Alter any database audit + Alter any database audit + + + + Alter any contract + Alter any contract + + + + Alter any database DDL trigger + Alter any database DDL trigger + + + + Alter any database event notification + Alter any database event notification + + + + Alter any dataspace + Alter any dataspace + + + + Alter any external data source + Alter any external data source + + + + Alter any external file format + Alter any external file format + + + + Alter any fulltext catalog + Alter any fulltext catalog + + + + Alter any mask + Alter any mask + + + + Alter any message type + Alter any message type + + + + Alter any remote service binding + Alter any remote service binding + + + + Alter any role + Alter any role + + + + Alter any route + Alter any route + + + + Alter any schema + Alter any schema + + + + Alter any security policy + Alter any security policy + + + + Alter any sensitivity classification + Alter any sensitivity classification + + + + Alter any service + Alter any service + + + + Alter any user + Alter any user + + + + Alter any symmetric key + Alter any symmetric key + + + + Authenticate + Authenticate + + + + Backup database + Backup database + + + + Backup log + Backup log + + + + Checkpoint + Checkpoint + + + + Connect replication + Connect replication + + + + Create aggregate + Create aggregate + + + + Create assembly + Create assembly + + + + Create asymmetric key + Create asymmetric key + + + + Create certificate + Create certificate + + + + Create contract + Create contract + + + + Create database + Create database + + + + Create database DDL event notification + Create database DDL event notification + + + + Create default + Create default + + + + Create fulltext catalog + Create fulltext catalog + + + + Create function + Create function + + + + Create message type + Create message type + + + + Create procedure + Create procedure + + + + Create queue + Create queue + + + + Create remote service binding + Create remote service binding + + + + Create role + Create role + + + + Create route + Create route + + + + Create rule + Create rule + + + + Create schema + Create schema + + + + Create service + Create service + + + + Create symmetric key + Create symmetric key + + + + Create synonym + Create synonym + + + + Create sequence + Create sequence + + + + Create table + Create table + + + + Create type + Create type + + + + Create view + Create view + + + + Create XML schema collection + Create XML schema collection + + + + Show plan + Show plan + + + + Subscribe query notifications + Subscribe query notifications + + + + Unmask + Unmask + + + + View any column encryption key definition + View any column encryption key definition + + + + View any column master key definition + View any column master key definition + + + + View any sensitivity classification + View any sensitivity classification + + + + View database state + View database state + + + + Administer bulk operations + Administer bulk operations + + + + Alter any server audit + Alter any server audit + + + + Alter any connection + Alter any connection + + + + Alter any credential + Alter any credential + + + + Alter any database + Alter any database + + + + Alter any endpoint + Alter any endpoint + + + + Alter any event notification + Alter any event notification + + + + Alter any event session + Alter any event session + + + + Alter any linked server + Alter any linked server + + + + Alter any login + Alter any login + + + + Alter any server role + Alter any server role + + + + Alter resources + Alter resources + + + + Alter server state + Alter server state + + + + Alter settings + Alter settings + + + + Alter trace + Alter trace + + + + Authenticate server + Authenticate server + + + + Connect SQL + Connect SQL + + + + Control server + Control server + + + + Create any database + Create any database + + + + Create DDL event notification + Create DDL event notification + + + + Create endpoint + Create endpoint + + + + Create trace event notification + Create trace event notification + + + + Create server role + Create server role + + + + External access assembly + External access assembly + + + + Shutdown + Shutdown + + + + Unsafe assembly + Unsafe assembly + + + + View any database + View any database + + + + View any definition + View any definition + + + + View server state + View server state + + + + Alter any availability group + Alter any availability group + + + + Create availability group + Create availability group + + + + Select All User Securables + Select All User Securables + + + + Connect Any Database + Connect Any Database + + + + Impersonate Any Login + Impersonate Any Login + + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Security/AppRoleGeneral.cs b/src/Microsoft.SqlTools.ServiceLayer/Security/AppRoleGeneral.cs new file mode 100644 index 00000000..f37a58b6 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Security/AppRoleGeneral.cs @@ -0,0 +1,1191 @@ +// +// 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.Security +{ + /// + /// AppRoleGeneral - main app role page + /// + internal class AppRoleGeneral + { +#region Members + + private IServiceProvider serviceProvider = null; + + /// + /// 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 + /// + 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; + + + /// + /// execution mode by default for now is success + /// + private ExecutionMode m_executionMode = ExecutionMode.Success; + + /// + /// should UI be enabled? + /// + private bool executeEnabled = true; + + /// + /// should script buttons be enabled? + /// + private bool scriptEnabled = true; + + /// + /// F1 keyword to be passed to books on-line + /// + private string helpF1Keyword = null; + private RunType runType; + + //if derived class tries to call a protected method that relies on service provider, + //and the service provider hasn't been set yet, we will cache the values and will + //propagate them when we get the provider set + private System.Drawing.Icon cachedIcon = null; + private string cachedCaption = null; + + //whether or not try to auto resize grid columns inside OnLoad method + private bool attemtGridAutoResize = true; +#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; + private bool panelInitialized = false; + + + // 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) + { + // STrace.SetDefaultLevel(ComponentName , SQLToolsCommonTraceLvl.L1); + + // this.HelpF1Keyword = AssemblyVersionInfo.VersionHelpKeywordPrefix + @".swb.approle.general.f1"; + + // InitializeComponent(); + dataContainer = context; + + if (dataContainer != null) + { + document = dataContainer.Document; + } + else + { + document = null; + } + + this.isYukonOrLater = (9 <= context.Server.ConnectionContext.ServerVersion.Major); + } + + /// + /// Clean up any resources being used. + /// + // protected override void Dispose( bool disposing ) + // { + // if ( disposing ) + // { + // if (components != null) + // { + // components.Dispose(); + // } + // } + // base.Dispose( disposing ); + // } + +#endregion + +#region Implementation: LoadData(), InitProp(), SendDataToServer() + + + /// + /// LoadData + /// + /// loads connection parameters from an xml + /// + /// + 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); + } + + /// + /// InitProp + /// + /// talks with enumerator an retrieves info + /// + 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; + + /// + /// Called to validate all date in controls and save them in + /// temproary storage to be used when OnRunNow is called + /// + // 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; + // } + // } + + /// + /// SendDataToServer + /// + /// here we talk with server via smo and do the actual data changing + /// + 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 Update UI enable/disable controls +// private void EnableDisableControls() +// { +// if (!this.isYukonOrLater) +// { +// panelSchema.Enabled = false; +// textBoxDefaultSchema.Enabled = false; +// buttonBrowseSchema.Enabled = false; +// } + +// if (this.IsPropertiesMode == true) +// { +// System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(this.textBoxRoleName.Text), "textBoxRoleName is empty"); +// this.textBoxRoleName.Enabled = false; + +// this.AllUIEnabled = true; +// } +// else +// { +// this.textBoxRoleName.Enabled = true; + +// this.AllUIEnabled = (this.textBoxRoleName.Text.Trim().Length != 0); +// } + +// if ((passwordChanged==true) && (textBoxPasword.Text != textBoxConfirmPassword.Text)) +// { +// this.AllUIEnabled = false; +// } + +// buttonRemove.Enabled = (gridRoleMembership.SelectedRow>=0); + +// panelMembership.Enabled = false; // app role currently doesnt support any members +// } +// #endregion + +// #region Component Designer generated code +// /// +// /// Required method for Designer support - do not modify +// /// the contents of this method with the code editor. +// /// +// private void InitializeComponent() +// { +// System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AppRoleGeneral)); +// this.panelEntireUserControl = new System.Windows.Forms.Panel(); +// this.panelGeneral = new System.Windows.Forms.Panel(); +// this.buttonBrowseSchema = new System.Windows.Forms.Button(); +// this.textBoxDefaultSchema = new System.Windows.Forms.TextBox(); +// this.textBoxPasword = new System.Windows.Forms.TextBox(); +// this.labelPassword = new System.Windows.Forms.Label(); +// this.labelDefaultSchema = new System.Windows.Forms.Label(); +// this.textBoxRoleName = new System.Windows.Forms.TextBox(); +// this.labelRoleName = new System.Windows.Forms.Label(); +// this.textBoxConfirmPassword = new System.Windows.Forms.TextBox(); +// this.labelConfirmPassword = 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.labelMembersOfAppRole = new System.Windows.Forms.Label(); +// this.panelSchema = new System.Windows.Forms.Panel(); +// this.gridSchemasOwned = new Microsoft.SqlServer.Management.SqlManagerUI.SqlManagerUIDlgGrid(); +// this.labelSchemasOwnedByAppRole = new System.Windows.Forms.Label(); +// this.panelEntireUserControl.SuspendLayout(); +// this.panelGeneral.SuspendLayout(); +// this.panelMembership.SuspendLayout(); +// ((System.ComponentModel.ISupportInitialize)(this.gridRoleMembership)).BeginInit(); +// this.panelSchema.SuspendLayout(); +// ((System.ComponentModel.ISupportInitialize)(this.gridSchemasOwned)).BeginInit(); +// this.SuspendLayout(); +// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); +// this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; +// // +// // panelEntireUserControl +// // Important: For narrator accessibility please make sure all Controls.Add are in order from top to bottom, left to right +// // +// this.panelEntireUserControl.Controls.Add(this.panelGeneral); +// this.panelEntireUserControl.Controls.Add(this.panelMembership); +// this.panelEntireUserControl.Controls.Add(this.panelSchema); +// resources.ApplyResources(this.panelEntireUserControl, "panelEntireUserControl"); +// this.panelEntireUserControl.Name = "panelEntireUserControl"; +// // +// // panelGeneral +// // Important: For narrator accessibility please make sure all Controls.Add are in order from top to bottom, left to right +// // +// resources.ApplyResources(this.panelGeneral, "panelGeneral"); +// this.panelGeneral.Controls.Add(this.labelRoleName); +// this.panelGeneral.Controls.Add(this.textBoxRoleName); +// this.panelGeneral.Controls.Add(this.labelDefaultSchema); +// this.panelGeneral.Controls.Add(this.textBoxDefaultSchema); +// this.panelGeneral.Controls.Add(this.buttonBrowseSchema); +// this.panelGeneral.Controls.Add(this.labelPassword); +// this.panelGeneral.Controls.Add(this.textBoxPasword); +// this.panelGeneral.Controls.Add(this.labelConfirmPassword); +// this.panelGeneral.Controls.Add(this.textBoxConfirmPassword); +// this.panelGeneral.Name = "panelGeneral"; +// // +// // buttonBrowseSchema +// // +// resources.ApplyResources(this.buttonBrowseSchema, "buttonBrowseSchema"); +// this.buttonBrowseSchema.Name = "buttonBrowseSchema"; +// this.buttonBrowseSchema.Click += new System.EventHandler(this.buttonBrowseSchema_Click); +// // +// // textBoxDefaultSchema +// // +// resources.ApplyResources(this.textBoxDefaultSchema, "textBoxDefaultSchema"); +// this.textBoxDefaultSchema.Name = "textBoxDefaultSchema"; +// this.textBoxDefaultSchema.TextChanged += new System.EventHandler(this.textBoxRoleName_TextChanged); +// // +// // textBoxPasword +// // +// resources.ApplyResources(this.textBoxPasword, "textBoxPasword"); +// this.textBoxPasword.Name = "textBoxPasword"; +// this.textBoxPasword.TextChanged += new System.EventHandler(this.textBoxPasword_TextChanged); +// // +// // labelPassword +// // +// resources.ApplyResources(this.labelPassword, "labelPassword"); +// this.labelPassword.Name = "labelPassword"; +// // +// // labelDefaultSchema +// // +// resources.ApplyResources(this.labelDefaultSchema, "labelDefaultSchema"); +// this.labelDefaultSchema.Name = "labelDefaultSchema"; +// // +// // textBoxRoleName +// // +// resources.ApplyResources(this.textBoxRoleName, "textBoxRoleName"); +// this.textBoxRoleName.Name = "textBoxRoleName"; +// this.textBoxRoleName.TextChanged += new System.EventHandler(this.textBoxRoleName_TextChanged); +// // +// // labelRoleName +// // +// resources.ApplyResources(this.labelRoleName, "labelRoleName"); +// this.labelRoleName.Name = "labelRoleName"; +// // +// // textBoxConfirmPassword +// // +// resources.ApplyResources(this.textBoxConfirmPassword, "textBoxConfirmPassword"); +// this.textBoxConfirmPassword.Name = "textBoxConfirmPassword"; +// this.textBoxConfirmPassword.TextChanged += new System.EventHandler(this.textBoxConfirmPassword_TextChanged); +// // +// // labelConfirmPassword +// // +// resources.ApplyResources(this.labelConfirmPassword, "labelConfirmPassword"); +// this.labelConfirmPassword.Name = "labelConfirmPassword"; +// // +// // panelMembership +// // Important: For narrator accessibility please make sure all Controls.Add are in order from top to bottom, left to right +// // +// resources.ApplyResources(this.panelMembership, "panelMembership"); +// this.panelMembership.Controls.Add(this.labelMembersOfAppRole); +// this.panelMembership.Controls.Add(this.gridRoleMembership); +// this.panelMembership.Controls.Add(this.buttonAdd); +// this.panelMembership.Controls.Add(this.buttonRemove); +// 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); +// // +// // labelMembersOfAppRole +// // +// resources.ApplyResources(this.labelMembersOfAppRole, "labelMembersOfAppRole"); +// this.labelMembersOfAppRole.Name = "labelMembersOfAppRole"; +// // +// // panelSchema +// // Important: For narrator accessibility please make sure all Controls.Add are in order from top to bottom, left to right +// // +// resources.ApplyResources(this.panelSchema, "panelSchema"); +// this.panelSchema.Controls.Add(this.labelSchemasOwnedByAppRole); +// this.panelSchema.Controls.Add(this.gridSchemasOwned); +// 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); +// // +// // labelSchemasOwnedByAppRole +// // +// resources.ApplyResources(this.labelSchemasOwnedByAppRole, "labelSchemasOwnedByAppRole"); +// this.labelSchemasOwnedByAppRole.Name = "labelSchemasOwnedByAppRole"; +// // +// // AppRoleGeneral +// // +// this.Controls.Add(this.panelEntireUserControl); +// this.Name = "AppRoleGeneral"; +// resources.ApplyResources(this, "$this"); +// this.panelEntireUserControl.ResumeLayout(false); +// this.panelGeneral.ResumeLayout(false); +// this.panelGeneral.PerformLayout(); +// this.panelMembership.ResumeLayout(false); +// ((System.ComponentModel.ISupportInitialize)(this.gridRoleMembership)).EndInit(); +// this.panelSchema.ResumeLayout(false); +// ((System.ComponentModel.ISupportInitialize)(this.gridSchemasOwned)).EndInit(); +// this.ResumeLayout(false); + +// } +// #endregion + +#region Schemas - general operations with ... + HybridDictionary dictSchemas = null; + StringCollection schemaNames = null; + /// + /// loads initial schemas from server together with information about the schema owner + /// + 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); + } + } + } + + /// + /// initializes the columns and headers of schema grid - but doesnt populate grid with any data + /// + // 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, AppRoleSR.HeaderOwnedSchemas, null); + + // grid.SelectionType = GridSelectionType.SingleRow; + // grid.UpdateGrid(); + + // } + + // private void FillSchemasGrid() + // { + // if (this.isYukonOrLater) + // { + // Microsoft.SqlServer.Management.UI.Grid.DlgGridControl grid = this.gridSchemasOwned; + + // grid.DeleteAllRows(); + // foreach (string schemaName in this.schemaNames) + // { + // GridCellCollection row = new GridCellCollection(); + // GridCell cell = null; + + // STrace.Assert(!string.IsNullOrWhiteSpace(schemaName), "schemaName is empty"); + + // string owner = this.dictSchemas[schemaName].ToString(); + + // STrace.Assert(!string.IsNullOrWhiteSpace(owner), "owner is empty"); + + // bool owned = IsPropertiesMode ? (0 == String.Compare(owner, approleName, StringComparison.Ordinal)) : false; + + // // 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(owned ? GridCheckBoxState.Indeterminate : GridCheckBoxState.Unchecked); row.Add(cell); + // cell = new GridCell(schemaName); row.Add(cell); + + // grid.AddRow(row); + // } + + // if (grid.RowsNumber > 0) + // { + // grid.SelectedRow = 0; + // } + // } + // } + + /// + /// sends to server changes related to schema ownership + /// + 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; + + /// + /// loads from server initial membership information + /// + 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); + } + } + + /// + /// initialize grid column headers, but not the content + /// + // 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(); + // } + + /// + /// fills the membership grid with data (bitmaps, names, etc) + /// + // 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; + // } + // } + + /// + /// sends to server user changes related to membership + /// + 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(); + } + } + } + + /// + /// lookup in membership grid to see if user added a name + /// + /// + /// + /// + 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; + } + + + // private void gridRoleMembership_SelectionChanged(object sender, Microsoft.SqlServer.Management.UI.Grid.SelectionChangedEventArgs args) + // { + // EnableDisableControls(); + // } + + // private void buttonAdd_Click(object sender, System.EventArgs e) + // { + // DlgGridControl grid = this.gridRoleMembership; + + // using (SqlObjectSearch dlg = new SqlObjectSearch(this.Font, + // iconSearchUsers, + // this.HelpProvider, + // AppRoleSR.SearchUsers, + // this.DataContainer.ConnectionInfo, + // this.databaseName, + // new SearchableObjectTypeCollection(SearchableObjectType.User), + // new SearchableObjectTypeCollection(SearchableObjectType.User))) + // { + // DialogResult dr = dlg.ShowDialog(this.FindForm()); + // if (dr == DialogResult.OK) + // { + // foreach (SearchableObject principal in dlg.SearchResults) + // { + // grid = this.gridRoleMembership; + + // GridCellCollection row = new GridCellCollection(); + // GridCell cell = null; + + // string name = principal.Name; + + // 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 = grid.RowsNumber-1; + // } + // } + // } + // } + + // private void buttonRemove_Click(object sender, System.EventArgs e) + // { + // DlgGridControl grid = this.gridRoleMembership; + + // int rowNo = grid.SelectedRow; + + // System.Diagnostics.Debug.Assert(rowNo >= 0, "Invalid selected row"); + // if (rowNo >= 0) + // { + // grid.DeleteRow(rowNo); + // } + // } + +#endregion + + +// #region Bitmaps and Icons +// private Bitmap bitmapMember = null; +// private Icon iconSearchUsers = null; +// private Icon iconSchema = null; +// /// +// /// initialize bitmaps used for membership grid +// /// +// private void InitializeBitmapAndIcons() +// { +// CUtils utils = new CUtils(); +// bitmapMember = utils.LoadIcon("member.ico").ToBitmap(); + +// iconSearchUsers = utils.LoadIcon("search_users_roles.ico"); +// iconSchema = utils.LoadIcon("database_schema.ico"); +// } +// #endregion + + +// #region General Grid operations - helpers + +// /// +// /// gets status of checkbox +// /// +// /// +// /// +// /// +// /// +// bool IsEmbeededCheckboxChecked(DlgGridControl grid, int rowno, int colno) +// { +// // get the storage for the cell +// GridCell cell = grid.GetCellInfo(rowno, colno); +// GridCheckBoxState state = (GridCheckBoxState) cell.CellData; + +// return(state == GridCheckBoxState.Checked); +// } + + +// /// +// /// flips on/off checkboxes from grid +// /// +// /// +// /// +// void FlipCheckbox(DlgGridControl grid, int rowno, int colno) +// { +// // get the storage for the cell +// GridCell cell = grid.GetCellInfo(rowno, colno); +// GridCheckBoxState state = (GridCheckBoxState) cell.CellData; + +// // explicitly invert the cell state +// switch (state) +// { +// case GridCheckBoxState.Checked: +// cell.CellData = GridCheckBoxState.Unchecked; +// break; +// case GridCheckBoxState.Unchecked: +// cell.CellData = GridCheckBoxState.Checked; +// break; +// case GridCheckBoxState.Indeterminate: +// // do nothing if Indeterminate - this means that entry is checked and r/o (e.g. schemas already owned) +// break; + +// case GridCheckBoxState.None: +// break; +// default: +// System.Diagnostics.Debug.Assert(false,"unknown checkbox state"); +// break; +// } +// } +// #endregion + +// #region Non-Grid related Events +// private void textBoxRoleName_TextChanged(object sender, System.EventArgs e) +// { +// EnableDisableControls(); +// } + +// bool passwordChanged = false; +// private void textBoxPasword_TextChanged(object sender, System.EventArgs e) +// { +// passwordChanged = true; +// EnableDisableControls(); +// } + +// private void textBoxConfirmPassword_TextChanged(object sender, System.EventArgs e) +// { +// passwordChanged = true; +// EnableDisableControls(); +// } +// #endregion + +// #region ISupportValidation Members + +// bool ISupportValidation.Validate() +// { +// if (this.textBoxRoleName.Text.Trim().Length == 0) +// { +// System.Exception e = new System.Exception(AppRoleSR.ErrorApplicationRoleNameMustBeSpecified); +// this.DisplayExceptionMessage(e); + +// return false; +// } +// if (this.textBoxPasword.Text.Trim().Length == 0) +// { +// System.Exception e = new System.Exception(AppRoleSR.ErrorPasswordIsBlank); +// this.DisplayExceptionMessage(e); + +// return false; +// } +// if (this.textBoxPasword.Text != this.textBoxConfirmPassword.Text) +// { +// System.Exception e = new System.Exception(AppRoleSR.ErrorPasswordMismatch); +// this.DisplayExceptionMessage(e); + +// return false; +// } +// return true; +// } + +// #endregion + +// private void buttonBrowseSchema_Click(object sender, System.EventArgs e) +// { +// // +// // pop up object picker +// // +// using (SqlObjectSearch dlg = new SqlObjectSearch(this.Font, +// this.iconSchema, +// this.HelpProvider, +// AppRoleSR.BrowseSchemaTitle, +// this.DataContainer.ConnectionInfo, +// this.databaseName, +// new SearchableObjectTypeCollection(SearchableObjectType.Schema), +// new SearchableObjectTypeCollection(SearchableObjectType.Schema))) +// { +// if (DialogResult.OK == dlg.ShowDialog(this.FindForm())) +// { +// this.textBoxDefaultSchema.Text = dlg.SearchResults[0].Name; +// } +// } +// } + } + +} + + + + + + + + + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Security/DatabaseRoleGeneral.cs b/src/Microsoft.SqlTools.ServiceLayer/Security/DatabaseRoleGeneral.cs new file mode 100644 index 00000000..508ca27e --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Security/DatabaseRoleGeneral.cs @@ -0,0 +1,925 @@ +// +// 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.Security + +{ + /// + /// DatabaseRoleGeneral - main panel for database role + /// + internal class DatabaseRoleGeneral + { +#region Members + + private IServiceProvider serviceProvider = null; + + /// + /// 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 + /// + 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; + + + /// + /// execution mode by default for now is success + /// + private ExecutionMode m_executionMode = ExecutionMode.Success; + + /// + /// should UI be enabled? + /// + private bool executeEnabled = true; + + /// + /// should script buttons be enabled? + /// + private bool scriptEnabled = true; + + /// + /// F1 keyword to be passed to books on-line + /// + private string helpF1Keyword = null; + private RunType runType; + + //if derived class tries to call a protected method that relies on service provider, + //and the service provider hasn't been set yet, we will cache the values and will + //propagate them when we get the provider set + private System.Drawing.Icon cachedIcon = null; + private string cachedCaption = null; + + //whether or not try to auto resize grid columns inside OnLoad method + private bool attemtGridAutoResize = true; +#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; + private bool panelInitialized = false; + + // 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() + + + /// + /// LoadData + /// + /// loads connection parameters from an xml + /// + /// + 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); + } + + + /// + /// InitProp + /// + /// talks with enumerator an retrievives info + /// + 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; + // } + + /// + /// SendDataToServer + /// + /// here we talk with server via smo and do the actual data changing + /// + 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 +// /// +// /// Required method for Designer support - do not modify +// /// the contents of this method with the code editor. +// /// +// 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 ... + /// + /// loads initial schemas from server together with information about the schema owner + /// + 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); + } + } + + + /// + /// initializes the columns and headers of schema grid - but doesnt populate grid with any data + /// + // 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; + // } + + // } + + /// + /// sends to server changes related to schema ownership + /// + 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 ... + + /// + /// loads from server initial membership information + /// + 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); + } + } + } + + /// + /// initialize grid column headers, but not the content + /// + // 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(); + // } + + /// + /// fills the membership grid with data (bitmaps, names, etc) + /// + // 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; + // } + // } + + /// + /// sends to server user changes related to membership + /// + 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 + + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Security/NetStandardUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/Security/NetStandardUtils.cs new file mode 100644 index 00000000..e444c880 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Security/NetStandardUtils.cs @@ -0,0 +1,212 @@ +// +// 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.Globalization; +using SMO = Microsoft.SqlServer.Management.Smo; +using Microsoft.SqlServer.Management.Common; + +namespace Microsoft.SqlTools.ServiceLayer.Security +{ + /// + /// NetStandard compatible helpers + /// +#if NETCOREAPP2_0 + public class Utils +#else + internal partial class Utils +#endif + { + private Utils() { } + + public static bool IsKatmaiOrLater(int version) + { + return (10 <= version); + } + + public static bool IsKjOrLater(ServerVersion version) + { + return (version.Major > 10 + || (version.Major == 10 && version.Minor >= 50)); + } + + public static bool IsSql11OrLater(ServerVersion version) + { + return IsSql11OrLater(version.Major); + } + + public static bool IsSql11OrLater(int versionMajor) + { + return (versionMajor >= 11); + } + + public static bool IsSql12OrLater(ServerVersion version) + { + return IsSql12OrLater(version.Major); + } + + public static bool IsSql12OrLater(int versionMajor) + { + return (versionMajor >= 12); + } + + public static bool IsSql13OrLater(ServerVersion version) + { + return IsSql13OrLater(version.Major); + } + + public static bool IsSql13OrLater(int versionMajor) + { + return (versionMajor >= 13); + } + + public static bool IsSql14OrLater(ServerVersion version) + { + return IsSql14OrLater(version.Major); + } + + public static bool IsSql14OrLater(int versionMajor) + { + return (versionMajor >= 14); + } + + public static bool IsSql15OrLater(ServerVersion version) + { + return IsSql15OrLater(version.Major); + } + + public static bool IsSql15OrLater(int versionMajor) + { + return (versionMajor >= 15); + } + + + /// + /// Check if the version is SQL 2019 CU4 or later. + /// + /// + /// + /// + /// SQL2019 CU3 is going to be 4023; CU4 is going to be 4033 + /// SQL2019 CU4 (before the snap to the release branch) is 4028. + /// + public static bool IsSql15OCU4OrLater(Version version) + { + return(version >= new Version(15, 0, 4028)); + } + + /// + /// Check if the version is SQL 2016 SP1 or later. + /// + /// + /// true if the version is SQL 2016 SP1 or later, false otherwise + public static bool IsSql13SP1OrLater(Version version) + { + return (version >= new Version(13, 0, 3510)); + } + + public static bool IsXTPSupportedOnServer(SMO.Server server) + { + if(server.DatabaseEngineEdition == DatabaseEngineEdition.SqlOnDemand) + { + return false; + } + bool isXTPSupported = false; + + if (server.ConnectionContext.ExecuteScalar("SELECT SERVERPROPERTY('IsXTPSupported')") != DBNull.Value) + { + isXTPSupported = server.IsXTPSupported; + } + + return isXTPSupported; + } + + public static bool IsPolybasedInstalledOnServer(SMO.Server server) + { + bool isPolybaseInstalled = false; + + if (server.IsSupportedProperty("IsPolyBaseInstalled")) + { + isPolybaseInstalled = server.IsPolyBaseInstalled; + } + + return isPolybaseInstalled; + } + + /// + /// Returns true if current user has given permission on given server. + /// + /// + /// + /// + public static bool HasPermissionOnServer(SMO.Server server, string permissionName) + { + return Convert.ToBoolean(server.ConnectionContext.ExecuteScalar( + string.Format(CultureInfo.InvariantCulture, + "SELECT HAS_PERMS_BY_NAME(null, null, '{0}');", + permissionName))); + } + + public static bool FilestreamEnabled(SMO.Server svr) + { + bool result = false; + if (svr != null) + { + if (IsKatmaiOrLater(svr.Information.Version.Major) + && svr.ServerType != DatabaseEngineType.SqlAzureDatabase) //Azure doesn't support filestream + { + if (svr.Configuration.FilestreamAccessLevel.RunValue != 0) + { + result = true; + } + } + } + + return result; + } + + public static bool IsYukonOrAbove(SMO.Server server) + { + return server.Version.Major >= 9; + } + + public static bool IsBelowYukon(SMO.Server server) + { + return server.Version.Major < 9; + } + + /// + /// Some calendars, such as the UmAlQuraCalendar, support an upper date range that is earlier than MaxValue. + /// In these cases, trying to access MaxValue in variable assignments or formatting and parsing operations can throw + /// an ArgumentOutOfRangeException. Rather than retrieving the value of DateTime.MaxValue, you can retrieve the value + /// of the specified culture's latest valid date value from the + /// System.Globalization.CultureInfo.DateTimeFormat.Calendar.MaxSupportedDateTime property. + /// http://msdn.microsoft.com/en-us/library/system.datetime.maxvalue(v=VS.90).aspx + /// + /// + public static DateTime GetMaxCultureDateTime() + { + CultureInfo currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture; + return currentCulture.DateTimeFormat.Calendar.MaxSupportedDateTime; + } + + public static string MakeSqlBracket(string s) + { + return "[" + s.Replace("]", "]]") + "]"; + } + + /// + /// Returns whether the server is in AS Azure + /// + /// + /// + public static bool IsASAzure(string serverName) + { + return !string.IsNullOrEmpty(serverName) && serverName.StartsWith("asazure://", StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Security/PermissionsData.cs b/src/Microsoft.SqlTools.ServiceLayer/Security/PermissionsData.cs new file mode 100644 index 00000000..00abfea2 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Security/PermissionsData.cs @@ -0,0 +1,10876 @@ +// +// 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.Text; +using System.Data; +using System.Collections; +using System.Collections.Specialized; +using System.Collections.Generic; +using System.Linq; +using Microsoft.SqlServer.Management.Sdk.Sfc; +using Microsoft.SqlServer.Management.Common; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.SqlServer.Management.Smo.Broker; + +namespace Microsoft.SqlTools.ServiceLayer.Security +{ + /// + /// Enumeration of sql object types that can have permissions + /// +#if DEBUG || EXPOSE_MANAGED_INTERNALS + public +#else + internal +#endif + enum SecurableType + { + // !!IMPORTANT!! + // If adding a new type that is schema-scoped + // make sure to also add the SchemaScopedSecurable attribute + // so Principal!AddAllSecurables(schemaName) will correctly + // add securables of that type to its list + // + //Note there doesn't currently exist for Server or Database-scoped + // securables as the work was only initially done for schema-scoped + // (but there's no reason db or server-scoped attributes couldn't be + // added later). This DOES mean you need to manually update the + // methods below for those securable types though - e.g. in + //Principal::RelevantSecurableTypes + + [SchemaScopedSecurable(typeof(UserDefinedAggregate))] + AggregateFunction, + ApplicationRole, + Assembly, + AsymmetricKey, + AvailabilityGroup, + Certificate, + Column, + ColumnFunctionTable, + //Contract, // NYI in SMO + Database, + DatabaseRole, + Endpoint, + [SchemaScopedSecurable(typeof(ExtendedStoredProcedure))] + ExtendedStoredProcedure, + ExternalDataSource, + ExternalFileFormat, + FullTextCatalog, + [SchemaScopedSecurable(typeof(UserDefinedFunction), "FunctionType", (int)UserDefinedFunctionType.Inline)] + FunctionInline, + [SchemaScopedSecurable(typeof(UserDefinedFunction), "FunctionType", (int)UserDefinedFunctionType.Scalar)] + FunctionScalar, + [SchemaScopedSecurable(typeof(UserDefinedFunction), "FunctionType", (int)UserDefinedFunctionType.Table)] + FunctionTable, + Login, + //MessageType, // Assuming there is SMO support for this object type + //RemoteBindingService, // NYI in SMO + //Route, // NYI in SMO + Schema, + [SchemaScopedSecurable(typeof(SecurityPolicy))] + SecurityPolicy, + Server, + ServerRole, + //Service, // Assuming there is SMO support for this object type + //ServiceContract, // Assuming there is SMO support for this object type + [SchemaScopedSecurable(typeof(StoredProcedure))] + StoredProcedure, + [SchemaScopedSecurable(typeof(Synonym))] + Synonym, + [SchemaScopedSecurable(typeof(Sequence))] + Sequence, + SymmetricKey, + [SchemaScopedSecurable(typeof(Table))] + Table, + //Trigger, + User, + [SchemaScopedSecurable(typeof(View))] + View, + [SchemaScopedSecurable(typeof(UserDefinedDataType))] + UserDefinedDataType, + [SchemaScopedSecurable(typeof(UserDefinedTableType))] + UserDefinedTableType, + [SchemaScopedSecurable(typeof(XmlSchemaCollection))] + XmlSchemaCollection, + ServiceQueue, + Unknown + } + + namespace PermissionsData + { + + /// + /// The values a grant-state can take + /// + internal enum PermissionStatus + { + Revoke, // neither granted nor denied + Grant, // privilege granted + WithGrant, // with grant option + Deny // privilege denied + } + + /// + /// The display states a PermissionState can have in the UI + /// + internal enum PermissionDisplayStatus + { + Revoke, // neither granted nor denied, no checks + Grant, // privilege granted, checked "Grant" box, unchecked "With Grant" and "Deny" + WithGrant, // privelege granted, with grant option. grant is also checked. deny unchecked. + Deny, // privilege denied, unchecked "Grant" box, checked "Deny" box + PartialWithGrant, // with grant on some, but not all child objects - indeterminate "Grant" and "With Grant", unchecked "Deny" + PartialGrant, // privilege granted on some, but not all child objects - indeterminate "Grant", unchecked "Deny" + PartialDeny, // privilege denied on some, but not all child objects - unchecked "Grant", indeterminate "Deny" + PartialGrantDeny, // privilege granted on some, denied on others + Indeterminate // privilege granted to some child objects, with grant and denied to others - indeterminate "Grant", indeterminate "Deny" + } + + /// + /// A SQL Server object that can have permissions associated with it + /// + internal class Securable + { + /// + /// This class captures enumerated data about principals that are relevant to this securable + /// + private class EnumeratedPrincipalData + { + public string Name; + public PrincipalType PrincipalType; + public EnumeratedPrincipalData(string name, PrincipalType type) + { + this.Name = name; + this.PrincipalType = type; + } + + public override bool Equals(object obj) + { + bool result = false; + + EnumeratedPrincipalData other = obj as EnumeratedPrincipalData; + if (other != null) + { + result = ((this.PrincipalType == other.PrincipalType) && (this.Name == other.Name)); + } + + return result; + } + + public static bool operator ==(EnumeratedPrincipalData a, EnumeratedPrincipalData b) + { + bool result = false; + + if (((object)a == null) && ((object)b == null)) + { + result = true; + } + else if (((object)a != null) && ((object)b != null)) + { + result = a.Equals(b); + } + + return result; + } + + public static bool operator !=(EnumeratedPrincipalData a, EnumeratedPrincipalData b) + { + return !(a == b); + } + + public override int GetHashCode() + { + return this.Name.GetHashCode(); + } + } + + /// + /// This class contains the names of system principals + /// + private class SystemPrincipalDirectory + { + private Dictionary> systemPrincipalsMap; + private object connectionInfo; + private string databaseName; + + public SystemPrincipalDirectory(object connectionInfo, string databaseName) + { + this.connectionInfo = connectionInfo; + this.databaseName = databaseName; + this.systemPrincipalsMap = new Dictionary>(); + } + + /// + /// Get a list of the system principals of a particular type + /// + /// The type to look for + /// The names of the system principals + public List GetSystemPrincipalNames(PrincipalType principalType) + { + if (!this.systemPrincipalsMap.ContainsKey(principalType)) + { + Urn urn = null; + + switch (principalType) + { + case PrincipalType.User: + + urn = new Urn(String.Format( + System.Globalization.CultureInfo.InvariantCulture, + "Server/Database[@Name='{0}']/User[@IsSystemObject=true() and @Name!='guest']", + Urn.EscapeString(this.databaseName))); + break; + + case PrincipalType.DatabaseRole: + + urn = new Urn(String.Format( + System.Globalization.CultureInfo.InvariantCulture, + "Server/Database[@Name='{0}']/Role[@IsFixedRole=true()]", + Urn.EscapeString(this.databaseName))); + break; + + case PrincipalType.ApplicationRole: + + // do nothing - there are no system application roles + break; + + case PrincipalType.Login: + + urn = new Urn("Server/Login[@IsSystemObject=true()]"); + break; + + case PrincipalType.ServerRole: + + Version version = Securable.GetServerVersion(this.connectionInfo); + if (Utils.IsSql11OrLater(version.Major)) + { + urn = new Urn("Server/Role[@IsFixedRole=true()]"); + } + else + { + urn = new Urn("Server/Role"); + } + break; + + default: + + // STrace.Assert(false, "unexpected principal type"); + break; + } + + List systemPrincipalNames = new List(); + + if (urn != null) + { + Request request = new Request( + urn, + new string[] { "Name" }, + new OrderBy[] { new OrderBy("Name", OrderBy.Direction.Asc) }); + + DataTable systemPrincipalsTable = (new Enumerator()).Process(this.connectionInfo, request); + + foreach (DataRow systemPrincipalRow in systemPrincipalsTable.Rows) + { + systemPrincipalNames.Add(systemPrincipalRow[0].ToString()); + } + } + + this.systemPrincipalsMap[principalType] = systemPrincipalNames; + } + + return this.systemPrincipalsMap[principalType]; + } + } + + + private string name = String.Empty; + private string schema = String.Empty; + private string expectedGrantor = string.Empty; + private Urn urn = null; + + private SecurableType securableType; + private SqlSmoObject smoObject = null; + private bool exists = false; + + private SecurableList children = null; + private Securable parent = null; + + private PrincipalCollection principals = null; + private PrincipalCollection removedPrincipals = null; + + private event EventHandler observableChanged; + + /// + /// Dictionary mapping Principal to PermissionStateCollection + /// + private HybridDictionary principalToPermissionStates = null; + private object connectionInfo = null; + private Version serverVersion; + private DatabaseEngineType databaseEngineType; + private DatabaseEngineEdition databaseEngineEdition; + + private ArrayList relevantPermissions = null; + private bool isRemoved = false; + private const int DENALI = 11; + private const int KATMAI = 10; + private const int YUKON = 9; + private const int SHILOH = 8; + + public string ExpectedGrantor + { + get { return expectedGrantor; } + set { expectedGrantor = value; } + } + + /// + /// The object's name + /// + public string Name + { + get + { + string result = String.Empty; + + if (this.Exists) + { + string objectName = this.urn.GetAttribute("Name"); + result = (objectName != null) ? objectName : String.Empty; + } + else + { + result = this.name; + } + + return result; + } + + set + { + // STrace.Assert(!this.Exists, "Shouldn't be setting names for existing objects"); + this.name = value; + } + } + + /// + /// The object's schema or owner + /// + public string Schema + { + get + { + string result = String.Empty; + + if (this.Exists) + { + string schemaName = this.urn.GetAttribute("Schema"); + result = (schemaName != null) ? schemaName : String.Empty; + } + else + { + result = this.schema; + } + + return result; + } + + set + { + // STrace.Assert(!this.Exists, "Shouldn't be setting schema name for existing objects"); + this.schema = value; + } + } + + /// + /// The two-part name of the object + /// + public string FullName + { + get + { + string result = String.Empty; + + if (this.Name.Length != 0) + { + if (this.Schema.Length != 0) + { + result = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.{1}", this.Schema, this.Name); + } + else + { + result = this.Name; + } + } + + return result; + } + } + + /// + /// Get the name of the database containing this object, or String.Empty if no database contains this object + /// + public string DatabaseName + { + get + { + string result = String.Empty; + + Urn currentUrn = new Urn(this.urn.ToString()); + + if (currentUrn != null) + { + while (0 != String.Compare(currentUrn.Type, "Server", StringComparison.OrdinalIgnoreCase)) + { + if (0 == String.Compare(currentUrn.Type, "Database", StringComparison.OrdinalIgnoreCase)) + { + result = currentUrn.GetAttribute("Name"); + break; + } + else + { + currentUrn = currentUrn.Parent; + } + } + } + + return result; + } + } + + /// + /// This object's type + /// + public SecurableType SecurableType + { + get + { + return this.securableType; + } + } + + /// + /// The localized display name of the type of the securable + /// + public string TypeName + { + get + { + SearchableObjectType seachableType = Securable.GetSearchableObjectType(this.SecurableType); + SearchableObjectTypeDescription description = SearchableObjectTypeDescription.GetDescription(seachableType); + + return description.DisplayTypeNameSingular; + } + } + + /// + /// The URN representing this securable object + /// + public Urn Urn + { + get + { + return this.urn; + } + } + + /// + /// The collection of child objects + /// + public SecurableList Children + { + get + { + if (null == this.children) + { + this.children = this.GetChildren(); + } + + return this.children; + } + + } + + /// + /// Indicate whether this.children is initialized + /// + internal bool IsChildrenInitialized + { + get + { + return null != this.children; + } + } + + /// + /// The securable object that is the parent of this object + /// + internal Securable Parent + { + get + { + return this.parent; + } + + set + { + this.parent = value; + } + } + + /// + /// Are there permissions changes to persist to the server + /// + public bool ChangesExist + { + get + { + bool result = (this.removedPrincipals.Count != 0); + + if (!result) + { + ICollection permissionStateCollections = this.principalToPermissionStates.Values; + IEnumerator permissionStateCollectionsEnumerator = permissionStateCollections.GetEnumerator(); + + permissionStateCollectionsEnumerator.Reset(); + + while (!result && permissionStateCollectionsEnumerator.MoveNext()) + { + PermissionStateCollection permissionStates = (PermissionStateCollection)permissionStateCollectionsEnumerator.Current; + IEnumerator permissionStateEnumerator = permissionStates.GetEnumerator(); + + permissionStateEnumerator.Reset(); + + while (!result && permissionStateEnumerator.MoveNext()) + { + PermissionState permissionState = (PermissionState)permissionStateEnumerator.Current; + result = permissionState.StateChanged; + } + } + } + + // no changes in children if children were not initialized + if (!result && this.IsChildrenInitialized) + { + foreach (Securable child in this.Children) + { + if (child.ChangesExist) + { + result = true; + break; + } + } + } + + return result; + } + } + + /// + /// Whether the object exists on the server + /// + public bool Exists + { + get + { + return this.exists; + } + } + + /// + /// Has this securable been removed? + /// + public bool IsRemoved + { + get + { + return this.isRemoved; + } + + set + { + this.isRemoved = value; + } + } + + /// + /// The collection of security principals with interest in this object + /// + public PrincipalCollection Principals + { + get + { + if (null == this.principals) + { + this.principals = this.GetExistingPrincipals(); + } + + return this.principals; + } + } + + /// + /// The set of permissions relevant to this object's type + /// + public ArrayList RelevantPermissions + { + get + { +#pragma warning disable IDE0074 // Use compound assignment + if (this.relevantPermissions == null) + { + this.relevantPermissions = Securable.GetRelevantPermissions(this.SecurableType, this.serverVersion, this.DatabaseName, this.databaseEngineType, this.databaseEngineEdition); + } +#pragma warning restore IDE0074 // Use compound assignment + + return this.relevantPermissions; + } + } + + // /// + // /// The SMO object associated with this object + // /// + // protected SqlSmoObject SmoObject + // { + // get + // { + // return this.smoObject; + // } + // } + + /// + /// The connection info object used to interact with the SMO enumerator + /// + internal object ConnectionInfo + { + get + { + return this.connectionInfo; + } + } + + /// + /// The server version + /// + protected Version ServerVersion + { + get + { + return this.serverVersion; + } + } + + /// + /// The database engine type. + /// + protected DatabaseEngineType DatabaseEngineType + { + get + { + return this.databaseEngineType; + } + } + + /// + /// The database engine edition. + /// + protected DatabaseEngineEdition DatabaseEngineEdition + { + get + { + return this.databaseEngineEdition; + } + } + + /// + /// Constructor for existing objects. Used by the Permissions on Objects controls. + /// + /// The SMO object we are representing + /// The SecurableType for the SMO object + /// Connection information for enumerating permissions data + /// The version of the server + protected Securable(SqlSmoObject smoObject, SecurableType type, object connectionInfo, Version serverVersion) + { + this.smoObject = smoObject; + this.urn = smoObject.Urn; + this.securableType = type; + this.connectionInfo = connectionInfo; + this.exists = (SqlSmoState.Existing == smoObject.State); + this.principalToPermissionStates = new HybridDictionary(); + this.removedPrincipals = new PrincipalCollection(); + this.serverVersion = serverVersion; + this.databaseEngineType = GetDatabaseEngineType(this.connectionInfo); + this.databaseEngineEdition = GetDatabaseEngineEdition(this.connectionInfo); + } + + /// + /// Constructor for new objects or existing objects that have been enumerated or searched for. + /// + /// The securable type of the object + /// The URN of the object + /// Connection information for enumerating permissions data + /// The version of the server + /// True if the securable already exists on the server; otherwise, false + protected Securable(SecurableType type, string urn, object connectionInfo, Version serverVersion, bool exists) + { + this.urn = new Urn(urn); + this.securableType = type; + this.connectionInfo = connectionInfo; + this.exists = exists; + this.principalToPermissionStates = new HybridDictionary(); + this.removedPrincipals = new PrincipalCollection(); + this.serverVersion = serverVersion; + this.databaseEngineType = GetDatabaseEngineType(this.connectionInfo); + this.databaseEngineEdition = GetDatabaseEngineEdition(this.connectionInfo); + } + + /// + /// Factory method for Securables + /// + /// The type of the securable to create + /// The URN of the securable + /// Connection info used to enumerate permissions information + /// The version of the server + /// The securable that was created + protected static Securable AllocateSecurable(SecurableType type, string urn, object connectionInfo, Version serverVersion) + { + return new Securable(type, urn, connectionInfo, serverVersion, true); + } + + /// + /// Are all permissions for the principal revoked? + /// + /// The principal + /// True if all permissions are revoked, false if there are any permissions granted or denied + public bool AllPermissionsRevoked(Principal principal) + { + bool result = true; + + foreach (PermissionState ps in this.GetPermissionStates(principal)) + { + if (ps.State != PermissionStatus.Revoke) + { + result = false; + break; + } + } + + return result; + } + + /// + /// Apply changes to the permission states + /// + /// The object to modify + public void ApplyChanges(SqlSmoObject obj) + { + this.ApplyRevokes(obj); + this.ApplyGrantsAndDenies(obj); + } + + /// + /// Reset back to just loaded state + /// + public virtual void Reset() + { + this.principals = null; + this.children = null; + this.removedPrincipals = new PrincipalCollection(); + this.principalToPermissionStates = new HybridDictionary(); + this.isRemoved = false; + } + + /// + /// Reload permission states for the securable. This should be called after committing permission changes to the server. + /// + /// The smo securable that was committed to the server + public void ReloadPermissionStates(SqlSmoObject smoSecurable) + { + // STrace.Assert(smoSecurable != null, "smoSecurable is null"); + // STrace.Assert((this.SecurableType == GetSecurableType(smoSecurable)), "smoSecurable is not the same type as the original type"); + + if ((smoSecurable == null) || (this.SecurableType != GetSecurableType(smoSecurable))) + { + throw new ArgumentException(); + } + + this.principalToPermissionStates = new HybridDictionary(); + this.removedPrincipals = new PrincipalCollection(); + this.children = null; + this.isRemoved = false; + this.exists = ((smoSecurable != null) && (SqlSmoState.Existing == smoSecurable.State)); + this.smoObject = smoSecurable; + this.urn = smoSecurable.Urn; + + if (this.principals != null) + { + foreach (Principal principal in this.principals) + { + principal.Reset(); + } + } + + } + + /// + /// Factory method for PermissionStates + /// + /// The principal for which we are getting PermissionStates + /// The PermissionStates for this object and the principal + public PermissionStateCollection GetPermissionStates(Principal principal) + { + if (!this.principalToPermissionStates.Contains(principal)) + { + PermissionState.PopulatePermissionStates(this, principal); + PermissionState.AddChildrenToEmptyParents((PermissionStateCollection)this.principalToPermissionStates[principal]); + } + + return (PermissionStateCollection)this.principalToPermissionStates[principal]; + } + + /// + /// Add a principal to the set of principals + /// + /// The searchable object describing the principal to add + /// The Principal that was added + public Principal AddPrincipal(SearchableObject principal) + { + Principal result = null; + + if (!this.Principals.Contains(principal)) + { + // if the principal is removed, fetch it from the removed collection, + // otherwise create a new principal + if (this.removedPrincipals.Contains(principal)) + { + result = this.removedPrincipals[new PrincipalKey(principal)]; + result.IsRemoved = false; + this.removedPrincipals.Remove(principal); + } + else + { + result = new Principal(principal, this.connectionInfo, this.serverVersion); + } + + // add the principal to the principals collection + this.Principals.Add(result); + + // add the principal to the child columns as well + if (this.Children.Count != 0) + { + IEnumerator childEnumerator = this.Children.GetEnumerator(); + childEnumerator.Reset(); + + while (childEnumerator.MoveNext()) + { + Securable child = (Securable)childEnumerator.Current; + child.AddPrincipal(result); + } + } + } + else + { + result = this.Principals[new PrincipalKey(principal)]; + } + + return result; + } + + /// + /// Add a principal to the set of principals + /// + /// The principal to add + /// The Principal that was added + public Principal AddPrincipal(Principal principal) + { + // note: this method is called when child colums are being created. + // principal should never be in the removedPrincipals collection. + // STrace.Assert( + // !principal.IsRemoved && !this.removedPrincipals.Contains(principal), + // "principal shouldn't be in the removed collection when columns are being populated"); + + // if the principals collection does not exist, create it +#pragma warning disable IDE0074 // Use compound assignment + if (this.principals == null) + { + this.principals = new PrincipalCollection(); + } +#pragma warning restore IDE0074 // Use compound assignment + + // add the principal to the collection if it isn't already in the collection + if (!this.principals.Contains(principal)) + { + this.principals.Add(principal); + } + + return principal; + } + + /// + /// Remove a principal from the set of active principals + /// + /// The principal to remove + public void RemovePrincipal(Principal principal) + { + // STrace.Assert(this.principals.Contains(principal), "principal is not in the principals collection"); + + if (principal.HasExistingGrants(this)) + { + // STrace.Assert(!this.removedPrincipals.Contains(principal), "removedPrincipals already contains the principal"); + this.removedPrincipals.Add(principal); + principal.IsRemoved = true; + } + + this.principals.Remove(principal); + this.principalToPermissionStates.Remove(principal); + + this.NotifyObservers(); + } + + /// + /// Revoke all permissions that have been displayed in the UI. + /// + /// + /// This is called when one of the permissions on objects controls needs to + /// revoke all permissions on this securable for the principal. Any child + /// permissions are revoked as well. + /// + public void RevokeAll() + { + IEnumerator permissionStateCollectionEnumerator = this.principalToPermissionStates.Values.GetEnumerator(); + permissionStateCollectionEnumerator.Reset(); + + while (permissionStateCollectionEnumerator.MoveNext()) + { + PermissionStateCollection permissionStateCollection = (PermissionStateCollection)permissionStateCollectionEnumerator.Current; + IEnumerator permissionStateEnumerator = permissionStateCollection.GetEnumerator(); + permissionStateEnumerator.Reset(); + + while (permissionStateEnumerator.MoveNext()) + { + PermissionState permissionState = (PermissionState)permissionStateEnumerator.Current; + permissionState.Revoke(); + } + } + } + + /// + /// Get the collection of child securables + /// + /// The set of child securables + protected virtual SecurableList GetChildren() + { + return new SecurableList(); + } + + /// + /// Apply permission grants and denies in the permission states + /// + /// + /// This method should only be called by the Securable class or its derived classes. + /// It isn't protected because parent objects need to call Apply* on their children. + /// + /// The object to modify + internal virtual void ApplyGrantsAndDenies(SqlSmoObject obj) + { + SmoPermissionsAdapter adapter = SmoPermissionsAdapter.CreateAdapter(obj); + + // Apply changes for principals that have not been removed. + // The only principals that could have been changed are the ones that have been selected in the UI + // at some point, which are the ones that are keys in the principalToPermissionStates collection. + ICollection principalsCollection = this.principalToPermissionStates.Keys; + IEnumerator principalEnumerator = principalsCollection.GetEnumerator(); + principalEnumerator.Reset(); + + while (principalEnumerator.MoveNext()) + { + Principal principal = (Principal)principalEnumerator.Current; + this.ApplyGrantsAndDenies(adapter, principal); + } + + // apply changes for removed principals + principalEnumerator = this.removedPrincipals.GetEnumerator(); + principalEnumerator.Reset(); + + while (principalEnumerator.MoveNext()) + { + Principal removedPrincipal = (Principal)principalEnumerator.Current; + this.ApplyGrantsAndDenies(adapter, removedPrincipal); + } + } + + /// + /// Apply permission grants and denies in the permission states + /// + /// + /// This method should only be called by the Securable class or its derived classes. + /// It isn't protected because parent objects need to call Apply* on their children. + /// + /// The object to modify + internal virtual void ApplyRevokes(SqlSmoObject obj) + { + SmoPermissionsAdapter adapter = SmoPermissionsAdapter.CreateAdapter(obj); + + // Apply changes for principals that have not been removed. + // The only principals that could have been changed are the ones that have been selected in the UI + // at some point, which are the ones that are keys in the principalToPermissionStates collection. + ICollection principalsCollection = this.principalToPermissionStates.Keys; + IEnumerator principalEnumerator = principalsCollection.GetEnumerator(); + principalEnumerator.Reset(); + + while (principalEnumerator.MoveNext()) + { + Principal principal = (Principal)principalEnumerator.Current; + this.ApplyRevokes(adapter, principal); + } + + // apply changes for removed principals + principalEnumerator = this.removedPrincipals.GetEnumerator(); + principalEnumerator.Reset(); + + while (principalEnumerator.MoveNext()) + { + Principal removedPrincipal = (Principal)principalEnumerator.Current; + this.ApplyRevokes(adapter, removedPrincipal); + } + } + + /// + /// Actually commit permission grants and denies for a particular principal + /// + /// The SMO Permissions Adapter through which to save + /// The principal whose permissions changes are to be commited + private void ApplyGrantsAndDenies(SmoPermissionsAdapter adapter, Principal principal) + { + // If the principal is removed, then there won't be any PermissionState instances for the principal + // in this securable's principalToPermissionStates collection, but the principal will have the + // the relationship instances in it's counterpart collection. + PermissionStateCollection permissionStates = principal.IsRemoved ? + principal.GetPermissionStates(this) : + this.GetPermissionStates(principal); + + IEnumerator permissionStateEnumerator = permissionStates.GetEnumerator(); + List grants = new List(); + List denies = new List(); + List revokes = new List(); + List withGrants = new List(); + + permissionStateEnumerator.Reset(); + + while (permissionStateEnumerator.MoveNext()) + { + PermissionState permissionState = (PermissionState)permissionStateEnumerator.Current; + permissionState.AssignChange(grants, withGrants, denies, revokes); + } + + adapter.Grant(withGrants, principal, true); + adapter.Grant(grants, principal, false); + adapter.Deny(denies, principal); + } + + /// + /// Actually commit permission revokes for a particular principal + /// + /// The SMO Permissions Adapter through which to save + /// The principal whose permissions changes are to be commited + private void ApplyRevokes(SmoPermissionsAdapter adapter, Principal principal) + { + // If the principal is removed, then there won't be any PermissionState instances for the principal + // in this securable's principalToPermissionStates collection, but the principal will have the + // the relationship instances in it's counterpart collection. + PermissionStateCollection permissionStates = + principal.IsRemoved ? + principal.GetPermissionStates(this) : + this.GetPermissionStates(principal); + + IEnumerator permissionStateEnumerator = permissionStates.GetEnumerator(); + List grants = new List(); + List denies = new List(); + List revokes = new List(); + List withGrants = new List(); + + permissionStateEnumerator.Reset(); + + while (permissionStateEnumerator.MoveNext()) + { + PermissionState permissionState = (PermissionState)permissionStateEnumerator.Current; + permissionState.AssignChange(grants, withGrants, denies, revokes); + } + + adapter.Revoke(revokes, principal); + } + + + + /// + /// Populate the principals collection + /// + private PrincipalCollection GetExistingPrincipals() + { + // STrace.Assert(null == this.principals, "overwriting existing principals collection"); + + this.principals = new PrincipalCollection(); + + if (this.Exists) + { + Principal principal = null; + bool isDatabasePrincipal = (this.DatabaseName.Length != 0); + SystemPrincipalDirectory systemPrincipalDirectory = new SystemPrincipalDirectory(this.connectionInfo, this.DatabaseName); + List principalData = this.EnumerateExistingPrincipals(systemPrincipalDirectory); + + foreach (EnumeratedPrincipalData principalDatum in principalData) + { + // STrace.Assert(!this.principals.Contains(new PrincipalKey(principalDatum.Name, principalDatum.PrincipalType)), "the principal is already in the collection"); + + if (isDatabasePrincipal) + { + principal = new Principal( + principalDatum.Name, + this.DatabaseName, + principalDatum.PrincipalType, + true, + this.connectionInfo, + this.serverVersion); + } + else + { + principal = new Principal( + principalDatum.Name, + principalDatum.PrincipalType, + true, + this.connectionInfo, + this.serverVersion); + } + + this.principals.Add(principal); + } + + // principals with permissions on child objects (e.g. columns) should be treated + // as principals relevant to the parent too + foreach (Securable child in this.Children) + { + List childPrincipalData = child.EnumerateExistingPrincipals(systemPrincipalDirectory); + + foreach (EnumeratedPrincipalData childPrincipalDatum in childPrincipalData) + { + if (!this.principals.Contains(new PrincipalKey(childPrincipalDatum.Name, childPrincipalDatum.PrincipalType))) + { + if (isDatabasePrincipal) + { + principal = new Principal( + childPrincipalDatum.Name, + this.DatabaseName, + childPrincipalDatum.PrincipalType, + true, + this.connectionInfo, + this.serverVersion); + } + else + { + principal = new Principal( + childPrincipalDatum.Name, + childPrincipalDatum.PrincipalType, + true, + this.connectionInfo, + this.serverVersion); + } + + this.principals.Add(principal); + } + } + } + } + + return this.principals; + } + + /// + /// Get a list of the names and types of the principals that have permissions granted or denied + /// for the securable + /// + /// The directory from which to get the names of system principals + /// The list of principal names and types + private List EnumerateExistingPrincipals(SystemPrincipalDirectory systemPrincipals) + { + List result = new List(); + + if (this.Exists) + { + // STrace.Assert(systemPrincipals != null, "systemPrincipals is null"); + + string permissionsUrn = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}/Permission", this.urn.ToString()); + string[] fields = new string[] { "Grantee", "GranteeType" }; + Request request = new Request(new Urn(permissionsUrn), fields); + Enumerator enumerator = new Enumerator(); + DataTable grantees = enumerator.Process(this.connectionInfo, request); + string databaseName = this.DatabaseName; + bool isDatabasePrincipal = (databaseName.Length != 0); + + // map from principal type to a list of system principals of that type + Dictionary> systemPrincipalsMap = new Dictionary>(); + + for (int rowIndex = 0; rowIndex < grantees.Rows.Count; ++rowIndex) + { + DataRow row = grantees.Rows[rowIndex]; + string principalName = row["Grantee"].ToString(); + PrincipalType principalType = (PrincipalType)row["GranteeType"]; + + EnumeratedPrincipalData principalData = new EnumeratedPrincipalData(principalName, principalType); + + // permissions can't be granted or denied to system principals, so we need to filter system principals out + if (!systemPrincipals.GetSystemPrincipalNames(principalType).Contains(principalName) && !result.Contains(principalData)) + { + result.Add(principalData); + } + } + } + + return result; + } + + /// + /// This will update the PrincipalKey with the right ChangesExist value + /// + public void UpdatePrincipalKeyStatus(Principal principal) + { + this.principals.UpdateKey(principal); + } + + /// + /// Add a permission state to the collection + /// + /// The permission state to add + internal void AddPermissionState(PermissionState permissionState) + { + PermissionStateCollection permissionStates = null; + + if (this.principalToPermissionStates.Contains(permissionState.Principal)) + { + permissionStates = (PermissionStateCollection)this.principalToPermissionStates[permissionState.Principal]; + } + else + { + permissionStates = new PermissionStateCollection(); + this.principalToPermissionStates.Add(permissionState.Principal, permissionStates); + } + + permissionStates.Add(permissionState); + + permissionState.Changed += new EventHandler(this.OnChanged); + + // in the case of the permissions of principals controls, the principals collection will be + // initially null because no control will have asked for the principals. In that case + // we need to create the collection without fetching the collection of other principals + // with permissions on the securable before adding the new principal to the collection. +#pragma warning disable IDE0074 // Use compound assignment + if (this.principals == null) + { + this.principals = new PrincipalCollection(); + } +#pragma warning restore IDE0074 // Use compound assignment + + if (!this.principals.Contains(permissionState.Principal)) + { + this.principals.Add(permissionState.Principal); + } + } + + /// + /// Handle permission selection change events + /// + /// + /// + private void OnChanged(object sender, EventArgs e) + { + this.NotifyObservers(sender, e); + } + + /// + /// Property to access the observable event. + /// + internal event EventHandler Changed + { + add { this.observableChanged += value; } + remove { this.observableChanged -= value; } + } + + /// + /// Notify all observers that this object has changed. + /// + /// The object that changed + /// Hint for the notification, usually null + private void NotifyObservers(object sender, EventArgs e) + { + if (this.observableChanged != null) + { + this.observableChanged(sender, e); + } + } + + /// + /// Notify all observers that this object or one of its children has changed. + /// + private void NotifyObservers() + { + this.NotifyObservers(this, new EventArgs()); + } + + + /// + /// Static constructor + /// + static Securable() + { + } + + /// + /// Get the set of permissions relevent to a particular object type + /// + /// The object type + /// + /// + /// + /// + /// The relevant permissions + public static ArrayList GetRelevantPermissions(SecurableType type, Version serverVersion, string databaseName,DatabaseEngineType databaseEngineType, DatabaseEngineEdition engineEdition) + { + // $CONSIDER caching relevent permission sets + ArrayList result = new ArrayList(); + + switch (type) + { + case SecurableType.AggregateFunction: + + // STrace.Assert(YUKON <= serverVersion.Major, "Aggregate Function's permissions don't exist for pre-yukon servers"); + + result.Add(Permission.References); + result.Add(Permission.Execute); + result.Add(Permission.ViewDefinition); + result.Add(Permission.Alter); + result.Add(Permission.TakeOwnership); + result.Add(Permission.Control); + + break; + + case SecurableType.ApplicationRole: + + // STrace.Assert(YUKON <= serverVersion.Major, "application role permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.Assembly: + + // STrace.Assert(YUKON <= serverVersion.Major, "assembly permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + // Permission Execute has been removed by engine from katmai. This was because deny was not honoured by engine silently earlier + // on assemblies. see vsts:30530 for details.-anchals + if (serverVersion.Major < KATMAI) + { + result.Add(Permission.Execute); + } + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.AsymmetricKey: + + // STrace.Assert(YUKON <= serverVersion.Major, "asymmetric key permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.Certificate: + + // STrace.Assert(YUKON <= serverVersion.Major, "certificate permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.Column: + + // permissions for columns of tables, views, and inline functions + + result.Add(Permission.Update); + result.Add(Permission.Select); + + if (YUKON <= serverVersion.Major) + { + result.Add(Permission.References); + } + + break; + + case SecurableType.ColumnFunctionTable: + + // permissions for columns of table-valued functions + + result.Add(Permission.Select); + + if (YUKON <= serverVersion.Major) + { + result.Add(Permission.References); + } + + break; + + // case SecurableType.Contract: + // + // // STrace.Assert(YUKON <= serverVersion.Major, "contract permissions don't exist for pre-yukon servers"); + // + // result.Add(Permission.Alter); + // result.Add(Permission.Control); + // result.Add(Permission.References); + // result.Add(Permission.TakeOwnership); + // result.Add(Permission.ViewDefinition); + // + // break; + + case SecurableType.Database: + + result.Add(Permission.BackupDatabase); + if (databaseName == "master") + { + // create database permission only valid in master + result.Add(Permission.CreateDatabase); + } + + if (engineEdition != DatabaseEngineEdition.SqlDataWarehouse) + { + result.Add(Permission.BackupLog); + result.Add(Permission.CreateDefault); + result.Add(Permission.CreateRule); + } + + result.Add(Permission.CreateProcedure); + result.Add(Permission.CreateTable); + result.Add(Permission.CreateView); + + if (SHILOH <= serverVersion.Major) + { + result.Add(Permission.CreateFunction); + } + + if (YUKON <= serverVersion.Major) + { + result.Add(Permission.Alter); + + if (engineEdition != DatabaseEngineEdition.SqlDataWarehouse) + { + result.Add(Permission.AlterAnyApplicationRole); + result.Add(Permission.AlterAnyAssembly); + result.Add(Permission.AlterAnyAsymmetricKey); + result.Add(Permission.AlterAnyCertificate); + } + + if (engineEdition != DatabaseEngineEdition.SqlDataWarehouse) + { + if (KATMAI <= serverVersion.Major) + { + result.Add(Permission.AlterAnyDatabaseAudit); + } + result.Add(Permission.AlterAnyContract); + result.Add(Permission.AlterAnyDatabaseDdlTrigger); + result.Add(Permission.AlterAnyDatabaseEventNotification); + result.Add(Permission.AlterAnyDataspace); + result.Add(Permission.AlterAnyFulltextCatalog); + result.Add(Permission.AlterAnyMessageType); + result.Add(Permission.AlterAnyRemoteServiceBinding); + result.Add(Permission.AlterAnyRoute); + result.Add(Permission.AlterAnyService); + result.Add(Permission.AlterAnySymmetricKey); + result.Add(Permission.Authenticate); + result.Add(Permission.Checkpoint); + result.Add(Permission.ConnectReplication); + result.Add(Permission.CreateAggregate); + result.Add(Permission.CreateAssembly); + result.Add(Permission.CreateAsymmetricKey); + result.Add(Permission.CreateCertificate); + result.Add(Permission.CreateContract); + result.Add(Permission.CreateDatabaseDdlEventNotification); + + result.Add(Permission.CreateFulltextCatalog); + result.Add(Permission.CreateService); + result.Add(Permission.CreateSymmetricKey); + result.Add(Permission.CreateSynonym); + result.Add(Permission.CreateType); + result.Add(Permission.CreateXmlSchemaCollection); + result.Add(Permission.CreateMessageType); + result.Add(Permission.CreateQueue); + result.Add(Permission.CreateRemoteServiceBinding); + result.Add(Permission.CreateRoute); + result.Add(Permission.SubscribeQueryNotifications); + } + + result.Add(Permission.AlterAnyRole); + result.Add(Permission.AlterAnySchema); + + result.Add(Permission.AlterAnyUser); + result.Add(Permission.Connect); + + result.Add(Permission.Control); + + result.Add(Permission.CreateRole); + result.Add(Permission.CreateSchema); + + + result.Add(Permission.Delete); + result.Add(Permission.Execute); + result.Add(Permission.Insert); + result.Add(Permission.References); + result.Add(Permission.Select); + result.Add(Permission.ShowPlan); + + result.Add(Permission.TakeOwnership); + result.Add(Permission.Update); + result.Add(Permission.ViewDatabaseState); + result.Add(Permission.ViewDefinition); + if (Utils.IsSql13OrLater(serverVersion.Major)) + { + if (engineEdition != DatabaseEngineEdition.SqlDataWarehouse) + { + result.Add(Permission.AlterAnySecurityPolicy); + } + + result.Add(Permission.AlterAnyExternalDataSource); + result.Add(Permission.AlterAnyExternalFileFormat); + result.Add(Permission.AlterAnyMask); + result.Add(Permission.Unmask); + result.Add(Permission.ViewAnyColumnEncryptionKeyDefinition); + result.Add(Permission.ViewAnyColumnMasterKeyDefinition); + } + + if (Utils.IsSql15OrLater(serverVersion.Major)) + { + // The condition will be removed once Data classification feature will be deployed on DW + if (engineEdition != DatabaseEngineEdition.SqlDataWarehouse) + { + result.Add(Permission.AlterAnySensitivityClassification); + result.Add(Permission.ViewAnySensitivityClassification); + } + + } + } + break; + + case SecurableType.DatabaseRole: + + // STrace.Assert(YUKON <= serverVersion.Major, "role permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.Endpoint: + + // STrace.Assert(YUKON <= serverVersion.Major, "endpoint permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Connect); + result.Add(Permission.Control); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.FullTextCatalog: + + // STrace.Assert(YUKON <= serverVersion.Major, "full-text catalog permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.ExtendedStoredProcedure: + case SecurableType.StoredProcedure: + + result.Add(Permission.Execute); + + if (YUKON <= serverVersion.Major) + { + result.Add(Permission.ViewDefinition); + result.Add(Permission.Alter); + result.Add(Permission.TakeOwnership); + result.Add(Permission.Control); + } + + break; + + case SecurableType.FunctionInline: + + if (YUKON <= serverVersion.Major) + { + result.Add(Permission.Select); + result.Add(Permission.References); + result.Add(Permission.ViewDefinition); + result.Add(Permission.Alter); + result.Add(Permission.TakeOwnership); + result.Add(Permission.Control); + result.Add(Permission.Insert); + result.Add(Permission.Delete); + result.Add(Permission.Update); + } + else + { + result.Add(Permission.Insert); + result.Add(Permission.Update); + result.Add(Permission.Delete); + result.Add(Permission.Select); + result.Add(Permission.References); + } + + break; + + case SecurableType.FunctionTable: + + if (YUKON <= serverVersion.Major) + { + result.Add(Permission.Select); + result.Add(Permission.References); + result.Add(Permission.ViewDefinition); + result.Add(Permission.Alter); + result.Add(Permission.TakeOwnership); + result.Add(Permission.Control); + } + else + { + result.Add(Permission.Insert); + result.Add(Permission.Update); + result.Add(Permission.Delete); + result.Add(Permission.Select); + result.Add(Permission.References); + } + + break; + + case SecurableType.FunctionScalar: + + result.Add(Permission.References); + result.Add(Permission.Execute); + + if (YUKON <= serverVersion.Major) + { + result.Add(Permission.ViewDefinition); + result.Add(Permission.Alter); + result.Add(Permission.TakeOwnership); + result.Add(Permission.Control); + } + + break; + + case SecurableType.Login: + + // STrace.Assert(YUKON <= serverVersion.Major, "login permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.Impersonate); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.Schema: + + // STrace.Assert(YUKON <= serverVersion.Major, "schema permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.Delete); + result.Add(Permission.Execute); + result.Add(Permission.Insert); + result.Add(Permission.References); + result.Add(Permission.Select); + result.Add(Permission.TakeOwnership); + result.Add(Permission.Update); + result.Add(Permission.ViewDefinition); + if (KATMAI <= serverVersion.Major) + { + result.Add(Permission.ViewChangeTracking); + } + if (Utils.IsSql11OrLater(serverVersion.Major)) + { + result.Add(Permission.CreateSequence); + } + break; + + case SecurableType.Server: + + // STrace.Assert(YUKON <= serverVersion.Major, "server permissions don't exist for pre-yukon servers"); + + result.Add(Permission.AdministerBulkOperations); + + if (Utils.IsSql11OrLater(serverVersion.Major)) + { + result.Add(Permission.AlterAnyServerRole); + result.Add(Permission.CreateServerRole); + result.Add(Permission.AlterAnyAvailabilityGroup); + result.Add(Permission.CreateAvailabilityGroup); + } + + if (Utils.IsSql11OrLater(serverVersion.Major)) + { + result.Add(Permission.AlterAnyEventSession); + } + if (KATMAI <= serverVersion.Major) + { + result.Add(Permission.AlterAnyServerAudit); + } + result.Add(Permission.AlterAnyLinkedServer); + + if (Utils.IsSql12OrLater(serverVersion.Major)) + { + result.Add(Permission.SelectAllUserSecurables); + result.Add(Permission.ConnectAnyDatabase); + result.Add(Permission.ImpersonateAnyLogin); + } + + result.Add(Permission.AlterAnyConnection); + result.Add(Permission.AlterAnyCredential); + result.Add(Permission.AlterAnyDatabase); + result.Add(Permission.AlterAnyEndpoint); + result.Add(Permission.AlterAnyEventNotification); + result.Add(Permission.AlterAnyLogin); + result.Add(Permission.AlterResources); + result.Add(Permission.AlterServerState); + result.Add(Permission.AlterSettings); + result.Add(Permission.AlterTrace); + result.Add(Permission.AuthenticateServer); + result.Add(Permission.ConnectSql); + result.Add(Permission.ControlServer); + result.Add(Permission.CreateAnyDatabase); + result.Add(Permission.CreateDdlEventNotification); + result.Add(Permission.CreateEndpoint); + result.Add(Permission.CreateTraceEventNotification); + result.Add(Permission.ExternalAccessAssembly); + result.Add(Permission.Shutdown); + result.Add(Permission.UnsafeAssembly); + result.Add(Permission.ViewAnyDatabase); + result.Add(Permission.ViewAnyDefinition); + result.Add(Permission.ViewServerState); + break; + + case SecurableType.ServerRole: + + // STrace.Assert(Utils.IsSql11OrLater(serverVersion.Major), "Server Role permissions don't exist for pre-sql11 servers"); + + if (Utils.IsSql11OrLater(serverVersion.Major)) + { + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + } + break; + + case SecurableType.ServiceQueue: + + // STrace.Assert(YUKON <= serverVersion.Major, "Service Queue permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.References); + result.Add(Permission.Receive); + result.Add(Permission.Select); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + + break; + + case SecurableType.SymmetricKey: + + // STrace.Assert(YUKON <= serverVersion.Major, "symmetric key permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + + break; + + case SecurableType.Synonym: + + // STrace.Assert(YUKON <= serverVersion.Major, "user permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Control); + result.Add(Permission.Delete); + result.Add(Permission.Execute); + result.Add(Permission.Insert); + result.Add(Permission.Select); + result.Add(Permission.TakeOwnership); + result.Add(Permission.Update); + result.Add(Permission.ViewDefinition); + + break; + case SecurableType.Sequence: + + if (Utils.IsSql11OrLater(serverVersion.Major)) + { + result.Add(Permission.Control); + result.Add(Permission.Alter); + result.Add(Permission.TakeOwnership); + result.Add(Permission.Update); + result.Add(Permission.ViewDefinition); + result.Add(Permission.References); + } + break; + + case SecurableType.Table: + case SecurableType.View: + + result.Add(Permission.Insert); + result.Add(Permission.Update); + result.Add(Permission.Delete); + result.Add(Permission.Select); + result.Add(Permission.References); + + if (YUKON <= serverVersion.Major) + { + result.Add(Permission.ViewDefinition); + result.Add(Permission.Alter); + result.Add(Permission.TakeOwnership); + result.Add(Permission.Control); + } + + if (KATMAI <= serverVersion.Major) + { + result.Add(Permission.ViewChangeTracking); + } + + break; + + case SecurableType.User: + + // STrace.Assert(YUKON <= serverVersion.Major, "user permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.Impersonate); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.UserDefinedDataType: + + // STrace.Assert(YUKON <= serverVersion.Major, "UDDT permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Control); + result.Add(Permission.Execute); + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.UserDefinedTableType: + + // STrace.Assert(KATMAI <= serverVersion.Major, "UDTT permissions don't exist for pre-Katmai servers"); + + result.Add(Permission.Control); + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.XmlSchemaCollection: + + // STrace.Assert(YUKON <= serverVersion.Major, "XML schema collection permissions don't exist for pre-yukon servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.Execute); + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.AvailabilityGroup: + + // STrace.Assert(DENALI <= serverVersion.Major, "Availability Group permissions do not exists pre-Denali servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.TakeOwnership); + result.Add(Permission.ViewDefinition); + break; + + case SecurableType.SecurityPolicy: + + // STrace.Assert(Utils.IsSql13OrLater(serverVersion.Major), "Security polices do not exist for pre-SQL15 servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.ViewDefinition); + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + break; + + case SecurableType.ExternalDataSource: + + // STrace.Assert(Utils.IsSql13OrLater(serverVersion.Major), "External Data Sources do not exist for pre-SQL15 servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.ViewDefinition); + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + break; + + case SecurableType.ExternalFileFormat: + + // STrace.Assert(Utils.IsSql13OrLater(serverVersion.Major), "External File Formats do not exist for pre-SQL15 servers"); + + result.Add(Permission.Alter); + result.Add(Permission.Control); + result.Add(Permission.ViewDefinition); + result.Add(Permission.References); + result.Add(Permission.TakeOwnership); + break; + + default: + + // STrace.Assert(false, "need to add relevent permissions for permissible object type"); + break; + } + + + return result; + } + + + /// + /// Factory method for existing Securables. This is used by the Permissions on Objects controls. + /// + /// The SMO object for which to create a Securable + /// The connection object + /// A corresponding Securable + public static Securable Create(SqlSmoObject smoObject, object connectionInfo) + { + Securable result = null; + SecurableType type = Securable.GetSecurableType(smoObject); + + switch (type) + { + + case SecurableType.Table: + case SecurableType.View: + case SecurableType.FunctionInline: + case SecurableType.FunctionTable: + + result = new SecurableColumnParent(smoObject, type, connectionInfo, GetServerVersion(connectionInfo)); + break; + + default: + + result = new Securable(smoObject, type, connectionInfo, GetServerVersion(connectionInfo)); + break; + } + + return result; + } + + /// + /// Factory method for new Securables. This is used by the Permissions on Objects controls. + /// + /// The object type + /// The URN string for the parent of the securable + /// Connection information for the server + /// A new Securable + public static Securable Create(SecurableType type, string parentUrn, object connectionInfo) + { + Securable result = null; + + switch (type) + { + case SecurableType.Table: + case SecurableType.View: + case SecurableType.FunctionInline: + case SecurableType.FunctionTable: + + result = new SecurableColumnParent(type, parentUrn, connectionInfo, GetServerVersion(connectionInfo), false); + break; + + default: + + result = new Securable(type, parentUrn, connectionInfo, GetServerVersion(connectionInfo), false); + break; + + } + + return result; + } + + /// + /// Factory method for existing securables that have been enumerated. This is used by the Permission of Principals controls. + /// + /// The type of the object that is to be created + /// The URN describing the object on the server + /// The connection information that should be used with the enumerator + /// The version of the server + /// The securable that is created + public static Securable Create(SecurableType type, string urn, object connectionInfo, Version serverVersion) + { + Securable result = null; + + switch (type) + { + case SecurableType.Table: + case SecurableType.View: + case SecurableType.FunctionInline: + case SecurableType.FunctionTable: + + result = new SecurableColumnParent(type, urn, connectionInfo, serverVersion, true); + break; + + default: + + result = new Securable(type, urn, connectionInfo, serverVersion, true); + break; + + } + + return result; + } + + /// + /// Factory method for existing securables that have been enumerated. This is used by the Permission of Principals controls. + /// + /// The SMO object class for the object + /// The sys.objects or sys.server_principals type string for the object + /// The name of the object + /// The schema containing the object, or String.Empty if the object is not contained by a schema + /// for user-defined types, indicate whether it is a data type or a table type + /// The database containing the object, or String.Empty if the object is not contained by a database + /// The connection information that should be used with the enumerator + /// The version of the server + /// The securable that is created + public static Securable Create( + ObjectClass objectClass, + string objectType, + string name, + string schemaName, + bool isTableType, + string databaseName, + object connectionInfo, + Version serverVersion) + { + + Securable result = null; + string urn = String.Empty; + + if (FormUrn(objectClass, objectType, databaseName, schemaName, name, isTableType, out urn)) + { + SecurableType type = GetSecurableType(objectClass, objectType, isTableType); + result = Create(type, urn, connectionInfo, serverVersion); + } + else + { + throw new ArgumentException(); + } + + return result; + } + + /// + /// Factory method for existing securables that have been returned by the SQL Object Search dialog. + /// + /// The search dialog result + /// The connection information that should be used with the enumerator + /// The version of the server + /// The securable that is created + public static Securable Create(SearchableObject searchableObject, object connectionInfo, Version serverVersion) + { + SecurableType type = GetSecurableType(searchableObject.SearchableObjectType); + return Create(type, searchableObject.Urn.ToString(), connectionInfo, serverVersion); + } + + + /// + /// Get a URN string for all server Objects of a particular securable type + /// + /// The type of the securable to enumerate + /// The URN string + public static string GetUrnForAll(SecurableType type) + { + string result = String.Empty; + + switch (type) + { + case SecurableType.Login: + + result = "Server/Login"; + break; + + case SecurableType.Endpoint: + + result = "Server/Endpoint"; + break; + + case SecurableType.ServerRole: + + result = "Server/Role"; + break; + + default: + + // STrace.Assert(false, "Unexpected securable type. Is this a server object?"); + throw new ArgumentException(); + } + + return result; + } + + /// + /// Get a URN string for all database Objects of a particular securable type + /// + /// The securable type + /// The name of the database + /// The URN string + public static string GetUrnForAll(SecurableType type, string databaseName) + { + // STrace.Assert((databaseName != null) && (databaseName.Length != 0), "database name is empty"); + + StringBuilder urn = new StringBuilder(); + urn.AppendFormat("Server/Database[@Name='{0}']/", Urn.EscapeString(databaseName)); + + switch (type) + { + case SecurableType.AggregateFunction: + + urn.Append("UserDefinedAggregate"); + break; + + case SecurableType.ApplicationRole: + + urn.Append("ApplicationRole"); + break; + + case SecurableType.Assembly: + + urn.Append("SqlAssembly"); + break; + + case SecurableType.AsymmetricKey: + + urn.Append("AsymmetricKey"); + break; + + case SecurableType.Certificate: + + urn.Append("Certificate"); + break; + + case SecurableType.DatabaseRole: + + urn.Append("Role"); + break; + + case SecurableType.ExtendedStoredProcedure: + + urn.Append("ExtendedStoredProcedure"); + break; + + case SecurableType.ExternalDataSource: + + urn.Append("ExternalDataSource"); + break; + + case SecurableType.ExternalFileFormat: + + urn.Append("ExternalFileFormat"); + break; + + case SecurableType.FullTextCatalog: + + urn.Append("FullTextCatalog"); + break; + + case SecurableType.FunctionInline: + case SecurableType.FunctionScalar: + case SecurableType.FunctionTable: + + urn.Append("UserDefinedFunction"); + break; + + case SecurableType.Schema: + + urn.Append("Schema"); + break; + + case SecurableType.SecurityPolicy: + + urn.Append("SecurityPolicy"); + break; + + case SecurableType.ServiceQueue: + + urn.Append("ServiceBroker/ServiceQueue"); + break; + + case SecurableType.StoredProcedure: + + urn.Append("StoredProcedure"); + break; + + case SecurableType.SymmetricKey: + + urn.Append("SymmetricKey"); + break; + + case SecurableType.Synonym: + + urn.Append("Synonym"); + break; + + case SecurableType.Sequence: + + urn.Append("Sequence"); + break; + + case SecurableType.Table: + + urn.Append("Table"); + break; + + case SecurableType.User: + + urn.Append("User"); + break; + + case SecurableType.UserDefinedDataType: + + urn.Append("UserDefinedDataType"); + break; + + case SecurableType.UserDefinedTableType: + + urn.Append("UserDefinedTableType"); + break; + + case SecurableType.View: + + urn.Append("View"); + break; + + case SecurableType.XmlSchemaCollection: + + urn.Append("XmlSchemaCollection"); + break; + + case SecurableType.AvailabilityGroup: + + urn.Append("AvailabilityGroup"); + break; + + default: + + // STrace.Assert(false, "Unexpected securable type. Is this a database object?"); + throw new ArgumentException(); + } + + return urn.ToString(); + } + + /// + /// Get a URN string for all database Objects of a particular securable type in a particular schema + /// + /// The securable type + /// The name of the database + /// The name of the schema + /// The URN string + public static string GetUrnForAll(SecurableType type, string databaseName, string schemaName) + { + // STrace.Assert((databaseName != null) && (databaseName.Length != 0), "database name is empty"); + // STrace.Assert((schemaName != null) && (schemaName.Length != 0), "schema name is empty"); + + StringBuilder urn = new StringBuilder(); + urn.AppendFormat("Server/Database[@Name='{0}']/", Urn.EscapeString(databaseName)); + + switch (type) + { + case SecurableType.AggregateFunction: + + urn.Append("UserDefinedAggregate"); + break; + + case SecurableType.ExtendedStoredProcedure: + + urn.Append("ExtendedStoredProcedure"); + break; + + case SecurableType.FunctionInline: + case SecurableType.FunctionScalar: + case SecurableType.FunctionTable: + + urn.Append("UserDefinedFunction"); + break; + + case SecurableType.StoredProcedure: + + urn.Append("StoredProcedure"); + break; + + case SecurableType.Synonym: + + urn.Append("Synonym"); + break; + + case SecurableType.Sequence: + + urn.Append("Sequence"); + break; + + case SecurableType.Table: + + urn.Append("Table"); + break; + + case SecurableType.UserDefinedDataType: + + urn.Append("UserDefinedDataType"); + break; + + case SecurableType.UserDefinedTableType: + + urn.Append("UserDefinedTableType"); + break; + + case SecurableType.View: + + urn.Append("View"); + break; + + case SecurableType.XmlSchemaCollection: + + urn.Append("XmlSchemaCollection"); + break; + + default: + + // STrace.Assert(false, "Unexpected securable type. Is this a schema object?"); + throw new ArgumentException(); + } + + urn.AppendFormat("[@Schema='{0}']", Urn.EscapeString(schemaName)); + return urn.ToString(); + } + + + /// + /// Get the SecurableType for a particular SMO object + /// + /// The SMO object + /// The type for the SMO object + public static SecurableType GetSecurableType(SqlSmoObject smoObject) + { + SecurableType result = SecurableType.Unknown; + Type smoObjectType = smoObject.GetType(); + + // $CONSIDER this switch statement is ugly and almost certainly has abysmal performance, but it + // should be called only once in the lifetime of the dialog. On the other hand, it's called + // during start-up, so we might want to try to think of a better way to map from Type to + // SecurableType. + + if (typeof(UserDefinedAggregate).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.AggregateFunction; + } + else if (typeof(ApplicationRole).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.ApplicationRole; + } + else if (typeof(SqlAssembly).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Assembly; + } + else if (typeof(AsymmetricKey).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.AsymmetricKey; + } + else if (typeof(Certificate).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Certificate; + } + else if (typeof(Column).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Column; + } + else if (typeof(Database).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Database; + } + else if (typeof(DatabaseRole).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.DatabaseRole; + } + else if (typeof(Endpoint).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Endpoint; + } + else if (typeof(ExtendedStoredProcedure).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.ExtendedStoredProcedure; + } + else if (typeof(ExternalDataSource).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.ExternalDataSource; + } + else if (typeof(ExternalFileFormat).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.ExternalFileFormat; + } + else if (typeof(FullTextCatalog).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.FullTextCatalog; + } + else if (typeof(UserDefinedFunction).IsAssignableFrom(smoObjectType)) + { + UserDefinedFunction function = (UserDefinedFunction)smoObject; + + switch (function.FunctionType) + { + case UserDefinedFunctionType.Inline: + + result = SecurableType.FunctionInline; + break; + + case UserDefinedFunctionType.Scalar: + + result = SecurableType.FunctionScalar; + break; + + default: + + // STrace.Assert(UserDefinedFunctionType.Table == function.FunctionType, "unexpected UDF type"); + result = SecurableType.FunctionTable; + break; + } + } + else if (typeof(Login).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Login; + } + else if (typeof(ServerRole).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.ServerRole; + } + else if (typeof(Schema).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Schema; + } + else if (typeof(SecurityPolicy).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.SecurityPolicy; + } + else if (typeof(Microsoft.SqlServer.Management.Smo.Server).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Server; + } + else if (typeof(ServiceQueue).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.ServiceQueue; + } + else if (typeof(StoredProcedure).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.StoredProcedure; + } + else if (typeof(SymmetricKey).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.SymmetricKey; + } + else if (typeof(Synonym).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Synonym; + } + else if (typeof(Sequence).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Sequence; + } + else if (typeof(Table).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.Table; + } + else if (typeof(User).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.User; + } + else if (typeof(UserDefinedDataType).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.UserDefinedDataType; + } + else if (typeof(UserDefinedTableType).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.UserDefinedTableType; + } + else if (typeof(View).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.View; + } + else if (typeof(XmlSchemaCollection).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.XmlSchemaCollection; + } + else if (typeof(AvailabilityGroup).IsAssignableFrom(smoObjectType)) + { + result = SecurableType.AvailabilityGroup; + } + else + { + // STrace.Assert(false, "don't know which permissible object type corresponds to smo object"); + throw new InvalidArgumentException(); + } + + // STrace.Assert(SecurableType.Unknown != result, "result is still unknown!"); + return result; + } + + /// + /// Get the SecurableType corresponding to a particular SearchableType + /// + /// The searchable type + /// The corresponding securable type, or SecurableType.Unknown if there is no corresponding securable type + public static SecurableType GetSecurableType(SearchableObjectType searchableType) + { + SecurableType result = SecurableType.Unknown; + + switch (searchableType) + { + case SearchableObjectType.AggregateFunction: + + result = SecurableType.AggregateFunction; + break; + + case SearchableObjectType.ApplicationRole: + + result = SecurableType.ApplicationRole; + break; + + case SearchableObjectType.Assembly: + + result = SecurableType.Assembly; + break; + + case SearchableObjectType.AsymmetricKey: + + result = SecurableType.AsymmetricKey; + break; + + case SearchableObjectType.Certificate: + + result = SecurableType.Certificate; + break; + + case SearchableObjectType.Database: + + result = SecurableType.Database; + break; + + case SearchableObjectType.DatabaseRole: + + result = SecurableType.DatabaseRole; + break; + + case SearchableObjectType.Endpoint: + + result = SecurableType.Endpoint; + break; + + case SearchableObjectType.ExtendedStoredProcedure: + + result = SecurableType.ExtendedStoredProcedure; + break; + + case SearchableObjectType.ExternalDataSource: + + result = SecurableType.ExternalDataSource; + break; + + case SearchableObjectType.ExternalFileFormat: + + result = SecurableType.ExternalFileFormat; + break; + + case SearchableObjectType.FullTextCatalog: + + result = SecurableType.FullTextCatalog; + break; + + case SearchableObjectType.FunctionInline: + + result = SecurableType.FunctionInline; + break; + + case SearchableObjectType.FunctionScalar: + + result = SecurableType.FunctionScalar; + break; + + case SearchableObjectType.FunctionTable: + + result = SecurableType.FunctionTable; + break; + + case SearchableObjectType.Login: + + result = SecurableType.Login; + break; + + case SearchableObjectType.ServerRole: + + result = SecurableType.ServerRole; + break; + + case SearchableObjectType.Schema: + + result = SecurableType.Schema; + break; + + case SearchableObjectType.Server: + + result = SecurableType.Server; + break; + + case SearchableObjectType.SecurityPolicy: + + result = SecurableType.SecurityPolicy; + break; + + case SearchableObjectType.ServiceQueue: + + result = SecurableType.ServiceQueue; + break; + + case SearchableObjectType.StoredProcedure: + + result = SecurableType.StoredProcedure; + break; + + case SearchableObjectType.SymmetricKey: + + result = SecurableType.SymmetricKey; + break; + + case SearchableObjectType.Synonym: + + result = SecurableType.Synonym; + break; + + case SearchableObjectType.Sequence: + + result = SecurableType.Sequence; + break; + + case SearchableObjectType.Table: + + result = SecurableType.Table; + break; + + case SearchableObjectType.User: + + result = SecurableType.User; + break; + + case SearchableObjectType.UserDefinedDataType: + + result = SecurableType.UserDefinedDataType; + break; + + case SearchableObjectType.UserDefinedTableType: + + result = SecurableType.UserDefinedTableType; + break; + + case SearchableObjectType.View: + + result = SecurableType.View; + break; + + case SearchableObjectType.XmlSchemaCollection: + + result = SecurableType.XmlSchemaCollection; + break; + + case SearchableObjectType.AvailabilityGroup: + + result = SecurableType.AvailabilityGroup; + break; + + default: + + // STrace.Assert(false, "unexpected SeachableObjectType - we need to add a new case here."); + break; + } + + return result; + } + + /// + /// Get the Securable type corresponding to a particular ObjectClass and sys.objects type + /// + /// The SMO ObjectClass + /// The sys.objects type string + /// for user-defined types, indicate whether it is a data type or a table type + /// The corresponding securable type, or SecurableType.Unknown if the ObjectClass/string isn't recognized + public static SecurableType GetSecurableType(ObjectClass smoObjectClass, string objectTypeString, bool isTableType) + { + SecurableType result = SecurableType.Unknown; + + if (objectTypeString.Length != 0) + { + result = GetSecurableType(objectTypeString); + } + else + { + switch (smoObjectClass) + { + case ObjectClass.ApplicationRole: + + result = SecurableType.ApplicationRole; + break; + + case ObjectClass.Certificate: + + result = SecurableType.Certificate; + break; + + case ObjectClass.Database: + + result = SecurableType.Database; + break; + + case ObjectClass.DatabaseRole: + + result = SecurableType.DatabaseRole; + break; + + case ObjectClass.Endpoint: + + result = SecurableType.Endpoint; + break; + + case ObjectClass.ExternalDataSource: + + result = SecurableType.ExternalDataSource; + break; + + case ObjectClass.ExternalFileFormat: + + result = SecurableType.ExternalFileFormat; + break; + + case ObjectClass.FullTextCatalog: + + result = SecurableType.FullTextCatalog; + break; + + case ObjectClass.Login: + + result = SecurableType.Login; + break; + + case ObjectClass.ServerRole: + + result = SecurableType.ServerRole; + break; + + case ObjectClass.Schema: + + result = SecurableType.Schema; + break; + + case ObjectClass.Server: + + result = SecurableType.Server; + break; + + case ObjectClass.Service: + case ObjectClass.SqlAssembly: + + result = SecurableType.Assembly; + break; + + case ObjectClass.SymmetricKey: + + result = SecurableType.SymmetricKey; + break; + + case ObjectClass.User: + + result = SecurableType.User; + break; + + case ObjectClass.ObjectOrColumn: + + result = GetSecurableType(objectTypeString); + break; + + case ObjectClass.UserDefinedType: + + if (isTableType) + { + result = SecurableType.UserDefinedTableType; + } + else + { + result = SecurableType.UserDefinedDataType; + } + break; + + case ObjectClass.AvailabilityGroup: + + result = SecurableType.AvailabilityGroup; + break; + + default: + // STrace.Assert(result != SecurableType.Unknown, "unknown ObjectClass: " + smoObjectClass.ToString()); + break; + } + } + + return result; + } + + /// + /// Get the SecurableType corresponding to a particular sys.objects.type value + /// + /// The sys.objects.type value + /// The corresponding securable type, or SecurableType.Unknown if the string isn't recognized + public static SecurableType GetSecurableType(string objectTypeString) + { + SecurableType result = SecurableType.Unknown; + + switch (objectTypeString) + { + case "AF": + + result = SecurableType.AggregateFunction; + break; + + case "P": + case "PC": + case "RF": + + result = SecurableType.StoredProcedure; + break; + + case "FN": + case "FS": + + result = SecurableType.FunctionScalar; + break; + + case "IF": + + result = SecurableType.FunctionInline; + break; + + case "TF": + case "FT": + + result = SecurableType.FunctionTable; + break; + + case "SQ": + + result = SecurableType.ServiceQueue; + break; + + case "SN": + + result = SecurableType.Synonym; + break; + + case "SO": + + result = SecurableType.Sequence; + break; + + case "SP": + + result = SecurableType.SecurityPolicy; + break; + + case "U": + + result = SecurableType.Table; + break; + + case "V": + + result = SecurableType.View; + break; + + case "X": + + result = SecurableType.ExtendedStoredProcedure; + break; + + default: + + // object must be one of the types that we aren't showing in the UI + result = SecurableType.Unknown; + break; + } + + return result; + } + + + /// + /// Get the SearchableObjectType equivalent to the input SecurableType + /// + /// The Securable type to convert + /// The equivalent SearchableObjectType + public static SearchableObjectType GetSearchableObjectType(SecurableType type) + { + SearchableObjectType result = SearchableObjectType.LastType; + + switch (type) + { + case SecurableType.AggregateFunction: + + result = SearchableObjectType.AggregateFunction; + break; + + case SecurableType.ApplicationRole: + + result = SearchableObjectType.ApplicationRole; + break; + + case SecurableType.Assembly: + + result = SearchableObjectType.Assembly; + break; + + case SecurableType.AsymmetricKey: + + result = SearchableObjectType.AsymmetricKey; + break; + + case SecurableType.Certificate: + + result = SearchableObjectType.Certificate; + break; + + case SecurableType.Database: + + result = SearchableObjectType.Database; + break; + + case SecurableType.DatabaseRole: + + result = SearchableObjectType.DatabaseRole; + break; + + case SecurableType.Endpoint: + + result = SearchableObjectType.Endpoint; + break; + + case SecurableType.ExtendedStoredProcedure: + + result = SearchableObjectType.ExtendedStoredProcedure; + break; + + case SecurableType.ExternalDataSource: + + result = SearchableObjectType.ExternalDataSource; + break; + + case SecurableType.ExternalFileFormat: + + result = SearchableObjectType.ExternalFileFormat; + break; + + case SecurableType.FullTextCatalog: + + result = SearchableObjectType.FullTextCatalog; + break; + + case SecurableType.FunctionInline: + + result = SearchableObjectType.FunctionInline; + break; + + case SecurableType.FunctionScalar: + + result = SearchableObjectType.FunctionScalar; + break; + + case SecurableType.FunctionTable: + + result = SearchableObjectType.FunctionTable; + break; + + case SecurableType.Login: + + result = SearchableObjectType.Login; + break; + + case SecurableType.ServerRole: + + result = SearchableObjectType.ServerRole; + break; + + case SecurableType.Schema: + + result = SearchableObjectType.Schema; + break; + + case SecurableType.SecurityPolicy: + + result = SearchableObjectType.SecurityPolicy; + break; + + case SecurableType.Server: + + result = SearchableObjectType.Server; + break; + + case SecurableType.ServiceQueue: + + result = SearchableObjectType.ServiceQueue; + break; + + case SecurableType.StoredProcedure: + + result = SearchableObjectType.StoredProcedure; + break; + + case SecurableType.SymmetricKey: + + result = SearchableObjectType.SymmetricKey; + break; + + case SecurableType.Synonym: + + result = SearchableObjectType.Synonym; + break; + + case SecurableType.Sequence: + + result = SearchableObjectType.Sequence; + break; + + case SecurableType.Table: + + result = SearchableObjectType.Table; + break; + + case SecurableType.User: + + result = SearchableObjectType.User; + break; + + case SecurableType.UserDefinedDataType: + + result = SearchableObjectType.UserDefinedDataType; + break; + + case SecurableType.UserDefinedTableType: + + result = SearchableObjectType.UserDefinedTableType; + break; + + case SecurableType.View: + + result = SearchableObjectType.View; + break; + + case SecurableType.XmlSchemaCollection: + + result = SearchableObjectType.XmlSchemaCollection; + break; + + case SecurableType.AvailabilityGroup: + + result = SearchableObjectType.AvailabilityGroup; + break; + + default: + + // STrace.Assert(false, "Can't convert securable type to searchable object type"); + throw new ArgumentException(); + } + + return result; + + } + + /// + /// Get an image for display in the securable selector for the securable type + /// + /// The type + /// The image + // public static System.Drawing.Image GetImage(SecurableType type) + // { + // SearchableObjectType searchableType = GetSearchableObjectType(type); + // SearchableObjectTypeDescription description = SearchableObjectTypeDescription.GetDescription(searchableType); + // return description.Image; + // } + + /// + /// Form a URN string for the object + /// + /// The SMO ObjectClass of the object + /// The sys.objects type of the object if applicable, String.Empty if not applicable + /// The name of the database containing the object if applicable, String.Empty if not applicable + /// The name of the schema containing the object if applicable, String.Empty if not applicable + /// The name of the object + /// for user-defined types, indicate whether it is a data type or a table type + /// The urn that is formed for the object + /// True if the URN could be formed, false otherwise + public static bool FormUrn( + ObjectClass objectClass, + string objectType, + string databaseName, + string schemaName, + string name, + bool isTableType, + out string urn) + { + string objectTypeString = String.Empty; + bool result = GetUrnTypeString(objectClass, objectType, isTableType, out objectTypeString); + + if (result) + { + StringBuilder urnBuilder; + + if (objectTypeString != "Server") + { + urnBuilder = new StringBuilder("Server/"); + + if (databaseName.Length != 0) + { + urnBuilder.AppendFormat("Database[@Name='{0}']/", Urn.EscapeString(databaseName)); + } + + urnBuilder.AppendFormat("{0}[", objectTypeString); + + if (schemaName.Length != 0) + { + urnBuilder.AppendFormat("@Schema='{0}' and ", Urn.EscapeString(schemaName)); + } + } + else + { + urnBuilder = new StringBuilder("Server["); + } + + urnBuilder.AppendFormat("@Name='{0}']", Urn.EscapeString(name)); + + urn = urnBuilder.ToString(); + } + else + { + urn = String.Empty; + } + + return result; + } + + /// + /// Get the URN substring filtering for object type + /// + /// The SMO ObjectClass of the object + /// The sys.objects type string of the object + /// for user-defined types, indicate whether it is a data type or a table type + /// The substring that is formed + /// True if the substring could be formed, false otherwise + private static bool GetUrnTypeString(ObjectClass objectClass, string objectType, bool isTableType, out string urnTypeString) + { + bool result = false; + urnTypeString = String.Empty; + + if (objectType.Length != 0) + { + result = GetUrnTypeString(objectType, out urnTypeString); + } + else + { + result = GetUrnTypeString(objectClass, isTableType, out urnTypeString); + } + + return result; + + } + + /// + /// Get the URN substring filtering for object type + /// + /// The SMO ObjectClass for the object + /// for user-defined types, indicate whether it is a data type or a table type + /// The substring that is formed + /// True if the substring could be formed, false otherwise + private static bool GetUrnTypeString(ObjectClass objectClass, bool isTableType, out string urnTypeString) + { + bool result = false; + + switch (objectClass) + { + case ObjectClass.ApplicationRole: + + urnTypeString = "ApplicationRole"; + result = true; + break; + + case ObjectClass.Certificate: + + urnTypeString = "Certificate"; + result = true; + break; + + case ObjectClass.Database: + + urnTypeString = "Database"; + result = true; + break; + + case ObjectClass.DatabaseRole: + + urnTypeString = "Role"; + result = true; + break; + + case ObjectClass.Endpoint: + + urnTypeString = "Endpoint"; + result = true; + break; + + case ObjectClass.ExternalDataSource: + urnTypeString = "ExternalDataSource"; + result = true; + break; + + case ObjectClass.ExternalFileFormat: + urnTypeString = "ExternalFileFormat"; + result = true; + break; + + case ObjectClass.FullTextCatalog: + + urnTypeString = "FullTextCatalog"; + result = true; + break; + + case ObjectClass.Schema: + + urnTypeString = "Schema"; + result = true; + break; + + case ObjectClass.Server: + + urnTypeString = "Server"; + result = true; + break; + + case ObjectClass.SqlAssembly: + + urnTypeString = "SqlAssembly"; + result = true; + break; + + case ObjectClass.SymmetricKey: + + urnTypeString = "SymmetricKey"; + result = true; + break; + + case ObjectClass.User: + + urnTypeString = "User"; + result = true; + break; + + case ObjectClass.UserDefinedType: + + if (isTableType) + { + urnTypeString = "UserDefinedTableType"; + } + else + { + urnTypeString = "UserDefinedDataType"; + } + result = true; + break; + + case ObjectClass.XmlNamespace: + + urnTypeString = "XmlSchemaCollection"; + result = true; + break; + + case ObjectClass.Login: + + urnTypeString = "Login"; + result = true; + break; + + case ObjectClass.ServerRole: + + urnTypeString = "Role"; + result = true; + break; + + case ObjectClass.AvailabilityGroup: + + urnTypeString = "AvailabilityGroup"; + result = true; + break; + + default: + + urnTypeString = String.Empty; + result = false; + break; + } + + return result; + } + + /// + /// Get the URN substring filtering for object type + /// + /// The sys.objects type string of the object + /// The substring that is formed + /// True if the substring could be formed, false otherwise + private static bool GetUrnTypeString(string objectType, out string urnTypeString) + { + bool result = false; + + switch (objectType) + { + case "AF": + + urnTypeString = "UserDefinedAggregate"; + result = true; + break; + + case "P": + case "PC": + case "RF": + + urnTypeString = "StoredProcedure"; + result = true; + break; + + case "FN": + case "IF": + case "TF": + case "FS": + case "FT": + + urnTypeString = "UserDefinedFunction"; + result = true; + break; + + case "SQ": + + urnTypeString = "ServiceBroker/ServiceQueue"; + result = true; + break; + + case "SN": + + urnTypeString = "Synonym"; + result = true; + break; + + case "SO": + + urnTypeString = "Sequence"; + result = true; + break; + + case "U": + + urnTypeString = "Table"; + result = true; + break; + + case "V": + + urnTypeString = "View"; + result = true; + break; + + case "X": + + urnTypeString = "ExtendedStoredProcedure"; + result = true; + break; + + default: + + // object must be one of the types that we aren't showing in the UI + urnTypeString = String.Empty; + result = false; + break; + } + + return result; + } + + /// + /// Get the version of the server on the other end of the connection + /// + /// Connection information to connect to the server + /// The server's version + public static Version GetServerVersion(object connectionInfo) + { + Version result; + + // enumerate granted/denied permissions for the principal + string urn = "Server/Information"; + string[] fields = new string[] { "VersionMajor", "VersionMinor", "BuildNumber" }; + Request request = new Request(new Urn(urn), fields); + DataTable table = new Enumerator().Process(connectionInfo, request); + + if (1 == table.Rows.Count) + { + int major = (int)table.Rows[0][0]; + int minor = (int)table.Rows[0][1]; + int build = (int)table.Rows[0][2]; + + result = new Version(major, minor, build); + } + else + { + // STrace.Assert(false, "couldn't get server version, defaulting to YUKON"); + + result = new Version(9, 0, 0); + } + + return result; + } + + public static Microsoft.SqlServer.Management.Common.DatabaseEngineType GetDatabaseEngineType(object connectionInfo) + { + Microsoft.SqlServer.Management.Common.DatabaseEngineType result; + + // enumerate granted/denied permissions for the principal + string urn = "Server"; + string[] fields = new string[] { "ServerType" }; + Request request = new Request(new Urn(urn), fields); + DataTable table = new Enumerator().Process(connectionInfo, request); + + if (1 == table.Rows.Count) + { + result = (Microsoft.SqlServer.Management.Common.DatabaseEngineType)table.Rows[0][0]; + } + else + { + // STrace.Assert(false, "couldn't get server type, defaulting to Standalone"); + + result = Microsoft.SqlServer.Management.Common.DatabaseEngineType.Standalone; + } + + return result; + } + + /// + /// Get the database engine edition value. + /// + /// The connection information. + /// The database engine edition value. + public static Microsoft.SqlServer.Management.Common.DatabaseEngineEdition GetDatabaseEngineEdition(object connectionInfo) + { + return Microsoft.SqlServer.Management.Sdk.Sfc.ExecuteSql.GetDatabaseEngineEdition(connectionInfo); + } + } + + /// + /// delegate for Securable.OnPermissionStateChanged events + /// + internal delegate void SecurableChangedEventHandler(bool permissionsChangesExist); + + #region Securable Collections + + /// + /// Key class for SecurableList and SecurableDictionary + /// + internal class SecurableKey : IComparable + { + private string name; + private string schema; + private int securableType; + private bool changesExist; + + internal string Name + { + get + { + return this.name; + } + } + + internal string Schema + { + get + { + return this.schema; + } + } + + internal int SecurableType + { + get + { + return this.securableType; + } + } + + internal bool ChangesExist + { + get + { + return this.changesExist; + } + } + + internal SecurableKey(Securable securable) + { + this.name = securable.Name; + this.schema = securable.Schema; + this.securableType = (int)securable.SecurableType; + this.changesExist = securable.ChangesExist; + } + + internal SecurableKey(SearchableObject searchable) + { + this.name = searchable.Name; + this.schema = searchable.Schema; + this.securableType = (int)Securable.GetSecurableType(searchable.SearchableObjectType); + this.changesExist = false; + } + + internal SecurableKey(string schema, string name, SecurableType type) + { + this.name = name; + this.schema = schema; + this.securableType = (int)type; + this.changesExist = false; + } + + internal SecurableKey(string schema, string name, SecurableType type, bool changesExist) + { + this.name = name; + this.schema = schema; + this.securableType = (int)type; + this.changesExist = changesExist; + } + + + public override int GetHashCode() + { + string fullname = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.{1}.{2}", this.schema, this.name, this.securableType); + return fullname.GetHashCode(); + } + + public override bool Equals(object obj) + { + bool result = false; + + SecurableKey other = obj as SecurableKey; + + if (other != null) + { + result = (this.CompareTo(other) == 0); + } + + return result; + } + + + #region IComparable Members + + public int CompareTo(object obj) + { + int result = 0; + SecurableKey other = (SecurableKey)obj; + + result = String.Compare(this.schema, other.schema, StringComparison.Ordinal); + + if (0 == result) + { + result = String.Compare(this.name, other.name, StringComparison.Ordinal); + } + + if (0 == result) + { + if (this.securableType < other.securableType) + { + result = -1; + } + else if (other.securableType < this.securableType) + { + result = 1; + } + } + + return result; + } + + #endregion + } + + /// + /// A collection of Securables, with sorted list-like behavior. Inserts, Deletes, and Contains are O(lg N). + /// + internal class SecurableList : ICollection + { + private SortedList data; + + public SecurableList() + { + this.data = new SortedList(new SecurableComparer(SecurableComparer.DefaultSortingOrder, true)); + } + + public SecurableList(SecurableComparer comparer) + { + this.data = new SortedList(comparer); + } + + public SecurableList(SecurableList original, SecurableComparer comparer) + { + if (original.Count != 0) + { + this.data = new SortedList(original.data, comparer); + } + else + { + this.data = new SortedList(comparer); + } + } + + public SecurableList(SecurableDictionary dictionary, SecurableComparer comparer) + { + if (dictionary.Count != 0) + { + this.data = new SortedList(dictionary.GetData(), comparer); + } + else + { + this.data = new SortedList(comparer); + } + } + + + internal IDictionary GetData() + { + return this.data; + } + + + #region IList Members + + public bool IsReadOnly + { + get + { + return false; + } + } + + public Securable this[int index] + { + get + { + return (Securable)this.data.GetByIndex(index); + } + set + { + this.data.SetByIndex(index, value); + } + } + + internal Securable this[string columnName] + { + get + { + SecurableKey key = new SecurableKey(String.Empty, columnName, SecurableType.Column); + return (Securable)this.data[key]; + } + + set + { + SecurableKey key = new SecurableKey(String.Empty, columnName, SecurableType.Column); + this.data[key] = value; + } + } + + internal Securable this[SecurableKey key] + { + get + { + return (Securable)this.data[key]; + } + + set + { + this.data[key] = value; + } + } + + public void RemoveAt(int index) + { + this.data.RemoveAt(index); + } + + public void Add(Securable value) + { + this.data.Add(new SecurableKey(value), value); + } + + public void Remove(Securable value) + { + this.data.Remove(new SecurableKey(value)); + } + + public void Remove(SearchableObject value) + { + this.data.Remove(new SecurableKey(value)); + } + + public bool Contains(Securable value) + { + return this.data.Contains(new SecurableKey(value)); + } + + public bool Contains(SearchableObject value) + { + return this.data.Contains(new SecurableKey(value)); + } + + public void Clear() + { + this.data.Clear(); + } + + public int IndexOf(Securable value) + { + return this.data.IndexOfKey(new SecurableKey(value)); + } + + public int IndexOf(SearchableObject value) + { + return this.data.IndexOfKey(new SecurableKey(value)); + } + + public bool IsFixedSize + { + get + { + return false; + } + } + + + #endregion + + #region ICollection Members + + public bool IsSynchronized + { + get + { + return false; + } + } + + public int Count + { + get + { + return this.data.Count; + } + } + + public void CopyTo(Array array, int index) + { + for (int i = 0; i < this.data.Count; ++i) + { + array.SetValue(this.data.GetByIndex(i), index + i); + } + } + + public object SyncRoot + { + get + { + return this; + } + } + + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return this.data.Values.GetEnumerator(); + } + + + #endregion + } + + enum SecurableSortType + { + Schema, + Name, + Type, + Status + } + + + + /// + /// Comparer for securable keys + /// + internal class SecurableComparer : IComparer + { + internal static SecurableSortType[] DefaultSortingOrder = + { + SecurableSortType.Schema, + SecurableSortType.Name, + SecurableSortType.Type, + SecurableSortType.Status + }; + + private SecurableSortType[] sortOrder; + private bool ascending; + + /// + /// Constructor + /// + /// Indicate which column to sort + /// Whether to sort in ascending order + public SecurableComparer(SecurableSortType[] sortOrder, bool ascending) + { + this.sortOrder = sortOrder; + this.ascending = ascending; + } + + /// + /// Compare two securable keys + /// + /// The first securable key + /// The second securable key + /// -1 if first is less than second, 0 if first equals second, 1 if second is less than first + public int Compare(object x, object y) + { + int result = 0; + + if (x == null) + { + result = -1; + } + else if (y == null) + { + result = 1; + } + else + { + SecurableKey securableKey1; + SecurableKey securableKey2; + + // if not ascending sort, reverse the roles of x and y + if (this.ascending) + { + securableKey1 = (SecurableKey)x; + securableKey2 = (SecurableKey)y; + } + else + { + securableKey1 = (SecurableKey)y; + securableKey2 = (SecurableKey)x; + } + + int i = 0; + + while (0 == result && i < this.sortOrder.Length) + { + switch (this.sortOrder[i]) + { + case SecurableSortType.Name: + + result = String.Compare( + securableKey1.Name, + securableKey2.Name, + StringComparison.CurrentCulture); + break; + + case SecurableSortType.Schema: + + result = String.Compare( + securableKey1.Schema, + securableKey2.Schema, + StringComparison.CurrentCulture); + break; + + case SecurableSortType.Type: + + result = securableKey1.SecurableType - securableKey2.SecurableType; + break; + + case SecurableSortType.Status: + + if (!securableKey1.ChangesExist && securableKey2.ChangesExist) + { + result = -1; + } + else if (securableKey1.ChangesExist && !securableKey2.ChangesExist) + { + result = 1; + } + break; + + default: + // STrace.Assert(true, "Unknown SecurableSortType"); + result = 0; + break; + } + + ++i; + } + } + + return result; + } + + } + + /// + /// A collection of Securables, with dictionary-like behavior. Inserts, Deletes, and Contains are O(1). + /// + internal class SecurableDictionary : ICollection + { + private Hashtable data; + + public SecurableDictionary() + { + this.data = new Hashtable(); + } + + public SecurableDictionary(SecurableList list) + { + if (list.Count != 0) + { + this.data = new Hashtable(list.GetData()); + } + else + { + this.data = new Hashtable(); + } + } + + internal IDictionary GetData() + { + return this.data; + } + + internal void UpdateKey(Securable securable) + { + this.data.Remove(new SecurableKey(securable.Schema, securable.Name, securable.SecurableType)); + this.data.Add(new SecurableKey(securable), securable); + } + + + #region IDictionary Members + + public bool IsReadOnly + { + get + { + return false; + } + } + + public IDictionaryEnumerator GetDictionaryEnumerator() + { + return this.data.GetEnumerator(); + } + + public Securable this[SecurableKey key] + { + get + { + return (Securable)this.data[key]; + } + + set + { + this.data[key] = value; + } + } + + public Securable this[Securable key] + { + get + { + SecurableKey securableKey = new SecurableKey(key); + return (Securable)this.data[securableKey]; + } + + set + { + SecurableKey securableKey = new SecurableKey(key); + this.data[securableKey] = value; + } + } + + public Securable this[SearchableObject key] + { + get + { + SecurableKey securableKey = new SecurableKey(key); + return (Securable)this.data[securableKey]; + } + + set + { + SecurableKey securableKey = new SecurableKey(key); + this.data[securableKey] = value; + } + } + + public void Remove(Securable key) + { + this.data.Remove(new SecurableKey(key)); + } + + public bool Contains(SecurableKey key) + { + return this.data.Contains(key); + } + + public bool Contains(Securable key) + { + return this.data.Contains(new SecurableKey(key)); + } + + public bool Contains(SearchableObject key) + { + return this.data.Contains(new SecurableKey(key)); + } + + public void Clear() + { + this.data.Clear(); + } + + public ICollection Values + { + get + { + return this.data.Values; + } + } + + public void Add(Securable securable) + { + this.data.Add(new SecurableKey(securable), securable); + } + + public ICollection Keys + { + get + { + return this.data.Keys; + } + } + + public bool IsFixedSize + { + get + { + return false; + } + } + + #endregion + + #region ICollection Members + + public bool IsSynchronized + { + get + { + return false; + } + } + + public int Count + { + get + { + return this.data.Count; + } + } + + public void CopyTo(Array array, int index) + { + this.data.Values.CopyTo(array, index); + } + + public object SyncRoot + { + get + { + return this; + } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return this.data.Values.GetEnumerator(); + } + + + #endregion + + } + + #endregion + + #region Securable Subclasses + + + /// + /// Securable class for tables, views, inline UDF's, and table-valued UDF's + /// + internal class SecurableColumnParent : Securable + { + private Principal currentPrincipal; + /// + /// Constructor for existing tables, views, or table valued functions + /// + /// The SMO object we are representing + /// The SecurableType for the SMO object + /// Connection information for enumerating permissions data + /// The version of the server + public SecurableColumnParent(SqlSmoObject smoObject, SecurableType type, object connectionInfo, Version serverVersion) + : base(smoObject, type, connectionInfo, serverVersion) + { + // STrace.Assert((smoObject is TableViewBase) || (smoObject is UserDefinedFunction), "smoObject is not a table, view, or UDF"); + // STrace.Assert( + // (SecurableType.Table == type) || + // (SecurableType.View == type) || + // (SecurableType.FunctionInline == type) || + // (SecurableType.FunctionTable == type), + // "type is not table, view, or table-valued UDF"); + CurrentPrincipal = null; + } + + /// + /// Constructor for new tables, views, or table valued functions, or existing tables, views, or + /// table valued functions that have been enumerated or searched for. + /// + /// The securable type of the object + /// The URN of the object + /// Connection information for enumerating permissions data + /// The version of the server + /// + public SecurableColumnParent(SecurableType type, string urn, object connectionInfo, Version serverVersion, bool exists) + : base(type, urn, connectionInfo, serverVersion, exists) + { + // STrace.Assert( + // (SecurableType.Table == type) || + // (SecurableType.View == type) || + // (SecurableType.FunctionInline == type) || + // (SecurableType.FunctionTable == type), + // "type is not table, view, or table-valued UDF"); + CurrentPrincipal = null; + } + + + /// + /// Apply grants and denies to the table/view/function and its columns + /// + /// + internal override void ApplyGrantsAndDenies(SqlSmoObject obj) + { + base.ApplyGrantsAndDenies(obj); + + if (obj is TableViewBase) + { + TableViewBase table = (TableViewBase)obj; + + for (int columnIndex = 0; columnIndex < table.Columns.Count; ++columnIndex) + { + Column column = table.Columns[columnIndex]; + Securable child = this.Children[column.Name]; + + // STrace.Assert(child != null, "child not found for column, permissions control is out of sync with SMO object state"); + + // VSTS 1458762 - avoid duplicate if this child is already in current principal's list. + if (CurrentPrincipal != null && CurrentPrincipal.SecurableToPermissionStatesContains(child)) + { + continue; + } + + if (child != null) + { + child.ApplyGrantsAndDenies(column); + } + } + } + else if (obj is UserDefinedFunction) + { + UserDefinedFunction function = (UserDefinedFunction)obj; + + for (int columnIndex = 0; columnIndex < function.Columns.Count; ++columnIndex) + { + Column column = function.Columns[columnIndex]; + Securable child = this.Children[column.Name]; + + // STrace.Assert(child != null, "child not found for column, permissions control is out of sync with SMO object state"); + + // VSTS 1458762 - avoid duplicate if this child is already in current principal's list. + if (CurrentPrincipal != null && CurrentPrincipal.SecurableToPermissionStatesContains(child)) + { + continue; + } + + if (child != null) + { + child.ApplyGrantsAndDenies(column); + } + } + } +#if DEBUG + else + { + // STrace.Assert(false, "unexpected object type - obj is not a table, view, or UDF"); + } +#endif + } + + /// + /// Apply revokes to the table/view/function and its columns + /// + /// + internal override void ApplyRevokes(SqlSmoObject obj) + { + base.ApplyRevokes(obj); + + if (obj is TableViewBase) + { + TableViewBase table = (TableViewBase)obj; + + for (int columnIndex = 0; columnIndex < table.Columns.Count; ++columnIndex) + { + Column column = table.Columns[columnIndex]; + Securable child = this.Children[column.Name]; + + // STrace.Assert(child != null, "child not found for column, permissions control is out of sync with SMO object state"); + + // VSTS 1458762 - avoid duplicate if this child is already in current principal's list. + if (CurrentPrincipal != null && CurrentPrincipal.SecurableToPermissionStatesContains(child)) + { + continue; + } + + if (child != null) + { + child.ApplyRevokes(column); + } + } + } + else if (obj is UserDefinedFunction) + { + UserDefinedFunction function = (UserDefinedFunction)obj; + + for (int columnIndex = 0; columnIndex < function.Columns.Count; ++columnIndex) + { + Column column = function.Columns[columnIndex]; + Securable child = this.Children[column.Name]; + + // STrace.Assert(child != null, "child not found for column, permissions control is out of sync with SMO object state"); + + // VSTS 1458762 - avoid duplicate if this child is already in current principal's list. + if (CurrentPrincipal != null && CurrentPrincipal.SecurableToPermissionStatesContains(child)) + { + continue; + } + + if (child != null) + { + child.ApplyRevokes(column); + } + } + } +#if DEBUG + else + { + // STrace.Assert(false, "unexpected object type - obj is not a table, view, or UDF"); + } +#endif + } + + /// + /// Get a collection of child columns + /// + /// The columns collection + protected override SecurableList GetChildren() + { + SecurableList result = new SecurableList(); + + if (this.Exists) + { + SecurableType childType = (SecurableType.FunctionTable == this.SecurableType) ? + SecurableType.ColumnFunctionTable : + SecurableType.Column; + + string columnsUrn = String.Format(System.Globalization.CultureInfo.InvariantCulture, + "{0}/Column", + this.Urn); + Enumerator enumerator = new Enumerator(); + Request request = new Request(); + request.Urn = new Urn(columnsUrn); + request.Fields = new string[] { "Urn" }; + + DataTable columns = enumerator.Process(this.ConnectionInfo, request); + + for (int columnIndex = 0; columnIndex < columns.Rows.Count; ++columnIndex) + { + DataRow columnData = columns.Rows[columnIndex]; + string columnUrn = columnData["Urn"].ToString(); + Securable column = Securable.AllocateSecurable(childType, + columnUrn, + this.ConnectionInfo, + this.ServerVersion); + + // STrace.Assert(!result.Contains(column), "column is already in the collection"); + + // set the column's parent + column.Parent = this; + + // the column should have all the same principals as its parent + IEnumerator principalEnumerator = this.Principals.GetEnumerator(); + principalEnumerator.Reset(); + + while (principalEnumerator.MoveNext()) + { + Principal principal = (Principal)principalEnumerator.Current; + column.AddPrincipal(principal); + } + + // add the column to the result collection + result.Add(column); + } + } + + return result; + } + + internal Principal CurrentPrincipal + { + get + { + return this.currentPrincipal; + } + set + { + this.currentPrincipal = value; + } + } + } + + + #endregion + + + /// + /// A security principal + /// + internal class Principal + { + private string name = String.Empty; + private string databaseName = String.Empty; + private string serverName = String.Empty; + private PrincipalType principalType; + private object connectionInfo = null; + /// + /// Map from Securable to PermissionStateCollection + /// + private HybridDictionary securableToPermissionStates = null; + private SecurableDictionary securables = null; + private SecurableDictionary removedSecurables = null; + private bool isRemoved = false; + private bool exists = false; + private Version serverVersion; + private DatabaseEngineType databaseEngineType; + private DatabaseEngineEdition databaseEngineEdition; + private event EventHandler observableChanged; + + private const int YUKON = 9; + private const int SHILOH = 8; + + /// + /// The name of the principal + /// + public string Name + { + get + { + return this.name; + } + + set + { + this.name = value; + } + } + + /// + /// Get the type of the principal + /// + public PrincipalType PrincipalType + { + get + { + return this.principalType; + } + } + + /// + /// Get the searchable object type of the principal + /// + public SearchableObjectType SearchableObjectType + { + get + { + return Principal.GetSearchableObjectType(this.principalType); + } + } + + /// + /// The localized display name of the type of the securable + /// + public string TypeName + { + get + { + SearchableObjectTypeDescription description = + SearchableObjectTypeDescription.GetDescription(this.SearchableObjectType); + + return description.DisplayTypeNameSingular; + } + } + + /// + /// The name of the database containing the principal, or String.Empty if the principal is a Login or Server Role + /// + public string DatabaseName + { + get + { + return this.databaseName; + } + } + + /// + /// The name of the server containing the principal + /// + public string ServerName + { + get + { + if (0 == this.serverName.Length) + { + // STrace.Assert(this.connectionInfo != null, "connection info is null"); + + Enumerator enumerator = new Enumerator(); + Urn urn = new Urn("Server"); + string[] fields = new string[] { "Name" }; + Request request = new Request(urn, fields); + DataTable results = enumerator.Process(this.connectionInfo, request); + + // STrace.Assert(0 < results.Rows.Count, "Enumerator for server name did not return any rows"); + + if (0 < results.Rows.Count) + { + this.serverName = results.Rows[0]["Name"].ToString(); + } + } + + return this.serverName; + } + } + + /// + /// Whether the principal has been removed + /// + public bool IsRemoved + { + get + { + return this.isRemoved; + } + + set + { + this.isRemoved = true; + } + } + + /// + /// Whether the principal exists on the server + /// + public bool Exists + { + get + { + return this.exists; + } + } + + /// + /// Are there permissions changes to persist to the server + /// + public bool ChangesExist + { + get + { + bool result = (this.removedSecurables.Count != 0); + + if (!result) + { + ICollection permissionStateCollections = this.securableToPermissionStates.Values; + IEnumerator permissionStateCollectionsEnumerator = permissionStateCollections.GetEnumerator(); + + permissionStateCollectionsEnumerator.Reset(); + + while (!result && permissionStateCollectionsEnumerator.MoveNext()) + { + PermissionStateCollection permissionStates = (PermissionStateCollection)permissionStateCollectionsEnumerator.Current; + IEnumerator permissionStateEnumerator = permissionStates.GetEnumerator(); + + permissionStateEnumerator.Reset(); + + while (!result && permissionStateEnumerator.MoveNext()) + { + PermissionState permissionState = (PermissionState)permissionStateEnumerator.Current; + result = permissionState.StateChanged; + } + } + } + + return result; + } + } + + /// + /// Whether the principal is a database principal + /// + public bool IsDatabasePrincipal + { + get + { + bool result = + (PrincipalType.User == this.principalType) || + (PrincipalType.DatabaseRole == this.principalType) || + (PrincipalType.ApplicationRole == this.principalType); + + return result; + } + } + + /// + /// The version of the server + /// + public Version ServerVersion + { + get + { + return this.serverVersion; + } + } + + /// + /// The of the current database + /// + public DatabaseEngineType DatabaseEngineType + { + get + { + return this.databaseEngineType; + } + } + + /// + /// The of the current database + /// + public DatabaseEngineEdition DatabaseEngineEdition + { + get + { + return this.databaseEngineEdition; + } + } + + /// + /// The types of objects on which this principal can have permissions + /// + public ArrayList RelevantSecurableTypes + { + get + { + ArrayList result = new ArrayList(); + + if (this.IsDatabasePrincipal) + { + result.Add(SecurableType.Database); + result.Add(SecurableType.StoredProcedure); + result.Add(SecurableType.Table); + result.Add(SecurableType.View); + + if (this.databaseName == "master") + { + result.Add(SecurableType.ExtendedStoredProcedure); + } + + if (SHILOH <= this.serverVersion.Major) + { + result.Add(SecurableType.FunctionInline); + result.Add(SecurableType.FunctionScalar); + result.Add(SecurableType.FunctionTable); + } + + if (YUKON <= this.serverVersion.Major) + { + result.Add(SecurableType.ApplicationRole); + result.Add(SecurableType.Assembly); + result.Add(SecurableType.AsymmetricKey); + result.Add(SecurableType.Certificate); + result.Add(SecurableType.DatabaseRole); + result.Add(SecurableType.AggregateFunction); + result.Add(SecurableType.FullTextCatalog); + result.Add(SecurableType.ServiceQueue); //Display name is Queue. + result.Add(SecurableType.Schema); + result.Add(SecurableType.SymmetricKey); + result.Add(SecurableType.Synonym); + result.Add(SecurableType.User); + result.Add(SecurableType.UserDefinedDataType); + result.Add(SecurableType.XmlSchemaCollection); + } + + if (Utils.IsKatmaiOrLater(this.ServerVersion.Major)) + { + result.Add(SecurableType.UserDefinedTableType); + } + if (Utils.IsSql11OrLater(this.ServerVersion.Major)) + { + result.Add(SecurableType.Sequence); + } + if (Utils.IsSql13OrLater(this.serverVersion.Major)) + { + result.Add(SecurableType.SecurityPolicy); + result.Add(SecurableType.ExternalDataSource); + result.Add(SecurableType.ExternalFileFormat); + } + } + else + { + if (YUKON <= this.serverVersion.Major) + { + result.Add(SecurableType.Endpoint); + result.Add(SecurableType.Login); + } + result.Add(SecurableType.Server); + + if (Utils.IsSql11OrLater(this.serverVersion.Major)) + { + result.Add(SecurableType.AvailabilityGroup); + result.Add(SecurableType.ServerRole); + } + } + + return result; + } + } + + + /// + /// Constructor for existing principals. + /// + /// The SMO principal we are abstracting + /// Connection info that the enumerator is to use + public Principal(SqlSmoObject principal, object connectionInfo) + { + NamedSmoObject principalAsNamedSmoObject = principal as NamedSmoObject; + if (principalAsNamedSmoObject != null) + { + this.name = principalAsNamedSmoObject.Name; + } + else + { + // STrace.Assert(false, "principal must be a NamedSmoObject!"); + // STrace.LogExThrow(); + throw new ArgumentException("principal"); + } + this.principalType = Principal.GetPrincipalType(principal); + this.connectionInfo = connectionInfo; + this.exists = (SqlSmoState.Existing == principal.State); + this.serverVersion = Securable.GetServerVersion(connectionInfo); + this.databaseEngineType = Securable.GetDatabaseEngineType(connectionInfo); + this.databaseEngineEdition = Securable.GetDatabaseEngineEdition(connectionInfo); + if (this.IsDatabasePrincipal) + { + this.databaseName = principal.Urn.Parent.GetAttribute("Name"); + } + + this.Initialize(); + } + + /// + /// Constructor for server principals that are being created or existing principals that have been enumerated. + /// The name of the principal + /// The type of the principal + /// Whether the principal exists on the server + /// Connection info that the enumerator is to use + /// The version of the server + /// + public Principal(string name, + PrincipalType principalType, + bool exists, + object connectionInfo, + Version serverVersion) + { + this.name = name; + this.principalType = principalType; + this.connectionInfo = connectionInfo; + this.exists = exists; + this.serverVersion = serverVersion; + + this.Initialize(); + } + + /// + /// Constructor for database principals that are being created or existing principals that have been enumerated. + /// + /// The name of the principal + /// The name of the database containing the principal + /// The type of the principal + /// Whether the principal exists on the server + /// Connection info that the enumerator is to use + /// The version of the server + public Principal(string name, string database, PrincipalType principalType, bool exists, object connectionInfo, Version serverVersion) + { + this.name = name; + this.databaseName = database; + this.principalType = principalType; + this.connectionInfo = connectionInfo; + this.exists = exists; + this.serverVersion = serverVersion; + + // STrace.Assert(this.IsDatabasePrincipal, "wrong constructor for a server principal"); + + this.Initialize(); + } + + /// + /// Constructor for database principals that are being created or existing principals that have been enumerated. + /// + /// The name of the principal + /// The name of the database containing the principal + /// The type of the principal + /// Whether the principal exists on the server + /// Connection info that the enumerator is to use + /// The version of the server + /// + /// + internal Principal(string name, string database, PrincipalType principalType, bool exists, object connectionInfo, Version serverVersion, DatabaseEngineType databaseEngineType, DatabaseEngineEdition databaseEngineEdition) + { + this.name = name; + this.databaseName = database; + this.principalType = principalType; + this.connectionInfo = connectionInfo; + this.exists = exists; + this.serverVersion = serverVersion; + this.databaseEngineType = databaseEngineType; + this.databaseEngineEdition = databaseEngineEdition; + // STrace.Assert(this.IsDatabasePrincipal, "wrong constructor for a server principal"); + + this.Initialize(); + } + + /// + /// Constructor for principals that have been searched for and added. + /// + /// The search result identifying the principal + /// Connection info that the enumerator is to use + /// The version of the server + internal Principal(SearchableObject searchableObject, object connectionInfo, Version serverVersion) + { + this.name = searchableObject.Name; + this.principalType = Principal.GetPrincipalType(searchableObject.SearchableObjectType); + this.connectionInfo = connectionInfo; + this.exists = true; + this.serverVersion = serverVersion; + + if (this.IsDatabasePrincipal) + { + this.databaseName = searchableObject.Urn.Parent.GetAttribute("Name"); + } + + this.Initialize(); + } + + /// + /// The list of Schema-Scoped SecurableTypes + /// + internal IEnumerable SchemaTypes + { + get + { + return Enum.GetValues(typeof(SecurableType)) + .Cast() + .Where( + t => + t.IsValidSchemaBoundSecurable( + new ServerVersion(ServerVersion.Major, ServerVersion.Minor, ServerVersion.Build), + this.DatabaseEngineEdition, + this.DatabaseEngineType)); + } + } + + internal bool SecurableToPermissionStatesContains(Securable securable) + { + return this.securableToPermissionStates.Contains(securable); + } + + /// + /// Commit permissions changes to the server + /// + /// The name of the principal for the changes + /// The SMO Server object on which permissions changes are to be committed + public void ApplyChanges(string principalName, Microsoft.SqlServer.Management.Smo.Server server) + { + this.name = principalName; + + // commit changes to non-removed securables + // The only securables that could have been changed are the ones + // that have been selected in the UI at some point, which are the + // ones that are keys in the securableToPermissionStates collection. + IDictionaryEnumerator securableCollectionEnumerator = this.securableToPermissionStates.GetEnumerator(); + securableCollectionEnumerator.Reset(); + + while (securableCollectionEnumerator.MoveNext()) + { + Securable securable = (Securable)securableCollectionEnumerator.Key; + + // STrace.Assert(securable.Urn != null, "Unexpected null URN. Securable should exist and existing securables should have a URN."); + + SqlSmoObject smoSecurable = (SqlSmoObject)server.GetSmoObject(securable.Urn); + if (securable is SecurableColumnParent) + { + // VSTS 1458762 - Set the current principal for this SecurableColumnParent, will check the children + // against current principal's list later. + SecurableColumnParent securableColumnParent = (SecurableColumnParent)securable; + securableColumnParent.CurrentPrincipal = this; + securable.ApplyChanges(smoSecurable); + securableColumnParent.CurrentPrincipal = null; // clean up + } + else + { + securable.ApplyChanges(smoSecurable); + } + } + + // commit changes to removed securables + IEnumerator removedSecurablesEnumerator = this.removedSecurables.GetEnumerator(); + removedSecurablesEnumerator.Reset(); + + while (removedSecurablesEnumerator.MoveNext()) + { + Securable removed = (Securable)removedSecurablesEnumerator.Current; + // STrace.Assert(removed.Urn != null, "Unexpected null URN. Removed securable should exist and existing securables should have a URN."); + + SqlSmoObject smoSecurable = (SqlSmoObject)server.GetSmoObject(removed.Urn); + removed.ApplyChanges(smoSecurable); + } + } + + /// + /// Abandon all changes and get new state data from the server + /// + public void Reset() + { + this.Initialize(); + } + + /// + /// Get an ordered list of the securables that have been "added" to the Principal in the UI + /// + /// The SecurableComparer to use to sort the securables + /// The list of securables + public SecurableList GetSecurables(SecurableComparer comparer) + { + return new SecurableList(this.securables, comparer); + } + + /// + /// This will update the SecurableKey with the right ChangesExist value + /// + /// + public void UpdateSecurableKeyStatus(Securable securable) + { + this.securables.UpdateKey(securable); + } + + /// + /// Get the permission states relating this principal to the input securable + /// + /// The securable for which we are getting permission states + /// The collection of permission states + public PermissionStateCollection GetPermissionStates(Securable securable) + { + if (!this.securableToPermissionStates.Contains(securable)) + { + PermissionState.PopulatePermissionStates(securable, this); + PermissionState.AddChildrenToEmptyParents((PermissionStateCollection)this.securableToPermissionStates[securable]); + } + + return (PermissionStateCollection)this.securableToPermissionStates[securable]; + } + + + /// + /// Add the set of securables related to this principal + /// + /// The set of securables + public void AddExistingSecurables() + { + if (this.exists) + { + // STrace.Assert(this.connectionInfo != null, "connectionInfo is not set"); + + string urn = this.IsDatabasePrincipal ? + new Urn( + String.Format( + System.Globalization.CultureInfo.InvariantCulture, + "Server/Database[@Name='{0}']/LevelPermission[@Grantee='{1}']", + Urn.EscapeString(this.databaseName), + Urn.EscapeString(this.Name))) : + new Urn( + String.Format( + System.Globalization.CultureInfo.InvariantCulture, + "Server/LevelPermission[@Grantee='{0}']", + Urn.EscapeString(this.Name))); + + this.AddRelatedSecurables(urn, this.securables, this.IsDatabasePrincipal); + } + } + + /// + /// Add the securables in the input schema to the securables collection + /// + /// The name of the schema that contains the securables + /// The set of securables + public void AddAllSecurables(string schemaName) + { + // STrace.Assert(this.IsDatabasePrincipal, "Server objects don't have schemas"); + + //Schema-bound Securables should always be under a Database - so there's + //nothing to add if we aren't a database principal + if (!this.IsDatabasePrincipal) + { + return; + } + + foreach (SecurableType securableType in this.SchemaTypes) + { + this.AddSecurables(securableType, securableType.GetSchemaScopedUrn(schemaName, this.databaseName), this.securables); + } + } + + + /// + /// Add the set of securables whose types are in the list of securable types + /// + /// The securable types to return + /// The set of securables + public void AddAllSecurables(ArrayList securableTypes) + { + foreach (SecurableType securableType in securableTypes) + { + this.AddSecurables(securableType, this.GetSecurablesUrn(securableType), this.securables); + } + + } + + /// + /// Add a securable to the collection of related securables + /// + /// The searchable object for the securable + /// The securable that was added + public Securable AddSecurable(SearchableObject securable) + { + Securable result = null; + + if (!this.securables.Contains(securable)) + { + if (this.removedSecurables.Contains(securable)) + { + result = this.removedSecurables[securable]; + result.IsRemoved = false; + this.removedSecurables.Remove(result); + } + else + { + result = Securable.Create(securable, this.connectionInfo, this.serverVersion); + } + + this.securables.Add(result); + result.Changed += this.OnChanged; + } + else + { + result = this.securables[securable]; + } + + return result; + } + + /// + /// Remove a securable from the collection of related securables + /// + /// The securable to remove + public void RemoveSecurable(Securable securable) + { + // STrace.Assert(this.securables.Contains(securable), "securable is not in the securables collection"); + + if (this.HasExistingGrants(securable)) + { + // STrace.Assert(!this.removedSecurables.Contains(securable), "removedSecurables already contains the securable"); + this.removedSecurables.Add(securable); + securable.IsRemoved = true; + } + + this.securables.Remove(securable); + this.securableToPermissionStates.Remove(securable); + } + + /// + /// Revoke all permissions that have been displayed in the UI. + /// + /// + /// This is called when one of the permissions on objects controls needs to + /// revoke all permissions on the securable for this principal. Any child + /// permissions are revoked as well. + /// + public void RevokeAll() + { + IEnumerator permissionStateCollectionEnumerator = this.securableToPermissionStates.Values.GetEnumerator(); + permissionStateCollectionEnumerator.Reset(); + + while (permissionStateCollectionEnumerator.MoveNext()) + { + PermissionStateCollection permissionStateCollection = (PermissionStateCollection)permissionStateCollectionEnumerator.Current; + IEnumerator permissionStateEnumerator = permissionStateCollection.GetEnumerator(); + permissionStateEnumerator.Reset(); + + while (permissionStateEnumerator.MoveNext()) + { + PermissionState permissionState = (PermissionState)permissionStateEnumerator.Current; + permissionState.Revoke(); + } + } + } + + /// + /// Handle permission selection change events + /// + /// + /// + private void OnChanged(object sender, EventArgs e) + { + this.NotifyObservers(sender, e); + } + + /// + /// Property to access the observable event. + /// + internal event EventHandler Changed + { + add { this.observableChanged += value; } + remove { this.observableChanged -= value; } + } + + /// + /// Notify all observers that this object has changed. + /// + /// The object that changed + /// Hint for the notification, usually null + private void NotifyObservers(object sender, EventArgs e) + { + if (this.observableChanged != null) + { + this.observableChanged(sender, e); + } + } + + /// + /// Notify all observers that this object or one of its children has changed. + /// + private void NotifyObservers() + { + this.NotifyObservers(this, new EventArgs()); + } + + + /// + /// Does this principal have any granted or denied permissions on the securable? + /// + /// The securable we are checking for existing grants/denies + /// True if there are existing grants or denies, false if all all permissions are revoked + internal bool HasExistingGrants(Securable securable) + { + bool result = false; + PermissionStateCollection permissionStates = this.GetPermissionStates(securable); + + for (int i = 0; i < permissionStates.Count; ++i) + { + PermissionState permissionState = permissionStates[i]; + + if (permissionState.OriginalState != PermissionStatus.Revoke) + { + result = true; + break; + } + } + + return result; + } + + /// + /// Add a permission state to the collection of permission states + /// + /// The permission state to add + internal void AddPermissionState(PermissionState permissionState) + { + PermissionStateCollection permissionStates = null; + + if (this.securableToPermissionStates.Contains(permissionState.Securable)) + { + permissionStates = (PermissionStateCollection)this.securableToPermissionStates[permissionState.Securable]; + } + else + { + permissionStates = new PermissionStateCollection(); + this.securableToPermissionStates.Add(permissionState.Securable, permissionStates); + } + + permissionStates.Add(permissionState); + } + + /// + /// Perform common initialization tasks + /// + private void Initialize() + { + this.securableToPermissionStates = new HybridDictionary(); + this.securables = new SecurableDictionary(); + this.removedSecurables = new SecurableDictionary(); + + //If we don't have a DatabaseEngineType try to fetch it from our connection now + if(this.DatabaseEngineType == DatabaseEngineType.Unknown) + { + var conn = this.connectionInfo as SqlConnectionInfoWithConnection; + if(conn != null) + { + this.databaseEngineType = conn.ServerConnection.DatabaseEngineType; + } + } + } + + /// + /// Get a urn to enumerate all objects of a particular type + /// + /// The type of objects to enumerate + /// The URN to enumerate the objects + private string GetSecurablesUrn(SecurableType type) + { + StringBuilder result = new StringBuilder("Server"); + + if (this.IsDatabasePrincipal) + { + result.AppendFormat("/Database[@Name='{0}']", Urn.EscapeString(this.databaseName)); + } + + switch (type) + { + case SecurableType.AggregateFunction: + + result.Append("/UserDefinedAggregate"); + break; + + case SecurableType.ApplicationRole: + + result.Append("/ApplicationRole"); + break; + + case SecurableType.Assembly: + + result.Append("/SqlAssembly"); + break; + + case SecurableType.AsymmetricKey: + + result.Append("/AsymmetricKey"); + break; + + case SecurableType.Certificate: + + result.Append("/Certificate"); + break; + + case SecurableType.Database: + + // no additional text needed + break; + + case SecurableType.DatabaseRole: + + result.Append("/Role"); + break; + + case SecurableType.Endpoint: + + result.Append("/Endpoint"); + break; + + case SecurableType.ExtendedStoredProcedure: + + result.Append("/ExtendedStoredProcedure"); + break; + + case SecurableType.ExternalDataSource: + + result.Append("/ExternalDataSource"); + break; + + case SecurableType.ExternalFileFormat: + + result.Append("/ExternalFileFormat"); + break; + + case SecurableType.FullTextCatalog: + + result.Append("/FullTextCatalog"); + break; + + case SecurableType.FunctionInline: + + result.AppendFormat("/UserDefinedFunction[@FunctionType='{0}']", ((int)UserDefinedFunctionType.Inline)); + break; + + case SecurableType.FunctionScalar: + + result.AppendFormat("/UserDefinedFunction[@FunctionType='{0}']", ((int)UserDefinedFunctionType.Scalar)); + break; + + case SecurableType.FunctionTable: + + result.AppendFormat("/UserDefinedFunction[@FunctionType='{0}']", ((int)UserDefinedFunctionType.Table)); + break; + + case SecurableType.Login: + + result.Append("/Login"); + break; + + case SecurableType.ServerRole: + + result.Append("/Role"); + break; + + case SecurableType.Schema: + + result.Append("/Schema"); + break; + + case SecurableType.SecurityPolicy: + + result.Append("/SecurityPolicy"); + break; + + case SecurableType.Server: + + // no additional text needed + break; + + case SecurableType.ServiceQueue: + + result.Append("/ServiceBroker/ServiceQueue"); + break; + + case SecurableType.StoredProcedure: + + result.Append("/StoredProcedure"); + break; + + case SecurableType.SymmetricKey: + + result.Append("/SymmetricKey"); + break; + + case SecurableType.Synonym: + + result.Append("/Synonym"); + break; + + case SecurableType.Sequence: + + result.Append("/Sequence"); + break; + + case SecurableType.Table: + + result.Append("/Table"); + break; + + case SecurableType.User: + + result.Append("/User"); + break; + + case SecurableType.UserDefinedDataType: + + result.Append("/UserDefinedDataType"); + break; + + case SecurableType.UserDefinedTableType: + + result.Append("/UserDefinedTableType"); + break; + + case SecurableType.View: + + result.Append("/View"); + break; + + case SecurableType.XmlSchemaCollection: + + result.Append("/XmlSchemaCollection"); + break; + + case SecurableType.AvailabilityGroup: + + result.Append("/AvailabilityGroup"); + break; + + default: + + // STrace.Assert(false, "Unexpected securable type for this principal type"); + throw new ArgumentException(); + } + + + return result.ToString(); + } + + /// + /// Enumerate related securables and put the securables into the input collection + /// + /// The URN for enumerating the securables + /// The collection into which the securables are to be put + /// for database principals, include isTableType in the query fields + private void AddRelatedSecurables(string urn, SecurableDictionary relatedSecurables, bool isDatabasePrincipal) + { + // STrace.Assert(this.exists, "new principals don't have related securables"); + // STrace.Assert(this.connectionInfo != null, "connectionInfo is not set"); + // STrace.Assert(urn.Length != 0, "urn is empty"); + + String[] fields = null; + if (isDatabasePrincipal) + { + fields = new string[] { "ObjectName", "ObjectSchema", "ObjectClass", "ObjectType", "IsTableType" }; + } + else + { + fields = new string[] { "ObjectName", "ObjectSchema", "ObjectClass", "ObjectType" }; + } + + Enumerator enumerator = new Enumerator(); + Request request = new Request(urn, fields); + DataTable securableTable = enumerator.Process(this.connectionInfo, request); + + for (int securableIndex = 0; securableIndex < securableTable.Rows.Count; ++securableIndex) + { + DataRow securableRow = securableTable.Rows[securableIndex]; + + string objectName = securableRow["ObjectName"].ToString(); + object schemaData = securableRow["ObjectSchema"]; + string objectSchema = (schemaData is DBNull) ? String.Empty : schemaData.ToString(); + ObjectClass objectClass = (ObjectClass)securableRow["ObjectClass"]; + object objectTypeData = securableRow["ObjectType"]; + string objectType = (objectTypeData is DBNull) ? String.Empty : objectTypeData.ToString().Trim(); + + // SMO and SSMS integration not yet complete for security policies, so do not add them to the view + // + if (objectType.Equals("SP", StringComparison.InvariantCultureIgnoreCase)) + { + continue; + } + + bool isTableType = false; + if (isDatabasePrincipal) + { + isTableType = (bool)securableRow["IsTableType"]; + } + + Securable securable = Securable.Create(objectClass, + objectType, + objectName, + objectSchema, + isTableType, + this.databaseName, + this.connectionInfo, + this.serverVersion); + + if (!relatedSecurables.Contains(securable)) + { + relatedSecurables.Add(securable); + securable.Changed += this.OnChanged; + } + } + } + + /// + /// Enumerate securables and put the securables into the input collection + /// + /// The type of securable we are enumerating + /// The URN to enumerate the securables + /// The collection to which new securables are to be added + private void AddSecurables(SecurableType type, string urn, SecurableDictionary securablesCollection) + { + // STrace.Assert(this.connectionInfo != null, "connectionInfo is not set"); + // STrace.Assert(urn.Length != 0, "urn is empty"); + + Enumerator enumerator = new Enumerator(); + String[] fields = new string[] { "Urn" }; + Request request = new Request(urn, fields); + DataTable securableTable = enumerator.Process(this.connectionInfo, request); + + for (int securableIndex = 0; securableIndex < securableTable.Rows.Count; ++securableIndex) + { + DataRow securableRow = securableTable.Rows[securableIndex]; + + Urn securableUrn = new Urn(securableRow["Urn"].ToString()); + string securableName = Urn.UnEscapeString(securableUrn.GetAttribute("Name")); + string securableSchema = securableUrn.GetAttribute("Schema"); + securableSchema = (securableSchema != null) ? Urn.UnEscapeString(securableSchema) : String.Empty; + SecurableKey key = new SecurableKey(securableSchema, securableName, type); + + if (!securablesCollection.Contains(key)) + { + Securable securable = Securable.Create(type, securableUrn.ToString(), this.connectionInfo, this.serverVersion); + securablesCollection.Add(securable); + securable.Changed += this.OnChanged; + } + } + } + + + /// + /// Get the principal type for the input object + /// + /// The SMO object representing the principal + /// >The corresponding PrincipalType + public static PrincipalType GetPrincipalType(SqlSmoObject smoPrincipal) + { + PrincipalType result; + + Type smoPrincipalType = smoPrincipal.GetType(); + + if (typeof(User) == smoPrincipalType) + { + result = PrincipalType.User; + } + else if (typeof(DatabaseRole) == smoPrincipalType) + { + result = PrincipalType.DatabaseRole; + } + else if (typeof(Login) == smoPrincipalType) + { + result = PrincipalType.Login; + } + else if (typeof(ApplicationRole) == smoPrincipalType) + { + result = PrincipalType.ApplicationRole; + } + else if (typeof(ServerRole) == smoPrincipalType) + { + result = PrincipalType.ServerRole; + } + else + { + + // STrace.Assert(false, "smoPrincipal is not a supported principal type"); + throw new ArgumentException(); + } + + return result; + } + + /// + /// Get the principal type for the input object + /// + /// The searchable type for the principal + /// The corresponding PrincipalType + public static PrincipalType GetPrincipalType(SearchableObjectType searchableType) + { + PrincipalType result; + + switch (searchableType) + { + case SearchableObjectType.Login: + + result = PrincipalType.Login; + break; + + case SearchableObjectType.ServerRole: + + result = PrincipalType.ServerRole; + break; + + case SearchableObjectType.User: + + result = PrincipalType.User; + break; + + case SearchableObjectType.DatabaseRole: + + result = PrincipalType.DatabaseRole; + break; + + case SearchableObjectType.ApplicationRole: + + result = PrincipalType.ApplicationRole; + break; + + default: + + // STrace.Assert(false, "searchableType is not a supported principal type"); + throw new ArgumentException(); + } + + return result; + } + + /// + /// Get the searchable object type equivalent to the input principal type + /// + /// + /// + public static SearchableObjectType GetSearchableObjectType(PrincipalType principalType) + { + // TypeCount is an invalid pseudo type + SearchableObjectType result; + + switch (principalType) + { + case PrincipalType.ApplicationRole: + + result = SearchableObjectType.ApplicationRole; + break; + + case PrincipalType.DatabaseRole: + + result = SearchableObjectType.DatabaseRole; + break; + + case PrincipalType.Login: + + result = SearchableObjectType.Login; + break; + + case PrincipalType.ServerRole: + + result = SearchableObjectType.ServerRole; + break; + + case PrincipalType.User: + + result = SearchableObjectType.User; + break; + + default: + + // STrace.Assert(false, "unexpected principal type"); + throw new ArgumentException(); + } + + return result; + } + } + + internal class PrincipalKey : IComparable + { + private string name; + private int principalType; + private bool changesExist; + + internal string Name + { + get + { + return this.name; + } + } + + internal int PrincipalType + { + get + { + return this.principalType; + } + } + + internal bool ChangesExist + { + get + { + return this.changesExist; + } + } + + internal PrincipalKey(Principal principal) + { + this.name = principal.Name; + this.principalType = (int)principal.PrincipalType; + this.changesExist = principal.ChangesExist; + } + + internal PrincipalKey(SearchableObject searchable) + { + this.name = searchable.Name; + this.principalType = (int)Principal.GetPrincipalType(searchable.SearchableObjectType); + this.changesExist = false; + } + + internal PrincipalKey(string name, PrincipalType type) + { + this.name = name; + this.principalType = (int)type; + this.changesExist = false; + } + + internal PrincipalKey(string name, SearchableObjectType searchableType) + { + this.name = name; + this.principalType = (int)Principal.GetPrincipalType(searchableType); + this.changesExist = false; + } + + public override int GetHashCode() + { + string fullname = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.{1}", this.name, this.principalType); + return fullname.GetHashCode(); + } + + public override bool Equals(object obj) + { + bool result = false; + + PrincipalKey other = obj as PrincipalKey; + + if (other != null) + { + result = (this.CompareTo(other) == 0); + } + + return result; + } + + public int CompareTo(object obj) + { + int result = 0; + PrincipalKey other = (PrincipalKey)obj; + + result = String.Compare(this.name, other.name, StringComparison.Ordinal); + + if (0 == result) + { + result = this.principalType - other.principalType; + } + + return result; + } + } + + /// + /// A sorted collection of Principals + /// + internal class PrincipalCollection : ICollection + { + private SortedList data; + + /// + /// Constructor + /// + public PrincipalCollection() + { + data = new SortedList(StringComparer.Ordinal); + } + + public PrincipalCollection(PrincipalComparer comparer) + { + this.data = new SortedList(comparer); + } + + public PrincipalCollection(PrincipalCollection original, PrincipalComparer comparer) + { + if (original.Count != 0) + { + this.data = new SortedList(original.data, comparer); + } + else + { + this.data = new SortedList(comparer); + } + } + + /// + /// Indexer, by numeric index + /// +#pragma warning disable IDE0026 // Use expression body for indexer + public Principal this[int index] + { + get + { + return ((Principal)this.data.GetByIndex(index)); + } + } +#pragma warning restore IDE0026 // Use expression body for indexer + + /// + /// Indexer, by name + /// +#pragma warning disable IDE0026 // Use expression body for indexer + public Principal this[PrincipalKey principalKey] + { + get + { + return ((Principal)this.data[principalKey]); + } + } +#pragma warning restore IDE0026 // Use expression body for indexer + + /// + /// Update the PrincipalKey associated with this principal + /// + /// The principal to update the key of + internal void UpdateKey(Principal principal) + { + this.data.Remove(new PrincipalKey(principal.Name, principal.PrincipalType)); + this.data.Add(new PrincipalKey(principal), principal); + } + + /// + /// Add an object to the collection + /// + /// the object to add + public void Add(Principal value) + { + this.data.Add(new PrincipalKey(value), value); + this.NotifyObservers(); + } + + /// + /// Get the index of the object in the collection + /// + /// The object to search for + /// The object's index + public int IndexOf(Principal principal) + { + return this.data.IndexOfKey(new PrincipalKey(principal)); + } + + /// + /// Remove an object from the collection + /// + /// The object to remove + public void Remove(Principal principal) + { + if (this.Contains(principal)) + { + this.data.Remove(new PrincipalKey(principal)); + } + + this.NotifyObservers(); + } + + public void Remove(SearchableObject searchable) + { + if (this.Contains(searchable)) + { + this.data.Remove(new PrincipalKey(searchable)); + } + + this.NotifyObservers(); + } + + /// + /// Does the collection contain a particular object + /// + /// The name of the object to check for + /// true if the object is in the collection, false otherwise + public bool Contains(Principal principal) + { + return this.data.Contains(new PrincipalKey(principal)); + } + + public bool Contains(SearchableObject principal) + { + return this.data.Contains(new PrincipalKey(principal)); + } + + public bool Contains(PrincipalKey principalKey) + { + return this.data.Contains(principalKey); + } + + /// + /// Notify iterators that the collection has changed + /// + private void NotifyObservers() + { + if (null != this.OnInvalidateEnumerator) + { + this.OnInvalidateEnumerator(); + } + } + + + /// + /// Delegate declaration for delegates that will be called when the collection changes + /// + internal delegate void InvalidateEnumerator(); + /// + /// Event that is fired when the collection changes + /// + internal event InvalidateEnumerator OnInvalidateEnumerator; + + #region ICollection Members + + /// + /// Is access to collection thread-safe? + /// + public bool IsSynchronized + { + get + { + return false; + } + } + + /// + /// How many objects are in the collection? + /// + public int Count + { + get + { + return this.data.Count; + } + } + + /// + /// Copy the collection to an array + /// + /// The target array + /// The array index where copying is to begin + public void CopyTo(Array array, int index) + { + for (int i = 0; i < this.data.Count; ++i) + { + array.SetValue(this.data.GetByIndex(i), index + i); + } + } + + /// + /// The object to be used to lock the collection + /// + public object SyncRoot + { + get + { + return this; + } + } + + + #endregion + + #region IEnumerable Members + + /// + /// Get an enumerator for the collection + /// + /// An enumerator + public IEnumerator GetEnumerator() + { + return new PrincipalCollectionEnumerator(this); + } + + + #endregion + } + + enum PrincipalSortType + { + Name, + Type, + Status + } + + /// + /// Comparer for principals + /// + internal class PrincipalComparer : IComparer + { + internal static PrincipalSortType[] DefaultSortingOrder = + { + PrincipalSortType.Name, + PrincipalSortType.Type, + PrincipalSortType.Status + }; + + private PrincipalSortType[] sortOrder; + private bool ascending; + + /// + /// Constructor + /// + /// Indicate which column to sort + /// Whether to sort in ascending order + public PrincipalComparer(PrincipalSortType[] sortOrder, bool ascending) + { + this.sortOrder = sortOrder; + this.ascending = ascending; + } + + /// + /// Compare two securable keys + /// + /// The first principal + /// The second principal + /// -1 if first is less than second, 0 if first equals second, 1 if second is less than first + public int Compare(object x, object y) + { + int result = 0; + + if (x == null) + { + result = -1; + } + else if (y == null) + { + result = 1; + } + else + { + PrincipalKey principalKey1; + PrincipalKey principalKey2; + + // if not ascending sort, reverse the roles of x and y + if (this.ascending) + { + principalKey1 = (PrincipalKey)x; + principalKey2 = (PrincipalKey)y; + } + else + { + principalKey1 = (PrincipalKey)y; + principalKey2 = (PrincipalKey)x; + } + + int i = 0; + + while (0 == result && i < this.sortOrder.Length) + { + switch (this.sortOrder[i]) + { + case PrincipalSortType.Name: + + result = String.Compare( + principalKey1.Name, + principalKey2.Name, + StringComparison.CurrentCulture); + break; + + case PrincipalSortType.Type: + + result = principalKey1.PrincipalType - principalKey2.PrincipalType; + break; + + case PrincipalSortType.Status: + + if (!principalKey1.ChangesExist && principalKey2.ChangesExist) + { + result = -1; + } + else if (principalKey1.ChangesExist && !principalKey2.ChangesExist) + { + result = 1; + } + break; + + default: + // STrace.Assert(true, "Unknown PrincipalSortType"); + result = 0; + break; + } + + ++i; + } + } + + return result; + } + + } + + /// + /// An enumerator for PrincipalCollections + /// + internal class PrincipalCollectionEnumerator : IEnumerator + { + private PrincipalCollection collection; + private int currentIndex; + private Principal currentObject; + private bool isValid; + + /// + /// Constructor + /// + /// The collection to enumerate + internal PrincipalCollectionEnumerator(PrincipalCollection collection) + { + this.collection = collection; + this.currentIndex = -1; + this.currentObject = null; + this.isValid = true; + + this.collection.OnInvalidateEnumerator += new PrincipalCollection.InvalidateEnumerator(this.Invalidate); + } + + + /// + /// The method the collection should call when the collection's state changes + /// + internal void Invalidate() + { + this.isValid = false; + } + + + #region IEnumerator Members + + /// + /// Set the enumerator index to "before the start" + /// + public void Reset() + { + if (!this.isValid) + { + // STrace.Assert(false, "The enumerator has been invalidated."); + throw new InvalidOperationException(); + } + + this.currentIndex = -1; + this.currentObject = null; + } + + /// + /// The current SqlObject + /// + public object Current + { + get + { + if (this.currentIndex < 0) + { + // STrace.Assert(false, "The enumerator is positioned before start of collection. Did you forget to call MoveNext()?"); + throw new InvalidOperationException(); + } + + if (null == this.currentObject) + { + // STrace.Assert(false, "There is no current object. Did you forget to check the result of MoveNext()?"); + throw new InvalidOperationException(); + } + + return this.currentObject; + } + } + + /// + /// Move to the next object in the colection + /// + /// True if there was a next object, false otherwise + public bool MoveNext() + { + if (!this.isValid) + { + // STrace.Assert(false, "The enumerator has been invalidated."); + throw new InvalidOperationException(); + } + + bool result = false; + + if (this.currentIndex < (this.collection.Count - 1)) + { + ++(this.currentIndex); + this.currentObject = this.collection[this.currentIndex]; + result = true; + } + + return result; + } + + #endregion + } + + /// + /// The relationship between a securable, a principal, and a grant state. + /// + internal class PermissionState : IComparable + { + private Permission permission; + private Securable securable; + private Principal principal; + private string grantor; + + private PermissionStatus originalState; + private PermissionStatus currentState; + private PermissionDisplayStatus displayState; + private ArrayList children = null; + private PermissionState parent = null; + private bool settingState = false; + + private event EventHandler observableChanged; + private event PermissionStateChangedEventHandler permissionStateChanged; + + /// + /// The permission role-player + /// + public Permission Permission + { + get + { + return this.permission; + } + } + + public string Grantor + { + get { return grantor; } + } + + /// + /// The securable role-player + /// + public Securable Securable + { + get + { + return this.securable; + } + } + + /// + /// The principal role-player + /// + public Principal Principal + { + get + { + return this.principal; + } + } + + /// + /// determines if we need to issue CASCADE with a deny or revoke + /// + public bool CascadeNeeded + { + get + { + bool cascade = this.OriginalState == PermissionStatus.WithGrant; + if (!cascade && this.HasChildren) + { + IEnumerator e = this.children.GetEnumerator(); + e.Reset(); + + while (e.MoveNext()) + { + PermissionState ps = (PermissionState)e.Current; + if (ps.OriginalState == PermissionStatus.WithGrant) + { + cascade = true; + break; + } + } + } + return cascade; + } + } + + /// + /// The grant-state of the permission relationship + /// + public PermissionStatus State + { + get + { + return this.currentState; + } + set + { + if (value != this.currentState) + { + this.settingState = true; + PermissionStatus oldState = this.currentState; + PermissionDisplayStatus oldDisplayState = this.displayState; + this.currentState = value; + + switch (this.currentState) + { + case PermissionStatus.Grant: + + this.displayState = PermissionDisplayStatus.Grant; + break; + + case PermissionStatus.WithGrant: + + this.displayState = PermissionDisplayStatus.WithGrant; + break; + + case PermissionStatus.Deny: + + this.displayState = PermissionDisplayStatus.Deny; + break; + + case PermissionStatus.Revoke: + + this.displayState = PermissionDisplayStatus.Revoke; + break; + } + + this.NotifyObservers(oldState, oldDisplayState); + this.settingState = false; + } + } + } + + /// + /// The original grant-state of the permission relationship + /// + public PermissionStatus OriginalState + { + get + { + return this.originalState; + } + } + + /// + /// The display state for the permission relationship in the UI + /// + public PermissionDisplayStatus DisplayState + { + get + { + return this.displayState; + } + } + + /// + /// Has the user changed the grant-state of this permission? + /// + public bool StateChanged + { + get + { + return (this.originalState != this.currentState); + } + } + + /// + /// Whether the user has removed the Permission state in the UI + /// + public bool IsRemoved + { + get + { + return (this.principal.IsRemoved || this.securable.IsRemoved); + } + } + + /// + /// Does this PermissionState have child states + /// + public bool HasChildren + { + get + { + return ((this.children != null) && (this.children.Count != 0)); + } + } + + /// + /// The parent PermissionState (e.g. if this permission state is for a column, Parent is the permission state of the parent table) + /// + public PermissionState Parent + { + get + { + return this.parent; + } + + set + { + // STrace.Assert(null == this.parent, "parent has already been set"); + this.parent = value; + this.parent.PermissionStateChanged += new PermissionStateChangedEventHandler(this.OnParentStateChanged); + } + } + + + /// + /// Constructor + /// + /// The securable in the relationship + /// The principal in the relationship + /// The permission in the relationship + /// The permission status of the relationship + /// + public PermissionState(Securable securable, + Principal principal, + Permission permission, + PermissionStatus state, + string grantor) + { + this.permission = permission; + this.principal = principal; + this.securable = securable; + this.currentState = state; + this.originalState = state; + this.grantor = grantor; + this.DetermineDisplayState(); + } + + + /// + /// Put the permission into the right category + /// + /// Set of granted permissions + /// + /// Set of denied permissions + /// Set of revoked permissions + public void AssignChange(List grants, + List withGrants, + List denies, + List revokes) + { + if (this.StateChanged) + { + PermissionStatus effectiveCurrentState = this.currentState; + + switch (effectiveCurrentState) + { + case PermissionStatus.Grant: + grants.Add(this); + break; + + case PermissionStatus.WithGrant: + withGrants.Add(this); + break; + + case PermissionStatus.Deny: + denies.Add(this); + break; + + default: + // STrace.Assert((PermissionStatus.Revoke == this.State), "unexpected permission state"); + revokes.Add(this); + break; + } + } + } + + /// + /// Revoke all this permission and all child permissions + /// + public void Revoke() + { + if (PermissionDisplayStatus.Revoke != this.displayState) + { + this.settingState = true; + + PermissionStatus oldState = this.currentState; + PermissionDisplayStatus oldDisplayState = this.displayState; + + this.currentState = PermissionStatus.Revoke; + this.displayState = PermissionDisplayStatus.Revoke; + + // there are two kinds of observers: those interested in modifying there own state + // to reflect changes in this object's state, and those who only need to know that + // something has changed. Notify both kinds of observers of the state change. + this.NotifyObservers(oldState, oldDisplayState); + this.NotifyObservers(); + + this.settingState = false; + } + } + + /// + /// Toggle the grant-state between Grant and not-Grant + /// + /// + /// This supposed to handle click events on the "Allow" check-box in the UI. + /// + /// If the current state is Grant (or effectively Grant), transition to Revoke + /// If the current state is Revoke or Deny (or effectively Deny), transition to Grant + /// If the current state is indeterminate, transition to Grant + /// + public void ToggleGrant(bool withGrant) + { + this.settingState = true; + + PermissionStatus oldState = this.currentState; + PermissionDisplayStatus oldDisplayState = this.displayState; + + PermissionStatus effectiveState = this.GetEffectiveState(); + + PermissionStatus stateToToggle = withGrant ? + PermissionStatus.WithGrant : + PermissionStatus.Grant; + + if (stateToToggle == effectiveState && withGrant) + { + this.currentState = PermissionStatus.Grant; + this.displayState = PermissionDisplayStatus.Grant; + } + else if (stateToToggle == effectiveState || + (!withGrant && effectiveState == PermissionStatus.WithGrant)) + { + this.currentState = PermissionStatus.Revoke; + this.displayState = PermissionDisplayStatus.Revoke; + } + else + { + this.currentState = stateToToggle; + this.displayState = withGrant ? + PermissionDisplayStatus.WithGrant : + PermissionDisplayStatus.Grant; + } + + // there are two kinds of observers: those interested in modifying there own state + // to reflect changes in this object's state, and those who only need to know that + // something has changed. Notify both kinds of observers of the state change. + this.NotifyObservers(oldState, oldDisplayState); + this.NotifyObservers(); + + this.settingState = false; + } + + /// + /// Toggle the grant-state between Deny and not-Deny + /// + /// + /// This supposed to handle click events on the "Deny" check-box in the UI. + /// + /// If the current state is Deny (or effectively Deny), transition to Revoke + /// If the current state is Revoke or Grant (or effectively Grant), transition to Deny + /// If the current state is indeterminate, transition to Deny + /// + public void ToggleDeny() + { + this.settingState = true; + + PermissionStatus oldState = this.currentState; + PermissionDisplayStatus oldDisplayState = this.displayState; + + PermissionStatus effectiveState = this.GetEffectiveState(); + + if (PermissionStatus.Deny == effectiveState) + { + this.currentState = PermissionStatus.Revoke; + this.displayState = PermissionDisplayStatus.Revoke; + } + else + { + this.currentState = PermissionStatus.Deny; + this.displayState = PermissionDisplayStatus.Deny; + } + + // there are two kinds of observers: those interested in modifying there own state + // to reflect changes in this object's state, and those who only need to know that + // something has changed. Notify both kinds of observers of the state change. + this.NotifyObservers(oldState, oldDisplayState); + this.NotifyObservers(); + + this.settingState = false; + } + + /// + /// Add a child permission state to the child collection and hook up notifications + /// + /// The child to add + internal void AddChild(PermissionState child) + { + if (null == this.children) + { + this.children = new ArrayList(); + } + + child.Parent = this; + this.children.Add(child); + this.DetermineDisplayState(); + child.PermissionStateChanged += new PermissionStateChangedEventHandler(this.OnChildStateChanged); + } + + /// + /// Set the display state to whatever it should be for this object's grant-state + /// and the grant-state of all its children + /// + private void DetermineDisplayState() + { + // if there are no children, display state is the same as state + if (!this.HasChildren) + { + switch (this.currentState) + { + case PermissionStatus.Revoke: + this.displayState = PermissionDisplayStatus.Revoke; + break; + + case PermissionStatus.Grant: + this.displayState = PermissionDisplayStatus.Grant; + break; + + case PermissionStatus.WithGrant: + this.displayState = PermissionDisplayStatus.WithGrant; + break; + + default: + // STrace.Assert(PermissionStatus.Deny == this.currentState, "unexpected permission status"); + this.displayState = PermissionDisplayStatus.Deny; + break; + } + } + else + { + // if there are children + // - display state is INDETERMINATE if some children are GRANTED and some are DENIED + // - display state is PARTIALLY GRANTED if some children are GRANTED and the rest are REVOKED + // - display state is PARTIALLY DENIED if some children are DENIED and the rest are REVOKED + // - display state is GRANTED if the parent is GRANTED or if ALL the children are GRANTED + // - display state is DENIED if the parent is DENIED or if ALL the children are DENIED + // - display state is REVOKED if the parent is REVOKED and ALL the children are REVOKED as well + + bool anyChildrenRevoked = false; + bool anyChildrenGranted = false; + bool anyChildrenWithGrant = false; + bool anyChildrenDenied = false; + + IEnumerator childEnumerator = this.children.GetEnumerator(); + childEnumerator.Reset(); + + while (childEnumerator.MoveNext()) + { + PermissionState childState = (PermissionState)childEnumerator.Current; + + if (PermissionStatus.Deny == childState.State) + { + anyChildrenDenied = true; + } + else if (PermissionStatus.WithGrant == childState.State) + { + anyChildrenWithGrant = true; + } + else if (PermissionStatus.Grant == childState.State) + { + anyChildrenGranted = true; + } + else + { + anyChildrenRevoked = true; + } + + if (anyChildrenWithGrant && anyChildrenDenied && anyChildrenGranted && anyChildrenRevoked) + { + break; + } + } + + bool allChildrenDenied = (!anyChildrenGranted && !anyChildrenRevoked && !anyChildrenWithGrant); + bool allChildrenGranted = (!anyChildrenDenied && !anyChildrenRevoked && !anyChildrenWithGrant); + bool allChildrenRevoked = (!anyChildrenGranted && !anyChildrenDenied && !anyChildrenWithGrant); + bool allChildrenWithGrant = (!anyChildrenGranted && !anyChildrenRevoked && !anyChildrenDenied); + + // if (this state is DENY) then ((all children are denied) or (all children are revoked)) + // STrace.Assert((PermissionStatus.Deny != this.currentState) || (allChildrenDenied || allChildrenRevoked), "conflicting parent and child object permissions detected"); + + // if (this state is GRANT) then ((all children are granted) or (all children are revoked)) + // STrace.Assert((PermissionStatus.Grant != this.currentState) || (allChildrenGranted || allChildrenRevoked), "conflicting parent and child object permissions detected"); + + if (anyChildrenWithGrant && anyChildrenDenied) + { + this.displayState = PermissionDisplayStatus.Indeterminate; + } + else if (anyChildrenWithGrant && anyChildrenRevoked) + { + this.displayState = PermissionDisplayStatus.PartialWithGrant; + } + else if (anyChildrenDenied && anyChildrenGranted && anyChildrenRevoked) + { + this.displayState = PermissionDisplayStatus.PartialGrantDeny; + } + else if (anyChildrenGranted && anyChildrenRevoked) + { + this.displayState = PermissionDisplayStatus.PartialGrant; + } + else if (anyChildrenDenied && anyChildrenRevoked) + { + this.displayState = PermissionDisplayStatus.PartialDeny; + } + else if (anyChildrenWithGrant || (PermissionStatus.WithGrant == this.currentState)) + { + this.displayState = PermissionDisplayStatus.WithGrant; + } + else if (anyChildrenGranted || (PermissionStatus.Grant == this.currentState)) + { + this.displayState = PermissionDisplayStatus.Grant; + } + else if (anyChildrenDenied || (PermissionStatus.Deny == this.currentState)) + { + this.displayState = PermissionDisplayStatus.Deny; + } + else + { + this.displayState = PermissionDisplayStatus.Revoke; + } + } + } + + /// + /// Get the effective state (e.g. GRANT if state is GRANT or if all the children are GRANTED) + /// + /// The effective state + private PermissionStatus GetEffectiveState() + { + // if there are no child objects, the effective state is just the current state + // if there are children and the display state is not "partial", then effective state is display state + // if there are children and the display state is "partial", then effective state is "REVOKE" + PermissionStatus result = PermissionStatus.Revoke; + + if (!this.HasChildren) + { + result = this.currentState; + } + else + { + switch (this.displayState) + { + case PermissionDisplayStatus.Grant: + result = PermissionStatus.Grant; + break; + + case PermissionDisplayStatus.WithGrant: + result = PermissionStatus.WithGrant; + break; + + case PermissionDisplayStatus.Deny: + result = PermissionStatus.Deny; + break; + + default: + result = PermissionStatus.Revoke; + break; + } + } + + return result; + } + + /// + /// Handle change events on child PermissionStates + /// + /// The child that changed + /// The new state of the child + /// The old state of the child + /// The new display state of the child + /// The old display state of the child + internal void OnChildStateChanged(PermissionState sender, + PermissionStatus childNewStatus, + PermissionStatus childOldStatus, + PermissionDisplayStatus childNewDisplayStatus, + PermissionDisplayStatus childOldDisplayStatus) + { + if (!this.settingState && (childNewStatus != childOldStatus)) + { + PermissionStatus oldStatus = this.currentState; + PermissionDisplayStatus oldDisplayStatus = this.displayState; + this.currentState = PermissionStatus.Revoke; + + this.DetermineDisplayState(); + + if ((oldStatus != this.currentState) || (oldDisplayStatus != this.displayState)) + { + this.settingState = true; + this.NotifyObservers(oldStatus, oldDisplayStatus); + this.settingState = false; + } + + this.NotifyObservers(); + } + } + + /// + /// Handle change events on parent PermissionStates + /// + /// The parent that changed + /// The new state of the parent + /// The old state of the parent + /// The new display state of the parent + /// The old display state of the parent + private void OnParentStateChanged(PermissionState sender, + PermissionStatus parentNewStatus, + PermissionStatus parentOldStatus, + PermissionDisplayStatus parentNewDisplayStatus, + PermissionDisplayStatus parentOldDisplayStatus) + { + // revoke permission if parent changes were not caused by changes to this object, parent state + // actually changed and wasn't just a display changed, and if this permission isn't already revoked + + if (!this.settingState && + (parentNewStatus != parentOldStatus) && + (PermissionDisplayStatus.Revoke != this.displayState)) + { + this.settingState = true; + + // parent status has changed, so all children are to be revoked + PermissionStatus oldStatus = this.currentState; + PermissionDisplayStatus oldDisplayStatus = this.displayState; + this.currentState = PermissionStatus.Revoke; + + this.DetermineDisplayState(); + + this.NotifyObservers(oldStatus, oldDisplayStatus); + this.settingState = false; + } + } + + + + #region IComparable Members + /// + /// Determine whether this object is less than, equal to, or greater than another object + /// + /// The object to compare + /// Less than 0 if this is less, 0 if equal, greater than 0 if this is greater + public int CompareTo(object obj) + { + // STrace.Assert(typeof(PermissionState) == obj.GetType(), "unexpected object type"); + + PermissionState other = (PermissionState)obj; + return this.permission.Name.CompareTo(other.permission.Name); + } + + #endregion + + + public static void AddChildrenToEmptyParents(PermissionStateCollection states) + { + for (int i = 0; i < states.Count; ++i) + { + // + // loop through all states that have children + // + if (states[i].HasChildren) + { + // + // find all other states that: + // 1. map to the same permission + // 2. have a grantor + // + for (int j = 0; j < states.Count; ++j) + { + if (i != j && + !string.IsNullOrEmpty(states[j].Grantor) && + states[i].Permission.Name == states[j].Permission.Name) + { + // + // copy any children present in i that are not in j, + // all with Revoked status + // + foreach (PermissionState ps in states[i].children) + { + // see if j already has this child + bool hasThisChild = false; + if (states[j].HasChildren) + { + foreach (PermissionState ps2 in states[j].children) + { + if (ps.Securable.Name == ps2.Securable.Name && + ps.Permission.Name == ps2.Permission.Name) + { + hasThisChild = true; + break; + } + } + } + if (!hasThisChild) + { + PermissionState child = new PermissionState(ps.Securable, + ps.Principal, + ps.Permission, + PermissionStatus.Revoke, + states[j].Grantor); + states[j].AddChild(child); + } + } + break; + } + } + } + } + } + + /// + /// Create the set of PermissionStates relating securable to principal. Child permission states, if any, + /// are created as well. The permission state relationship instances are added to the securable's and principal's + /// PermissionState collections. + /// + /// The securable in the relationships + /// The principal in the relationships + static public void PopulatePermissionStates(Securable securable, Principal principal) + { + PermissionStateCollection permissionStates = GetPermissionStates(securable, principal); + + for (int permissionStateIndex = 0; + permissionStateIndex < permissionStates.Count; + ++permissionStateIndex) + { + PermissionState permissionState = permissionStates[permissionStateIndex]; + + securable.AddPermissionState(permissionState); + principal.AddPermissionState(permissionState); + + AddPermissionStateToParent(securable, principal, permissionState); + } + + PopulateChildPermissionStates(securable, principal); + } + + /// + /// If the permission state should be a child of some other permission state, add the child to the parent's collection + /// + /// The securable in the relationships + /// The principal in the relationships + /// The (possible) child permission state + static private void AddPermissionStateToParent(Securable securable, + Principal principal, + PermissionState child) + { + if (securable.Parent != null) + { + PermissionStateCollection parentStates = securable.Parent.GetPermissionStates(principal); + // STrace.Assert(parentStates != null, "parent securable did not have permissions populated for principal."); + + PermissionState parentState = parentStates[child.Permission.Name + child.Grantor]; + if (parentState == null) + { + // parent doesn't exist, create it. + parentState = new PermissionState(securable.Parent, + child.Principal, + child.Permission, + PermissionStatus.Revoke, + child.Grantor); + + securable.Parent.AddPermissionState(parentState); + principal.AddPermissionState(parentState); + } + parentState.AddChild(child); + } + } + + /// + /// If the securable has child columns, create the child permission states relating the columns to the principal + /// + /// The securable whose children we are hooking up + /// The principal to whom the children are to be hooked + static private void PopulateChildPermissionStates(Securable securable, Principal principal) + { + if (securable.Children.Count != 0) + { + IEnumerator childEnumerator = securable.Children.GetEnumerator(); + childEnumerator.Reset(); + + while (childEnumerator.MoveNext()) + { + Securable child = (Securable)childEnumerator.Current; + PopulatePermissionStates(child, principal); + } + } + } + + /// + /// Create the set of permission states relating securable to principal + /// + /// The securable in the relationships + /// The principal in the relationships + /// The set of permission state relationship objects that was created + static private PermissionStateCollection GetPermissionStates(Securable securable, + Principal principal) + { + PermissionStateCollection result = new PermissionStateCollection(); + + GetGrantedOrDeniedPermissions(securable, principal, result); + GetRevokedPermissions(securable, principal, result); + + return result; + } + + /// + /// Enumerate granted and denied permissions on the securable for the principal and create permission states for them + /// + /// The securable in the relationships + /// The principal in the relationships + /// The collection into which the new PermissionStates are to be added + static private void GetGrantedOrDeniedPermissions(Securable securable, + Principal principal, + PermissionStateCollection permissionStates) + { + // add granted/denied permissions to the result + if (securable.Exists && principal.Exists) + { + // enumerate granted/denied permissions for the principal + string permissionsUrn = String.Format(System.Globalization.CultureInfo.InvariantCulture, + "{0}/Permission[@Grantee='{1}']", + securable.Urn.ToString(), + Urn.EscapeString(principal.Name)); + + string[] fields = new string[] { "PermissionState", "Code", "Grantor" }; + Request request = new Request(new Urn(permissionsUrn), fields); + DataTable table = new Enumerator().Process(securable.ConnectionInfo, request); + + // process enumeration results + for (int rowIndex = 0; rowIndex < table.Rows.Count; ++rowIndex) + { + DataRow row = table.Rows[rowIndex]; + + // get result data + PermissionStatus state = GetGrantStatusFromEnumeratorResult(row); + Permission permission = GetPermissionFromEnumeratorResult(securable, row); + + string grantor = string.Empty; + object o = row["Grantor"]; + if (o != null) + { + grantor = o.ToString(); + } + + if ((permission != null)) + { + // create the PermissionState + PermissionState permissionState = new PermissionState(securable, + principal, + permission, + state, + grantor); + + // add the PermissionState to the collection + permissionStates.Add(permissionState); + } + } + } + } + + /// + /// Add permissions that are revoked on the securable for the principal to the collection + /// + /// The securable in the relationships + /// The principal in the relationships + /// The collection into which the new PermissionStates are to be added + static private void GetRevokedPermissions(Securable securable, + Principal principal, + PermissionStateCollection permissionStates) + { + // add the revoked permissions to the result + for (int permissionIndex = 0; + permissionIndex < securable.RelevantPermissions.Count; + ++permissionIndex) + { + Permission permission = (Permission)securable.RelevantPermissions[permissionIndex]; + + if ((permission != null)) + { + string expectedGrantor = string.Empty; + if (!string.IsNullOrEmpty(securable.ExpectedGrantor)) + { + expectedGrantor = securable.ExpectedGrantor; + } + else if (securable.Parent != null && !string.IsNullOrEmpty(securable.Parent.ExpectedGrantor)) + { + expectedGrantor = securable.Parent.ExpectedGrantor; + } + + if (!permissionStates.Contains(permission.Name + expectedGrantor)) + { + PermissionState permissionState = new PermissionState(securable, + principal, + permission, + PermissionStatus.Revoke, + expectedGrantor); + permissionStates.Add(permissionState); + } + } + } + } + + /// + /// Extract the permission from the data row + /// + /// The securable whose permissions are being enumerated + /// The data row returned by the enumerator + /// The Permission corresponding to the enumerator result + static private Permission GetPermissionFromEnumeratorResult(Securable securable, DataRow permissionRow) + { + Permission result = null; + + switch (securable.SecurableType) + { + case SecurableType.Server: + + result = Permission.GetPermission((Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue)permissionRow["Code"]); + break; + + case SecurableType.Database: + + result = Permission.GetPermission((Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue)permissionRow["Code"]); + break; + + default: + + result = Permission.GetPermission((Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue)permissionRow["Code"]); + break; + } + + return result; + } + + /// + /// Extract the grant status (Granted or Denied) from the data row + /// + /// The data row returned by the enumerator + /// The grant status corresponding to the enumerator result + static private PermissionStatus GetGrantStatusFromEnumeratorResult(DataRow permissionRow) + { + Microsoft.SqlServer.Management.Smo.PermissionState smoState = (Microsoft.SqlServer.Management.Smo.PermissionState)permissionRow["PermissionState"]; + PermissionStatus result; + + switch (smoState) + { + case Microsoft.SqlServer.Management.Smo.PermissionState.Grant: + result = PermissionStatus.Grant; + break; + + case Microsoft.SqlServer.Management.Smo.PermissionState.GrantWithGrant: + result = PermissionStatus.WithGrant; + break; + + case Microsoft.SqlServer.Management.Smo.PermissionState.Deny: + result = PermissionStatus.Deny; + break; + + default: + // STrace.Assert(smoState == Microsoft.SqlServer.Management.Smo.PermissionState.Revoke, "unexpected smo permission state"); + result = PermissionStatus.Revoke; + break; + } + + return result; + } + + + /// + /// Property to access the observable event. + /// + internal event EventHandler Changed + { + add { this.observableChanged += value; } + remove { this.observableChanged -= value; } + } + + /// + /// Event for detailed state change notifications, informs listeners of what changed + /// + internal event PermissionStateChangedEventHandler PermissionStateChanged + { + add { this.permissionStateChanged += value; } + remove { this.permissionStateChanged -= value; } + } + + /// + /// Notify all observers that this object has changed. + /// + /// The object that changed + /// Hint for the notification, usually null + private void NotifyObservers(object sender, EventArgs e) + { + if (this.observableChanged != null) + { + this.observableChanged(sender, e); + } + } + + /// + /// Notify all observers that this object or one of its children has changed. + /// + private void NotifyObservers() + { + this.NotifyObservers(this, new EventArgs()); + } + + + /// + /// Inform observers of state changes on this object + /// + /// The state before the change + /// The display state before the change + private void NotifyObservers(PermissionStatus oldState, PermissionDisplayStatus oldDisplayState) + { + if (this.permissionStateChanged != null) + { + this.permissionStateChanged(this, this.currentState, oldState, this.displayState, oldDisplayState); + } + } + + } + + /// + /// Permission state changed event delegate + /// + internal delegate void PermissionStateChangedEventHandler( + PermissionState sender, + PermissionStatus newStatus, + PermissionStatus oldStatus, + PermissionDisplayStatus newDisplayStatus, + PermissionDisplayStatus oldDisplayStatus); + + + /// + /// A sorted collection of PermissionState objects + /// + internal class PermissionStateCollection : ICollection + { + private SortedList data; + + /// + /// Constructor + /// + public PermissionStateCollection() + { + data = new SortedList(); + } + + /// + /// Indexer, by numeric index + /// +#pragma warning disable IDE0026 // Use expression body for indexer + public PermissionState this[int index] + { + get + { + return ((PermissionState)this.data.GetByIndex(index)); + } + } +#pragma warning restore IDE0026 // Use expression body for indexer + + /// + /// Indexer, by permission + /// +#pragma warning disable IDE0026 // Use expression body for indexer + public PermissionState this[string key] + { + get + { + return ((PermissionState)this.data[key]); + } + } +#pragma warning restore IDE0026 // Use expression body for indexer + + /// + /// Add an object to the collection + /// + /// the object to add + public void Add(PermissionState value) + { + this.data.Add(value.Permission.Name + value.Grantor, value); + this.NotifyObservers(); + } + + /// + /// Get the index of the object in the collection + /// + /// The object for which to find the index + /// The object's index + public int IndexOf(string key) + { + return this.data.IndexOfKey(key); + } + + /// + /// Remove an object from the collection + /// + /// The object to remove + public void Remove(string key) + { + if (this.data.Contains(key)) + { + this.data.Remove(key); + } + + this.NotifyObservers(); + } + + /// + /// Does the collection contain a particular object + /// + /// The object for which to check + /// true if the object is in the collection, false otherwise + public bool Contains(string key) + { + return this.data.Contains(key); + } + + /// + /// Notify iterators that the collection has changed + /// + private void NotifyObservers() + { + if (null != this.OnInvalidateEnumerator) + { + this.OnInvalidateEnumerator(); + } + } + + + /// + /// Delegate declaration for delegates that will be called when the collection changes + /// + internal delegate void InvalidateEnumerator(); + /// + /// Event that is fired when the collection changes + /// + internal event InvalidateEnumerator OnInvalidateEnumerator; + + #region ICollection Members + + /// + /// Is access to collection thread-safe? + /// + public bool IsSynchronized + { + get + { + return false; + } + } + + /// + /// How many objects are in the collection? + /// + public int Count + { + get + { + return this.data.Count; + } + } + + /// + /// Copy the collection to an array + /// + /// The target array + /// The array index where copying is to begin + public void CopyTo(Array array, int index) + { + for (int i = 0; i < this.data.Count; ++i) + { + array.SetValue(this.data.GetByIndex(i), index + i); + } + } + + /// + /// The object to be used to lock the collection + /// + public object SyncRoot + { + get + { + return this; + } + } + + + #endregion + + #region IEnumerable Members + + /// + /// Get an enumerator for the collection + /// + /// An enumerator + public IEnumerator GetEnumerator() + { + return new PermissionStateCollectionEnumerator(this); + } + + + #endregion + } + + /// + /// An enumerator for PermissionStateCollections + /// + internal class PermissionStateCollectionEnumerator : IEnumerator + { + private PermissionStateCollection collection; + private int currentIndex; + private PermissionState currentObject; + private bool isValid; + + /// + /// Constructor + /// + /// The collection to enumerate + internal PermissionStateCollectionEnumerator(PermissionStateCollection collection) + { + this.collection = collection; + this.currentIndex = -1; + this.currentObject = null; + this.isValid = true; + + this.collection.OnInvalidateEnumerator += new PermissionStateCollection.InvalidateEnumerator(this.Invalidate); + } + + + /// + /// The method the collection should call when the collection's state changes + /// + internal void Invalidate() + { + this.isValid = false; + } + + + #region IEnumerator Members + + /// + /// Set the enumerator index to "before the start" + /// + public void Reset() + { + if (!this.isValid) + { + // STrace.Assert(false, "The enumerator has been invalidated."); + throw new InvalidOperationException(); + } + + this.currentIndex = -1; + this.currentObject = null; + } + + /// + /// The current SqlObject + /// + public object Current + { + get + { + if (this.currentIndex < 0) + { + // STrace.Assert(false, "The enumerator is positioned before start of collection. Did you forget to call MoveNext()?"); + throw new InvalidOperationException(); + } + + if (null == this.currentObject) + { + // STrace.Assert(false, "There is no current object. Did you forget to check the result of MoveNext()?"); + throw new InvalidOperationException(); + } + + return this.currentObject; + } + } + + /// + /// Move to the next object in the colection + /// + /// True if there was a next object, false otherwise + public bool MoveNext() + { + if (!this.isValid) + { + // STrace.Assert(false, "The enumerator has been invalidated."); + throw new InvalidOperationException(); + } + + bool result = false; + + if (this.currentIndex < (this.collection.Count - 1)) + { + ++(this.currentIndex); + this.currentObject = this.collection[this.currentIndex]; + result = true; + } + + return result; + } + + #endregion + } + + /// + /// A SQL Server permission. Use one of the static properties (e.g. Permission.Alter) to acquire a permission instance. + /// + /// + /// Permissions are inherently immutable - how do you change the "EXECUTE" permission in SQL? + /// + internal class Permission : IComparable + { + // TODO: create subclasses as needed to handle disjoint SMO permission classes + + private string name; + private ObjectPermission smoObjectPermission; + private DatabasePermission smoDatabasePermission; + private ServerPermission smoServerPermission; + + /// + /// Constructor + /// + /// The name of the permission + /// The SMO object permission equivalent + /// The SMO database permission equivalent + private Permission( + string name, + ObjectPermission objectPermission, + DatabasePermission databasePermission) + { + this.name = name; + this.smoObjectPermission = objectPermission; + this.smoDatabasePermission = databasePermission; + this.smoServerPermission = null; + } + + + /// + /// Constructor + /// + /// The name of the permission + /// The SMO database permission equivalent + private Permission( + string name, + DatabasePermission databasePermission) + { + this.name = name; + this.smoObjectPermission = null; + this.smoDatabasePermission = databasePermission; + this.smoServerPermission = null; + } + + + /// + /// Constructor + /// + /// The name of the permission + /// The SMO server permission equivalent + private Permission( + string name, + ServerPermission serverPermission) + { + this.name = name; + this.smoObjectPermission = null; + this.smoDatabasePermission = null; + this.smoServerPermission = serverPermission; + } + + + + /// + /// The name of the permission + /// + public string Name + { + get + { + return this.name; + } + } + + /// + /// The equivalent SMO object permission + /// + public ObjectPermission SmoObjectPermission + { + get + { + return this.smoObjectPermission; + } + } + + /// + /// The equivalent SMO database permission + /// + public DatabasePermission SmoDatabasePermission + { + get + { + return this.smoDatabasePermission; + } + } + + /// + /// The equivaletn SMO server permission + /// + public ServerPermission SmoServerPermission + { + get + { + return this.smoServerPermission; + } + } + + + #region IComparable Members + + public int CompareTo(object obj) + { + return this.Name.CompareTo(((Permission)obj).Name); + } + + + #endregion + + #region static fields and methods + + // initialization flags + private static bool objectPermissionsPopulated = false; + private static bool databasePermissionsPopulated = false; + private static bool serverPermissionsPopulated = false; + + /// + /// Get the Permission equivalent to the SMO ObjectPermissionSetValue + /// + /// The permission to find + /// The corresponding Permission instance + public static Permission GetPermission(Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue permissionValue) + { + Permission result = null; + + switch (permissionValue) + { + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Alter: + + result = Permission.Alter; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Connect: + + result = Permission.Connect; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Control: + + result = Permission.Control; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Delete: + + result = Permission.Delete; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Execute: + + result = Permission.Execute; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Impersonate: + + result = Permission.Impersonate; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Insert: + + result = Permission.Insert; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Receive: + + result = Permission.Receive; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.References: + + result = Permission.References; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Select: + + result = Permission.Select; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Send: + + result = Permission.Send; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.TakeOwnership: + + result = Permission.TakeOwnership; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.Update: + + result = Permission.Update; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.ViewDefinition: + + result = Permission.ViewDefinition; + break; + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.ViewChangeTracking: + + result = Permission.ViewChangeTracking; + break; + + case Microsoft.SqlServer.Management.Smo.ObjectPermissionSetValue.CreateSequence: + + result = Permission.createSequence; + break; + + + default: + + string message = String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unexpected ObjectPermissionSetValue: {0}", permissionValue); + // STrace.Assert(false, message); + break; + + } + + return result; + + } + + /// + /// Get the Permission equivalent to the SMO DatabasePermissionSetValue + /// + /// The permission to find + /// The corresponding Permission instance + public static Permission GetPermission(Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue permissionValue) + { + Permission result = null; + + switch (permissionValue) + { + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Alter: + + result = Permission.Alter; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyApplicationRole: + + result = Permission.AlterAnyApplicationRole; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyAssembly: + + result = Permission.AlterAnyAssembly; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyAsymmetricKey: + + result = Permission.AlterAnyAsymmetricKey; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyCertificate: + + result = Permission.AlterAnyCertificate; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyDatabaseAudit: + + result = Permission.AlterAnyDatabaseAudit; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyContract: + result = Permission.AlterAnyContract; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyDatabaseEventNotification: + + result = Permission.AlterAnyDatabaseEventNotification; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyDataspace: + + result = Permission.AlterAnyDataspace; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyExternalDataSource: + + result = Permission.AlterAnyExternalDataSource; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyExternalFileFormat: + + result = Permission.AlterAnyExternalFileFormat; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyFulltextCatalog: + + result = Permission.AlterAnyFulltextCatalog; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyMask: + + result = Permission.AlterAnyMask; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyMessageType: + + result = Permission.AlterAnyMessageType; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyRemoteServiceBinding: + + result = Permission.AlterAnyRemoteServiceBinding; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyRole: + + result = Permission.AlterAnyRole; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyRoute: + + result = Permission.AlterAnyRoute; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnySchema: + + result = Permission.AlterAnySchema; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnySecurityPolicy: + + result = Permission.AlterAnySecurityPolicy; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyService: + + result = Permission.AlterAnyService; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnySymmetricKey: + + result = Permission.AlterAnySymmetricKey; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyDatabaseDdlTrigger: + + result = Permission.AlterAnyDatabaseDdlTrigger; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnyUser: + + result = Permission.AlterAnyUser; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Authenticate: + + result = Permission.Authenticate; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.BackupDatabase: + + result = Permission.BackupDatabase; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.BackupLog: + + result = Permission.BackupLog; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Checkpoint: + + result = Permission.Checkpoint; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Connect: + + result = Permission.Connect; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.ConnectReplication: + + result = Permission.ConnectReplication; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Control: + + result = Permission.Control; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateAggregate: + + result = Permission.CreateAggregate; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateAssembly: + + result = Permission.CreateAssembly; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateAsymmetricKey: + + result = Permission.CreateAsymmetricKey; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateCertificate: + + result = Permission.CreateCertificate; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateContract: + + result = Permission.CreateContract; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateDatabase: + + result = Permission.CreateDatabase; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateDatabaseDdlEventNotification: + + result = Permission.CreateDatabaseDdlEventNotification; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateDefault: + + result = Permission.CreateDefault; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateFunction: + + result = Permission.CreateFunction; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateFulltextCatalog: + + result = Permission.CreateFulltextCatalog; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateMessageType: + + result = Permission.CreateMessageType; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateProcedure: + + result = Permission.CreateProcedure; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateQueue: + + result = Permission.CreateQueue; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateRemoteServiceBinding: + + result = Permission.CreateRemoteServiceBinding; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateRole: + + result = Permission.CreateRole; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateRoute: + + result = Permission.CreateRoute; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateRule: + + result = Permission.CreateRule; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateSchema: + + result = Permission.CreateSchema; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateService: + + result = Permission.CreateService; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateSymmetricKey: + + result = Permission.CreateSymmetricKey; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateSynonym: + + result = Permission.CreateSynonym; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateTable: + + result = Permission.CreateTable; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateType: + + result = Permission.CreateType; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateView: + + result = Permission.CreateView; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.CreateXmlSchemaCollection: + + result = Permission.CreateXmlSchemaCollection; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Delete: + + result = Permission.Delete; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Execute: + + result = Permission.Execute; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Insert: + + result = Permission.Insert; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.References: + + result = Permission.References; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Select: + + result = Permission.Select; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Showplan: + + result = Permission.ShowPlan; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.SubscribeQueryNotifications: + + result = Permission.SubscribeQueryNotifications; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.TakeOwnership: + + result = Permission.TakeOwnership; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Unmask: + + result = Permission.Unmask; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.Update: + + result = Permission.Update; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.ViewAnyColumnEncryptionKeyDefinition: + + result = Permission.ViewAnyColumnEncryptionKeyDefinition; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.ViewAnyColumnMasterKeyDefinition: + + result = Permission.ViewAnyColumnMasterKeyDefinition; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.ViewDefinition: + + result = Permission.ViewDefinition; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.ViewDatabaseState: + + result = Permission.ViewDatabaseState; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.AlterAnySensitivityClassification: + + result = Permission.AlterAnySensitivityClassification; + break; + + case Microsoft.SqlServer.Management.Smo.DatabasePermissionSetValue.ViewAnySensitivityClassification: + + result = Permission.ViewAnySensitivityClassification; + break; + + default: + + string message = String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unexpected DatabasePermissionSetValue: {0}", permissionValue); + // STrace.Assert(false, message); + break; + } + + return result; + } + + /// + /// Get the Permission equivalent to the SMO Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue + /// + /// The permission to find + /// The corresponding Permission instance + public static Permission GetPermission(Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue permissionValue) + { + Permission result = null; + + switch (permissionValue) + { + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AdministerBulkOperations: + + result = Permission.AdministerBulkOperations; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyServerAudit: + + result = Permission.AlterAnyServerAudit; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyConnection: + + result = Permission.AlterAnyConnection; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyCredential: + + result = Permission.AlterAnyCredential; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyDatabase: + + result = Permission.AlterAnyDatabase; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyEndpoint: + + result = Permission.AlterAnyEndpoint; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyEventNotification: + + result = Permission.AlterAnyEventNotification; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyEventSession: + + result = Permission.AlterAnyEventSession; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyLinkedServer: + + result = Permission.AlterAnyLinkedServer; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyLogin: + + result = Permission.AlterAnyLogin; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyServerRole: + + result = Permission.AlterAnyServerRole; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterResources: + + result = Permission.AlterResources; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterServerState: + + result = Permission.AlterServerState; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterSettings: + + result = Permission.AlterSettings; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterTrace: + + result = Permission.AlterTrace; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AuthenticateServer: + + result = Permission.AuthenticateServer; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.ConnectSql: + + result = Permission.ConnectSql; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.ControlServer: + + result = Permission.ControlServer; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.CreateAnyDatabase: + + result = Permission.CreateAnyDatabase; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.CreateDdlEventNotification: + + result = Permission.CreateDdlEventNotification; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.CreateEndpoint: + + result = Permission.CreateEndpoint; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.CreateTraceEventNotification: + + result = Permission.CreateTraceEventNotification; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.CreateServerRole: + + result = Permission.CreateServerRole; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.ExternalAccessAssembly: + + result = Permission.ExternalAccessAssembly; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.Shutdown: + + result = Permission.Shutdown; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.UnsafeAssembly: + + result = Permission.UnsafeAssembly; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.ViewAnyDatabase: + + result = Permission.ViewAnyDatabase; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.ViewAnyDefinition: + + result = Permission.ViewAnyDefinition; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.ViewServerState: + + result = Permission.ViewServerState; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.AlterAnyAvailabilityGroup: + + result = Permission.AlterAnyAvailabilityGroup; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.CreateAvailabilityGroup: + + result = Permission.CreateAvailabilityGroup; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.SelectAllUserSecurables: + + result = Permission.SelectAllUserSecurables; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.ConnectAnyDatabase: + + result = Permission.ConnectAnyDatabase; + break; + + case Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue.ImpersonateAnyLogin: + + result = Permission.ImpersonateAnyLogin; + break; + + default: + +#if DEBUG + string message = String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unexpected Microsoft.SqlServer.Management.Smo.ServerPermissionSetValue: {0}", permissionValue); + // STrace.Assert(false, message); +#endif + break; + } + + return result; + } + + + #region object permission instances + + private static Permission alter = null; + private static Permission connect = null; + private static Permission control = null; + private static Permission delete = null; + private static Permission execute = null; + private static Permission impersonate = null; + private static Permission insert = null; + private static Permission receive = null; + private static Permission references = null; + private static Permission select = null; + private static Permission send = null; + private static Permission takeOwnership = null; + private static Permission update = null; + private static Permission viewDefinition = null; + #endregion + + #region database permission instances + + private static Permission alterAnyApplicationRole = null; + private static Permission alterAnyAssembly = null; + private static Permission alterAnyAsymmetricKey = null; + private static Permission alterAnyCertificate = null; + private static Permission alterAnyDatabaseAudit = null; + private static Permission alterAnyContract = null; + private static Permission alterAnyDatabaseDdlTrigger = null; + private static Permission alterAnyDatabaseEventNotification = null; + private static Permission alterAnyDataspace = null; + private static Permission alterAnyExternalDataSource = null; + private static Permission alterAnyExternalFileFormat = null; + private static Permission alterAnyFulltextCatalog = null; + private static Permission alterAnyMask = null; + private static Permission alterAnyMessageType = null; + private static Permission alterAnyRemoteServiceBinding = null; + private static Permission alterAnyRole = null; + private static Permission alterAnyRoute = null; + private static Permission alterAnySchema = null; + private static Permission alterAnySensitivityClassification = null; + private static Permission alterAnyService = null; + private static Permission alterAnySecurityPolicy = null; + private static Permission alterAnySymmetricKey = null; + private static Permission alterAnyUser = null; + private static Permission authenticate = null; + private static Permission backupDatabase = null; + private static Permission backupLog = null; + private static Permission checkpoint = null; + private static Permission connectReplication = null; + private static Permission createAggregate = null; + private static Permission createAssembly = null; + private static Permission createAsymmetricKey = null; + private static Permission createCertificate = null; + private static Permission createContract = null; + private static Permission createDatabase = null; + private static Permission createDatabaseDdlEventNotification = null; + private static Permission createDefault = null; + private static Permission createFulltextCatalog = null; + private static Permission createFunction = null; + private static Permission createMessageType = null; + private static Permission createProcedure = null; + private static Permission createQueue = null; + private static Permission createRemoteServiceBinding = null; + private static Permission createRole = null; + private static Permission createRoute = null; + private static Permission createRule = null; + private static Permission createSchema = null; + private static Permission createService = null; + private static Permission createSymmetricKey = null; + private static Permission createSynonym = null; + private static Permission createSequence = null; + private static Permission createTable = null; + private static Permission createType = null; + private static Permission createView = null; + private static Permission createXmlSchemaCollection = null; + private static Permission showPlan = null; + private static Permission subscribeQueryNotifications = null; + private static Permission unmask = null; + private static Permission viewAnyColumnEncryptionKeyDefinition = null; + private static Permission viewAnyColumnMasterKeyDefinition = null; + private static Permission viewDatabaseState = null; + private static Permission viewChangeTracking = null; + private static Permission viewAnySensitivityClassification = null; + + #endregion + + #region server permission instances + + private static Permission administerBulkOperations = null; + private static Permission alterAnyServerAudit = null; + private static Permission alterAnyConnection = null; + private static Permission alterAnyCredential = null; + private static Permission alterAnyDatabase = null; + private static Permission alterAnyEndpoint = null; + private static Permission alterAnyEventNotification = null; + private static Permission alterAnyEventSession = null; + private static Permission alterAnyLinkedServer = null; + private static Permission alterAnyLogin = null; + private static Permission alterAnyServerRole = null; + private static Permission alterResources = null; + private static Permission alterServerState = null; + private static Permission alterSettings = null; + private static Permission alterTrace = null; + private static Permission authenticateServer = null; + private static Permission connectSql = null; + private static Permission controlServer = null; + private static Permission createAnyDatabase = null; + private static Permission createDdlEventNotification = null; + private static Permission createEndpoint = null; + private static Permission createTraceEventNotification = null; + private static Permission createServerRole = null; + private static Permission externalAccessAssembly = null; + private static Permission shutdown = null; + private static Permission viewAnyDatabase = null; + private static Permission viewAnyDefinition = null; + private static Permission viewServerState = null; + private static Permission unsafeAssembly = null; + private static Permission alterAnyAvailabilityGroup = null; + private static Permission createAvailabilityGroup = null; + private static Permission selectAllUserSecurables = null; + private static Permission connectAnyDatabase = null; + private static Permission impersonateAnyLogin = null; + #endregion + + #region interface-based permission initialization methods + + private static void PopulateObjectPermissions() + { + alter = new Permission(SR.Permission_Alter, ObjectPermission.Alter, DatabasePermission.Alter); + connect = new Permission(SR.Permission_Connect, ObjectPermission.Connect, DatabasePermission.Connect); + control = new Permission(SR.Permission_Control, ObjectPermission.Control, DatabasePermission.Control); + delete = new Permission(SR.Permission_Delete, ObjectPermission.Delete, DatabasePermission.Delete); + execute = new Permission(SR.Permission_Execute, ObjectPermission.Execute, DatabasePermission.Execute); + impersonate = new Permission(SR.Permission_Impersonate, ObjectPermission.Impersonate, null); + insert = new Permission(SR.Permission_Insert, ObjectPermission.Insert, DatabasePermission.Insert); + receive = new Permission(SR.Permission_Receive, ObjectPermission.Receive, null); + references = new Permission(SR.Permission_References, ObjectPermission.References, DatabasePermission.References); + select = new Permission(SR.Permission_Select, ObjectPermission.Select, DatabasePermission.Select); + send = new Permission(SR.Permission_Send, ObjectPermission.Send, null); + takeOwnership = new Permission(SR.Permission_TakeOwnership, ObjectPermission.TakeOwnership, DatabasePermission.TakeOwnership); + update = new Permission(SR.Permission_Update, ObjectPermission.Update, DatabasePermission.Update); + viewDefinition = new Permission(SR.Permission_ViewDefinition, ObjectPermission.ViewDefinition, DatabasePermission.ViewDefinition); + viewChangeTracking = new Permission(SR.Permission_ViewChangeTracking, ObjectPermission.ViewChangeTracking, null); + createSequence = new Permission(SR.Permission_CreateSequence, ObjectPermission.CreateSequence, null); + objectPermissionsPopulated = true; + } + + private static void PopulateDatabasePermissions() + { + alterAnyApplicationRole = new Permission(SR.Permission_AlterAnyApplicationRole, DatabasePermission.AlterAnyApplicationRole); + alterAnyAssembly = new Permission(SR.Permission_AlterAnyAssembly, DatabasePermission.AlterAnyAssembly); + alterAnyAsymmetricKey = new Permission(SR.Permission_AlterAnyAsymmetricKey, DatabasePermission.AlterAnyAsymmetricKey); + alterAnyCertificate = new Permission(SR.Permission_AlterAnyCertificate, DatabasePermission.AlterAnyCertificate); + alterAnyDatabaseAudit = new Permission(SR.Permission_AlterAnyDatabaseAudit, DatabasePermission.AlterAnyDatabaseAudit); + alterAnyContract = new Permission(SR.Permission_AlterAnyContract, DatabasePermission.AlterAnyContract); + alterAnyDatabaseDdlTrigger = new Permission(SR.Permission_AlterAnyDatabaseDdlTrigger, DatabasePermission.AlterAnyDatabaseDdlTrigger); + alterAnyDatabaseEventNotification = new Permission(SR.Permission_AlterAnyDatabaseEventNotification, DatabasePermission.AlterAnyDatabaseEventNotification); + alterAnyDataspace = new Permission(SR.Permission_AlterAnyDataspace, DatabasePermission.AlterAnyDataspace); + alterAnyExternalDataSource = new Permission(SR.Permission_AlterAnyExternalDataSource, DatabasePermission.AlterAnyExternalDataSource); + alterAnyExternalFileFormat = new Permission(SR.Permission_AlterAnyExternalFileFormat, DatabasePermission.AlterAnyExternalFileFormat); + alterAnyFulltextCatalog = new Permission(SR.Permission_AlterAnyFulltextCatalog, DatabasePermission.AlterAnyFulltextCatalog); + alterAnyMask = new Permission(SR.Permission_AlterAnyMask, DatabasePermission.AlterAnyMask); + alterAnyMessageType = new Permission(SR.Permission_AlterAnyMessageType, DatabasePermission.AlterAnyMessageType); + alterAnyRemoteServiceBinding = new Permission(SR.Permission_AlterAnyRemoteServiceBinding, DatabasePermission.AlterAnyRemoteServiceBinding); + alterAnyRole = new Permission(SR.Permission_AlterAnyRole, DatabasePermission.AlterAnyRole); + alterAnyRoute = new Permission(SR.Permission_AlterAnyRoute, DatabasePermission.AlterAnyRoute); + alterAnySchema = new Permission(SR.Permission_AlterAnySchema, DatabasePermission.AlterAnySchema); + alterAnySecurityPolicy = new Permission(SR.Permission_AlterAnySecurityPolicy, DatabasePermission.AlterAnySecurityPolicy); + alterAnySensitivityClassification = new Permission(SR.Permission_AlterAnySensitivityClassification, DatabasePermission.AlterAnySensitivityClassification); + alterAnyService = new Permission(SR.Permission_AlterAnyService, DatabasePermission.AlterAnyService); + alterAnyUser = new Permission(SR.Permission_AlterAnyUser, DatabasePermission.AlterAnyUser); + alterAnySymmetricKey = new Permission(SR.Permission_AlterAnySymmetricKey, DatabasePermission.AlterAnySymmetricKey); + authenticate = new Permission(SR.Permission_Authenticate, DatabasePermission.Authenticate); + backupDatabase = new Permission(SR.Permission_BackupDatabase, DatabasePermission.BackupDatabase); + backupLog = new Permission(SR.Permission_BackupLog, DatabasePermission.BackupLog); + checkpoint = new Permission(SR.Permission_Checkpoint, DatabasePermission.Checkpoint); + connectReplication = new Permission(SR.Permission_ConnectReplication, DatabasePermission.ConnectReplication); + createAggregate = new Permission(SR.Permission_CreateAggregate, DatabasePermission.CreateAggregate); + createAssembly = new Permission(SR.Permission_CreateAssembly, DatabasePermission.CreateAssembly); + createAsymmetricKey = new Permission(SR.Permission_CreateAsymmetricKey, DatabasePermission.CreateAsymmetricKey); + createCertificate = new Permission(SR.Permission_CreateCertificate, DatabasePermission.CreateCertificate); + createContract = new Permission(SR.Permission_CreateContract, DatabasePermission.CreateContract); + createDatabase = new Permission(SR.Permission_CreateDatabase, DatabasePermission.CreateDatabase); + createDatabaseDdlEventNotification = new Permission(SR.Permission_CreateDatabaseDdlEventNotification, DatabasePermission.CreateDatabaseDdlEventNotification); + createDefault = new Permission(SR.Permission_CreateDefault, DatabasePermission.CreateDefault); + createFulltextCatalog = new Permission(SR.Permission_CreateFulltextCatalog, DatabasePermission.CreateFulltextCatalog); + createFunction = new Permission(SR.Permission_CreateFunction, DatabasePermission.CreateFunction); + createMessageType = new Permission(SR.Permission_CreateMessageType, DatabasePermission.CreateMessageType); + createProcedure = new Permission(SR.Permission_CreateProcedure, DatabasePermission.CreateProcedure); + createQueue = new Permission(SR.Permission_CreateQueue, DatabasePermission.CreateQueue); + createRemoteServiceBinding = new Permission(SR.Permission_CreateRemoteServiceBinding, DatabasePermission.CreateRemoteServiceBinding); + createRole = new Permission(SR.Permission_CreateRole, DatabasePermission.CreateRole); + createRoute = new Permission(SR.Permission_CreateRoute, DatabasePermission.CreateRoute); + createRule = new Permission(SR.Permission_CreateRule, DatabasePermission.CreateRule); + createSchema = new Permission(SR.Permission_CreateSchema, DatabasePermission.CreateSchema); + createService = new Permission(SR.Permission_CreateService, DatabasePermission.CreateService); + createSymmetricKey = new Permission(SR.Permission_CreateSymmetricKey, DatabasePermission.CreateSymmetricKey); + createSynonym = new Permission(SR.Permission_CreateSynonym, DatabasePermission.CreateSynonym); + createTable = new Permission(SR.Permission_CreateTable, DatabasePermission.CreateTable); + createType = new Permission(SR.Permission_CreateType, DatabasePermission.CreateType); + createView = new Permission(SR.Permission_CreateView, DatabasePermission.CreateView); + createXmlSchemaCollection = new Permission(SR.Permission_CreateXmlSchemaCollection, DatabasePermission.CreateXmlSchemaCollection); + showPlan = new Permission(SR.Permission_Showplan, DatabasePermission.Showplan); + subscribeQueryNotifications = new Permission(SR.Permission_SubscribeQueryNotifications, DatabasePermission.SubscribeQueryNotifications); + unmask = new Permission(SR.Permission_Unmask, DatabasePermission.Unmask); + viewAnyColumnEncryptionKeyDefinition = new Permission(SR.Permission_ViewAnyColumnEncryptionKeyDefinition, DatabasePermission.ViewAnyColumnEncryptionKeyDefinition); + viewAnyColumnMasterKeyDefinition = new Permission(SR.Permission_ViewAnyColumnMasterKeyDefinition, DatabasePermission.ViewAnyColumnMasterKeyDefinition); + viewDatabaseState = new Permission(SR.Permission_ViewDatabaseState, DatabasePermission.ViewDatabaseState); + viewAnySensitivityClassification = new Permission(SR.Permission_ViewAnySensitivityClassification, DatabasePermission.ViewAnySensitivityClassification); + + databasePermissionsPopulated = true; + } + + private static void PopulateServerPermissions() + { + administerBulkOperations = new Permission(SR.Permission_AdministerBulkOperations, ServerPermission.AdministerBulkOperations); + alterAnyServerAudit = new Permission(SR.Permission_AlterAnyServerAudit, ServerPermission.AlterAnyServerAudit); + alterAnyConnection = new Permission(SR.Permission_AlterAnyConnection, ServerPermission.AlterAnyConnection); + alterAnyCredential = new Permission(SR.Permission_AlterAnyCredential, ServerPermission.AlterAnyCredential); + alterAnyDatabase = new Permission(SR.Permission_AlterAnyDatabase, ServerPermission.AlterAnyDatabase); + alterAnyEndpoint = new Permission(SR.Permission_AlterAnyEndpoint, ServerPermission.AlterAnyEndpoint); + alterAnyEventNotification = new Permission(SR.Permission_AlterAnyEventNotification, ServerPermission.AlterAnyEventNotification); + alterAnyEventSession = new Permission(SR.Permission_AlterAnyEventSession, ServerPermission.AlterAnyEventSession); + alterAnyLinkedServer = new Permission(SR.Permission_AlterAnyLinkedServer, ServerPermission.AlterAnyLinkedServer); + alterAnyLogin = new Permission(SR.Permission_AlterAnyLogin, ServerPermission.AlterAnyLogin); + alterAnyServerRole = new Permission(SR.Permission_AlterAnyServerRole, ServerPermission.AlterAnyServerRole); + alterResources = new Permission(SR.Permission_AlterResources, ServerPermission.AlterResources); + alterServerState = new Permission(SR.Permission_AlterServerState, ServerPermission.AlterServerState); + alterSettings = new Permission(SR.Permission_AlterSettings, ServerPermission.AlterSettings); + alterTrace = new Permission(SR.Permission_AlterTrace, ServerPermission.AlterTrace); + authenticateServer = new Permission(SR.Permission_AuthenticateServer, ServerPermission.AuthenticateServer); + connectSql = new Permission(SR.Permission_ConnectSql, ServerPermission.ConnectSql); + controlServer = new Permission(SR.Permission_ControlServer, ServerPermission.ControlServer); + createAnyDatabase = new Permission(SR.Permission_CreateAnyDatabase, ServerPermission.CreateAnyDatabase); + createDdlEventNotification = new Permission(SR.Permission_CreateDdlEventNotification, ServerPermission.CreateDdlEventNotification); + createEndpoint = new Permission(SR.Permission_CreateEndpoint, ServerPermission.CreateEndpoint); + createTraceEventNotification = new Permission(SR.Permission_CreateTraceEventNotification, ServerPermission.CreateTraceEventNotification); + createServerRole = new Permission(SR.Permission_CreateServerRole, ServerPermission.CreateServerRole); + externalAccessAssembly = new Permission(SR.Permission_ExternalAccessAssembly, ServerPermission.ExternalAccessAssembly); + shutdown = new Permission(SR.Permission_Shutdown, ServerPermission.Shutdown); + unsafeAssembly = new Permission(SR.Permission_UnsafeAssembly, ServerPermission.UnsafeAssembly); + viewAnyDatabase = new Permission(SR.Permission_ViewAnyDatabase, ServerPermission.ViewAnyDatabase); + viewAnyDefinition = new Permission(SR.Permission_ViewAnyDefinition, ServerPermission.ViewAnyDefinition); + viewServerState = new Permission(SR.Permission_ViewServerState, ServerPermission.ViewServerState); + alterAnyAvailabilityGroup = new Permission(SR.Permission_AlterAnyAvailabilityGroup, ServerPermission.AlterAnyAvailabilityGroup); + createAvailabilityGroup = new Permission(SR.Permission_CreateAvailabilityGroup, ServerPermission.CreateAvailabilityGroup); + selectAllUserSecurables = new Permission(SR.Permission_SelectAllUserSecurables, ServerPermission.SelectAllUserSecurables); + connectAnyDatabase = new Permission(SR.Permission_ConnectAnyDatabase, ServerPermission.ConnectAnyDatabase); + impersonateAnyLogin = new Permission(SR.Permission_ImpersonateAnyLogin, ServerPermission.ImpersonateAnyLogin); + + serverPermissionsPopulated = true; + } + + #endregion + + #region object permission properties + /// + /// Gets the one and only Alter permission object + /// + public static Permission Alter + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alter; + } + } + + /// + /// Gets the one and only Connect permission object + /// + public static Permission Connect + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return connect; + } + } + /// + /// Gets the one and only Control permission object + /// + public static Permission Control + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return control; + } + } + /// + /// Gets the one and only Delete permission object + /// + public static Permission Delete + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return delete; + } + } + /// + /// Gets the one and only Execute permission object + /// + public static Permission Execute + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return execute; + } + } + /// + /// Gets the one and only Impersonate permission object + /// + public static Permission Impersonate + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return impersonate; + } + } + /// + /// Gets the one and only Insert permission object + /// + public static Permission Insert + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return insert; + } + } + /// + /// Gets the one and only Receive permission object + /// + public static Permission Receive + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + return receive; + } + } + /// + /// Gets the one and only References permission object + /// + public static Permission References + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return references; + } + } + /// + /// Gets the one and only Select permission object + /// + public static Permission Select + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return select; + } + } + /// + /// Gets the one and only Send permission object + /// + public static Permission Send + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + return send; + } + } + /// + /// Gets the one and only TakeOwnership permission object + /// + public static Permission TakeOwnership + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return takeOwnership; + } + } + /// + /// Gets the one and only Update permission object + /// + public static Permission Update + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return update; + } + } + /// + /// Gets the one and only ViewDefinition permission object + /// + public static Permission ViewDefinition + { + get + { + if (!objectPermissionsPopulated) + { + PopulateObjectPermissions(); + } + + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return viewDefinition; + } + } + + #endregion + + #region database permission properties + /// + /// Gets the one and only AlterAnyApplicationRole permission object + /// + public static Permission AlterAnyApplicationRole + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyApplicationRole; + } + } + + /// + /// Gets the one and only AlterAnyAssembly permission object + /// + public static Permission AlterAnyAssembly + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyAssembly; + } + } + + /// + /// Gets the one and only AlterAnyAsymmetricKey permission object + /// + public static Permission AlterAnyAsymmetricKey + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyAsymmetricKey; + } + } + + /// + /// Gets the one and only AlterAnyCertificate permission object + /// + public static Permission AlterAnyCertificate + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyCertificate; + } + } + + /// + /// Gets the only and only AlterAnyDatabaseAudit permission object + /// + public static Permission AlterAnyDatabaseAudit + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyDatabaseAudit; + } + } + + /// + /// Gets the one and only AlterAnyContract permission object + /// + public static Permission AlterAnyContract + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyContract; + } + } + + /// + /// Gets the one and only AlterAnyDatabaseDdlTrigger permission object + /// + public static Permission AlterAnyDatabaseDdlTrigger + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyDatabaseDdlTrigger; + } + } + + /// + /// Gets the one and only AlterAnyDatabaseEventNotification permission object + /// + public static Permission AlterAnyDatabaseEventNotification + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyDatabaseEventNotification; + } + } + + /// + /// Gets the one and only AlterAnyDataspace permission object + /// + public static Permission AlterAnyDataspace + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyDataspace; + } + } + + /// + /// Gets the one and only AlterAnyExternalDataSource permission object + /// + public static Permission AlterAnyExternalDataSource + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyExternalDataSource; + } + } + + /// + /// Gets the one and only AlterAnyExternalFileFormat permission object + /// + public static Permission AlterAnyExternalFileFormat + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyExternalFileFormat; + } + } + + /// + /// Gets the one and only AlterAnyFulltextCatalog permission object + /// + public static Permission AlterAnyFulltextCatalog + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyFulltextCatalog; + } + } + + /// + /// Gets the one and only AlterAnyMask permission object + /// + public static Permission AlterAnyMask + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyMask; + } + } + + /// + /// Gets the one and only AlterAnyMessageType permission object + /// + public static Permission AlterAnyMessageType + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyMessageType; + } + } + + /// + /// Gets the one and only AlterAnyRemoteServiceBinding permission object + /// + public static Permission AlterAnyRemoteServiceBinding + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyRemoteServiceBinding; + } + } + + /// + /// Gets the one and only AlterAnyRole permission object + /// + public static Permission AlterAnyRole + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyRole; + } + } + + /// + /// Gets the one and only AlterAnyRoute permission object + /// + public static Permission AlterAnyRoute + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyRoute; + } + } + + /// + /// Gets the one and only AlterAnySchema permission object + /// + public static Permission AlterAnySchema + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnySchema; + } + } + + /// + /// Gets the one and only AlterAnySecurityPolicy permission object + /// + public static Permission AlterAnySecurityPolicy + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnySecurityPolicy; + } + } + + /// + /// Gets the one and only AlterAnyService permission object + /// + public static Permission AlterAnyService + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyService; + } + } + + /// + /// Gets the one and only AlterAnySymmetricKey permission object + /// + public static Permission AlterAnySymmetricKey + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnySymmetricKey; + } + } + + /// + /// Gets the one and only AlterAnyUser permission object + /// + public static Permission AlterAnyUser + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnyUser; + } + } + + /// + /// Gets the one and only Authenticate permission object + /// + public static Permission Authenticate + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return authenticate; + } + } + + /// + /// Gets the one and only BackupDatabase permission object + /// + public static Permission BackupDatabase + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return backupDatabase; + } + } + + /// + /// Gets the one and only BackupLog permission object + /// + public static Permission BackupLog + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return backupLog; + } + } + + /// + /// Gets the one and only Checkpoint permission object + /// + public static Permission Checkpoint + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return checkpoint; + } + } + + /// + /// Gets the one and only ConnectReplication permission object + /// + public static Permission ConnectReplication + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return connectReplication; + } + } + + /// + /// Gets the one and only CreateAggregate permission object + /// + public static Permission CreateAggregate + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createAggregate; + } + } + + /// + /// Gets the one and only CreateAssembly permission object + /// + public static Permission CreateAssembly + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createAssembly; + } + } + + /// + /// Gets the one and only CreateAsymmetricKey permission object + /// + public static Permission CreateAsymmetricKey + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createAsymmetricKey; + } + } + + /// + /// Gets the one and only CreateCertificate permission object + /// + public static Permission CreateCertificate + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createCertificate; + } + } + + /// + /// Gets the one and only CreateContract permission object + /// + public static Permission CreateContract + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createContract; + } + } + + /// + /// Gets the one and only CreateDatabase permission object + /// + public static Permission CreateDatabase + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createDatabase; + } + } + + /// + /// Gets the one and only CreateDatabaseDdlEventNotification permission object + /// + public static Permission CreateDatabaseDdlEventNotification + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createDatabaseDdlEventNotification; + } + } + + /// + /// Gets the one and only CreateDefault permission object + /// + public static Permission CreateDefault + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createDefault; + } + } + + /// + /// Gets the one and only CreateFulltextCatalog permission object + /// + public static Permission CreateFulltextCatalog + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createFulltextCatalog; + } + } + + /// + /// Gets the one and only CreateFunction permission object + /// + public static Permission CreateFunction + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createFunction; + } + } + + /// + /// Gets the one and only CreateMessageType permission object + /// + public static Permission CreateMessageType + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createMessageType; + } + } + + /// + /// Gets the one and only CreateProcedure permission object + /// + public static Permission CreateProcedure + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createProcedure; + } + } + + /// + /// Gets the one and only CreateQueue permission object + /// + public static Permission CreateQueue + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createQueue; + } + } + + /// + /// Gets the one and only CreateRemoteServiceBinding permission object + /// + public static Permission CreateRemoteServiceBinding + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createRemoteServiceBinding; + } + } + + /// + /// Gets the one and only CreateRole permission object + /// + public static Permission CreateRole + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createRole; + } + } + + /// + /// Gets the one and only CreateRoute permission object + /// + public static Permission CreateRoute + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createRoute; + } + } + + /// + /// Gets the one and only CreateRule permission object + /// + public static Permission CreateRule + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createRule; + } + } + + /// + /// Gets the one and only CreateSchema permission object + /// + public static Permission CreateSchema + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createSchema; + } + } + + /// + /// Gets the one and only CreateService permission object + /// + public static Permission CreateService + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createService; + } + } + + /// + /// Gets the one and only CreateSymmetricKey permission object + /// + public static Permission CreateSymmetricKey + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createSymmetricKey; + } + } + + /// + /// Gets the one and only CreateSynonym permission object + /// + public static Permission CreateSynonym + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createSynonym; + } + } + + /// + /// Gets the one and only CreateSequence permission object + /// + public static Permission CreateSequence + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createSequence; + } + } + + /// + /// Gets the one and only CreateTable permission object + /// + public static Permission CreateTable + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createTable; + } + } + + /// + /// Gets the one and only CreateType permission object + /// + public static Permission CreateType + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createType; + } + } + + /// + /// Gets the one and only CreateView permission object + /// + public static Permission CreateView + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createView; + } + } + + /// + /// Gets the one and only CreateXmlSchemaCollection permission object + /// + public static Permission CreateXmlSchemaCollection + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return createXmlSchemaCollection; + } + } + + /// + /// Gets the one and only ShowPlan permission object + /// + public static Permission ShowPlan + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return showPlan; + } + } + + /// + /// Gets the one and only SubscribeQueryNotifications permission object + /// + public static Permission SubscribeQueryNotifications + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return subscribeQueryNotifications; + } + } + + /// + /// Gets the one and only Unmask permission object + /// + public static Permission Unmask + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return unmask; + } + } + + /// + /// Gets the one and only ViewAnyColumnEncryptionKeyDefinition permission object + /// + public static Permission ViewAnyColumnEncryptionKeyDefinition + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return viewAnyColumnEncryptionKeyDefinition; + } + } + + /// + /// Gets the one and only ViewAnyColumnMasterKeyDefinition permission object + /// + public static Permission ViewAnyColumnMasterKeyDefinition + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return viewAnyColumnMasterKeyDefinition; + } + } + + /// + /// Gets the one and only ViewDatabaseState permission object + /// + public static Permission ViewDatabaseState + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return viewDatabaseState; + } + } + + /// + /// Gets the one and only AlterAnySensitivityClassification permission object + /// + public static Permission AlterAnySensitivityClassification + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return alterAnySensitivityClassification; + } + } + + /// + /// Gets the one and only ViewAnySensitivityClassification permission object + /// + public static Permission ViewAnySensitivityClassification + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return viewAnySensitivityClassification; + } + } + + /// + /// Gets the ViewChangeTracking permission object + /// + public static Permission ViewChangeTracking + { + get + { + if (!databasePermissionsPopulated) + { + PopulateDatabasePermissions(); + } + + return viewChangeTracking; + } + } + + + #endregion + + #region server permission properties + + /// + /// Gets the one and only AdministerBulkOperations permission object + /// + public static Permission AdministerBulkOperations + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return administerBulkOperations; + } + } + + /// + /// Gets the one and only AlterAnyServerAudit permission object + /// + public static Permission AlterAnyServerAudit + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyServerAudit; + } + } + + /// + /// Gets the one and only AlterAnyConnection permission object + /// + public static Permission AlterAnyConnection + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyConnection; + } + } + + /// + /// Gets the one and only AlterAnyCredential permission object + /// + public static Permission AlterAnyCredential + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyCredential; + } + } + + /// + /// Gets the one and only AlterAnyDatabase permission object + /// + public static Permission AlterAnyDatabase + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyDatabase; + } + } + + /// + /// Gets the one and only AlterAnyEndpoint permission object + /// + public static Permission AlterAnyEndpoint + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyEndpoint; + } + } + + /// + /// Gets the one and only AlterAnyEventNotification permission object + /// + public static Permission AlterAnyEventNotification + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyEventNotification; + } + } + + /// + /// Gets the one and only AlterAnyEventSession permission object + /// + public static Permission AlterAnyEventSession + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyEventSession; + } + } + + /// + /// Gets the one and only AlterAnyLinkedServer permission object + /// + public static Permission AlterAnyLinkedServer + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyLinkedServer; + } + } + + /// + /// Gets the one and only AlterAnyLogin permission object + /// + public static Permission AlterAnyLogin + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyLogin; + } + } + + /// + /// Gets the one and only AlterAnyServerRole permission object + /// + public static Permission AlterAnyServerRole + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyServerRole; + } + } + + /// + /// Gets the one and only AlterResources permission object + /// + public static Permission AlterResources + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterResources; + } + } + + /// + /// Gets the one and only AlterServerState permission object + /// + public static Permission AlterServerState + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterServerState; + } + } + + /// + /// Gets the one and only AlterSettings permission object + /// + public static Permission AlterSettings + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterSettings; + } + } + + /// + /// Gets the one and only AlterTrace permission object + /// + public static Permission AlterTrace + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterTrace; + } + } + + /// + /// Gets the one and only AuthenticateServer permission object + /// + public static Permission AuthenticateServer + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return authenticateServer; + } + } + + /// + /// Gets the one and only ConnectSql permission object + /// + public static Permission ConnectSql + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return connectSql; + } + } + + /// + /// Gets the one and only ControlServer permission object + /// + public static Permission ControlServer + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return controlServer; + } + } + + /// + /// Gets the one and only CreateAnyDatabase permission object + /// + public static Permission CreateAnyDatabase + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return createAnyDatabase; + } + } + + /// + /// Gets the one and only CreateDdlEventNotification permission object + /// + public static Permission CreateDdlEventNotification + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return createDdlEventNotification; + } + } + + /// + /// Gets the one and only CreateEndpoint permission object + /// + public static Permission CreateEndpoint + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return createEndpoint; + } + } + + /// + /// Gets the one and only CreateTraceEventNotification permission object + /// + public static Permission CreateTraceEventNotification + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return createTraceEventNotification; + } + } + + /// + /// Gets the one and only CreateServerRole permission object + /// + public static Permission CreateServerRole + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return createServerRole; + } + } + + /// + /// Gets the one and only ExternalAccess permission object + /// + public static Permission ExternalAccessAssembly + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return externalAccessAssembly; + } + } + + /// + /// Gets the one and only Shutdown permission object + /// + public static Permission Shutdown + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return shutdown; + } + } + + /// + /// Gets the one and only ViewAnyDatabase permission object + /// + public static Permission ViewAnyDatabase + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return viewAnyDatabase; + } + } + + /// + /// Gets the one and only ViewAnyDefinition permission object + /// + public static Permission ViewAnyDefinition + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return viewAnyDefinition; + } + } + + /// + /// Gets the one and only ViewServerState permission object + /// + public static Permission ViewServerState + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return viewServerState; + } + } + + /// + /// Gets the one and only UnsafeAssembly permission object + /// + public static Permission UnsafeAssembly + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return unsafeAssembly; + } + } + + /// + /// Gets the one and only AlterAnyAvailabilityGroup permission object + /// + public static Permission AlterAnyAvailabilityGroup + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return alterAnyAvailabilityGroup; + } + } + + /// + /// Gets the one and only CreateAvailabilityGroup permission object + /// + public static Permission CreateAvailabilityGroup + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return createAvailabilityGroup; + } + } + + /// + /// Gets the one and only SelectAllUserSecurable permission object + /// + public static Permission SelectAllUserSecurables + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return selectAllUserSecurables; + } + } + + /// + /// Gets the one and only ConnectAnyDatabase permission object + /// + public static Permission ConnectAnyDatabase + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return connectAnyDatabase; + } + } + + /// + /// Gets the one and only ImpersonateAnyLogin permission object + /// + public static Permission ImpersonateAnyLogin + { + get + { + if (!serverPermissionsPopulated) + { + PopulateServerPermissions(); + } + + return impersonateAnyLogin; + } + } + + #endregion + + #endregion + + } + + + /// + /// Adapter for applying permissions changes to SMO objects + /// + internal abstract class SmoPermissionsAdapter + { + /// + /// Grant permissions to a principal + /// + /// The set of permissions to grant + /// The principal to whom the permissions are to be granted + /// + public abstract void Grant(List permissions, Principal principal, bool withGrant); + /// + /// Deny permissions to a principal + /// + /// The set of permissions to deny + /// The principal to whom permissions are to be denied + public abstract void Deny(List permissions, Principal principal); + /// + /// Revoke permissions for a principal + /// + /// The set of permissions to be revoked + /// The principal whose permissions are to be revoked + public abstract void Revoke(List permissions, Principal principal); + + /// + /// Factory method to create a permissions adapter for a SMO object + /// + /// The SMO object for which we are creating an adapter + /// + public static SmoPermissionsAdapter CreateAdapter(SqlSmoObject obj) + { + if (obj is IObjectPermission) + { + return new ObjectPermissionsAdapter(obj); + } + else if (obj is Column column) + { + return new TableViewColumnPermissionsAdapter(column); + } + else if (obj is Database database) + { + return new DatabasePermissionsAdapter(database); + } + else if (obj is Microsoft.SqlServer.Management.Smo.Server server) + { + return new ServerPermissionsAdapter(server); + } + else + { + // STrace.Assert(false, "unexpected SqlSmoObject type"); + return new NoPermissionsAdapter(obj); + } + } + } + + + /// + /// Some objects do not have permissions methods yet, but will once interface-based + /// permissions are implemented in SMO. Once interface-based permissions are implemented, + /// class specific adapters will be removed. + /// + internal class NoPermissionsAdapter : SmoPermissionsAdapter + { + public NoPermissionsAdapter(SqlSmoObject smoObject) + { + } + + public override void Grant(List permissions, Principal principal, bool withGrant) + { + } + + public override void Deny(List permissions, Principal principal) + { + } + + public override void Revoke(List permissions, Principal principal) + { + } + } + + + /// + /// Permission adapter for objects implementing IObjectPermission, such as + /// Stored Procedures, Functions, etc. + /// + internal class ObjectPermissionsAdapter : SmoPermissionsAdapter + { + private IObjectPermission perm; + private SqlSmoObject smoObject; + + /// + /// Constructor + /// + /// The subject of the permissions + public ObjectPermissionsAdapter(SqlSmoObject obj) + { + this.perm = (IObjectPermission)obj; + this.smoObject = obj; + } + + /// + /// Grant permissions to a principal + /// + /// The set of permissions to grant + /// The principal to whom the permissions are to be granted + /// + public override void Grant(List permissions, Principal principal, bool withGrant) + { + foreach (PermissionState ps in permissions) + { + if (string.IsNullOrEmpty(ps.Grantor) || ps.Grantor == ps.Securable.ExpectedGrantor) + { + if (!withGrant && ps.OriginalState == PermissionStatus.WithGrant) + { + this.perm.Revoke(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + new string[] { principal.Name }, + true, + ps.CascadeNeeded); + } + else + { + this.perm.Grant(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + withGrant); + } + } + else + { + if (!withGrant && ps.OriginalState == PermissionStatus.WithGrant) + { + this.perm.Revoke(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + true, + ps.CascadeNeeded, + ps.Grantor); + } + else + { + this.perm.Grant(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + withGrant, + ps.Grantor); + } + } + } + } + + /// + /// Revoke permissions for a principal + /// + /// The set of permissions to be revoked + /// The principal whose permissions are to be revoked + public override void Revoke(List permissions, Principal principal) + { + foreach (PermissionState ps in permissions) + { + if (string.IsNullOrEmpty(ps.Grantor) || ps.Grantor == ps.Securable.ExpectedGrantor) + { + this.perm.Revoke(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + new string[] { principal.Name }, + false, + ps.CascadeNeeded); + } + else + { + this.perm.Revoke(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + false, + ps.CascadeNeeded, + ps.Grantor); + } + } + } + + /// + /// Deny permissions to a principal + /// + /// The set of permissions to deny + /// The principal to whom permissions are to be denied + public override void Deny(List permissions, Principal principal) + { + foreach (PermissionState ps in permissions) + { + this.perm.Deny(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + new string[] { principal.Name }, + ps.CascadeNeeded); + } + } + } + + /// + /// Permissions adapter for a column on a table or view + /// + internal class TableViewColumnPermissionsAdapter : SmoPermissionsAdapter + { + private Column column; + + /// + /// Constructor + /// + /// The column whose permissions we are modifying + public TableViewColumnPermissionsAdapter(Column column) + { + this.column = column; + } + + /// + /// Grant permissions to a principal + /// + /// The set of permissions to grant + /// The principal to whom the permissions are to be granted + /// + public override void Grant(List permissions, Principal principal, bool withGrant) + { + if (0 < permissions.Count) + { + IColumnPermission parent = (IColumnPermission)this.column.Parent; + + foreach (PermissionState ps in permissions) + { + if (string.IsNullOrEmpty(ps.Grantor) || ps.Grantor == ps.Securable.ExpectedGrantor) + { + if (!withGrant && ps.OriginalState == PermissionStatus.WithGrant) + { + parent.Revoke(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + new string[] { column.Name }, + true, + ps.CascadeNeeded); + } + else + { + parent.Grant(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + new string[] { column.Name }, + withGrant); + } + } + else + { + if (!withGrant && ps.OriginalState == PermissionStatus.WithGrant) + { + parent.Revoke(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + new string[] { column.Name }, + true, + ps.CascadeNeeded, + ps.Grantor); + } + else + { + parent.Grant(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + new string[] { column.Name }, + withGrant, + ps.Grantor); + } + } + } + } + } + + /// + /// Revoke permissions for a principal + /// + /// The set of permissions to be revoked + /// The principal whose permissions are to be revoked + public override void Revoke(List permissions, Principal principal) + { + if (0 < permissions.Count) + { + IColumnPermission parent = (IColumnPermission)this.column.Parent; + foreach (PermissionState ps in permissions) + { + if (string.IsNullOrEmpty(ps.Grantor) || ps.Grantor == ps.Securable.ExpectedGrantor) + { + parent.Revoke(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + new string[] { column.Name }, + false, + ps.CascadeNeeded); + } + else + { + parent.Revoke(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + new string[] { column.Name }, + false, + ps.CascadeNeeded, + ps.Grantor); + } + } + } + } + + /// + /// Deny permissions to a principal + /// + /// The set of permissions to deny + /// The principal to whom permissions are to be denied + public override void Deny(List permissions, Principal principal) + { + if (0 < permissions.Count) + { + IColumnPermission parent = (IColumnPermission)this.column.Parent; + foreach (PermissionState ps in permissions) + { + parent.Deny(new ObjectPermissionSet(ps.Permission.SmoObjectPermission), + principal.Name, + new string[] { column.Name }, + ps.CascadeNeeded); + } + } + } + } + + /// + /// Permissions adapter for a database + /// + internal class DatabasePermissionsAdapter : SmoPermissionsAdapter + { + private Database database; + /// + /// Constructor + /// + /// The object whose permissions we are modifying + public DatabasePermissionsAdapter(Database database) + { + this.database = database; + } + + /// + /// Grant permissions to a principal + /// + /// The set of permissions to grant + /// The principal to whom the permissions are to be granted + /// + public override void Grant(List permissions, Principal principal, bool withGrant) + { + foreach (PermissionState ps in permissions) + { + if (string.IsNullOrEmpty(ps.Grantor) || ps.Grantor == ps.Securable.ExpectedGrantor) + { + if (!withGrant && ps.OriginalState == PermissionStatus.WithGrant) + { + this.database.Revoke(new DatabasePermissionSet(ps.Permission.SmoDatabasePermission), + principal.Name, + true, + ps.CascadeNeeded); + } + else + { + this.database.Grant(new DatabasePermissionSet(ps.Permission.SmoDatabasePermission), + principal.Name, + withGrant); + } + } + else + { + if (!withGrant && ps.OriginalState == PermissionStatus.WithGrant) + { + this.database.Revoke(new DatabasePermissionSet(ps.Permission.SmoDatabasePermission), + principal.Name, + true, + ps.CascadeNeeded, + ps.Grantor); + } + else + { + this.database.Grant(new DatabasePermissionSet(ps.Permission.SmoDatabasePermission), + principal.Name, + withGrant, + ps.Grantor); + } + } + } + } + + /// + /// Revoke permissions for a principal + /// + /// The set of permissions to be revoked + /// The principal whose permissions are to be revoked + public override void Revoke(List permissions, Principal principal) + { + foreach (PermissionState ps in permissions) + { + if (string.IsNullOrEmpty(ps.Grantor) || ps.Grantor == ps.Securable.ExpectedGrantor) + { + this.database.Revoke(new DatabasePermissionSet(ps.Permission.SmoDatabasePermission), + principal.Name, + false, + ps.CascadeNeeded); + } + else + { + this.database.Revoke(new DatabasePermissionSet(ps.Permission.SmoDatabasePermission), + principal.Name, + false, + ps.CascadeNeeded, + ps.Grantor); + } + } + } + + /// + /// Deny permissions to a principal + /// + /// The set of permissions to deny + /// The principal to whom permissions are to be denied + public override void Deny(List permissions, Principal principal) + { + foreach (PermissionState ps in permissions) + { + this.database.Deny(new DatabasePermissionSet(ps.Permission.SmoDatabasePermission), + principal.Name, + ps.CascadeNeeded); + } + } + } + + /// + /// Permissions adapter for a server + /// + internal class ServerPermissionsAdapter : SmoPermissionsAdapter + { + private Microsoft.SqlServer.Management.Smo.Server server; + + /// + /// Constructor + /// + /// The server whose permissions we are modifying + public ServerPermissionsAdapter(Microsoft.SqlServer.Management.Smo.Server server) + { + this.server = server; + } + + /// + /// Grant permissions to a principal + /// + /// The set of permissions to grant + /// The principal to whom the permissions are to be granted + /// + public override void Grant(List permissions, Principal principal, bool withGrant) + { + foreach (PermissionState ps in permissions) + { + if (string.IsNullOrEmpty(ps.Grantor) || ps.Grantor == ps.Securable.ExpectedGrantor) + { + if (!withGrant && ps.OriginalState == PermissionStatus.WithGrant) + { + this.server.Revoke(new ServerPermissionSet(ps.Permission.SmoServerPermission), + principal.Name, + true, + ps.CascadeNeeded); + } + else + { + this.server.Grant(new ServerPermissionSet(ps.Permission.SmoServerPermission), + principal.Name, + withGrant); + } + } + else + { + if (!withGrant && ps.OriginalState == PermissionStatus.WithGrant) + { + this.server.Revoke(new ServerPermissionSet(ps.Permission.SmoServerPermission), + principal.Name, + true, + ps.CascadeNeeded, + ps.Grantor); + } + else + { + this.server.Grant(new ServerPermissionSet(ps.Permission.SmoServerPermission), + principal.Name, + withGrant, + ps.Grantor); + } + } + } + } + + /// + /// Revoke permissions for a principal + /// + /// The set of permissions to be revoked + /// The principal whose permissions are to be revoked + public override void Revoke(List permissions, Principal principal) + { + foreach (PermissionState ps in permissions) + { + if (string.IsNullOrEmpty(ps.Grantor) || ps.Grantor == ps.Securable.ExpectedGrantor) + { + this.server.Revoke(new ServerPermissionSet(ps.Permission.SmoServerPermission), + principal.Name, + false, + ps.CascadeNeeded); + } + else + { + this.server.Revoke(new ServerPermissionSet(ps.Permission.SmoServerPermission), + principal.Name, + false, + ps.CascadeNeeded, + ps.Grantor); + } + } + } + + /// + /// Deny permissions to a principal + /// + /// The set of permissions to deny + /// The principal to whom permissions are to be denied + public override void Deny(List permissions, Principal principal) + { + foreach (PermissionState ps in permissions) + { + this.server.Deny(new ServerPermissionSet(ps.Permission.SmoServerPermission), + principal.Name, + ps.CascadeNeeded); + } + } + } + } +} + + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Security/PermissionsDataExtensions.cs b/src/Microsoft.SqlTools.ServiceLayer/Security/PermissionsDataExtensions.cs new file mode 100644 index 00000000..b1e0cea5 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Security/PermissionsDataExtensions.cs @@ -0,0 +1,50 @@ +// +// 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 Microsoft.SqlServer.Management.Common; + +namespace Microsoft.SqlTools.ServiceLayer.Security +{ + internal static class PermissionsDataExtensions + { + /// + /// Whether this SecurableType is a valid Schema-Scoped Securable for the given server version, engine edition and engine type + /// + /// + /// + /// + /// + /// + public static bool IsValidSchemaBoundSecurable(this SecurableType type, ServerVersion serverVersion, DatabaseEngineEdition databaseEngineEdition, DatabaseEngineType databaseEngineType) + { + return + type.GetType().GetField(type.ToString()) + .GetCustomAttributes(typeof (SchemaScopedSecurableAttribute), true) + .Cast() + .Any(attr => attr.IsValid(serverVersion, databaseEngineType, databaseEngineEdition)); + } + + /// + /// Gets the Schema-Scoped URN for this SecurableType + /// + /// + /// + /// + /// + public static string GetSchemaScopedUrn(this SecurableType type, string schema, string databaseName) + { + SchemaScopedSecurableAttribute attr = + type.GetType().GetField(type.ToString()) + .GetCustomAttributes(typeof (SchemaScopedSecurableAttribute), true) + .Cast() + .FirstOrDefault() ?? throw new InvalidOperationException("Type {0} did not define a SchemaScopedSecurableUrn attribute"); + return attr.GetUrn(schema, databaseName); + } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Security/SchemaScopedSecurableAttribute.cs b/src/Microsoft.SqlTools.ServiceLayer/Security/SchemaScopedSecurableAttribute.cs new file mode 100644 index 00000000..156e96f5 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Security/SchemaScopedSecurableAttribute.cs @@ -0,0 +1,88 @@ +// +// 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.Reflection; +using System.Text; +using Microsoft.SqlServer.Management.Common; +using Microsoft.SqlServer.Management.Sdk.Sfc; +using Microsoft.SqlServer.Management.Smo; + +namespace Microsoft.SqlTools.ServiceLayer.Security +{ + /// + /// An attribute for sqlmgmt\src\permissionsdata.cs!SecurableType that maps it to the corresponding SMO + /// type. This allows us to use that type to decide whether that securable is valid for a given server + /// version/engine edition/engine type combo and to get the URN suffix value for that type using SMO + /// instead of duplicating it in SqlMgmt. + /// + [AttributeUsage(AttributeTargets.Field)] + internal class SchemaScopedSecurableAttribute : Attribute + { + private readonly Type _smoType; + private readonly string _urnSuffix; + private readonly string _additionalParam; + + /// + /// Basic public constructor + /// + /// The SMO Type this Securable is mapped to + /// (Optional) The name of an additional param + /// (Optional) The value of an additional param + public SchemaScopedSecurableAttribute(Type smoType, string additionalParamName = "", object additionalParamValue = null ) + { + _smoType = smoType; + //The additional param is optional - just ignore if we don't have a valid name + _additionalParam = string.IsNullOrEmpty(additionalParamName) + ? String.Empty + : string.Format("@{0}='{1}'", additionalParamName, Urn.EscapeString(additionalParamValue.ToString())); + PropertyInfo urnSuffixProperty = _smoType.GetProperty("UrnSuffix", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public) ?? throw new InvalidArgumentException(string.Format("Type {0} did not have expected UrnSuffix property defined", smoType.Name)); + _urnSuffix = urnSuffixProperty.GetValue(null, null).ToString(); + } + + /// + /// The SMO Type that this securable is mapped to + /// + public Type SmoType + { + get { return _smoType; } + } + + /// + /// Whether this Securable is valid for the given server version/engine type/engine edition combo. + /// + /// + /// + /// + /// + public bool IsValid(ServerVersion serverVersion, DatabaseEngineType databaseEngineType, DatabaseEngineEdition databaseEngineEdition) + { + return SmoUtility.IsSupportedObject(_smoType, serverVersion, databaseEngineType, databaseEngineEdition); + } + + /// + /// Builds the URN for this Securable using the specified schema name (with optional database name for db-scoped securables) + /// + /// + /// + /// + public string GetUrn(string schemaName, string databaseName = "") + { + StringBuilder urn = new StringBuilder("Server"); + if (!string.IsNullOrEmpty(databaseName)) + { + urn.AppendFormat("/Database[@Name='{0}']", Urn.EscapeString(databaseName)); + } + urn.AppendFormat("/{0}[{1}{2}@Schema='{3}']", + _urnSuffix, + _additionalParam, + string.IsNullOrEmpty(_additionalParam) ? string.Empty : " and ", + Urn.EscapeString(schemaName)); + return urn.ToString(); + } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Security/SqlObjectSearchData.cs b/src/Microsoft.SqlTools.ServiceLayer/Security/SqlObjectSearchData.cs new file mode 100644 index 00000000..68079454 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Security/SqlObjectSearchData.cs @@ -0,0 +1,2328 @@ +// +// 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; +using System.Collections.Specialized; +using System.Data; +using System.Resources; +using System.Text; +using System.Globalization; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.SqlServer.Management.Sdk.Sfc; + +namespace Microsoft.SqlTools.ServiceLayer.Security +{ + /// + /// An enumeration of the SQL object types the search dialog knows how to look for + /// +#if DEBUG || EXPOSE_MANAGED_INTERNALS + public +#else + internal +#endif + enum SearchableObjectType + { + AggregateFunction = 0, + ApplicationRole = 1, + Assembly = 2, + Database = 3, + DatabaseRole = 4, + Endpoint = 5, + ExtendedStoredProcedure = 6, + FunctionInline = 7, + FunctionScalar = 8, + FunctionTable = 9, + Login = 10, + Schema = 11, + Server = 12, + ServerRole = 13, + StoredProcedure = 14, + Synonym = 15, + Table = 16, + //Trigger = 17, + User = 17, + View = 18, + XmlSchemaCollection = 19, + Rule = 20, + Default = 21, + AgentJob = 22, + Credential = 23, + SymmetricKey = 24, + AsymmetricKey = 25, + Certificate = 26, + UserDefinedDataType = 27, + FullTextCatalog = 28, + LoginOnly = 29, + UserDefinedTableType = 30, + ServiceQueue = 31, + Sequence = 32, + AvailabilityGroup = 33, + SecurityPolicy = 34, + ExternalDataSource = 35, + ExternalFileFormat = 36, + LastType = 37 // do not add object types after LastType - insert ahead of LastType instead + } + + /// + /// Type-safe collection of SearchableObjectTypes + /// +#if DEBUG || EXPOSE_MANAGED_INTERNALS + public +#else + internal +#endif + class SearchableObjectTypeCollection : System.Collections.CollectionBase + { + /// + /// Constructor + /// + /// The types the collection should initially contain + public SearchableObjectTypeCollection(params SearchableObjectType[] types) + { + if (types != null) + { + foreach (SearchableObjectType type in types) + { + this.List.Add(type); + } + } + } + + /// + /// Constructor + /// + public SearchableObjectTypeCollection() {} + + /// + /// Indexer + /// +#pragma warning disable IDE0026 // Use expression body for indexer + public SearchableObjectType this[int index] + { + get + { + return ((SearchableObjectType) this.List[index]); + } + } +#pragma warning restore IDE0026 // Use expression body for indexer + + /// + /// Add a type to the collection + /// + /// The type to add + /// The index of the type in the collection + public int Add(SearchableObjectType type) + { + return this.List.Add(type); + } + + /// + /// Get the index of the type in the collection + /// + /// The type to find + /// The type's index + public int IndexOf(SearchableObjectType type) + { + return this.List.IndexOf(type); + } + + /// + /// Insert a type into the collection at a particular index + /// + /// The index to insert the type + /// The type to insert + public void Insert(int index, SearchableObjectType type) + { + this.List.Insert(index, type); + } + + /// + /// Does the collection contain the type? + /// + /// The type to check for + /// True if the type is in the collection, false otherwise + public bool Contains(SearchableObjectType type) + { + return this.List.Contains(type); + } + + protected override void OnInsert(int index, Object value) + { + if (value.GetType() != typeof(SearchableObjectType)) + { + // STrace.Assert(false, "value is not a SearchableObjectType"); + throw new ArgumentException(); + } + } + + protected override void OnRemove(int index, Object value) + { + if (value.GetType() != typeof(SearchableObjectType)) + { + // STrace.Assert(false, "value is not a SearchableObjectType"); + throw new ArgumentException(); + } + } + + protected override void OnSet(int index, Object oldValue, Object newValue) + { + if (newValue.GetType() != typeof(SearchableObjectType)) + { + // STrace.Assert(false, "newValue is not a SearchableObjectType"); + throw new ArgumentException(); + } + } + + protected override void OnValidate(Object value) + { + if (value.GetType() != typeof(SearchableObjectType)) + { + // STrace.Assert(false, "value is not a SearchableObjectType"); + throw new ArgumentException(); + } + } + + + } + + + /// + /// Descriptive information for each SQL object type + /// +#if DEBUG || EXPOSE_MANAGED_INTERNALS + public +#else + internal +#endif + class SearchableObjectTypeDescription + { + // private Image image; + private string typeNameSingular; + private string typeNamePlural; + private string urnObjectType; + private string specialRestrictions; + private string disallowSystemObjectsRestriction; + private bool isDatabaseObject; + private bool isSchemaObject; + private const int YUKON = 9; + + /// + /// The bitmap associated with the searchable object type + /// + // public Image Image + // { + // get + // { + // return this.image; + // } + // } + + /// + /// The singular display name for the object type + /// + public string DisplayTypeNameSingular + { + get + { + return this.typeNameSingular; + } + } + + /// + /// The plural display name for the object type + /// + public string DisplayTypeNamePlural + { + get + { + return this.typeNamePlural; + } + } + + /// + /// Whether the object type is a server object (i.e. not contained by a database) + /// + public bool IsServerObject + { + get + { + return !this.isDatabaseObject; + } + } + + /// + /// Whether the object type is a database object (i.e. contained by a database) + /// + public bool IsDatabaseObject + { + get + { + return this.isDatabaseObject; + } + } + + /// + /// Whether the object type is a schema object (i.e. contained by a schema) + /// + public bool IsSchemaObject + { + get + { + return this.isSchemaObject; + } + } + + /// + /// Constructor + /// + /// Bitmap for the object type + /// The key to look up localized type names, e.g. "objectType.functionTable" + /// The URN object type substring, e.g. "UserDefinedFunction" + /// Any special clauses needed for the URN, e.g. "@FunctionType='2'" + /// Clause to restrict selection to non-system objects, e.g. "@IsSystemObject='false'" + /// Whether the object is contained by a database + /// Whether the object is contained byt a schema + private SearchableObjectTypeDescription( + // Image image, + string typeNameKey, + string urnObjectType, + string specialRestrictions, + string disallowSystemObjectsRestriction, + bool isDatabaseObject, + bool isSchemaObject, + ResourceManager resourceManager) + { + // STrace.Assert(image != null, "image is null"); + // STrace.Assert((typeNameKey != null) && (typeNameKey.Length != 0), "typeNameKey is null or empty"); + // STrace.Assert(specialRestrictions != null, "specialRestrictions is null"); + // STrace.Assert(disallowSystemObjectsRestriction != null, "disallowSystemObjectsRestriction is null"); + // STrace.Assert(resourceManager != null, "resourceManager is null"); + + // this.image = image; + this.urnObjectType = urnObjectType; + this.specialRestrictions = specialRestrictions; + this.disallowSystemObjectsRestriction = disallowSystemObjectsRestriction; + this.isDatabaseObject = isDatabaseObject; + this.isSchemaObject = isSchemaObject; + + this.typeNamePlural = resourceManager.GetString(String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.plural", typeNameKey)); + this.typeNameSingular = resourceManager.GetString(String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.singular", typeNameKey)); + + // STrace.Assert((this.typeNamePlural != null) && (this.typeNamePlural.Length != 0), "could not get plural type name"); + // STrace.Assert((this.typeNameSingular != null) && (this.typeNameSingular.Length != 0), "could not get singular type name"); + } + + /// + /// Constructor + /// + /// Bitmap for the object type + /// The key to look up localized type names, e.g. "objectType.functionTable" + /// The URN object type substring, e.g. "UserDefinedFunction" + /// Whether the object is contained by a database + /// Whether the object is contained byt a schema + private SearchableObjectTypeDescription( + // Image image, + string typeNameKey, + string urnObjectType, + bool isDatabaseObject, + bool isSchemaObject, + ResourceManager resourceManager) + { + // STrace.Assert(image != null, "image is null"); + // STrace.Assert((typeNameKey != null) && (typeNameKey.Length != 0), "typeNameKey is null or empty"); + // STrace.Assert(resourceManager != null, "resourceManager is null"); + + // this.image = image; + this.urnObjectType = urnObjectType; + this.specialRestrictions = String.Empty; + this.disallowSystemObjectsRestriction = String.Empty; + this.isDatabaseObject = isDatabaseObject; + this.isSchemaObject = isSchemaObject; + + this.typeNamePlural = resourceManager.GetString(String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.plural", typeNameKey)); + this.typeNameSingular = resourceManager.GetString(String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.singular", typeNameKey)); + + // STrace.Assert((this.typeNamePlural != null) && (this.typeNamePlural.Length != 0), "could not get plural type name"); + // STrace.Assert((this.typeNameSingular != null) && (this.typeNameSingular.Length != 0), "could not get singular type name"); + } + + /// + /// Get a URN string to enumerate instances of the object type + /// + /// + /// The version is used to enumerate all server objects of a particular type + /// + /// Whether system or built-in objects should be included in the results + /// The URN string to enumerate the type + internal string GetSearchUrn(bool includeSystemObjects) + { + // STrace.Assert(!this.isDatabaseObject, "wrong overload for enumerating database objects"); + + StringBuilder builder = new StringBuilder("Server"); + + if (0 != this.urnObjectType.Length) + { + builder.AppendFormat("/{0}", this.urnObjectType); + } + + this.AppendRestrictions( + builder, + String.Empty, + false, + String.Empty, + false, + includeSystemObjects); + + return builder.ToString(); + } + + /// + /// Get a URN string to enumerate instances of the object type + /// + /// + /// This overload is used to enumerate all database objects of a particular type. + /// + /// The name of the database containing the objects that are to be enumerated + /// Whether system or built-in objects should be included in the results + /// The URN string to enumerate the type + internal string GetSearchUrn(string databaseName, bool includeSystemObjects) + { + // STrace.Assert(this.isDatabaseObject, "wrong overload for enumerating server objects"); + // STrace.Assert(databaseName.Length != 0, "database name is empty"); + + StringBuilder builder = new StringBuilder("Server"); + + builder.AppendFormat("/Database[@Name='{0}']", Urn.EscapeString(databaseName)); + + if (0 != this.urnObjectType.Length) + { + builder.AppendFormat("/{0}", this.urnObjectType); + } + + this.AppendRestrictions( + builder, + String.Empty, + false, + String.Empty, + false, + includeSystemObjects); + + return builder.ToString(); + } + + /// + /// Get a URN string to enumerate instances of the object type + /// + /// + /// This overload is used to enumerate all server objects of a particular type with + /// a particular name. + /// + /// The name of the object to enumerate + /// True if the name is complete, false if it is a fragment the name should contain + /// Whether system or built-in objects should be included in the results + /// The URN string to enumerate the type + internal string GetSearchUrn(string name, bool exactName, bool includeSystemObjects) + { + // STrace.Assert(!this.isDatabaseObject, "wrong overload for enumerating database objects"); + // STrace.Assert(name.Length != 0, "name is empty"); + + StringBuilder builder = new StringBuilder("Server"); + + if (0 != this.urnObjectType.Length) + { + builder.AppendFormat("/{0}", this.urnObjectType); + } + + this.AppendRestrictions( + builder, + name, + exactName, + String.Empty, + false, + includeSystemObjects); + + return builder.ToString(); + } + + /// + /// Get a URN string to enumerate instances of the object type + /// + /// + /// This overload is used to enumerate all database objects of a particular type with + /// a particular name. + /// + /// The name of the database containing the objects that are to be enumerated + /// The name of the object to enumerate + /// True if the name is complete, false if it is a fragment the name should contain + /// Whether system or built-in objects should be included in the results + /// The URN string to enumerate the type + internal string GetSearchUrn(string databaseName, string name, bool exactName, bool includeSystemObjects) + { + // STrace.Assert(this.isDatabaseObject, "wrong overload for enumerating database objects"); + // STrace.Assert(databaseName.Length != 0, "database name is empty"); + + StringBuilder builder = new StringBuilder("Server"); + + builder.AppendFormat("/Database[@Name='{0}']/{1}", Urn.EscapeString(databaseName), this.urnObjectType); + + this.AppendRestrictions( + builder, + name, + exactName, + String.Empty, + false, + includeSystemObjects); + + return builder.ToString(); + } + + /// + /// Get a URN string to enumerate instances of the object type + /// + /// + /// This overload is used to enumerate all database objects of a particular type with + /// a particular name and schema. If name or schema is omitted, all names/schemas will be matched. + /// + /// The name of the database containing the objects that are to be enumerated + /// The name of the object to enumerate + /// True if the name is complete, false if it is a fragment that the name should contain + /// The schema of the object to enumerate + /// True if the schema name is complete, false if it is a fragment that the schema name should contain + /// Whether system or built-in objects should be included in the results + /// The URN string to enumerate the type + internal string GetSearchUrn( + string databaseName, + string name, + bool exactName, + string schema, + bool exactSchema, + bool includeSystemObjects) + { + // STrace.Assert(this.isDatabaseObject, "wrong overload for enumerating server objects"); + // STrace.Assert(databaseName.Length != 0, "database name is empty"); + + StringBuilder builder = new StringBuilder("Server"); + + builder.AppendFormat("/Database[@Name='{0}']/{1}", Urn.EscapeString(databaseName), this.urnObjectType); + + this.AppendRestrictions( + builder, + name, + exactName, + schema, + exactSchema, + includeSystemObjects); + + return builder.ToString(); + } + + /// + /// Append the restriction portion of the URN (e.g. "[@Name='foo']") to the input StringBuilder + /// + /// The StringBuilder that is forming the URN string + /// The name of the object to enumerate + /// True if the name is complete, false if it is a fragment that the name should contain + /// The schema of the object to enumerate + /// True if the schema name is complete, false if it is a fragment that the schema name should contain + /// Whether system or built-in objects should be included in the results + private void AppendRestrictions( + StringBuilder builder, + string name, + bool exactName, + string schema, + bool exactSchema, + bool includeSystemObjects) + { + bool hasNameRestriction = (name.Length != 0); + bool hasSchemaRestriction = (schema.Length != 0); + bool hasSpecialRestriction = (0 != this.specialRestrictions.Length); + bool hasSystemObjectRestriction = (!includeSystemObjects && (this.disallowSystemObjectsRestriction.Length != 0)); + + if (hasNameRestriction || hasSchemaRestriction || hasSpecialRestriction || hasSystemObjectRestriction) + { + bool restrictionApplied = false; + builder.Append("["); + + if (hasNameRestriction) + { + if (exactName) + { + builder.AppendFormat("@Name='{0}'", Urn.EscapeString(name)); + } + else + { + builder.AppendFormat("contains(@Name, '{0}')", Urn.EscapeString(name)); + } + + restrictionApplied = true; + } + + if (hasSchemaRestriction) + { + if (restrictionApplied) + { + builder.Append(" and "); + } + + if (exactSchema) + { + builder.AppendFormat("@Schema='{0}'", Urn.EscapeString(schema)); + } + else + { + builder.AppendFormat("contains(@Schema, '{0}')", Urn.EscapeString(schema)); + } + + restrictionApplied = true; + } + + if (hasSpecialRestriction) + { + if (restrictionApplied) + { + builder.AppendFormat(CultureInfo.InvariantCulture, " and ({0}) ", this.specialRestrictions); + } + else + { + builder.AppendFormat(CultureInfo.InvariantCulture, this.specialRestrictions); + } + + restrictionApplied = true; + } + + if (hasSystemObjectRestriction) + { + if (restrictionApplied) + { + builder.Append(" and "); + } + + builder.Append(this.disallowSystemObjectsRestriction); + } + + builder.Append("]"); + } + } + + + private static HybridDictionary typeToDescription; + private static bool firstVersionSpecificTypeInfoUpdate = true; + + /// + /// Updates the typedescription with version specific information. + /// + private static void UpdateVersionSpecificTypeDescription(Version serverVersion) + { + if (SearchableObjectTypeDescription.firstVersionSpecificTypeInfoUpdate) + { + ResourceManager resourceManager = new ResourceManager("Microsoft.SqlServer.Management.SqlMgmt.SqlObjectSearchStrings", typeof(SearchableObjectTypeDescription).Assembly); + // Color transparent = ResourceUtils.StandardBitmapTransparentColor; + + //Re-writing the value of SearchableObjectType.ServerRole in the Dictionary. + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.ServerRole] = + new SearchableObjectTypeDescription( + // // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("Flexible_server_role.ico")).ToBitmap(), + "objectType.serverRole", + "Role", + string.Empty, + Utils.IsSql11OrLater(serverVersion.Major) + ? "@IsFixedRole=false()" + : serverVersion.Major >= YUKON + ? "@ID=2" //Public server role's ID is 2. + : string.Empty, + false, + false, + resourceManager); + + firstVersionSpecificTypeInfoUpdate = false; + } + } + + /// + /// Static constructor + /// + static SearchableObjectTypeDescription() + { + if (typeToDescription == null) + { + SearchableObjectTypeDescription.typeToDescription = new HybridDictionary(25); + } + + ResourceManager resourceManager = new ResourceManager("Microsoft.SqlServer.Management.SqlMgmt.SqlObjectSearchStrings", typeof(SearchableObjectTypeDescription).Assembly); + // Color transparent = ResourceUtils.StandardBitmapTransparentColor; + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.AggregateFunction] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("ScalarValuedFunction.ico")).ToBitmap(), + "objectType.aggregateFunction", + "UserDefinedAggregate", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.ApplicationRole] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("application_role_16x.ico")).ToBitmap(), + "objectType.applicationRole", + "ApplicationRole", + true, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Assembly] = + new SearchableObjectTypeDescription( + // // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("assemblies.ico")).ToBitmap(), + "objectType.assembly", + "SqlAssembly", + true, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.AsymmetricKey] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("asymmetric_key.ico")).ToBitmap(), + "objectType.asymmetricKey", + "AsymmetricKey", + true, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Certificate] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("certificate.ico")).ToBitmap(), + "objectType.certificate", + "Certificate", + true, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Database] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("database.ico")).ToBitmap(), + "objectType.database", + "Database", + String.Empty, + "@IsSystemObject=false()", + false, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.AgentJob] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("jobs.ico")).ToBitmap(), + "objectType.agentjob", + "JobServer/Job", + false, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.DatabaseRole] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("database_roles_16x.ico")).ToBitmap(), + "objectType.databaseRole", + "Role", + String.Empty, + "@IsFixedRole=false()", + true, + false, + resourceManager); + + //Without version info, we can't have system object Urn as it differs with version. + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.ServerRole] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("Flexible_server_role.ico")).ToBitmap(), + "objectType.serverRole", + "Role", + false, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Endpoint] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("endpoint.ico")).ToBitmap(), + "objectType.endpoint", + "Endpoint", + false, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.ExtendedStoredProcedure] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("user_extended_stored_proc.ico")).ToBitmap(), + "objectType.extendedStoredProcedure", + "ExtendedStoredProcedure", + String.Empty, + "@IsSystemObject=false()", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.ExternalDataSource] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("ExternalDataSource.ico")).ToBitmap(), + "objectType.externalDataSource", + "ExternalDataSource", + true, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.ExternalFileFormat] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("ExternalFileFormat.ico")).ToBitmap(), + "objectType.externalFileFormat", + "ExternalFileFormat", + true, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.FullTextCatalog] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("full_text_catalog.ico")).ToBitmap(), + "objectType.fullTextCatalog", + "FullTextCatalog", + true, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.FunctionInline] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("table_valued_function.ico")).ToBitmap(), + "objectType.functionInline", + "UserDefinedFunction", + String.Format(System.Globalization.CultureInfo.InvariantCulture, "@FunctionType='{0}'", (int)UserDefinedFunctionType.Inline), + "@IsSystemObject=false()", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.FunctionScalar] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("ScalarValuedFunction.ico")).ToBitmap(), + "objectType.functionScalar", + "UserDefinedFunction", + String.Format(System.Globalization.CultureInfo.InvariantCulture, "@FunctionType='{0}'", (int)UserDefinedFunctionType.Scalar), + "@IsSystemObject=false()", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.FunctionTable] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("table_valued_function.ico")).ToBitmap(), + "objectType.functionTable", + "UserDefinedFunction", + String.Format(System.Globalization.CultureInfo.InvariantCulture, "@FunctionType='{0}'", (int)UserDefinedFunctionType.Table), + "@IsSystemObject=false()", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Login] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("log_in_16x.ico")).ToBitmap(), + "objectType.login", + "Login", + String.Empty, + "@IsSystemObject=false()", + false, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.LoginOnly] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("log_in_16x.ico")).ToBitmap(), + "objectType.login", + "Login", + "@LoginType = 2 or @LoginType = 0", + "@IsSystemObject=false()", + false, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Schema] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("database_schema.ico")).ToBitmap(), + "objectType.schema", + "Schema", + true, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Server] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("server.ico")).ToBitmap(), + "objectType.server", + String.Empty, + false, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.SecurityPolicy] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("securitypolicy.ico")).ToBitmap(), + "objectType.securityPolicy", + "SecurityPolicy", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.ServiceQueue] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("queue.ico")).ToBitmap(), + "objectType.serviceQueue", + "ServiceBroker/ServiceQueue", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.StoredProcedure] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("stored_procedure.ico")).ToBitmap(), + "objectType.storedProcedure", + "StoredProcedure", + String.Empty, + "@IsSystemObject=false()", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Synonym] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("synonym.ico")).ToBitmap(), + "objectType.synonym", + "Synonym", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Sequence] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("sequence.ico")).ToBitmap(), + "objectType.sequence", + "Sequence", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Table] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("table.ico")).ToBitmap(), + "objectType.table", + "Table", + String.Empty, + "@IsSystemObject=false()", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.User] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("user_16x.ico")).ToBitmap(), + "objectType.user", + "User", + String.Empty, + "(@IsSystemObject=false() or @Name='guest')", + true, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.UserDefinedDataType] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("user_defined_data_type.ico")).ToBitmap(), + "objectType.userDefinedDataType", + "UserDefinedDataType", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.View] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("view.ico")).ToBitmap(), + "objectType.view", + "View", + String.Empty, + "@IsSystemObject=false()", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.XmlSchemaCollection] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("XML_schemas.ico")).ToBitmap(), + "objectType.xmlSchemaCollection", + "XmlSchemaCollection", + true, + true, + resourceManager); + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Rule] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("rule.ico")).ToBitmap(), + "objectType.rule", + "Rule", + true, + true, + resourceManager); + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Default] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("defaults_16x.ico")).ToBitmap(), + "objectType.default", + "Default", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.Credential] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("credential.ico")).ToBitmap(), + "objectType.credential", + "Credential", + false, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.SymmetricKey] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("symmetric_key.ico")).ToBitmap(), + "objectType.symmetricKey", + "SymmetricKey", + true, + false, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.UserDefinedTableType] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("table.ico")).ToBitmap(), + "objectType.userDefinedTableType", + "UserDefinedTableType", + true, + true, + resourceManager); + + SearchableObjectTypeDescription.typeToDescription[SearchableObjectType.AvailabilityGroup] = + new SearchableObjectTypeDescription( + // DpiUtil.GetScaledIcon(ResourceUtils.LoadIcon("Availability_Group.ico")).ToBitmap(), + "objectType.AvailabilityGroup", + "AvailabilityGroup", + false, + false, + resourceManager); + } + + /// + /// Get the type description for a particular searchable object type + /// + /// The searchable object type + /// The type description + public static SearchableObjectTypeDescription GetDescription(SearchableObjectType objectType) + { + // STrace.Assert( + // SearchableObjectTypeDescription.typeToDescription.Contains(objectType), + // "unexpected object type - did you add the object type description?"); + + return (SearchableObjectTypeDescription) SearchableObjectTypeDescription.typeToDescription[objectType]; + } + + /// + /// Get the type description for a particular searchable object type + /// + /// + /// The searchable object type + /// The type description + public static SearchableObjectTypeDescription GetDescription(object connectionInfo, SearchableObjectType objectType) + { + // STrace.Assert( + // SearchableObjectTypeDescription.typeToDescription.Contains(objectType), + // "unexpected object type - did you add the object type description?"); + + SearchableObjectTypeDescription.UpdateVersionSpecificTypeDescription(PermissionsData.Securable.GetServerVersion(connectionInfo)); + return (SearchableObjectTypeDescription)SearchableObjectTypeDescription.typeToDescription[objectType]; + } + } + + /// + /// Selection status for an object type + /// +#if DEBUG || EXPOSE_MANAGED_INTERNALS + public +#else + internal +#endif + class SearchableObjectTypeSelection + { + private SearchableObjectType objectType; + private bool isSelected; + + /// + /// The object type + /// + public SearchableObjectType SearchableObjectType + { + get + { + return this.objectType; + } + } + + /// + /// Whether the object type has been selected + /// + public bool IsSelected + { + get + { + return this.isSelected; + } + + set + { + this.isSelected = value; + } + } + + + /// + /// Constructor + /// + /// The type of the object + /// Whether it is selected + public SearchableObjectTypeSelection(SearchableObjectType objectType, bool isSelected) + { + this.objectType = objectType; + this.isSelected = isSelected; + } + } + + /// + /// A SQL server object + /// +#if DEBUG || EXPOSE_MANAGED_INTERNALS + public +#else + internal +#endif + class SearchableObject : IComparable + { + private SearchableObjectType objectType; + private Urn urn; + private System.Globalization.CompareOptions compareOptions; + + /// + /// The type of the object + /// + public SearchableObjectType SearchableObjectType + { + get + { + return this.objectType; + } + } + + /// + /// The display text for the type of the object + /// + public string TypeName + { + get + { + return SearchableObjectTypeDescription.GetDescription(objectType).DisplayTypeNameSingular; + } + } + /// + /// The name of the object + /// + public string Name + { + get + { + return this.urn.GetAttribute("Name"); + } + } + + /// + /// The schema of the object + /// + public string Schema + { + get + { + string result = String.Empty; + + if (SearchableObjectTypeDescription.GetDescription(this.objectType).IsSchemaObject) + { + result = this.urn.GetAttribute("Schema"); + } + + return result; + } + } + + /// + /// The name of the database containing the object, or an empty string + /// if database doesn't apply + /// + public string DatabaseName + { + get + { + string result = String.Empty; + + if (!SearchableObjectTypeDescription.GetDescription(this.objectType).IsServerObject) + { + Urn currentUrn = this.urn; + + while ( + (currentUrn != null) && + (0 != String.Compare(currentUrn.Type, "Database", StringComparison.OrdinalIgnoreCase))) + { + currentUrn = currentUrn.Parent; + + // STrace.Assert(currentUrn != null, "ran off the top of the xpath"); + } + + if (currentUrn != null) + { + // STrace.Assert( + // (0 == String.Compare(currentUrn.Type, "Database", StringComparison.OrdinalIgnoreCase)), + // "currentUrn is not a database!"); + + result = currentUrn.GetAttribute("Name"); + } + } + + return result; + } + } + + /// + /// The URN for the object + /// + public Urn Urn + { + get + { + return this.urn; + } + } + + /// + /// The icon for the object + /// + // public Image Image + // { + // get + // { + // return SearchableObjectTypeDescription.GetDescription(this.objectType).Image; + // } + // } + + /// + /// The CompareOptions that should be used to compare this SearchableObject + /// + internal System.Globalization.CompareOptions CompareOptions + { + get + { + return this.compareOptions; + } + } + + /// + /// Constructor + /// + /// The type of the object + /// The urn for the object + /// The collation used to compare object names + public SearchableObject(SearchableObjectType objectType, string urn, string sqlCollation) + { + this.objectType = objectType; + this.urn = new Urn(urn); + this.compareOptions = SqlSupport.GetCompareOptionsFromCollation(sqlCollation); + } + + /// + /// Constructor + /// + /// The type of the object + /// The urn for the object + /// The CompareOptions used to compare object names + public SearchableObject(SearchableObjectType objectType, string urn, System.Globalization.CompareOptions compareOptions) + { + this.objectType = objectType; + this.urn = urn; + this.compareOptions = compareOptions; + } + + /// + /// Determine whether this object should be considered less than, equal to, or greater than another object + /// + /// The object to compare to + /// less than zero if this is less, 0 if equal, greater than zero if this is greater + public int CompareTo(object obj) + { + int result = 0; + + if (obj.GetType() == this.GetType()) + { + SearchableObject other = (SearchableObject) obj; + SqlCollationSensitiveStringComparer comparer = new SqlCollationSensitiveStringComparer(this.compareOptions); + + string thisSchema = this.Schema; + string otherSchema = other.Schema; + + if ((thisSchema.Length != 0) && (otherSchema.Length != 0)) + { + result = comparer.Compare(thisSchema, otherSchema); + } + else if ((thisSchema.Length == 0) && (otherSchema.Length == 0)) + { + result = 0; + } + else if (thisSchema.Length == 0) + { + result = 1; + } + else + { + result = -1; + } + + if (0 == result) + { + result = comparer.Compare(this.Name, other.Name); + } + + if (0 == result) + { + result = this.objectType.CompareTo(((SearchableObject) obj).objectType); + } + } + else + { + throw new ArgumentException("unexpected object type", "obj"); + } + + return result; + } + + /// + /// Get the object's two-part name (e.g. "[schema].[name]") or one-part name + /// for non-schema objects (e.g. "[name]") + /// + /// The formatted multi-part name + public override string ToString() + { + return (new ObjectName(this)).ToString(); + } + + /// + /// Search for all object instances matching the input criteria and add them to the collection + /// + /// + /// This overload is used to enumerate all server objects of a particular type + /// + /// The type of objects to search for + /// Connection information used to enumerate objects + /// Whether system or built-in objects should be included in the search results + /// True if any objects were found, false otherwise + public static bool Search( + SearchableObjectCollection collection, + SearchableObjectType type, + object connectionInfo, + bool includeSystemObjects) + { + string urn = SearchableObjectTypeDescription.GetDescription(connectionInfo, type).GetSearchUrn(includeSystemObjects); + return SearchImpl(collection, type, connectionInfo, urn, String.Empty); + } + + /// + /// Search for all object instances matching the input criteria and add them to the collection + /// + /// + /// This overload is used to enumerate all database objects of a particular type + /// + /// The type of objects to search for + /// Connection information used to enumerate objects + /// The name of the database containing the objects + /// Whether system or built-in objects should be included in the search results + /// True if any objects were found, false otherwise + public static bool Search( + SearchableObjectCollection collection, + SearchableObjectType type, + object connectionInfo, + string databaseName, + bool includeSystemObjects) + { + string urn = SearchableObjectTypeDescription.GetDescription(connectionInfo, type).GetSearchUrn(databaseName, includeSystemObjects); + return SearchImpl(collection, type, connectionInfo, urn, databaseName); + } + + /// + /// Search for all object instances matching the input criteria and add them to the collection + /// + /// + /// This overload is used to enumerate all server objects of a particular type with a + /// particular name + /// + /// The type of objects to search for + /// Connection information used to enumerate objects + /// The name of the object we're looking for + /// + /// If true, search for an object whose name exactly matches objectName, + /// otherwise search for an object whose name contains objectName + /// + /// Whether system or built-in objects should be included in the search results + /// True if any objects were found, false otherwise + public static bool Search( + SearchableObjectCollection collection, + SearchableObjectType type, + object connectionInfo, + string objectName, + bool exactNameMatch, + bool includeSystemObjects) + { + string urn = SearchableObjectTypeDescription.GetDescription(connectionInfo, type).GetSearchUrn( + objectName, + exactNameMatch, + includeSystemObjects); + + return SearchImpl(collection, type, connectionInfo, urn, String.Empty); + } + + /// + /// Search for all object instances matching the input criteria and add them to the collection + /// + /// + /// This overload is used to enumerate all non-schema database objects of a particular type with a + /// particular name. + /// + /// The type of objects to search for + /// Connection information used to enumerate objects + /// The name of the database containing the objects + /// The name of the object we're looking for + /// + /// If true, search for an object whose name exactly matches objectName, + /// otherwise search for an object whose name contains objectName + /// + /// Whether system or built-in objects should be included in the search results + /// True if any objects were found, false otherwise + public static bool Search( + SearchableObjectCollection collection, + SearchableObjectType type, + object connectionInfo, + string databaseName, + string objectName, + bool exactNameMatch, + bool includeSystemObjects) + { + string urn = SearchableObjectTypeDescription.GetDescription(connectionInfo, type).GetSearchUrn( + databaseName, + objectName, + exactNameMatch, + includeSystemObjects); + + return SearchImpl(collection, type, connectionInfo, urn, databaseName); + } + + /// + /// Search for all object instances matching the input criteria and add them to the collection + /// + /// + /// This overload is used to enumerate all database objects of a particular type with a + /// particular object name and/or schema name. + /// + /// The type of objects to search for + /// Connection information used to enumerate objects + /// The name of the database containing the objects + /// The name of the object we're looking for + /// + /// If true, search for an object whose name exactly matches objectName, + /// otherwise search for an object whose name contains objectName + /// + /// The schema of the object we're looking for + /// + /// If true, search for an object whose schema exactly matches schemaName, + /// otherwise search for an object whose schema contains schemaName + /// + /// Whether system or built-in objects should be included in the search results + /// True if any objects were found, false otherwise + public static bool Search( + SearchableObjectCollection collection, + SearchableObjectType type, + object connectionInfo, + string databaseName, + string objectName, + bool exactNameMatch, + string schemaName, + bool exactSchemaMatch, + bool includeSystemObjects) + { + string urn = SearchableObjectTypeDescription.GetDescription(connectionInfo, type).GetSearchUrn( + databaseName, + objectName, + exactNameMatch, + schemaName, + exactSchemaMatch, + includeSystemObjects); + + return SearchImpl(collection, type, connectionInfo, urn, databaseName); + } + + /// + /// Get a SearchableObject for the input fully-qualified name. If no such object + /// exists on the server, then null is returned. + /// + /// The type of object to get + /// The connection information to be used by the SMO enumerator + /// The name of the database containing the object, or null if the object is not contained by a database + /// The fully-qualified name of the object (e.g. [Sales].[SalesSchemaCollection]) + /// The SearchableObject if such an object exists on the server; otherwise null + public static SearchableObject GetSearchableObject( + SearchableObjectType type, + object connectionInfo, + string databaseName, + string fullObjectName) + { + SearchableObjectCollection results = new SearchableObjectCollection(); + ObjectName objectName = null; + int startIndex = 0; + + if ((fullObjectName != null) && (fullObjectName.Length != 0) && + SearchableObject.GetNextName(fullObjectName, ref startIndex, CompareOptions.Ordinal, out objectName)) + { + SearchableObjectTypeDescription typeDescription = SearchableObjectTypeDescription.GetDescription(connectionInfo, type); + + if (typeDescription.IsDatabaseObject) + { + // STrace.Assert( + // ((databaseName != null) && (databaseName.Length != 0)), + // "database name not provided for database object"); + + if (typeDescription.IsSchemaObject) + { + string schemaName = String.Empty; + + // if the client specified a schema, use it + if (objectName.Schema.Length != 0) + { + schemaName = objectName.Schema; + } + else + { + // otherwise use the default schema in the database + string urn = String.Format( + "Server/Database[@Name='{0}']", + Urn.EscapeString(databaseName)); + + string[] fields = new string[] { "DefaultSchema" }; + + DataTable dt = (new Enumerator()).Process(connectionInfo, new Request(urn, fields)); + // STrace.Assert(dt.Rows.Count == 1, "unexpected number of rows returned"); + + if (0 < dt.Rows.Count) + { + schemaName = dt.Rows[0][0].ToString(); + } + } + + // STrace.Assert(schemaName.Length != 0, "schema name is empty"); + + SearchableObject.Search( + results, + type, + connectionInfo, + databaseName, + objectName.Name, + true, + schemaName, + (schemaName.Length != 0), + true); + } + else + { + SearchableObject.Search( + results, + type, + connectionInfo, + databaseName, + objectName.Name, + true, + true); + } + } + else + { + SearchableObject.Search( + results, + type, + connectionInfo, + objectName.Name, + true, + true); + } + } + + // STrace.Assert(results.Count <= 1, "more than one object found for an 'exact match' search"); + SearchableObject result = (results.Count != 0) ? results[0] : null; + return result; + } + + /// + /// Get the collation for a particular database or server + /// + /// The connection information to communicate with the server + /// The name of the database, or null to get the server collation + /// The name of the database or server collation + public static string GetSqlCollation(object connectionInfo, string databaseName) + { + string result = String.Empty; + Enumerator enumerator = new Enumerator(); + Request request = new Request(); + + if (databaseName != null && databaseName.Length != 0) + { + request.Urn = String.Format( + System.Globalization.CultureInfo.InvariantCulture, + "Server/Database[@Name='{0}']", + Urn.EscapeString(databaseName)); + } + else + { + request.Urn = "Server/Information"; + } + + request.Fields = new string[] { "Collation" }; + + System.Data.DataTable queryResults = enumerator.Process(connectionInfo, request); + // STrace.Assert(queryResults.Rows.Count == 1, "unexpected number of collations returned"); + if (queryResults.Rows.Count != 0) + { + result = queryResults.Rows[0][0].ToString(); + } + + return result; + } + + /// + /// Search for object instances and add them to the collection + /// + /// The type of objects to search for + /// Connection information used to enumerate objects + /// the urn describing the objects to enumerate + /// True if any objects were found, false otherwise + private static bool SearchImpl( + SearchableObjectCollection collection, + SearchableObjectType type, + object connectionInfo, + string urn, + string databaseName) + { + string sqlCollation = GetSqlCollation(connectionInfo, databaseName); + CompareOptions compareOptions = SqlSupport.GetCompareOptionsFromCollation(sqlCollation); + Enumerator enumerator = new Enumerator(); + Request request = new Request(); + + request.Fields = new string[] { "Urn" }; + request.Urn = new Urn(urn); + + DataTable enumeratedUrns = enumerator.Process(connectionInfo, request); + bool foundObjects = (0 < enumeratedUrns.Rows.Count); + + for (int i = 0; i < enumeratedUrns.Rows.Count; ++i) + { + string enumeratedUrn = enumeratedUrns.Rows[i]["Urn"].ToString(); + // STrace.Assert(enumeratedUrn.Length != 0, "received empty urn string"); + + SearchableObject enumeratedObject = new SearchableObject(type, enumeratedUrn, compareOptions); + // STrace.Assert(!collection.Contains(enumeratedObject), "enumerated object is already in the result"); + collection.Add(enumeratedObject); + } + + return foundObjects; + } + + + /// + /// Peel the next multi-part identifier from a string of semi-colon delimited identifiers + /// + /// The semi-colon delimited string of identifiers + /// The index in the names string where the next identifier begins + /// The multi-part identifier that was peeled + /// True if there was a next identifier, false otherwise + internal static bool GetNextName( + string names, + ref int startIndex, + CompareOptions compareOptions, + out ObjectName objectName) + { + objectName = new ObjectName(compareOptions); + + while (startIndex < names.Length) + { + string token = SearchableObject.GetNextToken(names, ref startIndex); + + if ((0 == token.Length) || (';' == token[0])) + { + break; + } + else if ('.' == token[0]) + { + // do nothing - skip part separator + } + else + { + objectName.Add(Unquote(token)); + } + } + + return (objectName.PartCount != 0); + } + + /// + /// Convert a quoted identifier part to a non-quoted identifier part. Non-quoted parts are + /// returned unchanged. + /// + /// The identifier part to unquote + /// The unquoted equivalent to the input identfier part + private static string Unquote(string identifierPart) + { + string result = identifierPart; + + if ((identifierPart != null) && (2 < identifierPart.Length)) + { + if ((('[' == identifierPart[0]) && (']' == identifierPart[identifierPart.Length - 1])) || + (('"' == identifierPart[0]) && ('"' == identifierPart[identifierPart.Length - 1]))) + { + result = identifierPart.Substring(1, identifierPart.Length - 2); + + if ('[' == identifierPart[0]) + { + result = result.Replace("]]", "]"); + } + else if ('"' == identifierPart[0]) + { + result = result.Replace("\"\"", "\""); + } + } + } + + return result; + } + + /// + /// Get the next token from the source string. Tokens are '.', ';', or identifier parts. + /// Identifier parts may or may not be quoted. + /// + /// The string from which to extract tokens + /// The index in the string where the next token starts. + /// The next token string in the string, or Empty if there are no more tokens + private static string GetNextToken(string source, ref int nextStartIndex) + { + string result = String.Empty; + + + if ((source != null) && (0 < (source.Length - nextStartIndex))) + { + // eat any leading space characters + while ((nextStartIndex < source.Length) && Char.IsWhiteSpace(source[nextStartIndex])) + { + ++nextStartIndex; + } + + if (nextStartIndex != source.Length) + { + char firstCharacter = source[nextStartIndex]; + int lastCharacterIndex = nextStartIndex; + char[] separators = new char[] { '.', ';' }; + + if (('.' == firstCharacter) || (';' == firstCharacter)) + { + // do nothing - just return the one character + } + else if (('[' == firstCharacter) || ('"' == firstCharacter)) + { + char terminatingQuoteCharacter = ('[' == firstCharacter) ? ']' : '"'; + + lastCharacterIndex = GetNextIndex(source, nextStartIndex + 1, terminatingQuoteCharacter, true); + + if (-1 == lastCharacterIndex) + { + lastCharacterIndex = source.IndexOfAny(separators, nextStartIndex + 1); + } + + if (-1 == lastCharacterIndex) + { + lastCharacterIndex = source.Length - 1; + } + + } + else + { + int separatorIndex = source.IndexOfAny(separators, nextStartIndex + 1); + + if (-1 == separatorIndex) + { + lastCharacterIndex = source.Length - 1; + } + else + { + lastCharacterIndex = separatorIndex - 1; + } + } + + int length = lastCharacterIndex - nextStartIndex + 1; + result = source.Substring(nextStartIndex, length).Trim(); + nextStartIndex = lastCharacterIndex + 1; + } + } + + return result; + } + + /// + /// Find the index of the next occurance of the input character in the string. This differs + /// from String.IndexOf() in that the caller can specify that escaped characters should not + /// be matched. + /// + /// The string to search for the character + /// The index in the string at which the search should start + /// The character to search for + /// If true, characters that are escaped (e.g. "]]") are skipped in the search + /// The index at which the next occurance of character occurs in the string, or -1 if there is no such occurance + private static int GetNextIndex( + string source, + int startIndex, + char character, + bool ignoreDoubledCharacters) + { + int index = startIndex; + + while (index < source.Length) + { + if (source[index] == character) + { + // if we aren't ignoring escaped (doubled) characters or if we've + // reached the end of the string, return the index + if (!ignoreDoubledCharacters || + (index == (source.Length - 1)) || + (character != source[index + 1])) + { + return index; + } + + if (((index + 1) < source.Length) && (character == source[index + 1])) + { + // skip the doubled character + ++index; + } + } + + ++index; + } + + return -1; + } + } + + /// + /// A collection of SearchableObjects + /// +#if DEBUG || EXPOSE_MANAGED_INTERNALS + public +#else + internal +#endif + class SearchableObjectCollection : ICollection + { + private SortedList data; + + /// + /// Constructor + /// + public SearchableObjectCollection() + { + data = new SortedList(); + } + + /// + /// Indexer + /// +#pragma warning disable IDE0026 // Use expression body for indexer + public SearchableObject this[int index] + { + get + { + return ((SearchableObject) this.data.GetByIndex(index)); + } + } +#pragma warning restore IDE0026 // Use expression body for indexer + + /// + /// Add an object to the collection + /// + /// the object to add + public void Add(SearchableObject value) + { + if (!this.data.Contains(value)) + { + this.data.Add(value, value); + this.NotifyObservers(); + } + } + + /// + /// Get the index of the object in the collection + /// + /// The object for which to find the index + /// The object's index + public int IndexOf(SearchableObject value) + { + return this.data.IndexOfKey(value); + } + + /// + /// Remove an object from the collection + /// + /// The object to remove + public void Remove(SearchableObject value) + { + if (this.data.Contains(value)) + { + this.data.Remove(value); + } + + this.NotifyObservers(); + } + + /// + /// Does the collection contain a particular object + /// + /// The object for which to check + /// true if the object is in the collection, false otherwise + public bool Contains(SearchableObject value) + { + return this.data.Contains(value); + } + /// + /// Notify iterators that the collection has changed + /// + private void NotifyObservers() + { + if (null != this.OnInvalidateEnumerator) + { + this.OnInvalidateEnumerator(); + } + } + + + /// + /// Delegate declaration for delegates that will be called when the collection changes + /// + internal delegate void InvalidateEnumerator(); + + /// + /// Event that is fired when the collection changes + /// + internal event InvalidateEnumerator OnInvalidateEnumerator; + + #region ICollection Members + + /// + /// Is access to collection thread-safe? + /// + public bool IsSynchronized + { + get + { + return false; + } + } + + /// + /// How many objects are in the collection? + /// + public int Count + { + get + { + return this.data.Count; + } + } + + /// + /// Copy the collection to an array + /// + /// The target array + /// The array index where copying is to begin + public void CopyTo(Array array, int index) + { + for (int i = 0; i < this.data.Count; ++i) + { + array.SetValue(this.data.GetByIndex(i), index + i); + } + } + + /// + /// The object to be used to lock the collection + /// + public object SyncRoot + { + get + { + return this; + } + } + + + #endregion + + #region IEnumerable Members + + /// + /// Get an enumerator for the collection + /// + /// An enumerator + public IEnumerator GetEnumerator() + { + return new SearchableObjectCollectionEnumerator(this); + } + + + #endregion + } + + /// + /// An enumerator for SearchableObjectCollections + /// +#if DEBUG || EXPOSE_MANAGED_INTERNALS + public +#else + internal +#endif + class SearchableObjectCollectionEnumerator : IEnumerator + { + private SearchableObjectCollection collection; + private int currentIndex; + private SearchableObject currentObject; + private bool isValid; + + /// + /// Constructor + /// + /// The collection to enumerate + internal SearchableObjectCollectionEnumerator(SearchableObjectCollection collection) + { + this.collection = collection; + this.currentIndex = -1; + this.currentObject = null; + this.isValid = true; + + this.collection.OnInvalidateEnumerator += new SearchableObjectCollection.InvalidateEnumerator(this.Invalidate); + } + + + /// + /// The method the collection should call when the collection's state changes + /// + internal void Invalidate() + { + this.isValid = false; + } + + + #region IEnumerator Members + + /// + /// Set the enumerator index to "before the start" + /// + public void Reset() + { + if (!this.isValid) + { + // STrace.Assert(false, "The enumerator has been invalidated."); + throw new InvalidOperationException(); + } + + this.currentIndex = -1; + this.currentObject = null; + } + + /// + /// The current SearchableObject + /// + public object Current + { + get + { + if (this.currentIndex < 0) + { + // STrace.Assert(false, "The enumerator is positioned before start of collection. Did you forget to call MoveNext()?"); + throw new InvalidOperationException(); + } + + if (null == this.currentObject) + { + // STrace.Assert(false, "There is no current object. Did you forget to check the result of MoveNext()?"); + throw new InvalidOperationException(); + } + + return this.currentObject; + } + } + + /// + /// Move to the next object in the colection + /// + /// True if there was a next object, false otherwise + public bool MoveNext() + { + if (!this.isValid) + { + // STrace.Assert(false, "The enumerator has been invalidated."); + throw new InvalidOperationException(); + } + + bool result = false; + + if (this.currentIndex < (this.collection.Count - 1)) + { + ++(this.currentIndex); + this.currentObject = this.collection[this.currentIndex]; + result = true; + } + + return result; + } + + #endregion + + } + + /// + /// Internal class that encapsulates a multi-part name. + /// + /// + /// The name is assumed to be in one of the following forms: + /// [Name], [Schema].[Name], [Database].[Schema].[Name], + /// or [Server].[Database].[Schema].[Name] + /// +#if DEBUG || EXPOSE_MANAGED_INTERNALS + public +#else + internal +#endif + class ObjectName + { + private ArrayList parts; + private SqlCollationSensitiveStringComparer nameComparer; + + /// + /// The name portion of the multi-part name + /// + public string Name + { + get + { + string result = String.Empty; + + if (this.parts.Count != 0) + { + int namePartIndex = this.parts.Count - 1; + result = (string) this.parts[namePartIndex]; + } + + return result; + } + + set + { + if (this.parts.Count == 0) + { + this.parts.Add(value); + } + else + { + int namePartIndex = this.parts.Count - 1; + this.parts[namePartIndex] = value; + } + } + } + + /// + /// The schema portion of the multi-part name + /// + public string Schema + { + get + { + string result = String.Empty; + + if (1 < this.parts.Count) + { + int schemaPartIndex = this.parts.Count - 2; + result = (string) this.parts[schemaPartIndex]; + } + + return result; + } + + set + { + if (this.parts.Count == 0) + { + this.parts.Add(value); + this.parts.Add(String.Empty); + } + else if (this.parts.Count == 1) + { + this.parts.Insert(0, value); + } + else + { + int schemaPartIndex = this.parts.Count - 2; + this.parts[schemaPartIndex] = value; + } + } + } + + /// + /// The number of parts in the name + /// + public int PartCount + { + get + { + return this.parts.Count; + } + } + + /// + /// Constructor + /// + /// CompareOptions to use when comparing ObjectName objects + public ObjectName(CompareOptions compareOptions) + { + this.parts = new ArrayList(); + this.nameComparer = new SqlCollationSensitiveStringComparer(compareOptions); + } + + /// + /// Constructor + /// + /// The object schema + /// The object name + /// CompareOptions to use when comparing ObjectName objects + public ObjectName(string schema, string name, CompareOptions compareOptions) + { + this.parts = new ArrayList(); + this.nameComparer = new SqlCollationSensitiveStringComparer(compareOptions); + + this.parts.Add(schema); + this.parts.Add(name); + } + + /// + /// Constructor + /// + /// The seachable object to get the name from + public ObjectName(SearchableObject searchableObject) + { + this.parts = new ArrayList(); + this.nameComparer = new SqlCollationSensitiveStringComparer(searchableObject.CompareOptions); + + if (searchableObject.Schema.Length != 0) + { + this.parts.Add(searchableObject.Schema); + } + + this.parts.Add(searchableObject.Name); + } + + /// + /// Add a name part to the multi-part name + /// + /// The name-part to add + public void Add(string namePart) + { + this.parts.Add(namePart); + } + + /// + /// Get a display string for the multi-part name + /// + /// The string + public override string ToString() + { + StringBuilder result = new StringBuilder(); + bool isFirstPart = true; + + foreach (string part in this.parts) + { + if (isFirstPart) + { + isFirstPart = false; + } + else + { + result.Append("."); + } + + result.Append(this.Quote(part)); + } + + return result.ToString(); + } + + /// + /// Compare the values of this name with another name + /// + /// The name to compare to + /// True if the name values are the same; otherwise false + public bool IsSameAs(ObjectName other) + { + bool result = true; + + if (this.PartCount == other.PartCount) + { + for (int i = 0; i < this.PartCount; ++i) + { + if (0 != this.nameComparer.Compare(this.parts[i], other.parts[i])) + { + result = false; + break; + } + } + } + else + { + result = false; + } + + return result; + } + + /// + /// Quote the input name part + /// + /// The name part to quote + /// The quoted name part + private string Quote(string unquotedString) + { + string escaped = unquotedString.Replace("]", "]]"); + return String.Format(System.Globalization.CultureInfo.InvariantCulture, "[{0}]", escaped); + } + + } + + +}