{"id":213,"date":"2006-05-14T22:06:47","date_gmt":"2006-05-15T04:06:47","guid":{"rendered":"http:\/\/jameskovacs.com\/2006\/05\/15\/ASPNET+SiteMaps+Menus+And+The+ImpostorHttpModule"},"modified":"2006-05-14T22:06:47","modified_gmt":"2006-05-15T04:06:47","slug":"aspnet-sitemaps-menus-and-the-impostorhttpmodule","status":"publish","type":"post","link":"https:\/\/www.jameskovacs.com\/index.php\/2006\/05\/14\/aspnet-sitemaps-menus-and-the-impostorhttpmodule\/","title":{"rendered":"ASP.NET SiteMaps, Menus, and the ImpostorHttpModule"},"content":{"rendered":"<p>In our last cliff-hanger episode, I introduced the <a href=\"2006\/05\/10\/Developing-And-Testing-RoleBased-ASPNET-Applications-With-ImpostorHttpModule\">ImpostorHttpModule<\/a>. I&#8217;m going to show how you can use it to implement and test a sitemap and navigation menu in ASP.NET. We&#8217;ll use the new ASP.NET 2.0 Master Pages feature because it&#8217;s the easiest way to ensure that the same menu ends up on every page. We&#8217;ll start from the previous solution with the ImpostorHttpModule registered in the <em>Web.config<\/em>. I&#8217;ve created three pages, ~\/Default.aspx, ~\/Reports\/Default.aspx,&nbsp;and ~\/Admin\/Default.aspx. The Web.config files are set up as follows:<\/p>\n<table>\n<thead>\n<tr>\n<td><strong><u>Path<\/u><\/strong><\/td>\n<td><strong><u>Allowed Roles<\/u><\/strong><\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>~\/Default.aspx<\/td>\n<td>User, Manager, Administrator<\/td>\n<\/tr>\n<tr>\n<td>~\/Reports\/Defaults.aspx<\/td>\n<td>Manager, Administrator<\/td>\n<\/tr>\n<tr>\n<td>~\/Admin\/Default.aspx<\/td>\n<td>Administrator<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We&#8217;ll be using the security trimming feature of sitemaps, which removes nodes from the sitemap that are not accessible by the current user. Note that this is simply a UI nicety and not actual security &#8211; without the appropriate Web.config files and &lt;authorization&gt; sections, users could still access those areas by navigating directly to them. So let&#8217;s start by implementing the menu and then we&#8217;ll enable security trimming. We&#8217;ll see how ImpostorHttpModule can help us in testing these features.<\/p>\n<p>Our first step is to add a sitemap, which we&#8217;ll leave with the default name of <em>Web.sitemap<\/em>. We&#8217;ll add three nodes &#8211; Home, Reports&nbsp;and Administration. One of the odd things about the sitemap XML schema is that the child of &lt;siteMap&gt; must be a <strong>single<\/strong> &lt;siteMapNode&gt;. So if you want to have multiple nodes, you need to create an empty &lt;siteMapNode&gt; with further child nodes like this:<\/p>\n<p>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243; ?&gt;<br \/>&lt;siteMap xmlns=&#8221;<A href=\"http:\/\/schemas.microsoft.com\/aspnet\/sitemap-file-1.0\">http:\/\/schemas.microsoft.com\/AspNet\/SiteMap-File-1.0<\/A>&#8221; &gt;<br \/>&nbsp;&nbsp;&nbsp; &lt;siteMapNode&gt;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;siteMapNode url=&#8221;~\/Default.aspx&#8221; title=&#8221;Home&#8221;&nbsp; description=&#8221;Return to the Home page&#8221; \/&gt;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;siteMapNode url=&#8221;~\/Reports\/Default.aspx&#8221; title=&#8221;Reports&#8221; description=&#8221;Go to reports&#8221; \/&gt;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;siteMapNode url=&#8221;~\/Admin\/Default.aspx&#8221; title=&#8221;Administration&#8221;&nbsp; description=&#8221;Go to site administration&#8221; \/&gt;<br \/>&nbsp;&nbsp;&nbsp; &lt;\/siteMapNode&gt;<br \/>&lt;\/siteMap&gt;<\/p>\n<p>One quick note is the use of ~\/ which allows us to create links that are relative to the application&#8217;s virtual directory. This is a great ASP.NET feature, which works in most places links are found in server-side controls, as it allows you to deploy the site at <a href=\"http:\/\/servername\/\">http:\/\/servername\/<\/a> or <a href=\"http:\/\/servername\/someVdir\/someOtherVdir\/\">http:\/\/servername\/someVdir\/<\/a>&nbsp;or anywhere else.<\/p>\n<p>Now that we have our sitemap set up, we can create a Menu that is driven by the sitemap. We&#8217;ll create a master page called <em>Main.master<\/em> and&nbsp;add the Menu to it in design mode. We&#8217;ll create a new SiteMapDataSource and point the Menu control at it. Since we have an empty starting node, we&#8217;ll set SiteMapDataSource.ShowStartingNode = false. (I also changed the menu to use the Classic style and horizontal orientation.) We should now see three nodes: Home, Reports,&nbsp;and Administration in the Menu. If we try to browse the site, we&#8217;ll get a 401 &#8211; Access Denied because our user account is not in any of the appropriate roles. At least the&nbsp;<em>Web.config<\/em> files&nbsp;are doing their jobs. Let&#8217;s see how to use the ImpostorHttpModule to give ourselves access to these directories without having to create a local or domain group or add our user account to it. (In a deployment situation, you would likely have a domain group that a domain admin would add users to. We&#8217;re trying to avoid all the overhead of calling up your friendly neighbourhood domain admin every time you want to test a different security context when accessing your app. Believe me &#8211; your domain admin will thank you.)<\/p>\n<p>So let&#8217;s add our user,&nbsp;DOMAIN\\Foo,&nbsp;to the User, Manager, and Administrator role in the ~\/App_Data\/Impostors.xml file. (N.B. If you&#8217;re logged on using a local account, you&#8217;ll need to specify MACHINE\\Bar. If you logged in using the alternate user name syntax, <a href=\"mailto:foo@example.com\">foo@example.com<\/a>, you&#8217;ll need to use this in the name.)<\/p>\n<p>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243; ?&gt;<br \/>&lt;impostors&gt;<br \/>&nbsp;&nbsp;&nbsp; &lt;impostor name=&#8221;DOMAIN\\Foo&#8221; roles=&#8221;User, Manager, Administrator&#8221;\/&gt;<br \/>&lt;\/impostors&gt;<\/p>\n<p>Clicking on the Menu links should allow you to see the Reports and Administration sections. All is good in the world. Now let&#8217;s implement security trimming! Our next stop is <em>Web.config<\/em> where we&#8217;ll have to add a new sitemap provider as the default one declared in <em>Machine.config<\/em> does not have security trimming enabled. The key attribute here is securityTrimmingEnabled=&#8221;true&#8221;.<\/p>\n<p>&lt;siteMap defaultProvider=&#8221;XmlSiteMapProvider&#8221; enabled=&#8221;true&#8221;&gt;<br \/>&nbsp;&nbsp;&nbsp;&lt;providers&gt;<br \/>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;add name=&#8221;XmlSiteMapProvider&#8221; description=&#8221;Default SiteMap provider.&#8221; type=&#8221;System.Web.XmlSiteMapProvider&#8221; siteMapFile=&#8221;Web.sitemap&#8221; securityTrimmingEnabled=&#8221;true&#8221;\/&gt;<br \/>&nbsp; &nbsp;&lt;\/providers&gt;<br \/>&lt;\/siteMap&gt;<\/p>\n<p>With this change, the menu disappears entirely! We haven&#8217;t defined any roles that can see the nodes. So they are all trimmed off. Let&#8217;s update the <em>Web.sitemap<\/em> to add the roles:<\/p>\n<p>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243; ?&gt;<br \/>&lt;siteMap xmlns=&#8221;<A href=\"http:\/\/schemas.microsoft.com\/aspnet\/sitemap-file-1.0\">http:\/\/schemas.microsoft.com\/AspNet\/SiteMap-File-1.0<\/A>&#8221; &gt;<br \/>&nbsp;&nbsp;&nbsp; &lt;siteMapNode roles=&#8221;User, Manager, Administrator&#8221;&gt;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;siteMapNode url=&#8221;~\/Default.aspx&#8221; title=&#8221;Home&#8221;&nbsp; description=&#8221;Return to the Home page&#8221; roles=&#8221;User, Manager, Administrator&#8221; \/&gt;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;siteMapNode url=&#8221;~\/Reports\/Default.aspx&#8221; title=&#8221;Reports&#8221; description=&#8221;Go to reports&#8221; roles=&#8221;Manager, Administrator&#8221; \/&gt;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;siteMapNode url=&#8221;~\/Admin\/Default.aspx&#8221; title=&#8221;Administration&#8221;&nbsp; description=&#8221;Go to site administration&#8221; roles=&#8221;Administrator&#8221; \/&gt;<br \/>&nbsp;&nbsp;&nbsp; &lt;\/siteMapNode&gt;<br \/>&lt;\/siteMap&gt;<\/p>\n<p>A quick note is that you must specify all the roles on the empty &lt;siteMapNode&gt;. If you do not, it gets trimmed and none of the child nodes get displayed either. (Took me awhile to realize this the first time I used sitemaps and security trimming.)<\/p>\n<p>Now that we have everything in order, try removing your user account from the Administrator role in ~\/App_Data\/Impostors.xml and browse to ~\/Default.aspx. The Administration link disappears. You can now happily add and remove roles from your user account to test what different kinds of users would see when they browse the site.<\/p>\n<p>In summary, the ImpostorHttpModule allows us to easily test different security configurations for our site without having to change your local or domain group memberships. Since we&#8217;re replacing the list of roles that the incoming user is a member of, this technique not only works for testing sitemaps and website security using &lt;authorization&gt;, but it also works for declarative and imperative security demands in code. Full source code is available <a href=\"http:\/\/jameskovacs.com\/downloads\/Impostor2.zip\">here<\/a>. In our next episode, we&#8217;ll look at how the ImpostorHttpModule works under the covers.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In our last cliff-hanger episode, I introduced the ImpostorHttpModule. I&#8217;m going to show how you can use it to implement and test a sitemap and navigation menu in ASP.NET. We&#8217;ll use the new ASP.NET 2.0 Master Pages feature because it&#8217;s the easiest way to ensure that the same menu ends up on every page. We&#8217;ll [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,21],"tags":[],"class_list":["post-213","post","type-post","status-publish","format-standard","hentry","category-aspnet","category-security"],"_links":{"self":[{"href":"https:\/\/www.jameskovacs.com\/index.php\/wp-json\/wp\/v2\/posts\/213","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jameskovacs.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jameskovacs.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jameskovacs.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jameskovacs.com\/index.php\/wp-json\/wp\/v2\/comments?post=213"}],"version-history":[{"count":0,"href":"https:\/\/www.jameskovacs.com\/index.php\/wp-json\/wp\/v2\/posts\/213\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.jameskovacs.com\/index.php\/wp-json\/wp\/v2\/media?parent=213"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jameskovacs.com\/index.php\/wp-json\/wp\/v2\/categories?post=213"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jameskovacs.com\/index.php\/wp-json\/wp\/v2\/tags?post=213"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}