Saturday, 4 April 2015

Utilizing ‘ReplacePrivileges’ Plugin Message in CRM C#

In this post will talk about ‘ReplacePrivileges’ Message.

Introduction

This message will be triggered if you change the set of privilege collections from a security role.
In short word, when you change the ‘circle’ in the Security Role setting

image

When To Use?

Interfere this Plugin Message can be useful for some situations, example:

1. Prevent human error in security role modification for specific security role that already the best in the production.
Often, we have human error, this one cannot access, that one also cannot access, it can be caused by human error, someone accidently revoke or remove a privilege that is required to perform some action.

In addition, we cannot also remove some basic privilege that must be there to login and access CRM Data, such as System Form, User Settings, etc. This can be prevented by give validation by doing intervention of this plugin message

2. Prevent user from ‘abuse of power’ action
In some organization which is security is very important, you cannot just grant common role person a privilege to delete important records, right? For example for Salesperson, do not delete Competitor record, Customer Service cannot delete existing Case, etc.

But, we cannot just let it go and blame who if that happened? We can prevent it by add some logic in this plugin message.

3. Logging Purpose
We can actually turn on Auditing in CRM, but for advance log, you can put your logging logic into this plugin message.

Sample Code

First Sample, Prevent Any Changes for ‘Salesperson’ Role

Many people are assigned to Salesperson role, so maintaining its security is very important.

You have set correctly a privilege in the development server, you want to make sure that no one, including the new System Administrator (if you resigned) to not be able to make any changes.

So, here is the sample code:

public void Execute(IServiceProvider serviceProvider)
{
     #region must to have

     IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

     IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

     // Create service with context of current user
     IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

     //create tracing service
     ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

     #endregion

     Guid guidRoleId = new Guid();

     if (context.InputParameters.Contains("RoleId"))
     {
         guidRoleId = (Guid)context.InputParameters["RoleId"];               
     }

     //To prevent any changes for Salesperson privilege
     if(GetRoleName(service, guidRoleId).ToString().ToLower() == "Salesperson".ToLower())
     {
         throw new InvalidPluginExecutionException("Please do not modify any changes for Salesperson Role!, do not dare to do it!");
     }
}

private string GetRoleName(IOrganizationService service, Guid guidRoleId)
{
     Entity enRole = null;
     string strRoleName = string.Empty;

     enRole = service.Retrieve("role", guidRoleId, new ColumnSet("name"));

     if (enRole != null)
     {
         strRoleName = enRole.GetAttributeValue<string>("name");
     }
     return strRoleName;          
}

Result:

image

Second Sample, Prevent Grant ‘Delete’ Privilege for ‘Competitor’


We don’t want Salesperson to delete the ‘Competitor’ record and we don’t want any human error to give the privilege (prvDeleteCompetitor).

image

Here is the code:

public void Execute(IServiceProvider serviceProvider)
{
      #region must to have

      IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

     IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

      // Create service with context of current user
     IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

     //create tracing service
     ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

      #endregion

      Guid guidRoleId = new Guid();

       if (context.InputParameters.Contains("RoleId"))
       {
            guidRoleId = (Guid)context.InputParameters["RoleId"];               
       }

      //To prevent changes for Salesperson privilege
       if (GetRoleName(service, guidRoleId).ToString().ToLower() == "Salesperson".ToLower())
       {
            if (context.InputParameters.Contains("Privileges"))
            {
               RolePrivilege[] privileges = (RolePrivilege[])context.InputParameters["Privileges"];
               foreach (RolePrivilege rolePrivilege in privileges)
               {
                    //To prevent granting 'Delete' Access for 'Competitor' Entity
                    if(GetPrivilegeName(service, rolePrivilege.PrivilegeId) == "prvDeleteCompetitor")
                    {
                        throw new InvalidPluginExecutionException("Please do not give this Delete Competitor Privilege for Salesperson");
                     }                           
                }
              }
       }                   
}

private string GetRoleName(IOrganizationService service, Guid guidRoleId)
{
     Entity enRole = null;
     string strRoleName = string.Empty;

     enRole = service.Retrieve("role", guidRoleId, new ColumnSet("name"));

     if (enRole != null)
     {
          strRoleName = enRole.GetAttributeValue<string>("name");
     }

          return strRoleName;          
}

private string GetPrivilegeName(IOrganizationService service, Guid guidPrivilegeId)
{
     Entity enPrivilege= null;
     string strPrivilegeName = string.Empty;

     enPrivilege = service.Retrieve("privilege", guidPrivilegeId, new ColumnSet("name"));

     if (enPrivilege != null)
     {
         strPrivilegeName = enPrivilege.GetAttributeValue<string>("name");
     }

     return strPrivilegeName;
}

Result:

image

image

Checking Privilege Depth

You can use rolePrivilege.Depth also to check, whether this is Basic, Deep, Local or Global Access.

https://msdn.microsoft.com/en-us/library/microsoft.crm.sdk.messages.privilegedepth.aspx

How to Register The Plugin

Message: ReplacePrivileges

Primary Entity: role

Register as Pre-Operation or Post-Operation so far I don’t see any difference for this message, but better you register Pre-Operation stage for validation.

Hope this helps!

Thanks.

1 comment:

My Name is..