Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

Site Map Provider Integrated Authorization

The ASP.NET out of the box included site map provider, XmlSiteMapProvider, allows specifying one or more required roles for each node it knows about. Let’s say you have something like this on your Web.sitemap file:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
   3:     <siteMapNode url="/Default.aspx" title="Home">
   4:         <siteMapNode url="/About.aspx" title="About" />
   5:         <siteMapNode url="/SomePage.aspx" title="Some Page" roles="Administrator" />
   6:     </siteMapNode>
   7: </siteMap>

What it means is:

  • Page /Default.aspx is publicly accessible, since it has no roles attribute specified;
  • Page /About.aspx is also publicly accessible, for the same reason;
  • Page /SomePage.aspx can only be accessed by users with the Administrator role.

Of course, the site map provider doesn’t actually enforce these permissions; what it does is, if, for example, it is bound to a TreeView, it will only display the nodes that the current user is allowed to navigate to. But if someone attempts to navigate to /SomePage.aspx, unless a restriction is defined on the Web.config file, nothing will prevent it from happening.

Knowing this, I wrote a small module that fills in the gap. It strictly enforces what is specified in the site map provider – either XmlSiteMapProvider or any other –, no other restrictions are applied. If a restriction is added through the Web.config file, the access will also fail.

Here is the module:

   1: public class SiteMapAuthorizationModule : IHttpModule
   2: {
   3:     #region IHttpModule Members
   4:  
   5:     public void Dispose()
   6:     {            
   7:     }
   8:  
   9:     public void Init(HttpApplication context)
  10:     {
  11:         context.PostAcquireRequestState += this.OnPostAcquireRequestState;
  12:     }
  13:     
  14:     #endregion
  15:  
  16:     protected void OnPostAcquireRequestState(Object sender, EventArgs e)
  17:     {
  18:         AuthenticationSection section = WebConfigurationManager.OpenWebConfiguration("~").GetSection("system.web/authentication") as AuthenticationSection;
  19:         HttpApplication app = sender as HttpApplication;
  20:         SiteMapProvider provider = SiteMap.Provider;
  21:         SiteMapNode node = provider.CurrentNode;
  22:  
  23:         if (node != null)
  24:         {
  25:             if (node.Roles.Count != 0)
  26:             {
  27:                 if (node.Roles.OfType<String>().All(role => (role != "*") && (app.Context.User.IsInRole(role) == false)))
  28:                 {
  29:                     app.Context.Response.Buffer = true;
  30:                     app.Context.Response.Redirect(String.Format("{0}?ReturnUrl={1}", section.Forms.LoginUrl, HttpUtility.UrlEncode(app.Context.Request.Url.PathAndQuery)), false);
  31:                     app.Context.ApplicationInstance.CompleteRequest();
  32:                 }
  33:             }
  34:         }
  35:     }
  36: }

As you see, it allows specifying multiple roles, separated by commas, or the * symbol, in which case, all users will be granted access, and is effectively equivalent to not specifying a role at all.

You have to register it on Web.config, and it will use whatever site map provider is configured:

   1: <system.web>
   2:     <httpModules>
   3:         <!-- for IIS 6 -->
   4:         <add name="SiteMapAuthorization" type="MyNamespace.SiteMapAuthorizationModule, MyAssembly"/>
   5:     </httpModules>        
   6: </system.web>
   7: <system.webServer>
   8:     <!-- for IIS 7+ -->
   9:     <modules runAllManagedModulesForAllRequests="true">
  10:         <add name="SiteMapAuthorization" type="MyNamespace.SiteMapAuthorizationModule, MyAssembly"/>
  11:     </modules>
  12: </system.webServer>

As always, looking forward to hearing from you!

Comments

Klubovi said:

This is very nice :)

# May 4, 2012 10:23 AM

http://thesis911.com/ said:

Great so nice good!

# May 4, 2012 3:32 PM

RichardD said:

It's usually easier to go the other way - if you enable security trimming on the site map provider, it will pick up the authorization rules from the web.config file. That way, you only need to add the "roles" attribute for links outside of your application.

msdn.microsoft.com/.../ms178428.aspx

# May 9, 2012 4:17 PM

Ricardo Peres said:

@RicharD:

Probably it is. This (and most of the other stuff I post here) are essentially experiments, which may or may not be the best solutions, but merely proof of concept.

Thanks!

# May 10, 2012 3:49 AM