roles based menu does not work, what am I doing wrong? - asp.net

I can't figure this one out.
I have the following SiteMap
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="~/" title="Root" description="Go root">
<siteMapNode url="~/h" title="Home" description="Go home" />
<siteMapNode url="~/h/uo" title="Ultima Online" description="Ultima Online">
<siteMapNode url="~/h/uo/get" roles="RegisteredUser" title="Get account!" description="Get account!" />
</siteMapNode>
</siteMapNode>
</siteMap>
I've an XmlSiteMapProvider with securityTrimmingEnabled="true", which points to this site map file.
The file I want to trim has an authorization rule in it's folder's web.config
<configuration>
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</configuration>
The file can't be accessed via url, if I type http://localhost/h/uo/get I get redirected to login page.
I've set up an <asp:Menu> like this in the Master page file:
<asp:SiteMapDataSource ID="MenuSiteMap" ShowStartingNode="false"
SiteMapProvider="MenuSiteMapProvider" runat="server"
/>
<div>
<asp:Menu ID="NavigationMenu" runat="server" DataSourceID="MenuSiteMap"
CssClass="menu" EnableViewState="false"
IncludeStyleBlock="false" Orientation="Horizontal"
/>
</div>
Yet, when the page is rendered, I see the Get account node that is supposed to be trimmed when I'm not even logged in, no matter what.
What am I doing wrong?
Is there any other way to build a security trimming enabled site map navigation menu?
I'm using ASP.NET 4.0, and URL-rewritting with an HttpModule.

In reading http://forums.asp.net/t/975077.aspx/1 I found out that this is exactly what is happening to me.
If the node doesn't have an URL it behaves fine, but if it does, like all of my nodes do. Security trimming is just ignored.
I resolved my problem by resorting to a more intuitive role based site map implementation, to say:
public class TrimmingXmlSiteMapProvider : XmlSiteMapProvider
{
public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node)
{
if (node.Roles.Cast<string>().Any(r => r == "*"))
return true;
if (node.Roles.Count > 0 && node.Roles.Cast<string>().Count(Roles.IsUserInRole) == 0)
return false;
return node.ParentNode != null && node.ParentNode.IsAccessibleToUser(context);
}
}
Then, the only change I had to make was add an asterisk to the root level's role definition.
How does this work?
First I check if any of the roles definied for this node is an asterisk, if that's the case, then I can see the node.
Second, if the node isn't everyone-level, I check if there are any roles specified, and if the logged in user is part of at least one of them.
Lastly, I check if there is a parent node, and just inherit their rule.
This allows the security trimming to actually be "SECURITY TRIMMING" and not well, however the heck it's supposed to be working by default.

Related

XmlSiteMapProvider only parse the first node

I have an annoying problem and i can't find any start of a solution, so i hope you can help me.
I have a sitemap with roles defined for each node :
<?xml version="1.0" encoding="utf-8"?>
<siteMap enableLocalization="true">
<siteMapNode title="" url="" roles="">
<siteMapNode title="default" url="~/Default.aspx" roles="user" />
<siteMapNode title="supervision" url="~/EcranSupervision.aspx" roles="Admin" />
<siteMapNode title="exploitation" url="~/ChaineTraitementList.aspx" roles="Admin" />
</siteMapNode>
</siteMap>
And in my web.config, i enable security and i use a custom provider :
<siteMap defaultProvider="MainMenuSitemap">
<providers>
<add name="MainMenuSitemap" type="UbiXmlSiteMapProvider" siteMapFile="Web.sitemap" securityTrimmingEnabled="true" />
</providers>
</siteMap>
In my provider, i only override IsAccessibleToUser to do my logic :
public class UbiXmlSiteMapProvider : XmlSiteMapProvider
{
public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node)
{
// custom logic here
}
}
My problem is that the node used in IsAccessibleToUser is always the one with the url "Default.aspx".
So if I have the role to see it, all the nodes are shown and if i don't have the role, none of the nodes are shown.
I don't understand what is wrong here.
Do you have a hint for me ?

Disable Save and SaveAs buttons when opening Word using Asp.net

In the office project added below code in ribbon xml
<?xml version="1.0" encoding="UTF-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2010/07/customui" onLoad="Ribbon_Load">
<commands>
<command idMso="FileSaveAs" enabled="false" />
<command idMso="FileSave" enabled="false" />
</commands>
</customUI>
and also added below line of code in ThisAddIn.cs
protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
return new Ribbon1();
}
Could you please tell me how it is getting called when I open Word document using asp.net. Currently disabling of requested buttons not working.

How do I create multiple different layouts using only one SiteMap?

