Impersonation in C# App for D365

We can impersonate a user in console app or any 3rd party code my passing the Guid of impersonated user in the CallerId field of CrmServiceClient object. Below is sample code:

If we are retrieving a FLS field then the impersonating user and impersonated user both should have access to the field. If either doesn’t have access then no value is returned.

static void Main(string[] args)
{
    string ConnectionStringOAuth = @"AuthType = OAuth;
                                     Username = xxxxxx@xxxxxx.onmicrosoft.com;
                                     Password = xxxxxx;
                                     Integrated Security=true;
                                     Url = https://xxxxxx.crm.dynamics.com;
                                     AppId = xxxxxx;
                                     RedirectUri = https://xxxxxxxx;
                                     LoginPrompt=Auto";
    CrmServiceClient svc = new CrmServiceClient(ConnectionStringOAuth);
    svc.CallerId = Guid.Parse("{60FBEAFB-7724-EB11-A813-000D3A569CF5}");

    var cs = svc.RetrieveMultiple(new QueryExpression("ps_configurationsetting")
    {
          ColumnSet = new ColumnSet(true),
          Criteria =   {
                          Filters =
                          {
                                new FilterExpression
                                {
                                   FilterOperator = LogicalOperator.And,
                                   Conditions = {
                                         new ConditionExpression("ps_key", ConditionOperator.Equal, "azurekey")
                                   }
                                 }
                          }
                    }
     });
     string value = cs.Entities.Count != 0 ?
     (cs.Entities[0].Attributes.Contains("ps_value") ?
     cs.Entities[0].Attributes["ps_value"].ToString() : string.Empty) :
 string.Empty;

     Entity task = new Entity("task")
     {
          Attributes = new AttributeCollection()
          {
               new KeyValuePair<string, object>("regardingobjectid",
               new EntityReference("contact", Guid.Parse("{87D4EF7F-DE38-EB11-A813-0022481BFEB4}"))),
               new KeyValuePair<string, object>("subject", value)
          }
     };
     var newRecord = svc.Create(task);
     Console.ReadLine();
}

Possible Error :

contextUserId=<impersonating userid> is missing privilege <Privilege GUID>. Parameter’user’=<impersonated userid>, callerId=<impersonated userid>.

This error will occur if privilege prvActOnBehalfOfAnotherUser is missing on impersonating user.

Impersonation using JavaScript in D365

We can also impersonate a user using javascript in WebAPI by just passing the callerId in header. The impersonator should have the delegate role ( prvActOnBehalfOfAnotherUser) privilege.

impersonateuser

Below is the sample code for that.

var entity = {};
        entity.subject = value;
        entity["regardingobjectid_contact@odata.bind"] = "/contacts(" + recordId + ")";

        var req = new XMLHttpRequest();
        req.open("POST", serverUrl + "/api/data/v9.0/tasks", true);
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
        req.setRequestHeader("MSCRMCallerID", "60FBEAFB-7724-EB11-A813-000D3A569CF5");

        req.onreadystatechange = function () {
            if (this.readyState === 4) {
                req.onreadystatechange = null;
                if (this.status === 204) {
                    Xrm.Utility.alertDialog("New Task Record Created with Related Contact");
                } else {
                    Xrm.Utility.alertDialog(this.statusText);
                }
            }
        };
        req.send(JSON.stringify(entity));

We get a task created with following audit :

If a field is having FLS (Field level security) enabled then it won’t allow access even if the impersonated user has full access but impersonating user doesn’t have access to the field.

Below is the full code where we trigger a Create Task on click on ribbon button. We read the value from custom entity ps_configurationsetting and then create task with the same subject. If the calling user doesn’t have access to FLS, impersonation wont help too.

