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 - Information Technology Expert with Two-decades of hands-on experience, specializing in SharePoint, PowerShell, Microsoft 365, and related products. He has held various positions including SharePoint Architect, Administrator, Developer and consultant, has helped many organizations to implement and optimize SharePoint solutions. Known for his deep technical expertise, He's passionate about sharing the knowledge and insights to help others, through the real-world articles!

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

  • 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
    • 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
  • 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
  • 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
  • This worked perfectly, however I have some custom pages in the LAYOUTS folder which are being trimmed, anyway to get those displayed?

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

    Reply
  • 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
    • 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
  • 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
    • 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
  • 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
  • To fix the example.com/xyz/xyz issue use the XmlSiteMapProvider instead of SPXmlContentMapProvider

    Reply
  • 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
  • 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
  • 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
    • Hi I got it working your code had to be changed to inherit from a spxmlcontentprovider instead.

      Reply
    • 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
    • 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
  • 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
    • 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

Your email address will not be published. Required fields are marked *