1 //------------------------------------------------------------------------------
2 // <copyright file="WebFormRouteHandler.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 namespace System.Web.Routing {
8 
9     using System;
10     using System.Web.UI;
11     using System.Web.Compilation;
12     using System.Web.Security;
13     using System.Security;
14     using System.Security.Permissions;
15     using System.Security.Principal;
16 
17     public class PageRouteHandler : IRouteHandler {
PageRouteHandler(string virtualPath)18         public PageRouteHandler(string virtualPath)
19             : this(virtualPath, true) {
20         }
21 
PageRouteHandler(string virtualPath, bool checkPhysicalUrlAccess)22         public PageRouteHandler(string virtualPath, bool checkPhysicalUrlAccess) {
23             if (string.IsNullOrEmpty(virtualPath) || !virtualPath.StartsWith("~/", StringComparison.OrdinalIgnoreCase)) {
24                 throw new ArgumentException(SR.GetString(SR.PageRouteHandler_InvalidVirtualPath), "virtualPath");
25             }
26 
27             this.VirtualPath = virtualPath;
28             this.CheckPhysicalUrlAccess = checkPhysicalUrlAccess;
29             _useRouteVirtualPath = VirtualPath.Contains("{");
30         }
31 
32         /// <summary>
33         /// This is the full virtual path (using tilde syntax) to the WebForm page.
34         /// </summary>
35         /// <remarks>
36         /// Needs to be thread safe so this is only settable via ctor.
37         /// </remarks>
38         public string VirtualPath { get; private set; }
39 
40         /// <summary>
41         /// Because we're not actually rewriting the URL, ASP.NET's URL Auth will apply
42         /// to the incoming request URL and not the URL of the physical WebForm page.
43         /// Setting this to true (default) will apply URL access rules against the
44         /// physical file.
45         /// </summary>
46         /// <value>True by default</value>
47         public bool CheckPhysicalUrlAccess { get; private set; }
48 
49         private bool _useRouteVirtualPath;
50         private Route _routeVirtualPath;
51         private Route RouteVirtualPath {
52             get {
53                 if (_routeVirtualPath == null) {
54                     //Trim off ~/
55                     _routeVirtualPath = new Route(VirtualPath.Substring(2), this);
56                 }
57                 return _routeVirtualPath;
58             }
59         }
60 
CheckUrlAccess(string virtualPath, RequestContext requestContext)61         private bool CheckUrlAccess(string virtualPath, RequestContext requestContext) {
62             IPrincipal user = requestContext.HttpContext.User;
63             // If there's no authenticated user, use the default identity
64             if (user == null) {
65                 user = new GenericPrincipal(new GenericIdentity(String.Empty, String.Empty), new string[0]);
66             }
67             return CheckUrlAccessWithAssert(virtualPath, requestContext, user);
68         }
69 
70         [SecurityPermission(SecurityAction.Assert, Unrestricted = true)]
CheckUrlAccessWithAssert(string virtualPath, RequestContext requestContext, IPrincipal user)71         private bool CheckUrlAccessWithAssert(string virtualPath, RequestContext requestContext, IPrincipal user) {
72             return UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualPath, user, requestContext.HttpContext.Request.HttpMethod);
73         }
74 
GetHttpHandler(RequestContext requestContext)75         public virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
76             if (requestContext == null) {
77                 throw new ArgumentNullException("requestContext");
78             }
79 
80             string virtualPath = GetSubstitutedVirtualPath(requestContext);
81             // Virtual Path ----s up with query strings, so we need to strip them off
82             int qmark = virtualPath.IndexOf('?');
83             if (qmark != -1) {
84                 virtualPath = virtualPath.Substring(0, qmark);
85             }
86             if (this.CheckPhysicalUrlAccess && !CheckUrlAccess(virtualPath, requestContext)) {
87                 return new UrlAuthFailureHandler();
88             }
89 
90             Page page = BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page)) as Page;
91             return page;
92         }
93 
94         /// <summary>
95         /// Gets the virtual path to the resource after applying substitutions based on route data.
96         /// </summary>
97         /// <param name="requestContext"></param>
98         /// <returns></returns>
GetSubstitutedVirtualPath(RequestContext requestContext)99         public string GetSubstitutedVirtualPath(RequestContext requestContext) {
100             if (requestContext == null) {
101                 throw new ArgumentNullException("requestContext");
102             }
103 
104             if (!_useRouteVirtualPath)
105                 return VirtualPath;
106 
107             VirtualPathData vpd = RouteVirtualPath.GetVirtualPath(requestContext, requestContext.RouteData.Values);
108             //
109             if (vpd == null)
110                 return VirtualPath;
111             return "~/" + vpd.VirtualPath;
112         }
113     }
114 }
115