Suppose I have 3 areas on my page that have links
Header
Menu
Footer
Each have different links, but some links overlap:
I am using MVCSiteMapProvider to accomplish this. I have a SiteMap:
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0"
xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0 MvcSiteMapSchema.xsd"
enableLocalization="false">
<mvcSiteMapNode title="Home" controller="Home" action="Index">
<mvcSiteMapNode title="Link 1" controller="" action="" visibility="Header, Footer" />
<mvcSiteMapNode title="Link 2" controller="" action="" visibility="Menu" />
<mvcSiteMapNode title="Link 3" controller="" action="" visibility="Header, Menu" />
<mvcSiteMapNode title="Link 4" controller="" action="" visibility="Menu, Footer, Header" />
</mvcSiteMapNode>
</mvcSiteMap>
I thought that maybe Visibility was the way to do this, but it doesn't work the way I want it.
Public Class MenuVisibilityProvider
Implements ISiteMapNodeVisibilityProvider
Public Function IsVisible(ByVal node As SiteMapNode, ByVal context As HttpContext, ByVal sourceMetadata As IDictionary(Of String, Object)) As Boolean Implements ISiteMapNodeVisibilityProvider.IsVisible
Dim visibility As String = node("visibility")
If visibility IsNot Nothing Then Return True
Select Case visibility
Case "Menu"
Case "Header"
Case "Footer"
Return True
End Select
Return False
End Function
End Class
I end up with all of the links in every area.
Edit for clarification:
This is a similar question, but also with no answer:
https://stackoverflow.com/questions/12845929/how-to-show-partial-site-map-including-current-node-with-mvcsitemapprovider
Also similar, but I don't want to have to make multiple SiteMaps: Using Multiple MvcSiteMaps
OP here. I accomplished this using only one site map.
To do this:
I added visibility tags to each sitemap element, for example:
<mvcSiteMapNode title="Login" controller="Members" action="Login" visibility="SideMenu Footer" />
In this example "SideMenu Footer" are my tags. I will use String.Contains() later to determine visibility.
I added multiple different siteMap providers in the Web.config with different siteMapNodeVisibilityProvider:
<siteMap defaultProvider="MvcSiteMapProvider" enabled="true">
<providers>
<clear />
<add name="MvcSiteMapProvider" type="MvcSiteMapProvider.DefaultSiteMapProvider, MvcSiteMapProvider" siteMapFile="~/Mvc.Sitemap" securityTrimmingEnabled="true" cacheDuration="5" enableLocalization="true" scanAssembliesForSiteMapNodes="true" includeAssembliesForScan="" excludeAssembliesForScan="" attributesToIgnore="visibility" nodeKeyGenerator="MvcSiteMapProvider.DefaultNodeKeyGenerator, MvcSiteMapProvider" controllerTypeResolver="MvcSiteMapProvider.DefaultControllerTypeResolver, MvcSiteMapProvider" actionMethodParameterResolver="MvcSiteMapProvider.DefaultActionMethodParameterResolver, MvcSiteMapProvider" aclModule="MvcSiteMapProvider.DefaultAclModule, MvcSiteMapProvider" siteMapNodeUrlResolver="MvcSiteMapProvider.DefaultSiteMapNodeUrlResolver, MvcSiteMapProvider" siteMapNodeVisibilityProvider="MvcSiteMapProvider.DefaultSiteMapNodeVisibilityProvider, MvcSiteMapProvider" siteMapProviderEventHandler="MvcSiteMapProvider.DefaultSiteMapProviderEventHandler, MvcSiteMapProvider" />
<add name="NavSiteMapProvider" ... siteMapNodeVisibilityProvider="RootNamespace.Namespace.NavVisibilityProvider, RootNamespace" ... />
<add name="FooterSiteMapProvider" ... siteMapNodeVisibilityProvider="RootNamespace.Namespace.FooterVisibilityProvider, RootNamespace" ... />
</providers>
</siteMap>
I created a new code file (class) called CustomVisibilityProvider. Inside I created a class for each provider (Footer, Nav, Menu etc)
' Note: VB.NET :P
Public Class MenuVisibilityProvider
Implements ISiteMapNodeVisibilityProvider
Public Function IsVisible(ByVal node As SiteMapNode, ByVal context As HttpContext, ByVal sourceMetadata As IDictionary(Of String, Object)) As Boolean Implements ISiteMapNodeVisibilityProvider.IsVisible
Dim visibility As String = node("visibility")
If visibility Is Nothing Then Return False
If visibility.Contains("Menu") Then Return True
Return False
End Function
End Class
Public Class NavVisibilityProvider
Implements ISiteMapNodeVisibilityProvider
...
If visibility.Contains("Nav") Then Return True
...
End Class
When you're in a view file:
#Html.MvcSiteMap("FooterSiteMapProvider").Menu
Note: You can give the Menu() a custom view also, so that nav, footer, menu etc render the links differently (some might be in <ul></ul> format while others might be <a> tags).

