2 // System.Web.SiteMapProvider
5 // Ben Maurer (bmaurer@users.sourceforge.net)
6 // Lluis Sanchez Gual (lluis@novell.com)
9 // (C) 2005 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
35 using System.Collections.Specialized;
37 using System.Configuration.Provider;
38 using System.Web.Util;
39 using System.Globalization;
40 using System.Web.Configuration;
42 namespace System.Web {
43 public abstract class SiteMapProvider : ProviderBase {
45 bool enableLocalization;
46 SiteMapProvider parentProvider;
47 SiteMapProvider rootProviderCache;
48 bool securityTrimming;
49 object resolveLock = new Object();
52 protected virtual void AddNode (SiteMapNode node)
57 internal protected virtual void AddNode (SiteMapNode node, SiteMapNode parentNode)
59 throw new NotImplementedException ();
62 public virtual SiteMapNode FindSiteMapNode (HttpContext context)
67 SiteMapNode ret = this.FindSiteMapNode (context.Request.RawUrl);
69 ret = this.FindSiteMapNode (context.Request.Path);
73 public abstract SiteMapNode FindSiteMapNode (string rawUrl);
75 public virtual SiteMapNode FindSiteMapNodeFromKey (string key)
77 /* msdn2 says this function always returns
78 * null, but it seems to just call
79 * FindSiteMapNode(string rawUrl) */
80 return FindSiteMapNode (key);
83 public abstract SiteMapNodeCollection GetChildNodes (SiteMapNode node);
85 public virtual SiteMapNode GetCurrentNodeAndHintAncestorNodes (int upLevel)
87 if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
92 public virtual SiteMapNode GetCurrentNodeAndHintNeighborhoodNodes (int upLevel, int downLevel)
94 if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
95 if (downLevel < -1) throw new ArgumentOutOfRangeException ("downLevel");
100 public abstract SiteMapNode GetParentNode (SiteMapNode node);
102 public virtual SiteMapNode GetParentNodeRelativeToCurrentNodeAndHintDownFromParent (int walkupLevels, int relativeDepthFromWalkup)
104 if (walkupLevels < 0) throw new ArgumentOutOfRangeException ("walkupLevels");
105 if (relativeDepthFromWalkup < 0) throw new ArgumentOutOfRangeException ("relativeDepthFromWalkup");
107 SiteMapNode node = GetCurrentNodeAndHintAncestorNodes (walkupLevels);
108 for (int n=0; n<walkupLevels && node != null; n++)
109 node = GetParentNode (node);
111 if (node == null) return null;
113 HintNeighborhoodNodes (node, 0, relativeDepthFromWalkup);
117 public virtual SiteMapNode GetParentNodeRelativeToNodeAndHintDownFromParent (SiteMapNode node, int walkupLevels, int relativeDepthFromWalkup)
119 if (walkupLevels < 0) throw new ArgumentOutOfRangeException ("walkupLevels");
120 if (relativeDepthFromWalkup < 0) throw new ArgumentOutOfRangeException ("relativeDepthFromWalkup");
121 if (node == null) throw new ArgumentNullException ("node");
123 HintAncestorNodes (node, walkupLevels);
124 for (int n=0; n<walkupLevels && node != null; n++)
125 node = GetParentNode (node);
127 if (node == null) return null;
129 HintNeighborhoodNodes (node, 0, relativeDepthFromWalkup);
133 protected internal abstract SiteMapNode GetRootNodeCore ();
135 protected static SiteMapNode GetRootNodeCoreFromProvider (SiteMapProvider provider)
137 return provider.GetRootNodeCore ();
140 public virtual void HintAncestorNodes (SiteMapNode node, int upLevel)
142 if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
143 if (node == null) throw new ArgumentNullException ("node");
146 public virtual void HintNeighborhoodNodes (SiteMapNode node, int upLevel, int downLevel)
148 if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
149 if (downLevel < -1) throw new ArgumentOutOfRangeException ("downLevel");
150 if (node == null) throw new ArgumentNullException ("node");
153 protected virtual void RemoveNode (SiteMapNode node)
155 throw new NotImplementedException ();
158 public override void Initialize (string name, NameValueCollection attributes)
160 base.Initialize (name, attributes);
161 if (attributes ["securityTrimmingEnabled"] != null)
162 securityTrimming = (bool) Convert.ChangeType (attributes ["securityTrimmingEnabled"], typeof (bool));
165 [MonoTODO ("need to implement cases 2 and 3")]
166 public virtual bool IsAccessibleToUser (HttpContext context, SiteMapNode node)
168 if (context == null) throw new ArgumentNullException ("context");
169 if (node == null) throw new ArgumentNullException ("node");
171 if (!SecurityTrimmingEnabled)
174 /* the node is accessible (according to msdn2)
177 * 1. the current user is in the node's Roles.
179 * 2. the current thread's WindowsIdentity has
180 * file access to the url. (and the url is
181 * located within the current application).
183 * 3. the <authorization> configuration element
184 * lists the current user as being authorized
185 * for the node's url. (and the url is located
186 * within the current application)
190 if (node.Roles != null)
191 foreach (string rolename in node.Roles)
192 if (rolename == "*" || context.User.IsInRole (rolename))
198 string url = node.Url;
199 if(String.IsNullOrEmpty(url))
201 // TODO check url is located within the current application
203 if (VirtualPathUtility.IsAppRelative (url) || !VirtualPathUtility.IsAbsolute (url))
204 url = VirtualPathUtility.Combine (VirtualPathUtility.AppendTrailingSlash (HttpRuntime.AppDomainAppVirtualPath), url);
206 AuthorizationSection config = (AuthorizationSection) WebConfigurationManager.GetSection (
207 "system.web/authorization",
210 return config.IsValidUser (context.User, context.Request.HttpMethod);
215 public virtual SiteMapNode CurrentNode {
217 if (HttpContext.Current != null) {
218 SiteMapNode ret = ResolveSiteMapNode (HttpContext.Current);
219 if (ret != null) return ret;
220 return FindSiteMapNode (HttpContext.Current);
226 public virtual SiteMapProvider ParentProvider {
227 get { return parentProvider; }
228 set { parentProvider = value; }
231 public virtual SiteMapProvider RootProvider {
234 if (rootProviderCache == null) {
235 SiteMapProvider current = this;
236 while (current.ParentProvider != null)
237 current = current.ParentProvider;
239 rootProviderCache = current;
242 return rootProviderCache;
246 protected SiteMapNode ResolveSiteMapNode (HttpContext context)
248 SiteMapResolveEventArgs args = new SiteMapResolveEventArgs (context, this);
249 if (SiteMapResolve != null) {
251 if (resolving) return null;
253 SiteMapNode r = SiteMapResolve (this, args);
262 public bool EnableLocalization {
263 get { return enableLocalization; }
264 set { enableLocalization = value; }
267 public bool SecurityTrimmingEnabled {
268 get { return securityTrimming; }
272 public string ResourceKey {
273 get { return resourceKey; }
274 set { resourceKey = value; }
277 public virtual SiteMapNode RootNode {
279 SiteMapNode node = GetRootNodeCore ();
280 return ReturnNodeIfAccessible (node);
284 public event SiteMapResolveEventHandler SiteMapResolve;
286 internal static SiteMapNode ReturnNodeIfAccessible (SiteMapNode node)
288 if (node.IsAccessibleToUser (HttpContext.Current))
291 throw new InvalidOperationException (); /* need