Security Trimmed Top Navigation Menu Using Custom Sitemap Provider for SharePoint

Some time back shared my experience on creating consistent top navigation in SharePoint. Now, added with that, there is a requirement to make the Top navigation Security Trimmed!

Alright, to fulfill this requirement all we need to do is: Create our own sitemap provider which does the job of security trimming. Lets get started!

Brief: Create a Class project in Visual studio, Add references to SharePoint, System.web, System.Configuration. Place the following code in the .CS file, Strong Name it, Compile, Place the DLL to GAC, Update the web.config file. Place your own .sitemap file, Change your master page to link with the custom site map.

SharePoint Security Trimmed Navigation Provider – Source Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Navigation;
using System.Web;
using System.Xml;

namespace BpCustomNavProvider
{
    public class CustomNavProvider : SPXmlContentMapProvider
    {

        public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node)
        {
            try
            {
                if (node == null)
                {
                    throw new ArgumentNullException("node");
                }
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }
                if (!base.SecurityTrimmingEnabled)
                {
                    return true;
                }
                if (string.IsNullOrEmpty(node.Url))
                {
                    return this.IsGranted(context, node.ChildNodes);
                }
                return this.IsGranted(context, node);
            }
            catch
            {
                return false;
            }
        }


        private bool IsGranted(HttpContext context, SiteMapNode node)
        {
            bool isGranted = false;
            SPSecurity.RunWithElevatedPrivileges(delegate
            {
                using (SPWeb web = new SPSite(SPContext.Current.Site.MakeFullUrl(node.Url)).OpenWeb())
                {
                    SPUser user = web.AllUsers[context.User.Identity.Name];
                    if (user != null)
                    {
                        try
                        {
                            if ((node.Roles != null) && (node.Roles.Count > 0))
                            {
                                foreach (string str in node.Roles)
                                {
                                    isGranted = (str == "*") || (user.Groups[str] != null);
                                    if (isGranted)
                                    {
                                        break;
                                    }
                                }
                            }
                            isGranted = web.DoesUserHavePermissions(user.LoginName, SPBasePermissions.EmptyMask | SPBasePermissions.ViewPages);
                        }
                        catch
                        {
                        }
                    }
                }
            });
            return isGranted;
        }

        private bool IsGranted(HttpContext context, SiteMapNodeCollection childNodes)
        {
            bool flag = false;
            foreach (SiteMapNode node in childNodes)
            {
                flag = this.IsGranted(context, node);
                if (flag)
                {
                    return flag;
                }
                this.IsGranted(context, node.ChildNodes);
            }
            return false;
        }
    }
}

Web.config Change:
In web.config file, Under the <siteMap>   <providers> section add an entry to our custom site map provider:

<add name="BPCorpProvider" siteMapFile="_layouts/BPCorp.sitemap" type="BpCustomNavProvider.CustomNavProvider, BpCustomNavProvider , Version=1.0.0.0, Culture=neutral, PublicKeyToken=c7b63f4b9c6ca821" securityTrimmingEnabled="true"  />

Salaudeen Rajack

Salaudeen Rajack is a SharePoint Architect with Two decades of SharePoint Experience. He loves sharing his knowledge and experiences with the SharePoint community, through his real-world articles!