Show/Hide SiteMap Menu/Repeater on MasterPage

Master Page:
<ul>
<li class="first"><asp:HyperLink runat="server" ID="lnkHome"
NavigateUrl="~/Forms/Default.aspx">Home</asp:HyperLink></li>
<asp:Repeater runat="server" ID="Repeater1" DataSourceID="SiteMapDataSource1"
EnableViewState="False">
<ItemTemplate>
<li>
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %>
</asp:HyperLink>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
Web.SiteMap
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode id="SiteHome" url="~/Forms/Default.aspx" title="Home"
description="Default">
<siteMapNode id="SiteAbout" url="~/Forms/Aboutus.aspx" title="About us"
description="About Us"/>
<siteMapNode id="SiteNew" url="~/Forms/New.aspx" title="New"
description="My Sample Page"/>
</siteMapNode>
Design:
HOME | About us | My Sample Page
I am new on ASP.Net Webforms and i am creating my first Project.
I am using Repeater to navigate page urls.
On my Master/Page.cs Code Behind I need to Hide
[My Sample Page] based on my Login Account.
something like:
if(UserGroup="Admin")
{
//Show My Sample Page
HOME | About us | My Sample Page
}
else if(UserGroup="User1")
{
//Hide About Us
HOME | About us
}
else
{
// Show Home Only
HOME
}
How to do it in form Load?
Thanks in Regards..
The correct way to do this is define a site map provider in your Web.Config and make sure you set the attribute securityTrimmingEnabled="true".
<siteMap defaultProvider="MySiteMap">
<providers>
<clear/>
<add
name="MySiteMap"
type="System.Web.XmlSiteMapProvider"
securityTrimmingEnabled="true"
siteMapFile="~/Web.SiteMap" />
</providers>
</siteMap>
In your Forms folder create a Web.Config file and include the following
<?xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
<location path="New.aspx">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
</configuration>
Now ASP.Net will take care of showing which parts of your site map to which users.
Eg: In this case it will hide your My Sample Page page from un-authenticated users.
Try something like:
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%# Eval("Url") %>'
Visible='Eval("Title") = "My Sample Page" ? this.IsAdmin.ToString() : "True"' >
<%# Eval("Title") %>
</asp:HyperLink>

Change the link on a sitemap based on if a user is logged in?

I have a sitemap that has a link for when a user is not logged in, but when they do login, the link should change, for example, nonmember.aspx should change to member.aspx. This sitemap is tied to an asp:menu. Does anyone know how to do this?
A simple solution is to have two nodes in your sitemap.
One node shows up for Anonymous users.
One node shows up for Authenticated users with the security access
I believe you can set this up quite simply.
The end result is the same as changing the link but it's easier to maintain.
To add to this:
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode title="Home" url="~/" roles="*">
<siteMapNode url="~/Member.aspx" title="Home" roles="SpecialPeople" />
<siteMapNode url="~/Nonmember.aspx" title="Site Map" roles="HideForUsers" />
</siteMapNode>
</siteMap>
So, you set up a rule that denies access to the "HideForMembers" role to authenticated users. It's something like that. ASP.NET will take the first rule it finds a match, so you should be able to accomplish it this way.
Otherwise, you could do a Menu_OnDataBound and look for the node:
Protected Sub menMainDataBound(ByVal sender As Object, ByVal e As System.EventArgs)
Try
Dim myPage As New Page
Dim myPrincipal As IPrincipal
Dim colNodes As New Collection
myPrincipal = myPage.User
If myPrincipal.Identity.IsAuthenticated = True Then
Dim menNode As MenuItem
For Each menNode In menMain.Items
Select Case menNode.Value.ToString
Case "Products"
colNodes.Add(menNode)
Case "Contact Us"
colNodes.Add(menNode)
Case "About Us"
colNodes.Add(menNode)
Case "Links"
colNodes.Add(menNode)
End Select
Next
For Each menNode In colNodes
menMain.Items.Remove(menNode)
Next
End If
Catch ex As Exception
End Try
End Sub
source
The below is the web.config code you're looking for:
<location path="Registration.aspx">
<system.web>
<authorization>
<allow users="?" />
<deny users="*" />
</authorization>
</system.web>
</location>

Resources