Showing posts with label sdk. Show all posts
Showing posts with label sdk. Show all posts

Wednesday, April 30, 2014

Explaining the built-in SYSTEM and INTEGRATION users

If you have played with CRM long enough, you might have noticed the existence of 2 special user accounts: SYSTEM and INTEGRATION. In this post I’ll try to answer the typical questions I get around what these are and what you need to know about them.

Let me start with some of the facts and characteristics about these 2 user accounts which will help us draw some conclusions later on.

 

THE FACTS

1. SYSTEM and INTEGRATION users have a different SystemUserId (Guid) across all CRM organizations (and CRM Online organizations). To get their user ids you’d have to perform a query (or Advanced Find).

2. These users are very well hidden from the application. They are technically “disabled” and they are even filtered out from the “Disabled Users” view. If you’d like to see them you’d have to build your own Advanced Find without the default filters.

3. Nobody can log in CRM as either of these 2 users.

4. These users are read-only. You are not able to change their teams, security, FLS, business unit or any other field.

5. They do not consume a license.

6. These users are always on the root business unit.

7. They don’t have a mailbox or the ability to send or receive emails.

8. No security applies to these users (any action is allowed when executing as SYSTEM or INTEGRATION), all security validations are bypassed.

9. Unofficial fact: Seems like you cannot impersonate these users in CRM Online from outside of plugins. I haven’t been able to impersonate SYSTEM or INTEGRATION from an external application calling into CRM Online (however, works fine on my OnPrem orgs).

 

THE EFFECT

By now you might be wondering why do we even care about these obscure users. The answer is: we shouldn’t; there is a reason why they are so hidden and sometimes unheard of. However, you might also be thinking that if you have another application integrating with CRM then you could make use of [for example] the SYSTEM/INTEGRATION users to make all service calls into CRM. This way, whenever let’s say an audited record is updated via your integration then it will show as updated by INTEGRATION user which could be a neat indicator that the update came from an external system. This is technically possible (quite easy actually), all you have to do is set the CallerId in your proxy (OrganizationServiceProxy.CallerId or CrmConnection.CallerId) to their userId whenever you create your proxy from the external system to call into CRM, this is what it would look like:

image

Similarly, if you are working from a plugin, you can configure the plugin step to execute as SYSTEM or INTEGRATION user. You can configure that in the Plugin Registration Tool or the Development Toolkit:

image

So now that you know how to impersonate these users, let’s explore the details of why we would do so:

 

THE SCENARIOS

1. Elevation of Privileges.

You might have some business logic implemented in plugins which should bypass security checks (e.g. auto-calculated or rollup fields). In that case it might be useful to run the plugin as SYSTEM user. Additionally, you will see in the audit history that the record has been updated by SYSTEM user which gives us a hint that the update was made by an automated logic of a plugin. On the other hand, you have to be very careful when doing this. The reason is that a plugin can trigger another plugin or a workflow and you might end up with a chain of plugins/workflows triggering. Once you elevate the privileges, every action after that will also run in elevated privilege mode (SYSTEM). Therefore you need to make sure that whatever chain of plugins/workflows will be triggered is OK to execute as SYSTEM. For example, sending an email as SYSTEM will fail because that user does not have a mailbox/email address so if anywhere in your plugin chain you send an email then you might have a problem.

Here is an example: You have tasks with different priorities. The priority of the case is automatically taken from the highest priority of the tasks associated. Not all users have access to update the priority of the case but any user can update the priority of their task which will rollup to the case via a plugin. When a case priority is set to “1” a plugin will send a warning email to the case owner. If you impersonate SYSTEM to rollup the task priority to the case priority you need to make sure that in your plugin that sends the email you set the “from” field, otherwise CRM will try to send the email from SYSTEM which won’t work.

 

2. Generic “system” user for system operations

These special users can work whever you want to do actions on the system programmatically and tag the action to a generic system user. A typical example is when you have integrations with other systems and you want the automatic integration in CRM to execute as a generic system user. For example, if you have integration with ERP system, and whenever a new account is created in ERP it should also be created in CRM. In that case the accounts in CRM would be created by “SYSTEM” or “INTEGRATION” user if you use impersonation to perform the account create under one of those user accounts.

 

THE CAVEAT

