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.aspxtitle=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 (18)

  1. Anonymous says:

    What exactly is it that calls Isaccessible to user? When is that called?

    On the menuItemDataBind? or on the SitMap Initialize? Or where?

  2. dannychen says:

    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

  3. Serioga says:

    Does SecurityTrimming works when Windows authentication is used? I’ve tried use this feature with Menu component and Windows authentication, as a result, menu becomes just invisible. Is it a bug, o I’m doing something wrong?

  4. dannychen says:

    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

  5. Serioga says:

    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…

  6. dannychen says:

    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

  7. Serioga says:

    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.

  8. Anonymous says:

    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?

  9. dannychen says:

    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

  10. Anonymous says:

    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="
    ".

  11. wazzzuup says:

    I have problem corresponding discussing topic.

    Can anyone say something about this bug:

    I have two groups of roles: administrators and users and have root folder and admin folder of my site. I have two rules: allow acces to admin folder to administrators and deny acces to it for all other users.

    So, I’m logging in as administrator at first and then, if I don’t log out using LoginView Control and just go to page with login  control and log in as non-administrator user, I can type path to page in restricted folder Admin and I CAN load it! Remember – the required condition for this is not to log out from administrator role and directly log as user. I think this is possible situation – just forget to log out and user who even relogin as itself could get access to restrict site area…

    So, How can we close this hole?

  12. Anonymous says:

    Besides the problem with spaces in query strings (the same thing happens for the entire URL), you cannot

  13. Anonymous says:

    Além do problema com espaços em query strings (o mesmo acontece para todo o URL), não se pode derivar

  14. Anonymous says:

    Site Navigation, siteMap and SiteMapProvider overview

  15. vkelman says:

    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 either

    1) 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?