//
// Authors:
// Ben Maurer (bmaurer@users.sourceforge.net)
+// Lluis Sanchez Gual (lluis@novell.com)
//
// (C) 2003 Ben Maurer
+// (C) 2005-2009 Novell, Inc (http://www.novell.com)
//
//
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-#if NET_2_0
+using System.ComponentModel;
using System.Collections;
using System.Collections.Specialized;
using System.Text;
using System.Configuration.Provider;
using System.Web.Util;
using System.Globalization;
+using System.Web.Configuration;
-namespace System.Web {
- public abstract class SiteMapProvider : ISiteMapProvider, IProvider {
+namespace System.Web
+{
+ public abstract class SiteMapProvider : ProviderBase
+ {
+ static readonly object siteMapResolveEvent = new object ();
- public void AddNode (SiteMapNode node)
+ internal object this_lock = new object ();
+
+ bool enableLocalization;
+ SiteMapProvider parentProvider;
+ SiteMapProvider rootProviderCache;
+ bool securityTrimming;
+ object resolveLock = new Object();
+ bool resolving;
+
+ EventHandlerList events = new EventHandlerList ();
+
+ public event SiteMapResolveEventHandler SiteMapResolve {
+ add { events.AddHandler (siteMapResolveEvent, value); }
+ remove { events.RemoveHandler (siteMapResolveEvent, value); }
+ }
+
+ protected virtual void AddNode (SiteMapNode node)
{
AddNode (node, null);
}
- public void AddNode (SiteMapNode node, SiteMapNode parentNode)
+ internal protected virtual void AddNode (SiteMapNode node, SiteMapNode parentNode)
{
- if (node == null)
- throw new ArgumentNullException ("node");
-
- lock (this) {
- string url = node.Url;
- if (url != null && url.Length > 0) {
-
-
- if (UrlUtils.IsRelativeUrl (url))
- url = UrlUtils.Combine (HttpRuntime.AppDomainAppVirtualPath, url);
- else
- url = UrlUtils.ResolveVirtualPathFromAppAbsolute (url);
-
- if (FindSiteMapNode (url) != null)
- throw new InvalidOperationException ();
-
- UrlToNode [url] = node;
- }
-
- if (parentNode != null) {
- NodeToParent [node] = parentNode;
- if (NodeToChildren [parentNode] == null)
- NodeToChildren [parentNode] = new SiteMapNodeCollection ();
-
- ((SiteMapNodeCollection) NodeToChildren [parentNode]).Add (node);
- }
- }
+ throw new NotImplementedException ();
}
-
- Hashtable nodeToParent;
- Hashtable NodeToParent {
- get {
- if (nodeToParent == null) {
- lock (this) {
- if (nodeToParent == null)
- nodeToParent = new Hashtable ();
- }
- }
- return nodeToParent;
- }
+
+ public virtual SiteMapNode FindSiteMapNode (HttpContext context)
+ {
+ if (context == null)
+ return null;
+
+ HttpRequest req = context.Request;
+ if (req == null)
+ return null;
+
+ SiteMapNode ret = this.FindSiteMapNode (req.RawUrl);
+ if (ret == null)
+ ret = this.FindSiteMapNode (req.Path);
+ return ret;
}
+
+ public abstract SiteMapNode FindSiteMapNode (string rawUrl);
- Hashtable nodeToChildren;
- Hashtable NodeToChildren {
- get {
- if (nodeToChildren == null) {
- lock (this) {
- if (nodeToChildren == null)
- nodeToChildren = new Hashtable ();
- }
- }
- return nodeToChildren;
- }
+ public virtual SiteMapNode FindSiteMapNodeFromKey (string key)
+ {
+ /* msdn2 says this function always returns
+ * null, but it seems to just call
+ * FindSiteMapNode(string rawUrl) */
+ return FindSiteMapNode (key);
}
+
+ public abstract SiteMapNodeCollection GetChildNodes (SiteMapNode node);
- Hashtable urlToNode;
- Hashtable UrlToNode {
- get {
- if (urlToNode == null) {
- lock (this) {
- if (urlToNode == null) {
- urlToNode = new Hashtable (
- new CaseInsensitiveHashCodeProvider (),
- new CaseInsensitiveComparer ()
- );
- }
- }
- }
- return urlToNode;
- }
+ public virtual SiteMapNode GetCurrentNodeAndHintAncestorNodes (int upLevel)
+ {
+ if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
+
+ return CurrentNode;
}
- protected virtual void Clear ()
+ public virtual SiteMapNode GetCurrentNodeAndHintNeighborhoodNodes (int upLevel, int downLevel)
{
- lock (this) {
- if (urlToNode != null)
- urlToNode.Clear ();
- if (nodeToChildren != null)
- nodeToChildren.Clear ();
- if (nodeToParent != null)
- nodeToParent.Clear ();
- }
+ if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
+ if (downLevel < -1) throw new ArgumentOutOfRangeException ("downLevel");
+
+ return CurrentNode;
}
- public virtual SiteMapNode FindSiteMapNode (string rawUrl)
+ public abstract SiteMapNode GetParentNode (SiteMapNode node);
+
+ public virtual SiteMapNode GetParentNodeRelativeToCurrentNodeAndHintDownFromParent (int walkupLevels, int relativeDepthFromWalkup)
{
- if (rawUrl == null)
- throw new ArgumentNullException ("rawUrl");
+ if (walkupLevels < 0) throw new ArgumentOutOfRangeException ("walkupLevels");
+ if (relativeDepthFromWalkup < 0) throw new ArgumentOutOfRangeException ("relativeDepthFromWalkup");
- if (rawUrl.Length > 0) {
- this.BuildSiteMap();
- rawUrl = UrlUtils.ResolveVirtualPathFromAppAbsolute (rawUrl);
- return (SiteMapNode) UrlToNode [rawUrl];
- }
- return null;
+ SiteMapNode node = GetCurrentNodeAndHintAncestorNodes (walkupLevels);
+ for (int n=0; n<walkupLevels && node != null; n++)
+ node = GetParentNode (node);
+
+ if (node == null) return null;
+
+ HintNeighborhoodNodes (node, 0, relativeDepthFromWalkup);
+ return node;
}
- public virtual SiteMapNodeCollection GetChildNodes (SiteMapNode node)
+ public virtual SiteMapNode GetParentNodeRelativeToNodeAndHintDownFromParent (SiteMapNode node, int walkupLevels, int relativeDepthFromWalkup)
{
- if (node == null)
- throw new ArgumentNullException ("node");
-
- this.BuildSiteMap();
- SiteMapNodeCollection ret = (SiteMapNodeCollection) NodeToChildren [node];
+ if (walkupLevels < 0) throw new ArgumentOutOfRangeException ("walkupLevels");
+ if (relativeDepthFromWalkup < 0) throw new ArgumentOutOfRangeException ("relativeDepthFromWalkup");
+ if (node == null) throw new ArgumentNullException ("node");
- if (ret != null)
- return SiteMapNodeCollection.ReadOnly (ret);
+ HintAncestorNodes (node, walkupLevels);
+ for (int n=0; n<walkupLevels && node != null; n++)
+ node = GetParentNode (node);
+
+ if (node == null) return null;
- return null;
+ HintNeighborhoodNodes (node, 0, relativeDepthFromWalkup);
+ return node;
}
- public virtual SiteMapNode GetParentNode(SiteMapNode node) {
- if (node == null)
- throw new ArgumentNullException ("node");
- this.BuildSiteMap();
- return (SiteMapNode) NodeToParent [node];
+ protected internal abstract SiteMapNode GetRootNodeCore ();
+
+ protected static SiteMapNode GetRootNodeCoreFromProvider (SiteMapProvider provider)
+ {
+ return provider.GetRootNodeCore ();
}
- public void RemoveNode (SiteMapNode node)
+ public virtual void HintAncestorNodes (SiteMapNode node, int upLevel)
{
-
- if (node == null)
- throw new ArgumentNullException("node");
-
- lock (this) {
- SiteMapNode parent = (SiteMapNode) NodeToParent [node];
- if (NodeToParent.Contains (node))
- NodeToParent.Remove (node);
-
- if (node.Url != null && node.Url.Length > 0 && UrlToNode.Contains (node.Url))
- UrlToNode.Remove (node.Url);
-
- if (parent != null) {
- SiteMapNodeCollection siblings = (SiteMapNodeCollection) NodeToChildren [node];
- if (siblings != null && siblings.Contains (node))
- siblings.Remove (node);
- }
- }
+ if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
+ if (node == null) throw new ArgumentNullException ("node");
}
-
- public virtual void Initialize (string name, NameValueCollection attributes)
- {
- this.name = name;
- if (attributes != null)
- description = attributes ["description"];
+ public virtual void HintNeighborhoodNodes (SiteMapNode node, int upLevel, int downLevel)
+ {
+ if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
+ if (downLevel < -1) throw new ArgumentOutOfRangeException ("downLevel");
+ if (node == null) throw new ArgumentNullException ("node");
}
- public virtual SiteMapNode CurrentNode {
- get {
- SiteMapNode ret;
-
- if (HttpContext.Current != null) {
- ret = this.FindSiteMapNode (HttpContext.Current.Request.RawUrl);
- if (ret == null)
- ret = this.FindSiteMapNode (HttpContext.Current.Request.Path);
+ protected virtual void RemoveNode (SiteMapNode node)
+ {
+ throw new NotImplementedException ();
+ }
- return ret;
- }
-
- return null;
- }
+ public override void Initialize (string name, NameValueCollection attributes)
+ {
+ base.Initialize (name, attributes);
+ if (attributes ["securityTrimmingEnabled"] != null)
+ securityTrimming = (bool) Convert.ChangeType (attributes ["securityTrimmingEnabled"], typeof (bool));
}
- string description;
- public virtual string Description {
- get { return description != null ? description : "SiteMapProvider"; }
+ [MonoTODO ("need to implement cases 2 and 3")]
+ public virtual bool IsAccessibleToUser (HttpContext context, SiteMapNode node)
+ {
+ if (context == null) throw new ArgumentNullException ("context");
+ if (node == null) throw new ArgumentNullException ("node");
+
+ if (!SecurityTrimmingEnabled)
+ return true;
+
+ /* The node is accessible (according to msdn2) if:
+ *
+ * 1. The Roles exists on node and the current user is in at least one of the specified roles.
+ *
+ * 2. The current thread has an associated WindowsIdentity that has file access to the requested URL and
+ * the URL is located within the directory structure for the application.
+ *
+ * 3. The current user is authorized specifically for the requested URL in the authorization element for
+ * the current application and the URL is located within the directory structure for the application.
+ */
+
+ /* 1. */
+ IList roles = node.Roles;
+ if (roles != null && roles.Count > 0) {
+ foreach (string rolename in roles)
+ if (rolename == "*" || context.User.IsInRole (rolename))
+ return true;
+ }
+
+ /* 2. */
+ /* XXX */
+
+ /* 3. */
+ string url = node.Url;
+ if(!String.IsNullOrEmpty(url)) {
+ // TODO check url is located within the current application
+
+ if (VirtualPathUtility.IsAppRelative (url) || !VirtualPathUtility.IsAbsolute (url))
+ url = VirtualPathUtility.Combine (VirtualPathUtility.AppendTrailingSlash (HttpRuntime.AppDomainAppVirtualPath), url);
+
+ AuthorizationSection config = (AuthorizationSection) WebConfigurationManager.GetSection (
+ "system.web/authorization",
+ url);
+ if (config != null)
+ return config.IsValidUser (context.User, context.Request.HttpMethod);
+ }
+
+ return false;
}
- string name;
- public virtual string Name {
- get { return name; }
+ public virtual SiteMapNode CurrentNode {
+ get {
+ if (HttpContext.Current != null) {
+ SiteMapNode ret = ResolveSiteMapNode (HttpContext.Current);
+ if (ret != null) return ret;
+ return FindSiteMapNode (HttpContext.Current);
+ } else
+ return null;
+ }
}
- ISiteMapProvider parentProvider;
- public virtual ISiteMapProvider ParentProvider {
+ public virtual SiteMapProvider ParentProvider {
get { return parentProvider; }
set { parentProvider = value; }
}
- ISiteMapProvider rootProviderCache;
- public virtual ISiteMapProvider RootProvider {
+ public virtual SiteMapProvider RootProvider {
get {
- if (rootProviderCache == null) {
- lock (this) {
- if (rootProviderCache == null) {
- ISiteMapProvider current = this;
- while (current.ParentProvider != null)
- current = current.ParentProvider;
-
- rootProviderCache = current;
- }
+ lock (this_lock) {
+ if (rootProviderCache == null) {
+ SiteMapProvider current = this;
+ while (current.ParentProvider != null)
+ current = current.ParentProvider;
+
+ rootProviderCache = current;
}
}
return rootProviderCache;
}
}
+
+ protected SiteMapNode ResolveSiteMapNode (HttpContext context)
+ {
+ SiteMapResolveEventHandler eh = events [siteMapResolveEvent] as SiteMapResolveEventHandler;
+
+ if (eh != null) {
+ lock (resolveLock) {
+ if (resolving)
+ return null;
+ resolving = true;
+ SiteMapResolveEventArgs args = new SiteMapResolveEventArgs (context, this);
+ SiteMapNode r = eh (this, args);
+ resolving = false;
+ return r;
+ }
+ } else
+ return null;
+ }
+
+ public bool EnableLocalization {
+ get { return enableLocalization; }
+ set { enableLocalization = value; }
+ }
+
+ public bool SecurityTrimmingEnabled {
+ get { return securityTrimming; }
+ }
+
+ string resourceKey;
+ public string ResourceKey {
+ get { return resourceKey; }
+ set { resourceKey = value; }
+ }
+
+ public virtual SiteMapNode RootNode {
+ get {
+ SiteMapNode node = GetRootNodeCore ();
+ return ReturnNodeIfAccessible (node);
+ }
+ }
- public abstract SiteMapNode BuildSiteMap ();
- public abstract SiteMapNode RootNode { get; }
-
+ internal static SiteMapNode ReturnNodeIfAccessible (SiteMapNode node)
+ {
+ if (node.IsAccessibleToUser (HttpContext.Current))
+ return node;
+ else
+ throw new InvalidOperationException (); /* need
+ * a
+ * message
+ * here */
+ }
}
}
-#endif
+