As I mentioned earlier, impersonating these system accounts can have some bad side effects. The reason is that any action you perform under one of those user accounts can trigger plugins (which can trigger other plugins). You need to be very careful and make sure you understand that your impersonated action can trigger plugins then those plugins will also execute under the context of the SYSTEM /INTEGRATION accounts. Some plugins you might want to always execute under the context of the Calling User (depending on the scenario). The other things to consider is that these special accounts have no User Settings entity associated (they have no language, time zone, format, etc.) and in some cases your customizations might rely on the existence of user settings for every user account. For example, in some plugins you might check that the user’s language or time zone is in order to execute some business logic. This would break if the plugin executes as SYSTEM/INTEGRATION.

Another issue with these accounts is that they are always at the root business unit. If a record is created by one of these accounts, the record will belong to the root business unit which can mean that many users in child business units will have no visibility into the record (unless they have organization-level privileges). You would have to make sure that you assign the records when they get created if you need those records to sit on different business units other than the root.

 

THE CONCLUSION / ALTERNATIVE SOLUTION

Impersonating SYSTEM/INTEGRATION can be useful for some scenarios for privilege elevation purposes; however, it does have its side effects or considerations as explained above. You need to carefully consider whether it makes sense to impersonate these user accounts given the side effects. Another alternative would be to create a new user (e.g. “CRM System User”) in AD and CRM and chose to impersonate that user whenever you are performing “system” transactions that should execute with elevated privileges. The advantage of doing that is that now you can control exactly how you configure that “super user”. You can choose to give it System Administrator role or a more restrictive role. You can decide whether or not to give it field-level permissions and in what business unit the user should be. Furthermore, you can configure a “system” mailbox so that this user is able to send “system” communications to end users (which can be quite useful as well and cannot be done with built-in SYSTEM/INTEGRATION account).

Note that if your plugins are configured to run under the context of a specific user (e.g. CRM System User) then it’s a good practice that this same user exists in all your environments (DEV/QA/Prod) with the same full name. If that is the case then you can safely transport your solutions and the impersonation configuration will be preserved when you transport plugins across your environments because CRM will be able to find the impersonating user by full name (even though the systemuserid and the AD accounts might not match it will still be able to resolve by full name).

Monday, January 30, 2012

The CRM 2011 Endpoints

With CRM 2011 there is a new webpage in your organization which gives you the information about all the endpoints available to interact with the CRM server. You simply need to navigate to Settings –> Customizations –> Developer Resources and you will see a page similar to this:


image
These are the different resources available from this page:

Organization Information

This section provides you with some useful information about your CRM organization:

Organization Unique Name: When you install CRM you can specify the organization unique name. However, with CRM Online, you don’t have full control on this unique name. That is why Microsoft provides you with the unique name in this page as it can be useful, for example, if you contact Microsoft Support about an incident in CRM Online, it is always good to provide your Organization Unique Name. Sometimes this name is a GUID, but fortunately Microsoft has provided the capability to select and copy the name to your clipboard from this page.

Windows Azure AppFabric Certificate: If you plan to use Windows Azure integration this section will be useful to you. You will need to obtain a public certificate and configure it in CRM. Once this is done, you will see this section on your CRM organization “Developer Resources” page and you will be able to download the certificate and see which is the issuing authority. For CRM Online, a public certificate from crm.dynamics.com is already available for you to download and is already configured. You can find out more details about the Windows Azure integration with CRM here: http://msdn.microsoft.com/en-us/library/gg309340.aspx. Note that this section will be hidden until you have successfully configured a public certificate for your CRM deployment.
Developer Center: The developer center is simply a link to documentation, tools, forums and other public sources of information that are useful for the CRM developer: http://go.microsoft.com/fwlink/?LinkID=201190


 
Service Endpoints

This section provides you with an overview of all the supported service endpoints to access data or metadata from your CRM organization and/or deployment.

Discovery Service: The Discovery Service (SOAP protocol) provides information about the organizations available in your deployment. You can query the Discovery Service to get the URL of your organizations. This service is particularly useful for multi-tenant deployments and CRM Online organizations. You can learn more about the methods available from the Discovery Service here: http://technet.microsoft.com/en-us/library/microsoft.xrm.sdk.discovery.idiscoveryservice.aspx
Organization Service: The Organization Service (SOAP Protocol) is the primary web service can be used to access data and metadata in your organization. There are a number of “Messages” (or requests) that this service accepts to manipulate the business data as well as the metadata of your organization. For a complete list of supported messages see here: http://technet.microsoft.com/en-us/library/gg309482.aspx