ContactRibbon = {
    CreateTask: function (context) {
        var formContext = context;
        var recordId = formContext.data.entity.getId().replace("{", "").replace("}", "");
        var globalContext = Xrm.Utility.getGlobalContext();
        var serverUrl = globalContext.getClientUrl();

        var url = Xrm.Page.context.getClientUrl() + "/api/data/v9.1/ps_configurationsettings?$filter=ps_key eq 'azurekey'";
        var reqCS = new XMLHttpRequest();

        reqCS.open("GET", url, false);
        reqCS.setRequestHeader("Accept", "application/json");
        reqCS.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        reqCS.setRequestHeader("MSCRMCallerID", "60FBEAFB-7724-EB11-A813-000D3A569CF5");
        reqCS.send();

        if (reqCS.readyState == 4) {
            if (reqCS.status == 200) {
                var data = JSON.parse(reqCS.response);
                if (data != null && data.value.length > 0) {
                    var value = data.value[0].ps_value;
                }
            }
            else {
                alert("Error: " + reqCS.responseText);
            }
        }
        var entity = {};
        entity.subject = value;
        entity["regardingobjectid_contact@odata.bind"] = "/contacts(" + recordId + ")";

        var req = new XMLHttpRequest();
        req.open("POST", serverUrl + "/api/data/v9.0/tasks", true);
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
        req.setRequestHeader("MSCRMCallerID", "60FBEAFB-7724-EB11-A813-000D3A569CF5");
        req.onreadystatechange = function () {
            if (this.readyState === 4) {
                req.onreadystatechange = null;
                if (this.status === 204) {
                    Xrm.Utility.alertDialog("New Task Record Created with Related Contact");
                } else {
                    Xrm.Utility.alertDialog(this.statusText);
                }
            }
        };
        req.send(JSON.stringify(entity));
    }
};

Impersonation in a plugin D365

We can impersonate any user in plugin code by passing user GUID to CreateOrganizationService of IOrganizationServiceFactory. Below is sample plugin code. The code is impersonating with user GUID and then creating task.

public void Execute(IServiceProvider serviceProvider)
        {
            var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {
                var serviceFactory =
                    (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service;

                try
                {
                    service = serviceFactory.CreateOrganizationService(new Guid("60FBEAFB7724EB11A813000D3A569CF5"));
                    CreateTask(service, context);
                }

                catch (FaultException<OrganizationServiceFault> ex)
                {
                    throw new InvalidPluginExecutionException("An error occurred.", ex);
                }

                catch (Exception ex)
                {
                    tracingService.Trace("Error: {0}", ex.ToString());
                    throw;
                }
            }
        }

In create task function, we are retrieving value from FLS field and then creating a task with that description. If user which we are impersonating doesn’t have access to FLS, we will get ‘Access Denied’ in description.

public void CreateTask(IOrganizationService service, IPluginExecutionContext context)
{
       var cs = service.RetrieveMultiple(new QueryExpression("ps_configurationsetting")
       {
            ColumnSet = new ColumnSet(true),
            Criteria =   {
                                Filters =
                                {
                                    new FilterExpression
                                    {
                                        FilterOperator = LogicalOperator.And,
                                        Conditions = {
                                            new ConditionExpression("ps_key", ConditionOperator.Equal, "azurekey")
                                        }
                                    }
                                }
                    }
        });

        string securevalue = cs.Entities.Count != 0 ?
            (cs.Entities[0].Attributes.Contains("ps_securevalue") ?
            cs.Entities[0].Attributes["ps_securevalue"].ToString() : "Access Denied") :
            string.Empty;

        Entity followupTask = new Entity("task");
        followupTask["subject"] = "Send e-mail .";
        followupTask["description"] = securevalue;
        followupTask["scheduledstart"] = DateTime.Now.AddDays(7);
        followupTask["scheduledend"] = DateTime.Now.AddDays(7);
        followupTask["category"] = context.PrimaryEntityName;
        if (context.OutputParameters.Contains("id"))
        {
            Guid regardingobjectid = new Guid(context.OutputParameters["id"].ToString());
            string regardingobjectidType = "contact";
            followupTask["regardingobjectid"] = new EntityReference(regardingobjectidType, regardingobjectid);
        }
        service.Create(followupTask);
}

%d bloggers like this: