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
    }
}



20 comments:

  1. Jehanzeb Javeed,

    I'm not sure if you saw the third-to-last comment I left on the forum, but I just wanted to check to see if you are aware of this last minor issue. Here is the post again:

    "The new solution file works great, except for one small detail which may have not been addressed in enough detail in the original question I posed at the start of the forum. I created a set of Security Roles to meet the KCS multi-tiered article development strategy as I mentioned in the first question posed. Our KCS 1 role corresponds to most employees who can read published articles, comment and add notes when the article needs improvement, and create articles if necessary, and your plug-in supports that fully. However, we want another role (our KCS 2) to correspond to the editor user that can edit all articles (which is granted through the Write privilege and currently supported through your plug-in) and submit them for approval so that another higher security-level user can approve them for company use. Could you edit your solution to make it so the Write privilege (which we are giving to our editors) allows them to submit drafts for approval (in other words, make it so they don't need the Publish privilege to submit an article for approval, they just need the Write privilege)?"

    Thank you for your time.

    ReplyDelete
  2. Hi,

    I did not check the post on forum, i will get back to you soon on this issue.

    ReplyDelete
  3. Jehanzeb,

    Hello. Were you able to fix the issue that only those with the Publish privilege can submit articles for approval? We want those who have Write abilities to also be able to submit articles for approval. If you could either supply me with another updated solution or briefly explain how I could go about fixing that, it would be greatly appreciated.

    Thank you

    ReplyDelete
  4. Can the solution be updated so that we add restriction to the security roles to let only the owner of the article check it.

    ReplyDelete
  5. Hi all,

    I need to add a clarification .
    Can we let only one team see certain articles.
    I can do it through security roles because i can't assign in for "Business Unit"

    Thank you,

    ReplyDelete
  6. thanks
    this is the code of Equal Condition
    wod_ArticlePublishPrivEntity = RetrieveEntityByAttribute(ref wod_CrmService,
    "privilege"
    , new string[] { "privilegeid" }, new string[] { "name" }
    , new object[] { "prvPublishArticle" });

    but if we need not Equal Condition .so how is that possible in Crm 4?

    ReplyDelete
  7. Hi to every body, it's my first pay a quick visit of this
    webpage; this website includes awesome and truly good information for readers.


    Also visit my web blog - sale konferencyjne kielce

    ReplyDelete
  8. Choose whether any of your constraints are holding you back or whether you could employ the aid of others to
    pack in the spaces. Make the process of ordering be stress-free to complete at all times as possible.
    SEO is the most prominent tool to drive a
    huge traffic rate, as search engines really give closest attention to well-optimized
    pages.

    Look at my blog post - plus.google.com ()

    ReplyDelete
  9. Having read this I believed it was rather enlightening.
    I appreciate you taking the time and energy to put this informative article together.
    I once again find myself personally spending
    a significant amount of time both reading and leaving comments.

    But so what, it was still worth it!

    Have a look at my site - vlc player (freevlcmediaplayerdownload.Blogspot.com)

    ReplyDelete
  10. Basically oxidation enables life but also slowly kills us.
    To deal with them requires a lot of strength and help from
    a psychotherapist. Regardlessof whether one has
    dementia, through this article we've been in a
    position to see that the benefits of getting adequate nutrition can improve physical well-being and can help to boost functionality
    and improve the quality of life. In short vitamins are very essential for every individual.


    Also visit my website :: Procera AVH pills

    ReplyDelete
  11. Having read this I thought it was really informative.
    I appreciate you taking the time and effort to put this article together.
    I once again find myself personally spending a lot of time both
    reading and posting comments. But so what, it was still
    worth it!

    Here is my web page ... boston bruins tickets (matematik-ankara.ra5.us)

    ReplyDelete
  12. Let me first begin by introducing too. I am Mei a person can call me anything you just like.

    Her husband and her live in Kentucky and or even she
    doesn't plan place in changing it. It's not a common thing but what she likes doing
    is to read comics and he or s he is working to make it a profession. I used to be unemployed but now I am an office
    clerk on the additional hand plan on changing the device.
    He's been perfecting his website for a few days now. Find out about
    it here: Mia Airport Parking

    Review my web blog ... Mia Parking

    ReplyDelete
  13. Very soon this web page will be famous among all blogging
    visitors, due to it's pleasant posts

    My blog post :: deer hunter 2014 cheats, ,

    ReplyDelete