Organization Data Service: This Open Data (OData) Web service provides access to the business data of your organization by exposing a REST API. This link opens the Conceptual Schema Definition Language (CSDL) document that describes how to access your data by using this API. For more information, see Use the REST Endpoint with Ajax and JScript Web Resources, Use the REST Endpoint with Silverlight Web Resources, and Use the REST Endpoint with Ajax and JScript Web Resources.

Also note that for backwards compatibility, the CRM4 asmx endpoints are still supported in CRM 2011, but you should avoid using them since they are only provided for backwards compatibility.

Friday, December 9, 2011

Avoid duplicates when creating / updating records using the CRM SDK

When you enable duplicate detection and publish your duplicate detection rules, you will notice that when you try to create a duplicate in the CRM web application (or through Outlook client) you will get a pop-up indicating that you are trying to create a duplicate record. However, if the create/update request is sent via the web services to CRM (using the SDK) then by default, the duplicate record will be created without any warning.

The trick is that if you want to avoid creating duplicates when calling the CRM web services, you need to provide an optional parameter in the request which specifies that the server should check for duplicates before creating your record (by default the server will bypass duplicate detection). You must use a CreateRequest or UpdateRequest and provide the SuppressDuplicateDetection as “false”. Here is a sample for which my code will prevent creating duplicate accounts (note that I have already published a duplicate detection rule for accounts with the same name):

 

Account a = new Account();
a.Name = "My account";

CreateRequest req = new CreateRequest();
req.Parameters.Add("SuppressDuplicateDetection", false);
req.Target = a;
try
{
    service.Execute(req);
}
catch (FaultException<OrganizationServiceFault> ex)
{
    if (ex.Detail.ErrorCode == -2147220685)
    {
        // Account with name "My account" already exists
    }
    else
    {
        throw;
    }
}

Monday, May 9, 2011

Bulk updating user's preferences (UserSettings) in CRM: PART I


I’ve realized it has been some time since my last post. I was quite busy with a CRM project, and I’d like to share some of the lessons I have learned. Sometimes we need to change the user settings for multiple users in CRM and we don’t want to ask each user to do it themselves. For example, for a Canadian organization we are often given a list of users with their corresponding time zone and preferred language. However, there is no functionality in the CRM application to modify someone else’s personal options, even if you log in as a system administrator. In this blog post I will share a tool that I have developed for easily managing user preferences and I will walk you through the design so you can extend the tool if necessary.

 I have split this post into 3 parts:
·         Part One: Retrieving a spreadsheet with the list of available time zones and languages
·         Part Two: Generating a spreadsheet for entering the user preferences for each user
·         Part Three: Uploading the updated spreadsheet to update user preferences




Part One: Retrieving a spreadsheet with the list of available time zones and languages
Once you have installed all the language packs you will require, it will be useful to have a list of all available time zones and languages available. Because we have to deal with time zone and language codes, we need to keep a mapping between codes and names (e.g. 1033 = English). The mappings will be useful later on in part two and three. Note that in my sample code I am using strong types so you need to generate the strong types using crmsvcutil.exe. For convenience you can download mine here and include it in your project. I will also post the final VS Solution that I used at the end of part three.
 
1.       The program!

Let’s start with the skeleton of the program we will use:
class UpdateCRMSystemUserSettings
{
    static string serverName = "192.168.1.68:5555";
    static string organizationName = "Avanade";
    static string userMame = "administrator";
    static string userDomain = "avanadedom";
    static string userpassword = "xxxxx";
    static string usersFileName = @"C:\users.xml";
    static string timeZonesFile = @"C:\TimeZones.xml";
    static string languagesFile = @"C:\Languages.xml";
    static string usersCompletedFileName = @"C:\usersCompleted.xml";
    static Dictionary<int, string> TimeZoneCodeToName = new Dictionary<int, string>();
    static Dictionary<string, int> TimeZoneNameToCode = new Dictionary<string, int>();
    static Dictionary<int, string> LanguageCodeToName = new Dictionary<int, string>();
    static Dictionary<string, int> LanguageNameToCode = new Dictionary<string, int>();

    static void Main(string[] args)
    {
        try
        {
            Organization org = new Organization();
            IOrganizationService service = org.Open(serverName, organizationName, userMame, userDomain, userpassword);

            CreateLanguageMappings(service, languagesFile);
            CreateTimeZoneMappings(service, timeZonesFile);
               
            //CreateUserSettingsSpreadsheet(service, usersFileName);
            //UploadUserSettingsSpreadsheet(service, usersCompletedFileName);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            Console.ReadLine();
        }
    }
}

