Custom security trimming in ASP.NET sitemaps

In ASP.NET you can create a sitemap to capture the pages that are available in your web application. The web.sitemap is an XML file that is a hierarchical list that is provided for data binding to controls via a sitemap provider. The Menu, SiteMapPath and TreeView control are common controls used for the binding to the sitemap data.


The fragment shows a bit of a web.sitemap.



<?xml version=1.0 encoding=utf-8 ?>


<siteMap xmlns=http://schemas.microsoft.com/AspNet/SiteMap-File-1.0 enableLocalization=true>


  <siteMapNode title=Root description=My Links roles=*>


    <siteMapNode url=~/Default.aspx title=Home resourceKey=Home description=Go to homepage roles=*/>


    <siteMapNode url=~/Admin/EditPosting.aspx title=Add Entry resourceKey=AddEntry description=Adds a new posting


              roles=BlogContributor;BlogOwner;BlogAdmin;BlogEditor />


The default provider XmlSiteMapProvider has a built-in mechanism to trim the sitemap based on roles of an authenticated user. In the fragment you can see the roles attribute that lists the roles an authenticated user should have to “see” the corresponding siteMapNode. When everyone is allowed access you simply specify * as the role.


The security trimming from .NET’s Role Based Security (RBS) is all nice and easy if you use roles in your security. But what if you use application rights instead of roles to validate access to parts of your app? You will need to build your own custom sitemap provider. This is a fairly trivial task. Derive your custom provider class from XmlSiteMapProvider if you think that the XML files like web.sitemap is your thing. Otherwise you can derive from the abstract base class SiteMapProvider and role your own provider from scratch. I assume that you are OK with the XML files.



namespace KillerApps.Web


{


  public class CustomSiteMapProvider: XmlSiteMapProvider


  { … }


}


The key to creating custom security trimming is an override to the IsAccessibleToUser method. This method gives you two arguments for the current HTTP context of the request and the node to evaluate. This node is found by the base class after a lookup of the current URL. In the override we determine whether the current user has access to the given node. 



public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node)


{


  // Security trimming should be enabled, otherwise everything is accessible


  if (!this.SecurityTrimmingEnabled)


    return true;


 


  // Default to no access when no rights are specified


  if (node[“rights”] == null) return false;


  if (node[“rights”] == “*”) return true;


 


  // Split on separator and check if items exist


  string[] rights = node[“rights”].Split(‘;’, ‘,’);


  if (rights == null || rights.Length == 0) return false;


 


  // Check each right against security manager


  foreach (string right in rights)


  {


    if (SecurityManager.IsAuthorized(context.User, right))


    {


      return true;


    }


  }


 


  return false;


}


This sample shows a possible implementation of the override IsAccessibleToUser. First it checks if security trimming is enabled and continues to check what if rights are defined. Note the bold items: we’ll get to that in a minute. Next the rights are checked against your own security implementation. The SecurityManager mentioned is not part of the .NET Framework.


The bold items show a great extensibility point of sitemaps. You can define any attribute on a <siteMapNode>, even if it is not in the XML schema for sitemaps. Any attribute is available through the indexer property of the SiteMapNode class. The bold items show how you can read attributes from the sitemap nodes when defined like so:



    <siteMapNode url=~/Default.aspx title=Home resourceKey=Home description=Go to homepage rights=ViewHomePage/>


Side note: the XSD file for the sitemaps incorrectly lists the securityTrimmingEnabled attribute as part of <siteMapNode>. This is not correct, because this is an attribute in the web.config. Your web.config should contain a definition for the custom provider:



<siteMap enabled=true defaultProvider=CustomProvider>


  <providers>


    <add name=CustomProvider type=KillerApps.Web.CustomSiteMapProvider


      description=Rights based security trimmed sitemap provider


      siteMapFile=~/web.sitemap securityTrimmingEnabled=true />


  </providers>


</siteMap>


Notice how you can also specify another file as the sitemap. It is not uncommon to have multiple providers that offer sitemaps from different files.

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s