using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Globalization; using System.IO; using System.Net; using System.Reflection; using System.Net.Security; using System.Security.Principal; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.ServiceModel.Description; using Microsoft.Win32; using WebsitePanel.Providers.Common; using WebsitePanel.Providers.ResultObjects; using WebsitePanel.Server.Utils; using WebsitePanel.Providers.HostedSolution; using WebsitePanel.Providers; using WebsitePanel.Providers.Utils; using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Query; using Microsoft.Xrm.Sdk.Discovery; using Microsoft.Xrm.Sdk.Client; using Microsoft.Xrm.Sdk.Deployment; using Microsoft.Xrm.Sdk.Messages; namespace WebsitePanel.Providers.HostedSolution { public class CRMProvider2011 : HostingServiceProviderBase, ICRM { private static string crmPath = null; #region Properties private string UserName { get { return ProviderSettings[Constants.UserName]; } } private string Password { get { return ProviderSettings[Constants.Password]; } } private string SqlServer { get { return ProviderSettings[Constants.SqlServer]; } } private string ReportingServer { get { return ProviderSettings[Constants.ReportingServer]; } } private string CRMServiceUrl { get { string cRMServiceUrl = "https://" + ProviderSettings[Constants.AppRootDomain] + ":" + ProviderSettings[Constants.Port] + "/XRMDeployment/2011/Deployment.svc"; return cRMServiceUrl; } } private string CRMDiscoveryUri { get { string cRMDiscoveryUri = "https://" + ProviderSettings[Constants.AppRootDomain] + ":" + ProviderSettings[Constants.Port] + "/XRMServices/2011/Discovery.svc"; return cRMDiscoveryUri; } } private static string CrmPath { get { if (string.IsNullOrEmpty(crmPath)) { RegistryKey root = Registry.LocalMachine; RegistryKey rk = root.OpenSubKey("SOFTWARE\\Microsoft\\MSCRM"); if (rk != null) { crmPath = (string)rk.GetValue("CRM_Server_InstallDir", string.Empty); } } return crmPath; } } #endregion #region Static constructor static CRMProvider2011() { AppDomain.CurrentDomain.AssemblyResolve += ResolveCRMAssembly; } #endregion static Assembly ResolveCRMAssembly(object sender, ResolveEventArgs args) { var loadedAssembly = default(Assembly); // Ensure we load DLLs only. if (args.Name.ToLower().Contains("microsoft.crm") || args.Name.ToLower().Contains("antixsslibrary")) { // string crmToolsPath = Path.Combine(CrmPath, "tools"); // string path = Path.Combine(crmToolsPath, args.Name.Split(',')[0] + ".dll"); // Call to load an assembly only if its existence is confirmed. if (File.Exists(path)) { loadedAssembly = Assembly.LoadFrom(path); } } // return loadedAssembly; } private bool CheckCRMWebServicesAccess() { Log.WriteStart("CheckCRMWebServicesAccess"); bool ret = false; HttpWebResponse response = null; HttpWebRequest request; try { WindowsIdentity.GetCurrent(); request = WebRequest.Create(CRMServiceUrl) as HttpWebRequest; if (request != null) { request.UseDefaultCredentials = true; request.Credentials = CredentialCache.DefaultCredentials; response = request.GetResponse() as HttpWebResponse; } if (response != null) ret = (response.StatusCode == HttpStatusCode.OK); } catch (Exception ex) { Log.WriteError(ex); ret = false; } Log.WriteEnd("CheckCRMWebServicesAccess"); return ret; } private static bool CheckPermissions() { Log.WriteStart("CheckPermissions"); bool res = false; try { string group = "PrivUserGroup"; string user = WindowsIdentity.GetCurrent().Name.Split(new char[] { '\\' })[1]; res = ActiveDirectoryUtils.IsUserInGroup(user, group); } catch (Exception ex) { Log.WriteError(ex); res = false; } Log.WriteEnd("CheckPermissions"); return res; } private bool CheckOrganizationUnique(string databaseName, string orgName) { Log.WriteStart("CheckOrganizationUnique"); bool res = false; SqlConnection connection = null; try { connection = new SqlConnection(); connection.ConnectionString = string.Format("Server={1};Initial Catalog={0};Integrated Security=SSPI", databaseName, SqlServer); connection.Open(); string commandText = string.Format("SELECT COUNT(*) FROM dbo.Organization WHERE UniqueName = '{0}'", orgName); SqlCommand command = new SqlCommand(commandText, connection); int count = (int)command.ExecuteScalar(); res = count == 0; } catch (Exception ex) { res = false; Log.WriteError(ex); } finally { if (connection != null) connection.Dispose(); } Log.WriteEnd("CheckOrganizationUnique"); return res; } private bool CheckSqlServerConnection() { Log.WriteStart("CheckSqlServerConnection"); bool res = false; SqlConnection connection = null; try { connection = new SqlConnection(); connection.ConnectionString = string.Format("server={0}; Integrated Security=SSPI", SqlServer); connection.Open(); res = true; } catch (Exception ex) { Log.WriteError(ex); res = false; } finally { if (connection != null) connection.Dispose(); } Log.WriteEnd("CheckSqlServerConnection"); return res; } private bool CheckReportServerConnection() { Log.WriteStart("CheckReportServerConnection"); bool ret = false; HttpWebResponse response = null; HttpWebRequest request; try { WindowsIdentity.GetCurrent(); request = WebRequest.Create(ReportingServer) as HttpWebRequest; if (request != null) { request.UseDefaultCredentials = true; request.Credentials = CredentialCache.DefaultCredentials; response = request.GetResponse() as HttpWebResponse; } if (response != null) ret = (response.StatusCode == HttpStatusCode.OK); } catch (Exception ex) { Log.WriteError(ex); ret = false; } Log.WriteEnd("CheckReportServerConnection"); return ret; } private OrganizationResult CheckCrmEnvironment(string strDataBaseName, string organizationUniqueName) { OrganizationResult retOrganization = StartLog("CheckCrmEnvironment"); bool res = CheckSqlServerConnection(); if (!res) { EndLog("CheckCrmEnvironment", retOrganization, CrmErrorCodes.CRM_SQL_SERVER_ERROR); return retOrganization; } res = CheckOrganizationUnique(strDataBaseName, organizationUniqueName); if (!res) { EndLog("CheckCrmEnvironment", retOrganization, CrmErrorCodes.CRM_ORGANIZATION_ALREADY_EXISTS); return retOrganization; } res = CheckReportServerConnection(); if (!res) { EndLog("CheckCrmEnvironment", retOrganization, CrmErrorCodes.CRM_REPORT_SERVER_ERROR); return retOrganization; } res = CheckPermissions(); if (!res) { EndLog("CheckCrmEnvironment", retOrganization, CrmErrorCodes.CRM_PERMISSIONS_ERROR); return retOrganization; } res = CheckCRMWebServicesAccess(); if (!res) { EndLog("CheckCrmEnvironment", retOrganization, CrmErrorCodes.CRM_WEB_SERVICE_ERROR); return retOrganization; } EndLog("CheckCrmEnvironment"); return retOrganization; } public OrganizationResult CreateOrganization(Guid organizationId, string organizationUniqueName, string organizationFriendlyName, string baseCurrencyCode, string baseCurrencyName, string baseCurrencySymbol, string initialUserDomainName, string initialUserFirstName, string initialUserLastName, string initialUserPrimaryEmail, string organizationCollation) { return CreateOrganizationInternal(organizationId, organizationUniqueName, organizationFriendlyName, baseCurrencyCode, baseCurrencyName, baseCurrencySymbol, initialUserDomainName, initialUserFirstName, initialUserLastName, initialUserPrimaryEmail, organizationCollation); } const string CRMSysAdminRoleStr = "Ñèñòåìíûé àäìèíèñòðàòîð;System Administrator"; internal OrganizationResult CreateOrganizationInternal(Guid organizationId, string organizationUniqueName, string organizationFriendlyName, string baseCurrencyCode, string baseCurrencyName, string baseCurrencySymbol, string initialUserDomainName, string initialUserFirstName, string initialUserLastName, string initialUserPrimaryEmail, string organizationCollation) { OrganizationResult ret = StartLog("CreateOrganizationInternal"); if (organizationId == Guid.Empty) throw new ArgumentException("OrganizationId is Guid.Empty"); if (string.IsNullOrEmpty(organizationFriendlyName)) throw new ArgumentNullException("organizationFriendlyName"); if (string.IsNullOrEmpty(baseCurrencyCode)) throw new ArgumentNullException("baseCurrencyCode"); if (string.IsNullOrEmpty(baseCurrencySymbol)) throw new ArgumentNullException("baseCurrencySymbol"); if (string.IsNullOrEmpty(initialUserDomainName)) throw new ArgumentNullException("initialUserDomainName"); string strDataBaseName = "MSCRM_CONFIG"; OrganizationResult retCheckEn = CheckCrmEnvironment(strDataBaseName, organizationUniqueName); if (!retCheckEn.IsSuccess) { ret.ErrorCodes.AddRange(retCheckEn.ErrorCodes); EndLog("CreateOrganizationInternal", ret, null, null); return ret; } try { Uri serviceUrl = new Uri(CRMServiceUrl); DeploymentServiceClient deploymentService = Microsoft.Xrm.Sdk.Deployment.Proxy.ProxyClientHelper.CreateClient(serviceUrl); Microsoft.Xrm.Sdk.Deployment.Organization org = new Microsoft.Xrm.Sdk.Deployment.Organization { Id = organizationId, UniqueName = organizationUniqueName, FriendlyName = organizationFriendlyName, SqlServerName = SqlServer, SrsUrl = ReportingServer, BaseCurrencyCode = baseCurrencyCode, BaseCurrencyName = baseCurrencyName, BaseCurrencySymbol = baseCurrencySymbol, SqlCollation = organizationCollation, State = Microsoft.Xrm.Sdk.Deployment.OrganizationState.Enabled }; BeginCreateOrganizationRequest req = new BeginCreateOrganizationRequest { Organization = org }; if (!String.IsNullOrEmpty(UserName)) { req.SysAdminName = UserName; } BeginCreateOrganizationResponse resp = deploymentService.Execute(req) as BeginCreateOrganizationResponse; if (resp == null) throw new ArgumentException("BeginCreateOrganizationResponse is Null"); EntityInstanceId id = new EntityInstanceId(); id.Name = org.UniqueName; Microsoft.Xrm.Sdk.Deployment.OrganizationState OperationState = Microsoft.Xrm.Sdk.Deployment.OrganizationState.Pending; do { Thread.Sleep(30000); try { Microsoft.Xrm.Sdk.Deployment.Organization getorg = (Microsoft.Xrm.Sdk.Deployment.Organization)deploymentService.Retrieve(DeploymentEntityType.Organization, id); OperationState = getorg.State; } catch { } } while ((OperationState != Microsoft.Xrm.Sdk.Deployment.OrganizationState.Enabled) && (OperationState != Microsoft.Xrm.Sdk.Deployment.OrganizationState.Failed)); if (OperationState == Microsoft.Xrm.Sdk.Deployment.OrganizationState.Failed) throw new ArgumentException("Create organization failed."); try { OrganizationServiceProxy _serviceProxy = GetOrganizationProxy(organizationUniqueName); string ldap = ""; Guid SysAdminGuid = RetrieveSystemUser(GetDomainName(initialUserDomainName), initialUserFirstName, initialUserLastName, CRMSysAdminRoleStr, _serviceProxy, ref ldap); } catch { } } catch (Exception ex) { HostedSolutionLog.LogError(ex); EndLog("CheckCrmEnvironment", ret, CrmErrorCodes.CREATE_CRM_ORGANIZATION_GENERAL_ERROR, ex); return ret; } EndLog("CheckCrmEnvironment"); return ret; } private string GetDomainName(string username) { string domain = ActiveDirectoryUtils.GetNETBIOSDomainName(ServerSettings.ADRootDomain); string ret = string.Format(@"{0}\{1}", domain, username); return ret; } public string[] GetSupportedCollationNames() { return GetSupportedCollationNamesInternal(SqlServer); } internal static string[] GetSupportedCollationNamesInternal(string SqlServer) { HostedSolutionLog.LogStart("GetSupportedCollationNamesInternal"); List ret = new List(); string databaseName = "MSCRM_CONFIG"; SqlConnection connection = null; try { connection = new SqlConnection(); connection.ConnectionString = string.Format("Server={1};Initial Catalog={0};Integrated Security=SSPI", databaseName, SqlServer); connection.Open(); string commandText = "select * from fn_helpcollations() where " + "(name not like '%_WS') AND (name not like '%_KS') AND (name not like '%_100_%') " + " AND (name not like 'SQL_%') " + " order by name"; SqlCommand command = new SqlCommand(commandText, connection); SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { string name = reader["name"] as string; ret.Add(name); } } catch (Exception) { } finally { if (connection != null) connection.Dispose(); } HostedSolutionLog.LogEnd("GetSupportedCollationNamesInternal"); return ret.ToArray(); } public Currency[] GetCurrencyList() { return GetCurrencyListInternal(); } private Currency[] GetCurrencyListInternal() { HostedSolutionLog.LogStart("GetCurrencyListInternal"); List retList = new List(); CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures & ~CultureTypes.NeutralCultures); foreach (CultureInfo cultire in cultures) { try { RegionInfo Region = new RegionInfo(cultire.LCID); Console.WriteLine(cultire.NativeName + " " + Region.CurrencyNativeName); Currency currency = new Currency(); currency.RegionName = Region.NativeName; currency.CurrencyName = Region.CurrencyNativeName; currency.CurrencyCode = Region.ISOCurrencySymbol; currency.CurrencySymbol = Region.CurrencySymbol; retList.Add(currency); } catch { continue; } } retList.Sort(delegate(Currency a, Currency b) { return a.RegionName.CompareTo(b.RegionName); }); HostedSolutionLog.LogEnd("GetCurrencyListInternal"); return retList.ToArray(); } public ResultObject DeleteOrganization(Guid orgId) { return DeleteOrganizationInternal(orgId); } internal ResultObject DeleteOrganizationInternal(Guid orgId) { ResultObject res = StartLog("DeleteOrganizationInternal"); res.IsSuccess = true; try { Uri serviceUrl = new Uri(CRMServiceUrl); DeploymentServiceClient deploymentService = Microsoft.Xrm.Sdk.Deployment.Proxy.ProxyClientHelper.CreateClient(serviceUrl); EntityInstanceId i = new EntityInstanceId(); i.Id = orgId; //Organisation Id Microsoft.Xrm.Sdk.Deployment.Organization org = (Microsoft.Xrm.Sdk.Deployment.Organization)deploymentService.Retrieve(DeploymentEntityType.Organization, i); org.State = Microsoft.Xrm.Sdk.Deployment.OrganizationState.Disabled; Microsoft.Xrm.Sdk.Deployment.UpdateRequest updateRequest = new Microsoft.Xrm.Sdk.Deployment.UpdateRequest(); updateRequest.Entity = org; deploymentService.Execute(updateRequest); } catch (Exception ex) { EndLog("DeleteOrganizationInternal", res, CrmErrorCodes.DELETE_CRM_ORGANIZATION_GENERAL_ERROR, ex); return res; } EndLog("DeleteOrganizationInternal"); return res; } public override void DeleteServiceItems(ServiceProviderItem[] items) { foreach (ServiceProviderItem item in items) { try { if (item is Organization) { Organization org = item as Organization; DeleteOrganization(org.CrmOrganizationId); } } catch (Exception ex) { Log.WriteError(String.Format("Error deleting '{0}' {1}", item.Name, item.GetType().Name), ex); } } base.DeleteServiceItems(items); } private static void EndLog(string message, ResultObject res, string errorCode, Exception ex) { if (res != null) { res.IsSuccess = false; if (!string.IsNullOrEmpty(errorCode)) res.ErrorCodes.Add(errorCode); } if (ex != null) HostedSolutionLog.LogError(ex); HostedSolutionLog.LogEnd(message); } private static void EndLog(string message, ResultObject res, string errorCode) { EndLog(message, res, errorCode, null); } private static void EndLog(string message, ResultObject res) { EndLog(message, res, null); } private static void EndLog(string message) { EndLog(message, null); } private static T StartLog(string message) where T : ResultObject, new() { HostedSolutionLog.LogStart(message); T res = new T(); res.IsSuccess = true; return res; } public UserResult CreateCRMUser(OrganizationUser user, string orgName, Guid organizationId, Guid baseUnitId) { return CreateCRMUserInternal(user, orgName, organizationId, baseUnitId); } internal UserResult CreateCRMUserInternal(OrganizationUser user, string orgName, Guid organizationId, Guid businessUnitId) { UserResult res = StartLog("CreateCRMUserInternal"); try { if (user == null) throw new ArgumentNullException("user"); if (string.IsNullOrEmpty(orgName)) throw new ArgumentNullException("orgName"); if (organizationId == Guid.Empty) throw new ArgumentException("organizationId"); if (businessUnitId == Guid.Empty) throw new ArgumentException("businessUnitId"); try { OrganizationServiceProxy _serviceProxy = GetOrganizationProxy(orgName); string ldap = ""; Guid guid = RetrieveSystemUser(user.DomainUserName, user.FirstName, user.LastName, CRMSysAdminRoleStr, _serviceProxy, ref ldap); user.CrmUserId = guid; res.Value = user; } catch (Exception ex) { EndLog("CreateCRMUserInternal", res, CrmErrorCodes.CANNOT_CREATE_CRM_USER, ex); return res; } } catch (Exception ex) { EndLog("CreateCRMUserInternal", res, CrmErrorCodes.CANNOT_CREATE_CRM_USER_GENERAL_ERROR, ex); return res; } EndLog("CreateCRMUserInternal"); return res; } private static Guid CreateSystemUser(String userName, String firstName, String lastName, String domain, String roleStr, OrganizationServiceProxy serviceProxy, ref String ldapPath) { if (serviceProxy.ServiceConfiguration.AuthenticationType == AuthenticationProviderType.LiveId || serviceProxy.ServiceConfiguration.AuthenticationType == AuthenticationProviderType.OnlineFederation) throw new Exception(String.Format("To run this sample, {0} {1} must be an active system user in your Microsoft Dynamics CRM Online organization.", firstName, lastName)); Guid userId = Guid.Empty; Microsoft.Xrm.Sdk.Query.QueryExpression businessUnitQuery = new Microsoft.Xrm.Sdk.Query.QueryExpression { EntityName = BusinessUnit.EntityLogicalName, ColumnSet = new Microsoft.Xrm.Sdk.Query.ColumnSet("businessunitid"), Criteria = { Conditions = { new Microsoft.Xrm.Sdk.Query.ConditionExpression("parentbusinessunitid", Microsoft.Xrm.Sdk.Query.ConditionOperator.Null) } } }; BusinessUnit defaultBusinessUnit = serviceProxy.RetrieveMultiple( businessUnitQuery).Entities[0].ToEntity(); // Retrieve the specified security role. Role role = RetrieveRoleByName(serviceProxy, roleStr); //Create a new system user. SystemUser user = new SystemUser { DomainName = userName, FirstName = firstName, LastName = lastName, BusinessUnitId = new EntityReference { LogicalName = BusinessUnit.EntityLogicalName, Name = BusinessUnit.EntityLogicalName, Id = defaultBusinessUnit.Id } }; userId = serviceProxy.Create(user); // Assign the security role to the newly created Microsoft Dynamics CRM user. AssociateRequest associate = new AssociateRequest() { Target = new EntityReference(SystemUser.EntityLogicalName, userId), RelatedEntities = new EntityReferenceCollection() { new EntityReference(Role.EntityLogicalName, role.Id), }, Relationship = new Relationship("systemuserroles_association") }; serviceProxy.Execute(associate); return userId; } public static Guid RetrieveSystemUser(String userName, String firstName, String lastName, String roleStr, OrganizationServiceProxy serviceProxy, ref String ldapPath) { String domain; Guid userId = Guid.Empty; if (serviceProxy == null) throw new ArgumentNullException("serviceProxy"); if (String.IsNullOrWhiteSpace(userName)) throw new ArgumentNullException("UserName"); if (String.IsNullOrWhiteSpace(firstName)) throw new ArgumentNullException("FirstName"); if (String.IsNullOrWhiteSpace(lastName)) throw new ArgumentNullException("LastName"); if (String.IsNullOrWhiteSpace(roleStr)) throw new ArgumentNullException("Role"); // Obtain the current user's information. Microsoft.Crm.Sdk.Messages.WhoAmIRequest who = new Microsoft.Crm.Sdk.Messages.WhoAmIRequest(); Microsoft.Crm.Sdk.Messages.WhoAmIResponse whoResp = (Microsoft.Crm.Sdk.Messages.WhoAmIResponse)serviceProxy.Execute(who); Guid currentUserId = whoResp.UserId; SystemUser currentUser = serviceProxy.Retrieve(SystemUser.EntityLogicalName, currentUserId, new Microsoft.Xrm.Sdk.Query.ColumnSet("domainname")).ToEntity(); // Extract the domain and create the LDAP object. String[] userPath = currentUser.DomainName.Split(new char[] { '\\' }); if (userPath.Length > 1) domain = userPath[0] + "\\"; else domain = String.Empty; // Create the system user in Microsoft Dynamics CRM if the user doesn't // already exist. Microsoft.Xrm.Sdk.Query.QueryExpression userQuery = new Microsoft.Xrm.Sdk.Query.QueryExpression { EntityName = SystemUser.EntityLogicalName, ColumnSet = new Microsoft.Xrm.Sdk.Query.ColumnSet("systemuserid"), Criteria = { FilterOperator = Microsoft.Xrm.Sdk.Query.LogicalOperator.Or, Filters = { new Microsoft.Xrm.Sdk.Query.FilterExpression { FilterOperator = Microsoft.Xrm.Sdk.Query.LogicalOperator.And, Conditions = { new Microsoft.Xrm.Sdk.Query.ConditionExpression("domainname", Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, domain + userName) } }, new Microsoft.Xrm.Sdk.Query.FilterExpression { FilterOperator = Microsoft.Xrm.Sdk.Query.LogicalOperator.And, Conditions = { new Microsoft.Xrm.Sdk.Query.ConditionExpression("firstname", Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, firstName), new Microsoft.Xrm.Sdk.Query.ConditionExpression("lastname", Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, lastName) } } } } }; DataCollection existingUsers = (DataCollection)serviceProxy.RetrieveMultiple(userQuery).Entities; SystemUser existingUser = null; if (existingUsers.Count > 0) existingUser = existingUsers[0].ToEntity(); if (existingUser != null) { userId = existingUser.SystemUserId.Value; // Check to make sure the user is assigned the correct role. Role role = RetrieveRoleByName(serviceProxy, roleStr); // Associate the user with the role when needed. if (!UserInRole(serviceProxy, userId, role.Id)) { AssociateRequest associate = new AssociateRequest() { Target = new EntityReference(SystemUser.EntityLogicalName, userId), RelatedEntities = new EntityReferenceCollection() { new EntityReference(Role.EntityLogicalName, role.Id) }, Relationship = new Relationship("systemuserroles_association") }; serviceProxy.Execute(associate); } } else { userId = CreateSystemUser(userName, firstName, lastName, domain, roleStr, serviceProxy, ref ldapPath); } return userId; } private static Role RetrieveRoleByName(OrganizationServiceProxy serviceProxy, String roleSplitStr) { string[] RolesStr = roleSplitStr.Split(';'); foreach (string roleStr in RolesStr) { Microsoft.Xrm.Sdk.Query.QueryExpression roleQuery = new Microsoft.Xrm.Sdk.Query.QueryExpression { EntityName = Role.EntityLogicalName, ColumnSet = new Microsoft.Xrm.Sdk.Query.ColumnSet("roleid"), Criteria = { Conditions = { new Microsoft.Xrm.Sdk.Query.ConditionExpression("name", Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, roleStr) } } }; DataCollection roles = serviceProxy.RetrieveMultiple(roleQuery).Entities; if (roles.Count > 0) return roles[0].ToEntity(); } return null; } private static bool UserInRole(OrganizationServiceProxy serviceProxy, Guid userId, Guid roleId) { // Establish a SystemUser link for a query. Microsoft.Xrm.Sdk.Query.LinkEntity systemUserLink = new Microsoft.Xrm.Sdk.Query.LinkEntity() { LinkFromEntityName = SystemUserRoles.EntityLogicalName, LinkFromAttributeName = "systemuserid", LinkToEntityName = SystemUser.EntityLogicalName, LinkToAttributeName = "systemuserid", LinkCriteria = { Conditions = { new Microsoft.Xrm.Sdk.Query.ConditionExpression( "systemuserid", Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, userId) } } }; // Build the query. Microsoft.Xrm.Sdk.Query.QueryExpression query = new Microsoft.Xrm.Sdk.Query.QueryExpression() { EntityName = Role.EntityLogicalName, ColumnSet = new Microsoft.Xrm.Sdk.Query.ColumnSet("roleid"), LinkEntities = { new Microsoft.Xrm.Sdk.Query.LinkEntity() { LinkFromEntityName = Role.EntityLogicalName, LinkFromAttributeName = "roleid", LinkToEntityName = SystemUserRoles.EntityLogicalName, LinkToAttributeName = "roleid", LinkEntities = {systemUserLink} } }, Criteria = { Conditions = { new Microsoft.Xrm.Sdk.Query.ConditionExpression("roleid", Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, roleId) } } }; // Retrieve matching roles. EntityCollection ec = serviceProxy.RetrieveMultiple(query); if (ec.Entities.Count > 0) return true; return false; } int GetOrganizationProxyTryCount = 5; int GetOrganizationProxyTryTimeout = 30000; private OrganizationServiceProxy GetOrganizationProxy(string orgName) { Uri OrganizationUri = GetOrganizationAddress(orgName); OrganizationServiceProxy r = null; bool success = false; int tryItem = 0; Exception exception = null; while (!success) { try { // Set IServiceManagement for the current organization. IServiceManagement orgServiceManagement = ServiceConfigurationFactory.CreateManagement( OrganizationUri); r = new OrganizationServiceProxy( orgServiceManagement, GetUserLogonCredentials()); success = true; } catch (Exception exc) { Thread.Sleep(GetOrganizationProxyTryTimeout); tryItem++; if (tryItem >= GetOrganizationProxyTryCount) { exception = exc; success = true; } } } if (exception != null) throw new ArgumentException(exception.ToString()); r.EnableProxyTypes(); return r; } protected virtual ClientCredentials GetUserLogonCredentials() { ClientCredentials credentials = new ClientCredentials(); if (String.IsNullOrEmpty(UserName)) { credentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials; } else { credentials.UserName.UserName = UserName; credentials.UserName.Password = Password; } return credentials; } private DiscoveryServiceProxy GetDiscoveryProxy() { IServiceManagement serviceManagement = ServiceConfigurationFactory.CreateManagement( new Uri(CRMDiscoveryUri)); ClientCredentials Credentials = GetUserLogonCredentials(); DiscoveryServiceProxy r = new DiscoveryServiceProxy(serviceManagement, Credentials); return r; } public OrganizationDetailCollection DiscoverOrganizations(IDiscoveryService service) { if (service == null) throw new ArgumentNullException("service"); RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest(); RetrieveOrganizationsResponse orgResponse = (RetrieveOrganizationsResponse)service.Execute(orgRequest); return orgResponse.Details; } protected virtual Uri GetOrganizationAddress(string orgName) { string url = "https://" + ProviderSettings[Constants.AppRootDomain] + ":" + ProviderSettings[Constants.Port] + "/" + orgName + "/XRMServices/2011/Organization.svc"; try { using (DiscoveryServiceProxy serviceProxy = GetDiscoveryProxy()) { // Obtain organization information from the Discovery service. if (serviceProxy != null) { // Obtain information about the organizations that the system user belongs to. OrganizationDetailCollection orgs = DiscoverOrganizations(serviceProxy); for (int n = 0; n < orgs.Count; n++) { if (orgs[n].UniqueName == orgName) { // Return the organization Uri. return new System.Uri(orgs[n].Endpoints[EndpointType.OrganizationService]); } } } } } catch { } return new Uri(url); } internal CRMBusinessUnitsResult GetOrganizationBusinessUnitsInternal(Guid organizationId, string orgName) { CRMBusinessUnitsResult res = StartLog("GetOrganizationBusinessUnitsInternal"); try { if (organizationId == Guid.Empty) throw new ArgumentException("organizationId"); if (string.IsNullOrEmpty(orgName)) throw new ArgumentNullException("orgName"); OrganizationServiceProxy serviceProxy; try { serviceProxy = GetOrganizationProxy(orgName); } catch (Exception ex) { EndLog("GetOrganizationBusinessUnitsInternal", res, CrmErrorCodes.CANNOT_GET_CRM_SERVICE, ex); return res; } DataCollection BusinessUnits; try { Microsoft.Xrm.Sdk.Query.QueryExpression businessUnitQuery = new Microsoft.Xrm.Sdk.Query.QueryExpression { EntityName = BusinessUnit.EntityLogicalName, ColumnSet = new Microsoft.Xrm.Sdk.Query.ColumnSet(new string[] { "businessunitid", "name" }), Criteria = { Conditions = { new Microsoft.Xrm.Sdk.Query.ConditionExpression("parentbusinessunitid", Microsoft.Xrm.Sdk.Query.ConditionOperator.Null) } } }; BusinessUnits = serviceProxy.RetrieveMultiple( businessUnitQuery).Entities; } catch (Exception ex) { EndLog("GetOrganizationBusinessUnitsInternal", res, CrmErrorCodes.CANNOT_GET_CRM_BUSINESS_UNITS, ex); return res; } List businessUnits = new List(); try { for (int i = 0; i < BusinessUnits.Count; i++) { BusinessUnit bu = BusinessUnits[i].ToEntity(); CRMBusinessUnit unit = new CRMBusinessUnit(); unit.BusinessUnitId = (Guid)bu.BusinessUnitId; unit.BusinessUnitName = bu.Name; if (unit.BusinessUnitName == null) unit.BusinessUnitName = "default"; businessUnits.Add(unit); } res.Value = businessUnits; } catch (Exception ex) { EndLog("GetOrganizationBusinessUnitsInternal", res, CrmErrorCodes.CANNOT_FILL_BASE_UNITS_COLLECTION, ex); return res; } } catch (Exception ex) { EndLog("GetOrganizationBusinessUnitsInternal", res, CrmErrorCodes.GET_ORGANIZATION_BUSINESS_UNITS_GENERAL_ERROR, ex); return res; } EndLog("GetOrganizationBusinessUnitsInternal"); return res; } public CRMBusinessUnitsResult GetOrganizationBusinessUnits(Guid organizationId, string orgName) { return GetOrganizationBusinessUnitsInternal(organizationId, orgName); } public CrmRolesResult GetAllCrmRoles(string orgName, Guid businessUnitId) { return GetAllCrmRolesInternal(orgName, businessUnitId); } public CrmRolesResult GetCrmUserRoles(string orgName, Guid userId) { return GetCrmUserRolesInternal(userId, orgName); } public EntityCollection GetUserRoles(Guid userId, string orgName) { OrganizationServiceProxy serviceProxy = GetOrganizationProxy(orgName); // Establish a SystemUser link for a query. Microsoft.Xrm.Sdk.Query.LinkEntity systemUserLink = new Microsoft.Xrm.Sdk.Query.LinkEntity() { LinkFromEntityName = SystemUserRoles.EntityLogicalName, LinkFromAttributeName = "systemuserid", LinkToEntityName = SystemUser.EntityLogicalName, LinkToAttributeName = "systemuserid", LinkCriteria = { Conditions = { new Microsoft.Xrm.Sdk.Query.ConditionExpression( "systemuserid", Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, userId) } } }; // Build the query. Microsoft.Xrm.Sdk.Query.QueryExpression query = new Microsoft.Xrm.Sdk.Query.QueryExpression() { EntityName = Role.EntityLogicalName, ColumnSet = new Microsoft.Xrm.Sdk.Query.ColumnSet("roleid"), LinkEntities = { new Microsoft.Xrm.Sdk.Query.LinkEntity() { LinkFromEntityName = Role.EntityLogicalName, LinkFromAttributeName = "roleid", LinkToEntityName = SystemUserRoles.EntityLogicalName, LinkToAttributeName = "roleid", LinkEntities = {systemUserLink} } } }; // Retrieve matching roles. EntityCollection relations = serviceProxy.RetrieveMultiple(query); return relations; } internal CrmRolesResult GetCrmUserRolesInternal(Guid userId, string orgName) { CrmRolesResult res = StartLog("GetCrmUserRolesInternal"); try { EntityCollection relations; if (userId == Guid.Empty) throw new ArgumentException("userId"); if (string.IsNullOrEmpty(orgName)) throw new ArgumentNullException("orgName"); try { relations = GetUserRoles(userId, orgName); } catch (Exception ex) { EndLog("GetCrmUserRolesInternal", res, CrmErrorCodes.CANNOT_GET_CRM_USER_ROLES, ex); return res; } try { res.Value = FillCrmRoles(relations, true, Guid.Empty); } catch (Exception ex) { EndLog("GetCrmUserRolesInternal", res, CrmErrorCodes.CANNOT_FILL_ROLES_COLLECTION, ex); return res; } } catch (Exception ex) { EndLog("GetCrmUserRolesInternal", res, CrmErrorCodes.GET_CRM_USER_ROLE_GENERAL_ERROR, ex); return res; } EndLog("GetCrmUserRolesInternal"); return res; } private static List FillCrmRoles(EntityCollection entities, bool isUserRole, Guid businessUnitId) { List res = new List(); foreach (Entity current in entities.Entities) { Role role = current.ToEntity(); if (role == null) continue; if (businessUnitId != Guid.Empty) { if (businessUnitId != role.BusinessUnitId.Id) continue; } CrmRole crmRole = new CrmRole(); crmRole.IsCurrentUserRole = isUserRole; crmRole.RoleId = (Guid)role.RoleId; crmRole.RoleName = role.Name; res.Add(crmRole); } return res; } private static List FillCrmRoles(EntityCollection entities, Guid businessUnitId) { return FillCrmRoles(entities, false, businessUnitId); } internal CrmRolesResult GetAllCrmRolesInternal(string orgName, Guid businessUnitId) { CrmRolesResult res = StartLog("GetAllCrmRoles"); try { if (string.IsNullOrEmpty(orgName)) throw new ArgumentNullException("orgName"); EntityCollection roles; try { OrganizationServiceProxy serviceProxy = GetOrganizationProxy(orgName); Microsoft.Xrm.Sdk.Query.QueryExpression roleQuery = new Microsoft.Xrm.Sdk.Query.QueryExpression { EntityName = Role.EntityLogicalName, ColumnSet = new Microsoft.Xrm.Sdk.Query.ColumnSet(new string[] { "roleid", "name", "businessunitid" }), }; roles = serviceProxy.RetrieveMultiple(roleQuery); } catch (Exception ex) { EndLog("GetAllCrmRoles", res, CrmErrorCodes.CANNOT_GET_ALL_CRM_ROLES, ex); return res; } try { List crmRoles = FillCrmRoles(roles, businessUnitId); res.Value = crmRoles; } catch (Exception ex) { EndLog("GetAllCrmRoles", res, CrmErrorCodes.CANNOT_FILL_ROLES_COLLECTION, ex); return res; } } catch (Exception ex) { EndLog("GetAllCrmRoles", res, CrmErrorCodes.GET_ALL_CRM_ROLES_GENERAL_ERROR, ex); return res; } EndLog("GetAllCrmRoles"); return res; } public ResultObject SetUserRoles(string orgName, Guid userId, Guid[] roles) { return SetUserRolesInternal(orgName, userId, roles); } internal ResultObject SetUserRolesInternal(string orgName, Guid userId, Guid[] roles) { CrmRolesResult res = StartLog("SetUserRolesInternal"); try { if (string.IsNullOrEmpty(orgName)) throw new ArgumentNullException("orgName"); if (userId == Guid.Empty) throw new ArgumentException("userId"); if (roles == null) throw new ArgumentNullException("roles"); OrganizationServiceProxy serviceProxy = GetOrganizationProxy(orgName); CrmRolesResult tmpRoles = GetCrmUserRoles(orgName, userId); res.ErrorCodes.AddRange(tmpRoles.ErrorCodes); if (!tmpRoles.IsSuccess) return res; List remRoles = new List(); for (int i = 0; i < tmpRoles.Value.Count; i++) { if (Array.Find(roles, delegate(Guid current) { return current == tmpRoles.Value[i].RoleId; }) == Guid.Empty) { remRoles.Add(tmpRoles.Value[i].RoleId); } } try { DisassociateRequest removeRole = new DisassociateRequest() { Target = new EntityReference(SystemUser.EntityLogicalName, userId), RelatedEntities = new EntityReferenceCollection(), Relationship = new Relationship("systemuserroles_association") }; for (int i = 0; i < remRoles.Count; i++) removeRole.RelatedEntities.Add(new EntityReference(Role.EntityLogicalName, remRoles[i])); serviceProxy.Execute(removeRole); } catch (Exception ex) { EndLog("SetUserRolesInternal", res, CrmErrorCodes.CANNOT_REMOVE_CRM_USER_ROLES, ex); return res; } try { // Assign the security role to the newly created Microsoft Dynamics CRM user. AssociateRequest associate = new AssociateRequest() { Target = new EntityReference(SystemUser.EntityLogicalName, userId), RelatedEntities = new EntityReferenceCollection(), Relationship = new Relationship("systemuserroles_association") }; for (int i = 0; i < roles.Length; i++) { bool find = false; foreach (CrmRole current in tmpRoles.Value) { if (current.RoleId == roles[i]) find = true; } if (find) continue; associate.RelatedEntities.Add(new EntityReference(Role.EntityLogicalName, roles[i])); } serviceProxy.Execute(associate); } catch (Exception ex) { EndLog("SetUserRolesInternal", res, CrmErrorCodes.CANNOT_ASSIGN_CRM_USER_ROLES, ex); return res; } } catch (Exception ex) { EndLog("SetUserRolesInternal", res, CrmErrorCodes.CANNOT_SET_CRM_USER_ROLES_GENERAL_ERROR, ex); return res; } EndLog("SetUserRolesInternal"); return res; } public CrmUserResult GetCrmUserById(Guid crmUserId, string orgName) { return GetCrmUserByIdInternal(crmUserId, orgName); } internal CrmUserResult GetCrmUserByIdInternal(Guid crmUserId, string orgName) { CrmUserResult ret = StartLog("GetCrmUserByIdInternal"); try { if (crmUserId == Guid.Empty) throw new ArgumentNullException("crmUserId"); if (string.IsNullOrEmpty(orgName)) throw new ArgumentNullException("orgName"); OrganizationServiceProxy serviceProxy = GetOrganizationProxy(orgName); SystemUser retruveUser = serviceProxy.Retrieve(SystemUser.EntityLogicalName, crmUserId, new Microsoft.Xrm.Sdk.Query.ColumnSet("domainname", "businessunitid", "accessmode", "isdisabled")).ToEntity(); CrmUser user = null; if (retruveUser != null) { user = new CrmUser(); user.BusinessUnitId = retruveUser.BusinessUnitId.Id; user.CRMUserId = retruveUser.SystemUserId.Value; user.ClientAccessMode = (CRMUserAccessMode)retruveUser.AccessMode.Value; user.IsDisabled = (bool)retruveUser.IsDisabled; ret.Value = user; } } catch (Exception ex) { EndLog("GetCrmUserByIdInternal", ret, CrmErrorCodes.CANONT_GET_CRM_USER_BY_ID, ex); return ret; } EndLog("GetCrmUserByIdInternal"); return ret; } internal CrmUserResult GetCrmUserByDomainNameInternal(string domainName, string orgName) { CrmUserResult ret = StartLog("GetCrmUserByDomainNameInternal"); try { if (string.IsNullOrEmpty(domainName)) throw new ArgumentNullException("domainName"); if (string.IsNullOrEmpty(orgName)) throw new ArgumentNullException("orgName"); OrganizationServiceProxy serviceProxy = GetOrganizationProxy(orgName); Microsoft.Xrm.Sdk.Query.QueryExpression usereQuery = new Microsoft.Xrm.Sdk.Query.QueryExpression { EntityName = SystemUser.EntityLogicalName, ColumnSet = new Microsoft.Xrm.Sdk.Query.ColumnSet("domainname", "businessunitid", "accessmode", "isdisabled", "systemuserid"), }; EntityCollection users = serviceProxy.RetrieveMultiple(usereQuery); foreach (Entity entityuser in users.Entities) { SystemUser sysuser = entityuser.ToEntity(); if (sysuser == null) continue; if (sysuser.DomainName != domainName) continue; CrmUser user = new CrmUser(); user.BusinessUnitId = sysuser.BusinessUnitId.Id; user.CRMUserId = sysuser.SystemUserId.Value; user.ClientAccessMode = (CRMUserAccessMode)sysuser.AccessMode.Value; user.IsDisabled = sysuser.IsDisabled.Value; ret.Value = user; } } catch (Exception ex) { EndLog("GetCrmUserByDomainNameInternal", ret, CrmErrorCodes.CANONT_GET_CRM_USER_BY_DOMAIN_NAME, ex); return ret; } EndLog("GetCrmUserByDomainNameInternal"); return ret; } public CrmUserResult GetCrmUserByDomainName(string domainName, string orgName) { return GetCrmUserByDomainNameInternal(domainName, orgName); } private static Guid GetFetureId(string name) { if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name"); return Guid.Empty; } public ResultObject ChangeUserState(bool disable, string orgName, Guid crmUserId) { return ChangeUserStateInternal(disable, orgName, crmUserId); } internal ResultObject ChangeUserStateInternal(bool disable, string orgName, Guid crmUserId) { ResultObject res = StartLog("ChangeUserStateInternal"); res.IsSuccess = true; try { if (crmUserId == Guid.Empty) throw new ArgumentNullException("crmUserId"); if (string.IsNullOrEmpty(orgName)) throw new ArgumentNullException("orgName"); OrganizationServiceProxy serviceProxy = GetOrganizationProxy(orgName); // Retrieve a user. SystemUser user = serviceProxy.Retrieve(SystemUser.EntityLogicalName, crmUserId, new Microsoft.Xrm.Sdk.Query.ColumnSet(new String[] { "systemuserid", "firstname", "lastname" })).ToEntity(); if (user != null) { Microsoft.Crm.Sdk.Messages.SetStateRequest request = new Microsoft.Crm.Sdk.Messages.SetStateRequest() { EntityMoniker = user.ToEntityReference(), // Required by request but always valued at -1 in this context. Status = new OptionSetValue(-1), // Sets the user to disabled. State = disable ? new OptionSetValue(-1) : new OptionSetValue(0) }; serviceProxy.Execute(request); } } catch (Exception ex) { EndLog("ChangeUserStateInternal", res, CrmErrorCodes.CANNOT_CHANGE_USER_STATE, ex); return res; } EndLog("ChangeUserStateInternal"); return res; } public override bool IsInstalled() { string value = string.Empty; try { RegistryKey root = Registry.LocalMachine; RegistryKey rk = root.OpenSubKey("SOFTWARE\\Microsoft\\MSCRM"); if (rk == null) rk = root.OpenSubKey("SOFTWARE\\Wow6432Node\\Microsoft\\MSCRM"); if (rk != null) { value = (string)rk.GetValue("CRM_Server_Version", null); rk.Close(); } } catch (Exception ex) { Log.WriteError(ex); } return value.StartsWith("5."); } } }