You might notice we are keeping mappings between codes and names for languages and time zones in memory as well. You might also notice that I am using an Organization class that I have defined for connecting to an On-Premise deployment, but you can change those lines to get the IOrganizationService for your own organization.


2.       Create the language mappings
In this method I am retrieving the available languages in the organization and creating a two-way mapping between the language code and the language name. I am saving the mapping as an XML file (languagesFile) which is a spreadsheet that we can open in Excel. I am also keeping the mapping in memory using the dictionaries I defined (will be useful later):
private static void CreateLanguageMappings(IOrganizationService service, string fileName)



{
    XmlDocument xDoc = new XmlDocument();
    xDoc.AppendChild(xDoc.CreateElement("Languages"));
    RetrieveProvisionedLanguagesRequest req = new RetrieveProvisionedLanguagesRequest();
    RetrieveProvisionedLanguagesResponse resp = (RetrieveProvisionedLanguagesResponse)service.Execute(req);
    foreach (int lcid in resp.RetrieveProvisionedLanguages)
    {
        CultureInfo culture = CultureInfo.GetCultureInfo(lcid);

        XmlNode languageNode = xDoc.CreateElement("Language");
        XmlNode lcidNode = xDoc.CreateElement("LanguageID");
        XmlNode languageNameNode = xDoc.CreateElement("Name");
        xDoc.DocumentElement.AppendChild(languageNode);
        languageNode.AppendChild(lcidNode);
        languageNode.AppendChild(languageNameNode);

        lcidNode.InnerText = lcid.ToString();
        languageNameNode.InnerText = culture.EnglishName;

        LanguageCodeToName[lcid] = culture.EnglishName;
        LanguageNameToCode[culture.EnglishName] = lcid;
    }
    xDoc.Save(fileName);
}



3.       Create the time zone mappings


Now I am doing the same as I did with the languages but for the time zones:
private static void CreateTimeZoneMappings(IOrganizationService service, string fileName)
{
    XmlDocument xDoc = new XmlDocument();
    xDoc.AppendChild(xDoc.CreateElement("TimeZones"));

    QueryExpression query = new QueryExpression(TimeZoneDefinition.EntityLogicalName);
    query.ColumnSet = new ColumnSet("timezonecode", "standardname");

    EntityCollection coll = service.RetrieveMultiple(query);
    foreach (Entity e in coll.Entities)
    {
        XmlNode timeZoneNode = xDoc.CreateElement("TimeZone");
        XmlNode timeZoneCodeNode = xDoc.CreateElement("TimeZoneCode");
        XmlNode timeZoneNameNode = xDoc.CreateElement("Name");
        xDoc.DocumentElement.AppendChild(timeZoneNode);
        timeZoneNode.AppendChild(timeZoneCodeNode);
        timeZoneNode.AppendChild(timeZoneNameNode);

        int timeZoneCode = (int)e["timezonecode"];
        string timeZoneName =  e["standardname"] as string;
        timeZoneCodeNode.InnerText = timeZoneCode.ToString();
        timeZoneNameNode.InnerText = timeZoneName;

        TimeZoneCodeToName[timeZoneCode] = timeZoneName;
        TimeZoneNameToCode[timeZoneName] = timeZoneCode;
    }
    xDoc.Save(fileName);
}





4.       Verify your spreadsheets
By now you should have produced two XML files that when you open with Excel should look like this:


LanguageID

Name

1033

English (United States)

1036

French (France)



TimeZoneCode

Name

256

Canberra, Melbourne, Sydney (Commonwealth Games 2006)

55

SA Western Standard Time

85

GMT Standard Time

180

Ekaterinburg Standard Time

158

Arabic Standard Time

196

Bangladesh Standard Time

29

Central Standard Time (Mexico)

165

Arabian Standard Time

…list continues…

…list continues…



Wednesday, February 16, 2011

CRM 2011 for On-Premises released today

It is finally here! Check the news release, featuring Mark Barrett, Sr. VP at Avanade.

Microsoft Dynamics CRM 2011 Released for On-Premises and Partner-Hosted Deployments


Also, the RTM version of the SDK is available as well as the implementation guide:

Download the Microsoft Dynamics CRM 2011 Software Development Kit (SDK).