diff --git a/AuthorizationHttpModule.cs b/AuthorizationHttpModule.cs index 29f1af0..2db763a 100644 --- a/AuthorizationHttpModule.cs +++ b/AuthorizationHttpModule.cs @@ -8,7 +8,7 @@ using System.Web.UI; /// -/// Verify authorization on requests to AJAX WebServices or Pages. +/// Verify authorization on call to WebMethods or Pages with the attribute: <RequiresAuthentication> (VB) | [RequiresAuthentication] (C#). /// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] public class RequiresAuthenticationAttribute : Attribute { } @@ -33,7 +33,7 @@ public void Dispose() { } /// - /// Authorize request. + /// A request has hit IIS. This events handles authorization for the given request. /// /// Sender Parameter /// EventArgs Parameter @@ -43,8 +43,10 @@ private void OnPostAuthorizeRequest(object sender, EventArgs e) { var request = context.Request; var requestUrl = context.Request.Url.ToString(); - if (context.Handler is Page page) { + //The request is for a Page Class: + if (context.Handler is Page page) { var pageType = page.GetType(); + //Check if the MasterPage requires authentication: if (!requestUrl.Contains(".axd?")) { var masterPagePath = GetMasterPagePathFromMarkup(page.AppRelativeVirtualPath); if (!string.IsNullOrEmpty(masterPagePath)) { @@ -58,6 +60,7 @@ private void OnPostAuthorizeRequest(object sender, EventArgs e) { } } + //Check if the Page requires authentication: if (pageType.GetCustomAttribute() != null) { if (!request.IsAuthenticated || request.Cookies?[FormsAuthentication.FormsCookieName] == null) { DenyAccess(context); @@ -65,6 +68,7 @@ private void OnPostAuthorizeRequest(object sender, EventArgs e) { } } + //The request is for a WebMethod inside a Page Class: if (request.HttpMethod == "POST") { var methodName = GetWebMethodNameFromRequest(request); if (!string.IsNullOrEmpty(methodName)) { @@ -76,10 +80,10 @@ private void OnPostAuthorizeRequest(object sender, EventArgs e) { } } } + }; - } else if (requestUrl.Contains(".asmx/")) { - //Prøvd å hente Type via Handler._privateSomething - + //The request is for a WebService Class: + if (!(context.Handler is Page) & requestUrl.Contains(".asmx/")) { var segments = requestUrl.Split(new[] { ".asmx/" }, StringSplitOptions.RemoveEmptyEntries); if (segments.Length > 1) { string methodName = segments[1]; // Extract the part after .asmx/ as the method name @@ -91,15 +95,28 @@ private void OnPostAuthorizeRequest(object sender, EventArgs e) { dynamic _handler = context.CurrentHandler; dynamic handlerWrapper = context.Handler; + // Retrieve original handler and its metadata if (handlerWrapper != null) { - // Retrieve original handler and its metadata var originalHandlerField = handlerWrapper.GetType().GetField("_originalHandler", BindingFlags.NonPublic | BindingFlags.Instance); var originalHandler = originalHandlerField?.GetValue(handlerWrapper) as dynamic; if (originalHandler != null) { + //Session Disabled WebMethod is Called: var webServiceMethodDataField = originalHandler.GetType().GetField("_webServiceMethodData", BindingFlags.NonPublic | BindingFlags.Instance); var webServiceMethodData = webServiceMethodDataField?.GetValue(originalHandler) as dynamic; + //If the WebService Method has SessionEnabled=True the RestHandlerWithSession is used, instead of RestHandler class. + //RestHandlerWithSession is an empty class that inherits both the base RestHandler class and IRequireSessionState for session accsess + //Because of this we need to get the class type in a different way, through the BaseType. + //Since System.Web.Script.Services.RestHandlerWithSession is an internal class we also need to retive the type like so: + Type _RestHandlerWithSessionType = Type.GetType("System.Web.Script.Services.RestHandlerWithSession, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"); + + //Session Enabled WebMethod is Called: + if (_RestHandlerWithSessionType == originalHandler.GetType()) { + webServiceMethodDataField = originalHandler.GetType().BaseType.GetField("_webServiceMethodData", BindingFlags.NonPublic | BindingFlags.Instance); + webServiceMethodData = webServiceMethodDataField?.GetValue(originalHandler) as dynamic; + }; + if (webServiceMethodData != null) { var ownerField = webServiceMethodData.GetType().GetField("_owner", BindingFlags.NonPublic | BindingFlags.Instance); var owner = ownerField?.GetValue(webServiceMethodData) as dynamic; @@ -112,10 +129,11 @@ private void OnPostAuthorizeRequest(object sender, EventArgs e) { var actualTypeField = typeData.GetType().GetField("_actualType", BindingFlags.NonPublic | BindingFlags.Instance); var actualType = actualTypeField?.GetValue(typeData) as dynamic; + //The WebMethod's Class Type is retrived, we can now check for Custom Attributes: var attributes = actualType.GetCustomAttributes(typeof(RequiresAuthenticationAttribute), true); bool requiresAuthentication = attributes.Length > 0; - // Check if authentication is required for the main class + //Check if authentication is required for the main class if (requiresAuthentication) { if (!request.IsAuthenticated || request.Cookies?[FormsAuthentication.FormsCookieName] == null) { DenyAccess(context); @@ -123,14 +141,13 @@ private void OnPostAuthorizeRequest(object sender, EventArgs e) { } } - // Check for authentication attribute on the requested method + //Check if authentication is required for the requested method if (!requiresAuthentication) { var methodInfo = actualType.GetMethod(methodName); if (methodInfo != null) { var methodAttributes = methodInfo.GetCustomAttributes(typeof(RequiresAuthenticationAttribute), true); bool methodRequiresAuthentication = methodAttributes.Length > 0; - if (methodRequiresAuthentication) { if (!request.IsAuthenticated || request.Cookies?[FormsAuthentication.FormsCookieName] == null) { DenyAccess(context); @@ -140,7 +157,6 @@ private void OnPostAuthorizeRequest(object sender, EventArgs e) { } } } - } } } @@ -175,13 +191,21 @@ private string GetRelativeVirtualPath(string absolutePath) { } private string GetMasterPagePathFromMarkup(string virtualPath) { + string currentFolder = Path.GetDirectoryName(HttpContext.Current.Server.MapPath(virtualPath)); + string markup = File.ReadAllText(HttpContext.Current.Server.MapPath(virtualPath)); using (StringReader reader = new StringReader(markup)) { string line; while ((line = reader.ReadLine()) != null) { Match match = Regex.Match(line, "MasterPageFile\\s*=\\s*\"(.+?)\""); if (match.Success) { - return match.Groups[1].Value; + string masterPagePath = match.Groups[1].Value; + + if (!VirtualPathUtility.IsAppRelative(masterPagePath)) { + masterPagePath = VirtualPathUtility.Combine(virtualPath, masterPagePath); + } + + return masterPagePath; } } } @@ -208,4 +232,4 @@ private static string GetWebMethodNameFromRequest(HttpRequest request) { var slashIndex = pathInfo.IndexOf('/'); return slashIndex >= 0 ? pathInfo.Substring(0, slashIndex) : pathInfo; } -} \ No newline at end of file +}