An overview of how securityTrimmingEnabled is supposed to work.

I think that the #1 most confusing or misunderstood portion of Site Navigation is the securityTrimmingEnabled flag and the roles attribute on siteMapNodes.  This post wil hopefuly clear up some of the confusion.


Firstly, let me be explicit about this: out of the box, securityTrimmingEnabled is meant to be a security feature.

By secure, let me use the following definitions (hopefully we agree on them):
   1) A page that should not be accessed by a user, but can actually be accessed is not secure.  Even if the page is not linked to from any other page.
   2) A page that should not be accessed and cannot be accessed is secure.

Now, consider this in the context of a web.sitemap file.  Perhaps you have a rather simple file like this:

<?xml version="1.0" encoding="UTF-8"?>
<siteMapNode url="home.aspx" title="Home Page - Everone can access this">
<siteMapNode url="links.aspx" title="Links page - Anyone can access" />
<siteMapNode url="admin.aspx" title="Admin Page - Only the Admin can access" />

Per our definitions, the admin page must be inaccessible, not just invisible to be secure.  Therefore, simply not showing the admin link in our Menu or TreeView isn't an adequate technique.  Instead, file ACLs must be set (for Windows auth) or <location> tags for Forms auth.  Here's what web.config might look like for Forms auth:

<?xml version="1.0"?>
<siteMap defaultProvider="secureProvider">
<add name="secureProvider" type="System.Web.XmlSiteMapProvider"
               siteMapFile="web.sitemap" securityTrimmingEnabled="true"/>

<location path="~/admin.aspx">
<allow roles="Admin"/>
<deny users="*"/>

This, I would consider secure.  Because of the <location> tag, only the Admin role can access the admin.aspx page.  With securityTrimmingEnabled set to true, the navigation system will filter the admin.aspx node out from the data returned if the user is not an Admin.  You'll note that filtering was applied yet nothing was modified in the actual web.sitemap file (this is often the confusing part).  The filtering was directed by modifications to web.config and securing the site. 

The roles attribute on siteMapNodes.  

This attribute expands visibility to a particular node.  According to the previous section, a node is only visible if the user can access the node.  It is occasionally useful to show more nodes than would follow this rule.  Therefore, the SiteMapProvider additionally checks the roles attribute and, if the node wasn't already visible, will make it visible if the current user is in a role specified in the attribute.  There are two primary reasons this is useful:

   1) Nodes that don't have a url -- These nodes cannot be positively identified as accessible so they are considered inaccessible by the provider.  Therefore a role needs to be associated with them, often "*".  Ex:

<siteMapNode title="Child Pages" roles="*">
<!-- child pages under here -->

   2) Common pages that require login that users would access -- Typically, by clicking on one of these links, the user will be redirected to a login page first.

<siteMapNode url="membersOnly.aspx" title="Member Access Only" roles="Users" />

What else can you do?

Some users have reported that they don't actually care about the security aspect but really want the filtering ability.  A common request is to be able to filter based on the roles attribute instead of expand based on roles.  These are fairly easy to do by extending the built in providers.  There is a single method to override.  Keep in mind that the roles collection on the SiteMapNode refers to the roles that are specified in the web.sitemap file (or when the node was constructed):

Public Class ExampleProvider
    Inherits XmlSiteMapProvider

    Public Overrides Function IsAccessibleToUser(ByVal context As System.Web.HttpContext, _
                                                 ByVal node As System.Web.SiteMapNode) As Boolean
        ' Write your custom logic here
    End Function

End Class