The SQL SiteMap Provider and trimming by roles (originally posted 2006-09-20)

by ishaih 9/20/2006 4:01:00 PM

This is a post from my old blog and since I'm about to delete it I've decided to move the post over here, enjoy...

For a while now I've been using the SqlSiteMapProvider from the Wicked Code article by Jeff Prosise.
This provider works great but it was missing a few things, so I decided to improve it a bit.

One of the most common mistakes/confusions about sitemaps in ASP.Net 2.0 is that the Roles attribute in the sitemap will be used to trim these pages for users not in this role. From what I understand, in the providers that ship with ASP.Net 2.0, this attribute is actually used for showing this page links to this roles and not for hiding them from anyone not in those roles.

Another problem with the sitemap is that in order to trim the site navigation controls (TreeView and Menu or any control that uses the SiteMapDataSource) you must set authorization rules in the web.config files by using the <location> section or by having separate web.config files in different folders.

What I wanted to do is have the Roles set on a page in the sitemap control everything.

After looking around for a while, I found that the trimming solution is very simple and easy and it's actually just one override that's missing from the SqlSiteMapProvider.

IsAccessibleToUser is the method that needs to be overridden. This methods gets the HTTP context and the SiteMapNode of the current request.
You can get the User object from the context and the Roles from the SiteMapNode and simply check if the user is in any of these roles using the IsInRole method.

Here's the code:

public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node)
{
//If Security Trimming is not enabled return true
if (!SecurityTrimmingEnabled)
return true;

//If there are no roles defined for the page
//return true or false depending on your authorization scheme (when true pages with
//no roles are visible to all users, when false no user can access these pages)
if (node.Roles == null node.Roles.Count == 0)
return false;

//check each role, if the user is in any of the roles return true
foreach (string role in node.Roles)
{
if (context.User.IsInRole(role) String.Equals(role, "*", StringComparison.InvariantCultureIgnoreCase))
return true;
}

return false;
}

After adding this code, pages that have roles the user is not in will not be visible in menus and treeviews but the user will still be able to access these pages with a direct URL.
A simple check when the page loads using the SiteMap.CurrentNode.Roles and the User.IsInRole can helps us find out if the user should be able to see this page.
I usually use a base class that all pages inherit from (and that inherits from System.Web.UI.Page), so I simply added the code to the OnLoad method of the base class.
Here's the code:
if (User.Identity.IsAuthenticated)
{
bool isUserAllowed = false;
if (SiteMap.CurrentNode != null)
{
if (SiteMap.CurrentNode.Roles != null && SiteMap.CurrentNode.Roles.Count > 0)
{

foreach (string role in SiteMap.CurrentNode.Roles)
{
if (context.User.IsInRole(role) String.Equals(role, "*", StringComparison.InvariantCultureIgnoreCase))
{
isUserAllowed = true;
break;
}
}
}
else
{
//no roles for this page, deny access to the page
//if you want to allow access to pages without roles defined set to true

isUserAllowed = false;
}
}
if (!isUserAllowed)
Response.Redirect("AccessDenied.aspx");
}


After adding these methods you no longer need the <authorization> tags in the web.config file. the data from the UsersInRoles and SiteMap tables will be used instead, allowing full control of page access rules from your application.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

Asp.Net

Related posts

Comments

2/4/2008 12:21:49 PM

trackback

Trackback from DotNetKicks.com

The SQL SiteMap Provider and trimming by roles

DotNetKicks.com

2/11/2008 9:50:19 PM

Flemming Kristensen

Hi!

Just what I was looking for! This is great and works like a charm. But I got a problem with the last part of the code.

SiteMap.CurrentNode seems to always be null, when the user manually surfs to a page instead of using the menu. And I like to have role "Anonymous" (not authenticated) attached to pages also. In those cases, I believe the code in OnLoad does not work.

But I came very far thanks to you!

Thank you!!!

Flemming Kristensen

7/14/2008 9:45:47 PM

Asif Raza

HI Man,

Thanks a Lot, This really saves me a lot of time.

Asif Raza us

11/12/2008 7:11:28 AM

Laksh

this dosnt work when you roles are setup for parent node and you try to access its child node. For eaxmaple, if i have Parant Node has Roles "Manager". So only managers can see this node. This Parent node also has two child nodes. It works fine at the UI level. It will not show parent node and child nodes. But suppose you logged in as NON manager. and execute code SiteMap.Provider.FindSiteMapNode method, it returns the child nodes also. which it should not.

Laksh

12/2/2008 7:39:55 AM

uri

Great job. Thanks Really helped me alot!

uri ca

Add comment


(Will show your Gravatar icon)  

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

1/6/2009 7:03:51 PM

Powered by BlogEngine.NET 1.3.1.0
Theme by Mads Kristensen

About the author

Name of author Ishai Hachlili
I've been developing web applications using Microsoft technologies for over 10 years. This is my way of doing things, it might be a little different...

E-mail me Send mail

Calendar

<<  January 2009  >>
MoTuWeThFrSaSu
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar

Pages

    Recent comments

    Authors

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2009

    Sign in