# Wednesday, November 23, 2005
« Zen Micro 5 Gig $129.99 : Get it now! | Main | Dynamically add JavaScript events : Goog... »

It seems like forever ago that I started recommending Fredrik Normen's Permission Manager.  Recently I was tasked to find a way to restrict nodes in a SiteMap based on Permission.  Today I completed that task and thought I would share it with the world.  First of all, I appoligize for writing the code in VB.NET (employers standard), but you can all compile it and reference it from C# so get over it.

What I did to create the PermissionXmlSiteMapProvider was to inherit directly from XmlSiteMapProvider and then extend 2 methods.  First of all I extended the Initialize method so that I could verify that it was configured properly.  Since it is dependent on the presence of Permission Manager and it properly working I added a simple check to verify that it has a provider.

The second method to override for the addtion of Permission to a SiteNode was IsAccessibleToUser.  Thankfully the siteNode can have extra attributes on it without complaint.  I used that to check for the permission attribute.  If it is there then a call to Permission Manager is done for the named permission and the currently logged in user.

After configuring my applications to use my new Provider I restrict access to nodes as easy as this:

<siteMapNode url="Edit.aspx" title="Edit" permission="Modify" />

Since I built on top of the XmlSiteMapProvider I also get the ability to do Roles restriction and a combination of Roles and permission:

<siteMapNode url="Delete.aspx" title="Delete" Roles="Admins, Editors" permission="Delete" />

It is important to note a few things that I ran into while working on this solution.  You must enable Security Trimming.  If you will restrict based on Roles you also must enable RoleManager.  Restricting via Roles is a little quirky as described in the MSDN Site Map Providers document.  Specifically review the Security Trimming section.

Here is the siteMap section of Web.config that implements the PermssionXmlSiteMapProvider:

<siteMap enabled="true" defaultProvider="PersmissionXmlSiteMapProvider">
  <
providers>
    <
add name="PersmissionXmlSiteMapProvider
           
type="IDCL.Web.Security.PersmissionXmlSiteMapProvider, IDCL.Web"
           
description="Permission xml site map provider"
          
securityTrimmingEnabled="true"
          
siteMapFile="Web.sitemap"/>
  providers>
siteMap>

Obviously you also need to have Permission Manager installed and configured or this will not work.

Here is the code for the provider:

Imports System
Imports System.Web
Imports System.Configuration.Provider
Imports System.Web.Configuration
Imports Nsquared2.Security

Public Class PersmissionXmlSiteMapProvider
Inherits XmlSiteMapProvider

Public Overrides Sub Initialize(ByVal name As String, ByVal config As System.Collections.Specialized.NameValueCollection)

' Verify that config isn't null
If config Is Nothing Then
  Throw New ArgumentNullException("config")
End If

' Verify that Permission Manager is configured
If PermissionManager.Provider Is Nothing Then
  Throw New ProviderException("Permission Manager default provider missing.")
End If

' Add a default "description" attribute to config if the
' attribute doesn't exist or is empty
If String.IsNullOrEmpty(config("description")) Then
  config.Remove("description")
  config.Add(
"description", "PermissionXmlSiteMap provider")
End If

' Call the base class's Initialize method
MyBase.Initialize(name, config)
End Sub

Public Overrides Function IsAccessibleToUser(ByVal context As System.Web.HttpContext, ByVal node As System.Web.SiteMapNode) As Boolean

  Dim authorized As Boolean = MyBase.IsAccessibleToUser(context, node)

  'Pull the permission out of the sitemap node as an attribute
  Dim Permission As String = node.Item("permission")
  If Not Permission Is Nothing And authorized Then
    If context.User.Identity.IsAuthenticated Then
      ' Only check permission for known users
      Return PermissionManager.HasUserPermission(context.User.Identity.Name, Permission)
    Else
      ' The presence of a permission requires a known user
      Return False
    End If
  End If

Return authorized

End Function
End
Class

The PermissionSiteMapProvider.zip file with this article includes the Provider solution and a sample web.config