Saturday, July 16, 2011

Dynamics CRM 2011 : Security Role Article Publishing Privilege Not Working

  
While browsing Microsoft Dynamics CRM Development Forums, i have found an interesting security privilege issue post “Both the CSR Manager and Customer Service Representative can publish articles” , after performing a test i found that the security permissions are not working regardless of the Published Article Privileges. So i decided to write up a solution that will fix the issue to help the Microsoft Dynamics CRM customers.

Microsoft Dynamics CRM 2011 (On-Premise & Online) Solution Download & Installation Steps:

1. Click here to download solution file (ArticlePublishingSecurityPrivilegeFix_1_0_0_0.zip)

2. In CRM 2011, go to Settings -> Customization -> Solutions

3. Click on Import button and Browse for the ArticlePublishingSecurityPrivilegeFix_1_0_0_0.zip file

4. During wizard, in Import Options screen makes sure to select option “Activate any process and enable
any SDK message processing steps included in the solution.”

5. Now you can verify Article Publishing Privileges
[Plugin: C# Code]


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;

namespace wod.Crm.Article.Publishing.Fix
{
    public class wod_Plugin : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            #region Variable Declaration

            // Obtain the execution context from the service provider.
            Microsoft.Xrm.Sdk.IPluginExecutionContext context =  
            (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            IOrganizationServiceFactory wod_serviceFactory = null;

            IOrganizationService wod_CrmService = null;

            RetrieveUserPrivilegesRequest lclRetrieveUserPrivilegesRequest = null;

            RetrieveUserPrivilegesResponse lclRetrieveUserPrivilegesResponse = null;

            Entity wod_ArticlePublishPrivEntity = null;

            #endregion

            try
            {
                // Check if SetState message is triggered on kbarticle entity
                if (context.InputParameters.Contains("EntityMoniker")
                    && context.InputParameters["EntityMoniker"] is EntityReference
                    && ((EntityReference)context.InputParameters["EntityMoniker"]).LogicalName == "kbarticle")
                {
                    switch (context.MessageName)
                    {
                        case "SetStateDynamicEntity":

                            #region Article Publishing Privileges Checking Code


                            // check if input parameter contains status
                            if (context.InputParameters.Contains("Status"))
                            {
                                // Check if status paramter value is Published Article code
                                if (((OptionSetValue)context.InputParameters["Status"]).Value == -1)
                                {

                                    // Obtain the service factory to get the service object
                                    wod_serviceFactory = (IOrganizationServiceFactory)serviceProvider
                                                         .GetService(typeof(IOrganizationServiceFactory));

                                    // Obtain service object Imporsonated as plugin calling user
                                    wod_CrmService =
                                    wod_serviceFactory.CreateOrganizationService(context.UserId);

                                    // Retrieve Article publishing privilege Id
                                    wod_ArticlePublishPrivEntity = RetrieveEntityByAttribute(ref wod_CrmService,
                                   "privilege"
                                    , new string[] { "privilegeid" }, new string[] { "name" }
                                    , new object[] { "prvPublishArticle" });

                                    if (wod_ArticlePublishPrivEntity != null)
                                    {
                                        lclRetrieveUserPrivilegesRequest = new RetrieveUserPrivilegesRequest();

                                        // Pass current user id to for retrieving all privileges
                                        lclRetrieveUserPrivilegesRequest.UserId = context.InitiatingUserId;

                                        // Retrieve user all privileges
                                        lclRetrieveUserPrivilegesResponse = (RetrieveUserPrivilegesResponse)
                                        wod_CrmService.Execute(lclRetrieveUserPrivilegesRequest);

                                        // Search if user has privileges of publishing article
                                        RolePrivilege wod_UserArticlePublishPriv =
                                        lclRetrieveUserPrivilegesResponse.RolePrivileges
                                        ToList<RolePrivilege>().Find(delegate(RolePrivilege lclPublishPriv)
                                        {
                                            return lclPublishPriv.PrivilegeId == wod_ArticlePublishPrivEntity.Id
                                                && lclPublishPriv.BusinessUnitId == context.BusinessUnitId;
                                        });

                                        // If user does not have privileges then throw error and abort execution
                                        if (wod_UserArticlePublishPriv == null)
                                        {
                                            throw new InvalidPluginExecutionException("Not enough privileges to Publish article.");
                                        }
                                    }
                                }
                            }

                            #endregion

                            break;
                    }
                }

            }

            catch (System.Web.Services.Protocols.SoapException ex)
            {
                throw new InvalidPluginExecutionException(ex.Detail.InnerText);
            }
            catch (Exception ex)
            {
                throw new InvalidPluginExecutionException(ex.Message);
            }
        }

        #region Helper Method
       #region Helper Method

        // Helper method used to fetch entity record by column searching
        private Entity RetrieveEntityByAttribute(ref IOrganizationService CrmWebService, string EntityName
                                               , string[] RetrieveColumns, string[] FilterByColumns
                                               , object[] FilterByColumnsValue)
        {
            QueryByAttribute wod_Query = null;
            RetrieveMultipleRequest wod_Request = null;
            RetrieveMultipleResponse wod_Response = null;
            EntityCollection wod_RtrnEntyCollection = null;
            Entity wod_RtrnEntity = null;

            try
            {
                if (EntityName != string.Empty || RetrieveColumns != null || FilterByColumnsValue != null || FilterByColumnsValue != null)
                {
                    wod_Query = new QueryByAttribute();

                    wod_Request = new RetrieveMultipleRequest();

                    wod_Query.EntityName = EntityName;

                    wod_Query.ColumnSet = new ColumnSet(RetrieveColumns);

                    wod_Query.Attributes.AddRange(FilterByColumns);

                    wod_Query.Values.AddRange(FilterByColumnsValue);

                    wod_Request.Query = wod_Query;

                    wod_Response = (RetrieveMultipleResponse)CrmWebService.Execute(wod_Request);

                    wod_RtrnEntyCollection = wod_Response.EntityCollection;

                    if (wod_RtrnEntyCollection != null && wod_RtrnEntyCollection.Entities.Count > 0)
                    {
                        wod_RtrnEntity = (Entity)wod_RtrnEntyCollection.Entities[0];
                    }
                }
            }

            catch (System.Web.Services.Protocols.SoapException _sopEx)
            {
                throw new Exception(_sopEx.Detail.InnerText);
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return wod_RtrnEntity;
        }

        #endregion
    }
}