20 thoughts on “Security Trimmed Top Navigation Menu Using Custom Sitemap Provider for SharePoint

  • February 4, 2016 at 3:36 AM

    This has been working really well for me. Recently, I got a request to add a navigation menu item for a department which has the same URL as that of an existing menu item corresponding to another department. But when I do this, the page throws an exception and I cannot even load the page. Can URLs not be repeated when extending SPXmlContentMapProvider?

    Reply
    • February 4, 2016 at 8:42 AM

      Yes Ashwin, That’s the limitation in using this controls! We can’t have duplicate URLs as I’ve stated in my another post: https://www.sharepointdiary.com/2012/01/custom-top-navigation-using-sitemap.html

      Reply
  • December 6, 2013 at 7:29 PM

    Ive followed these steps, but when I load the page none of my navigation items show up. They worked fine in step one before the security trimming was added.

    Reply
  • October 18, 2013 at 8:43 PM

    SPUser user = web.AllUsers[context.User.Identity.Name]; only displays the node if the user is added explicitly, it does not display if they have been added via domain group until they have first visited the site. How can I get the node to display without the user having to visit the site if they are granted access via domain group?

    Reply
  • July 1, 2013 at 10:44 PM

    This worked perfectly, however I have some custom pages in the LAYOUTS folder which are being trimmed, anyway to get those displayed?

    Reply
  • October 4, 2012 at 3:53 PM

    Sorry i meant an SPlist which is used as an calendar which is part of the SPSite.

    Reply
  • October 4, 2012 at 3:18 PM

    thank you for your reply, I checked and he doesnt have any unique permissions. I am adding a link to a calendar and the user i am testing with has no permission granted to this calendar.
    Can you tell me a way to check where it is failing

    Reply
    • October 4, 2012 at 3:26 PM

      Hi There,

      This method Works ONLY on SPWeb! Not on Individual Items!! So use your sitemap nodes to point SPWeb Objects not Files/Pages.

      Regards,
      Sal

      Reply
  • October 3, 2012 at 4:33 PM

    I have implemented the dll but the nodes are still showing even when the users dont have any rights to the page/url, for example when they click the node it gives them a access denied. what am i doing wrong, do i have to implement roles

    Reply
    • October 4, 2012 at 10:33 AM

      Check whether user’s granted access to any of the underlying sub-sites/Lists with unique permission! If Yes, That will add a “Limited Access” to Root site collection!

      Reply
  • September 12, 2012 at 9:09 PM

    Thanks, I wish I had read not only the blog but even the replies. This has driven me crazy for a few days. I too inherited from SpXmlContentMapProvider and got those weird URL:s. As soon as I switched to XmlSiteMapProvider everything works as I wanted. And Salaudeen, thanks for a good article. This has really helped me.

    Reply
  • September 4, 2012 at 10:57 AM

    To fix the example.com/xyz/xyz issue use the XmlSiteMapProvider instead of SPXmlContentMapProvider

    Reply
  • August 27, 2012 at 2:27 PM

    Let me describe it again. if I have root site collection and /accounting, /IT, /Marketing etc.. There menu on the root : example.com/ is working fine. But when we are in the /accounting tab, the urls are arranged as example.com/accounting/accounting, example.com/accounting/IT, example.com/accounting/Marketing instead of example.com/accounting, example.com/IT, example.com/Marketing.
    Without Security Trimming, it works fine. but if I replace, it with my custom dll, then the urls are changed to above format.

    Please help me over here!!!

    Reply
  • August 23, 2012 at 10:14 PM

    Hi Rajack,

    Facing problem when implementing security trimming.
    I have added on top site collection and also on other site collections. Able to see the new topnavigationmenu but the urls are not appropriate.
    Top site collection urls are referenced good. [ example.com/] with other links to site collections.
    Added to the sub site collections as well. if the other site collection is of form example.com/xyz, it is referenced in topNavigationMenu as : example.com/xyz/xyz.
    Can you pls help on this?

    Reply
  • June 16, 2012 at 9:44 AM

    Hi,

    I also receive the same error..

    I have had my own xml site map working for quite some time, wanted to add your security trimming, but it is not working, please help.

    Reply
    • June 18, 2012 at 12:26 PM

      Hi I got it working your code had to be changed to inherit from a spxmlcontentprovider instead.

      Reply
    • August 7, 2012 at 5:06 PM

      Hi Chris, Let me know how you have worked it out? I followed all the steps but getting error. It was working before and extended to have security trimming and added following in Web.Config:

      But leading to error page.

      Reply
    • August 7, 2012 at 5:27 PM

      Hi Chris/All,

      I was able to recreate the first part. when want to add security trimming, it is giving error.

      Here is the web.config tags:

      and code bpCustomNavProvider:

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using Microsoft.SharePoint;
      using Microsoft.SharePoint.Utilities;
      using Microsoft.SharePoint.Navigation;
      using System.Web;
      using System.Xml;

      namespace WDCustomNavProvider
      {
      public class CustomNavProvider : XmlSiteMapProvider

      Tried both xmlsitemapprovider and spxmlcontentprovider but of no use. Pls let me how if I am making any mistake or steps to taken care off.

      Thanks
      Tom

      Reply
  • April 4, 2012 at 11:56 PM

    I get error as:

    The DataSourceID of ‘TopNavigationMenuV4’ must be the ID of a control of type IHierarchicalDataSource. A control with ID ‘topSiteMap’ could not be found.

    after I add the second line on the webconfig file. please let me know if I am making any mistakes..

    Reply
    • April 5, 2012 at 1:18 PM

      Follow my First post step by step:
      https://www.sharepointdiary.com/2012/01/custom-top-navigation-using-sitemap.html
      to bring custom Navigation control.

      and then build the above code as DLL, Add a Safecontrol Entry to Web.config
      file, That will fix your issue.

      e.g.

      Please note: Your PublicKeyToken will vary!

      Reply

Leave a Reply