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.

SecurityTrimmingEnabled

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"?>
<siteMap>
<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" />
</siteMapNode>
</siteMap>

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"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<siteMap defaultProvider="secureProvider">
<providers>
<add name="secureProvider" type="System.Web.XmlSiteMapProvider"
               siteMapFile="web.sitemap" securityTrimmingEnabled="true"/>
</providers>
</siteMap>
</system.web>

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

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 -->
</siteMapNode>

   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

Comments

  • Anonymous
    March 28, 2006
    What exactly is it that calls Isaccessible to user? When is that called?
    On the menuItemDataBind? or on the SitMap Initialize? Or where?
  • Anonymous
    March 28, 2006
    IsAccessibleToUser is called for a variety of APIs in the SiteMapProviders.  From the root SiteMapProvider it is only called for RootNode and CurrentNode since GetChildNodes and FindSiteMapNode are abstract methods.  From StaticSiteMapProvider, these methods as well as ParentNode all call into IsAccessibleToUser.  In essense, any time you give it a node and ask it for other nodes, this should be called to trim the set of nodes that is being returned.
    --
    Danny
  • Anonymous
    March 28, 2006
    The comment has been removed
  • Anonymous
    March 29, 2006
    SecurityTrimming does work with Windows Authentication.  However, in this case, the filtering is based on File ACLs.  I have more info in this blog post:  

    http://weblogs.asp.net/dannychen/archive/2005/04/19/403365.aspx

    --
    Danny
  • Anonymous
    March 29, 2006
    Yeah, I read this post yesterday, but the problem is that permissions work just fun, but my horizontal menu just disappeared. So, I mean user can access page, but horizontal menu from master page is not visible...
  • Anonymous
    March 29, 2006
    My initial suspicion then is that you have a dummy top level node with no url, in which case you will need to add roles="*" to it.  If this isn't enough to solve your issue, please email me through my blog and I can help you more with your issue over email.
    --
    Danny
  • Anonymous
    March 29, 2006
    Danny, yes!!! You was right. The whole issue was with empty top level element. After I added roles="*" everything started to wor as it suppose to.
    I wonder, why this thing is not documented, or my empty top level element is so unussual?

    Tanks, one more time.
  • Anonymous
    April 21, 2006
    I am having a similar problem.  I tried putting a roles="*" into my dummy top node but I still get an empty treenode.  Do you have any further advice?
  • Anonymous
    April 21, 2006
    Marty,
     Perhaps this blog post might help you.  Just a shot in the dark.  Otherwise, I'll need to see more info to help you.

    http://weblogs.asp.net/dannychen/archive/2005/04/04/397072.aspx

    You can also post this issue on the ASP.NET forums (http://forums.asp.net) in the "MasterPages Themes & Navigation Controls" forum and get a lot of help.  

    --
    Danny
  • Anonymous
    April 24, 2006
    Marty: I was having similar problem as Marty, I found that a siteMapNode in the very beginning of the site map was totally empty -
    stuck in roles="" - bingo.
    I was also not seeing the menu - and had all the other siteMapNodes containing roles="
    ".
  • Anonymous
    May 25, 2006
    The comment has been removed
  • Anonymous
    April 07, 2007
    Besides the problem with spaces in query strings (the same thing happens for the entire URL), you cannot
  • Anonymous
    April 07, 2007
    Além do problema com espaços em query strings (o mesmo acontece para todo o URL), não se pode derivar
  • Anonymous
    November 08, 2007
    Site Navigation, siteMap and SiteMapProvider overview
  • Anonymous
    January 14, 2008
    PingBack from http://ilopez.wordpress.com/2008/01/14/restriccion-de-accesos-en-aspnet-20/
  • Anonymous
    March 28, 2008
    PingBack from http://employmentwagesblog.info/danny-chen-an-overview-of-how-securitytrimmingenabled-is/
  • Anonymous
    May 29, 2008
    Hi Danny! I'm using a custom SQL-based Site Map provider.You said above, "A page that should not be accessed and cannot be accessed is secure." I think I can control both security trimming (a visibility of page on menu) and accessibility by using IsAccessibleToUser(). I can either1) Attach custom SiteMapResolve event handler method and inside check if SiteMap.CurrentNode.IsAccessibleToUser() == true. If it is false - redirect to an appropriate page (default.aspx, for example).2) Check and do the same thing in master page's  OnInit() method.3) Attach some custom page event handler using HttpModule or global.asax and perform that SiteMap.CurrentNode.IsAccessibleToUser() check and redirect there.Could you comment on it please? Is it a good approach?
  • Anonymous
    July 08, 2008
    PingBack from http://martinmelchior.wordpress.com/2008/07/08/recursos-interesantes/