Skip to content

Commit e1e53d3

Browse files
committed
Support for ASP.NET AJAX Web Service Handlers
Ref used when implementing reflection: https://tinyurl.com/Ref-Source
1 parent 5703067 commit e1e53d3

File tree

1 file changed

+136
-8
lines changed

1 file changed

+136
-8
lines changed

AuthorizationHttpModule.cs

Lines changed: 136 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
using System;
2+
using System.IO;
23
using System.Reflection;
4+
using System.Text.RegularExpressions;
35
using System.Web;
46
using System.Web.Compilation;
57
using System.Web.Security;
68
using System.Web.UI;
9+
710
/// <summary>
8-
/// Verify authorization on call to WebMethods or Pages with the attribute: &lt;RequiresAuthentication&gt; (VB) | [RequiresAuthentication] (C#).
11+
/// Verify authorization on requests to AJAX WebServices or Pages.
912
/// </summary>
1013
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
1114
public class RequiresAuthenticationAttribute : Attribute { }
@@ -38,26 +41,151 @@ private void OnPostAuthorizeRequest(object sender, EventArgs e) {
3841
var app = (HttpApplication)sender;
3942
var context = app.Context;
4043
var request = context.Request;
44+
var requestUrl = context.Request.Url.ToString();
4145

42-
if (context.Handler is Page page) {
43-
if (page?.GetType().GetCustomAttribute<RequiresAuthenticationAttribute>() != null) {
44-
if (!request.IsAuthenticated || request.Cookies[FormsAuthentication.FormsCookieName] == null) {
46+
if (context.Handler is Page page) {
47+
var pageType = page.GetType();
48+
if (!requestUrl.Contains(".axd?")) {
49+
var masterPagePath = GetMasterPagePathFromMarkup(page.AppRelativeVirtualPath);
50+
if (!string.IsNullOrEmpty(masterPagePath)) {
51+
var masterPageType = BuildManager.GetCompiledType(masterPagePath);
52+
if (masterPageType != null && masterPageType.GetCustomAttribute<RequiresAuthenticationAttribute>() != null) {
53+
if (!request.IsAuthenticated || request.Cookies?[FormsAuthentication.FormsCookieName] == null) {
54+
DenyAccess(context);
55+
return;
56+
}
57+
}
58+
}
59+
}
60+
61+
if (pageType.GetCustomAttribute<RequiresAuthenticationAttribute>() != null) {
62+
if (!request.IsAuthenticated || request.Cookies?[FormsAuthentication.FormsCookieName] == null) {
4563
DenyAccess(context);
64+
return;
4665
}
4766
}
67+
4868
if (request.HttpMethod == "POST") {
4969
var methodName = GetWebMethodNameFromRequest(request);
5070
if (!string.IsNullOrEmpty(methodName)) {
51-
var pageType = page?.GetType();
52-
var methodInfo = pageType?.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
71+
var methodInfo = pageType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
5372
if (methodInfo?.GetCustomAttribute<RequiresAuthenticationAttribute>() != null) {
54-
if (!request.IsAuthenticated || request.Cookies[FormsAuthentication.FormsCookieName] == null) {
73+
if (!request.IsAuthenticated || request.Cookies?[FormsAuthentication.FormsCookieName] == null) {
5574
DenyAccess(context);
5675
}
5776
}
5877
}
5978
}
79+
80+
} else if (requestUrl.Contains(".asmx/")) {
81+
//Prøvd å hente Type via Handler._privateSomething
82+
83+
var segments = requestUrl.Split(new[] { ".asmx/" }, StringSplitOptions.RemoveEmptyEntries);
84+
if (segments.Length > 1) {
85+
string methodName = segments[1]; // Extract the part after .asmx/ as the method name
86+
string asmxUrlWithoutMethod = requestUrl.Replace("/" + methodName, ""); // Remove the method name from the URL
87+
88+
var codeBehindPath = GetCodeBehindPathFromASMXUrl(asmxUrlWithoutMethod);
89+
90+
if (!string.IsNullOrEmpty(codeBehindPath)) {
91+
dynamic _handler = context.CurrentHandler;
92+
dynamic handlerWrapper = context.Handler;
93+
94+
if (handlerWrapper != null) {
95+
// Retrieve original handler and its metadata
96+
var originalHandlerField = handlerWrapper.GetType().GetField("_originalHandler", BindingFlags.NonPublic | BindingFlags.Instance);
97+
var originalHandler = originalHandlerField?.GetValue(handlerWrapper) as dynamic;
98+
99+
if (originalHandler != null) {
100+
var webServiceMethodDataField = originalHandler.GetType().GetField("_webServiceMethodData", BindingFlags.NonPublic | BindingFlags.Instance);
101+
var webServiceMethodData = webServiceMethodDataField?.GetValue(originalHandler) as dynamic;
102+
103+
if (webServiceMethodData != null) {
104+
var ownerField = webServiceMethodData.GetType().GetField("_owner", BindingFlags.NonPublic | BindingFlags.Instance);
105+
var owner = ownerField?.GetValue(webServiceMethodData) as dynamic;
106+
107+
if (owner != null) {
108+
var typeDataField = owner.GetType().GetField("_typeData", BindingFlags.NonPublic | BindingFlags.Instance);
109+
var typeData = typeDataField?.GetValue(owner) as dynamic;
110+
111+
if (typeData != null) {
112+
var actualTypeField = typeData.GetType().GetField("_actualType", BindingFlags.NonPublic | BindingFlags.Instance);
113+
var actualType = actualTypeField?.GetValue(typeData) as dynamic;
114+
115+
var attributes = actualType.GetCustomAttributes(typeof(RequiresAuthenticationAttribute), true);
116+
bool requiresAuthentication = attributes.Length > 0;
117+
118+
// Check if authentication is required for the main class
119+
if (requiresAuthentication) {
120+
if (!request.IsAuthenticated || request.Cookies?[FormsAuthentication.FormsCookieName] == null) {
121+
DenyAccess(context);
122+
return;
123+
}
124+
}
125+
126+
// Check for authentication attribute on the requested method
127+
if (!requiresAuthentication) {
128+
var methodInfo = actualType.GetMethod(methodName);
129+
if (methodInfo != null) {
130+
var methodAttributes = methodInfo.GetCustomAttributes(typeof(RequiresAuthenticationAttribute), true);
131+
bool methodRequiresAuthentication = methodAttributes.Length > 0;
132+
133+
134+
if (methodRequiresAuthentication) {
135+
if (!request.IsAuthenticated || request.Cookies?[FormsAuthentication.FormsCookieName] == null) {
136+
DenyAccess(context);
137+
return;
138+
}
139+
}
140+
}
141+
}
142+
}
143+
144+
}
145+
}
146+
}
147+
}
148+
}
149+
}
150+
}
151+
}
152+
153+
private string GetCodeBehindPathFromASMXUrl(string asmxUrl) {
154+
string relativePath = GetRelativeVirtualPath(asmxUrl);
155+
if (!string.IsNullOrEmpty(relativePath)) {
156+
string asmxMarkup = File.ReadAllText(HttpContext.Current.Server.MapPath(relativePath));
157+
158+
Match match = Regex.Match(asmxMarkup, @"<%@ WebService Language=""VB"" CodeBehind=""(.*?)"" Class=""(.*?)"" %>");
159+
if (match.Success && match.Groups.Count > 1) {
160+
string codeBehindPath = match.Groups[1].Value;
161+
return codeBehindPath;
162+
}
163+
}
164+
165+
return string.Empty;
166+
}
167+
168+
private string GetRelativeVirtualPath(string absolutePath) {
169+
Uri uri = new Uri(absolutePath);
170+
string rootPath = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);
171+
if (uri.AbsoluteUri.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase)) {
172+
return "~" + uri.AbsolutePath.Replace("\\", "/");
173+
}
174+
return string.Empty;
175+
}
176+
177+
private string GetMasterPagePathFromMarkup(string virtualPath) {
178+
string markup = File.ReadAllText(HttpContext.Current.Server.MapPath(virtualPath));
179+
using (StringReader reader = new StringReader(markup)) {
180+
string line;
181+
while ((line = reader.ReadLine()) != null) {
182+
Match match = Regex.Match(line, "MasterPageFile\\s*=\\s*\"(.+?)\"");
183+
if (match.Success) {
184+
return match.Groups[1].Value;
185+
}
186+
}
60187
}
188+
return null;
61189
}
62190

63191
/// <summary>
@@ -80,4 +208,4 @@ private static string GetWebMethodNameFromRequest(HttpRequest request) {
80208
var slashIndex = pathInfo.IndexOf('/');
81209
return slashIndex >= 0 ? pathInfo.Substring(0, slashIndex) : pathInfo;
82210
}
83-
}
211+
}

0 commit comments

Comments
 (0)