Using Impersonation in Dynamics CRM

While you can’t log in as another through the Dynamics CRM front  end, as a System Administrator it is possible to impersonate another user when making calls to the CRM API.

This is very useful if you want to be able to do the following:

  • Test the correct implementation of security roles.
  • Check which records can be seen by which users if sharing is being used.
  • Search for charts or views belonging to different users.

For example, if you have complex security rules involving automatic sharing of records with certain privileges, this can be very time-consuming to test through the CRM front end. Writing an integration test where a record is created by one user, and then the permissions on this record can be immediately checked for another user, is very simple using impersonation.

As another example, we recently had a support issue where a team were all using a personal view created by one of the team. A few of the team were on holiday and no-one knew who had originally created the view. It was straightforward to cycle through a list of users in a particular team and list the personal views to which they had access and who the views were created by. This information is not readily accessible through the front end, nor through the API without being able to switch users, but using impersonation it was very easy to retrieve the information needed.

Here is an example which works in LINQPad but which you can easily amend to work in a Visual Studio project. The line in which we switch caller id is highlighted.

/*
This sample shows how you can change the callerid of the organisation service proxy
allowing you to impersonate different users
*/
void Main()
{
	// Log in with system administrator account
	var orgService = ConnectToCrm(Util.GetPassword("dev org service url"));

	// Display name of currently logged in user
	WhoAmIResponse whoami = (WhoAmIResponse)orgService.Execute(new WhoAmIRequest());
	Entity u = orgService.Retrieve("systemuser",whoami.UserId, new ColumnSet("fullname"));
	Console.WriteLine("Current user is " + u["fullname"]);
	
	// Create an account and display the user who created it
	CreateAccountAndShowWhoCreatedIt(orgService);

	// Get the user details of a different user
    string username = Util.GetPassword("myusername");
	Entity user = GetUser(orgService, username);
	
	// Switch the Caller ID to that user
	Console.WriteLine("Switching caller id to " + username);
    orgService.CallerId = user.Id;

	// Create an account and display the user who created it
	CreateAccountAndShowWhoCreatedIt(orgService);
}

private void CreateAccountAndShowWhoCreatedIt(OrganizationServiceProxy orgService)
{
	Entity account = new Entity("account");
	Guid accountId = orgService.Create(account);
	account = orgService.Retrieve("account", accountId, new ColumnSet("createdby"));
	Console.WriteLine("Account record was created by " + ((EntityReference)account["createdby"]).Name);	
}

private static OrganizationServiceProxy ConnectToCrm(string uri)
{
	string UserName = Util.GetPassword("sysopsuser");
	string Password = Util.GetPassword("sysopspassword");

	AuthenticationCredentials clientCredentials = new AuthenticationCredentials();
	clientCredentials.ClientCredentials.UserName.UserName = UserName;
	clientCredentials.ClientCredentials.UserName.Password = Password;

	OrganizationServiceProxy serviceProxy = new OrganizationServiceProxy(new Uri(uri), null, clientCredentials.ClientCredentials, null);

	Console.WriteLine("Connected to " + serviceProxy.ServiceConfiguration.ServiceEndpoints.First().Value.Address.Uri);

	return serviceProxy;
}

public static Entity GetUser(OrganizationServiceProxy orgService, string domainName)
{
	QueryExpression queryUser = new QueryExpression
	{
		EntityName = "systemuser",
		ColumnSet = new ColumnSet("systemuserid", "businessunitid", "domainname"),
		Criteria = new FilterExpression
		{
			Conditions =
					{
						new ConditionExpression
						{
							AttributeName = "domainname",
							Operator = ConditionOperator.Equal,
							Values = {domainName}
						}
					}
		}
	};

	EntityCollection results = orgService.RetrieveMultiple(queryUser);
	return results.Entities[0];
}

Here is a LINQPad script of the above code.

For fairly obvious reasons, it is not possible to change the caller id to that of a user who is disabled, or to a user who has no security roles. Such a user would not be able to make any API calls, so there would be no point in doing so anyway.

Posted in Dynamics CRM, LINQPad | Tagged , | Leave a comment

Leave a Reply