I have a folder with multiple .aspx pages that I want to restrict access to. I have added web.config to that folder with <deny users="?"/>
.
The problem is that ReturnUrl is auto-generated with physical path to the .aspx file while I'm using UrlRewrite.
Is there a way to manipulate ReturnUrl without doing manual authentication check and redirection? Is there a way to set ReturnUrl from code-behind or from web.config?
EDIT: The application is using ASP.NET 2.0 WebForms. I cannot use 3.5 routing.
EDIT 2: It seems like 401 status code is never captured. It returns 302 for protected page and redirects to login page with ReturnUrl. It does not return 401 for protected page. Hmm... Interesting... Ref: http://msdn.microsoft.com/en-us/library/aa480476.aspx
This makes things harder... I might have to write reverse rewrite mapping rules to regex match ReturnUrl and replace it if it doesn't return 401... If it does return 401 I can either set RawUrl to Response.RedirectLocation or replace ReturnUrl with RawUrl.
Anyone else have any other ideas?
Check it out. Hope this helps.
#region [ Imports ]
using System;
using System.Web;
using System.Web.Security;
#endregion
namespace Foo.Handlers
{
public class AuthModule : IHttpModule
{
#region IHttpModule Members
public void Init(HttpApplication application)
{
application.PostReleaseRequestState += delegate(object s, EventArgs e)
{
if (application.Response.StatusCode == 401)
application.Response.Redirect(FormsAuthentication.LoginUrl + "?ReturnUrl=" + HttpUtility.UrlEncode(application.Request.RawUrl), true);
};
}
public void Dispose() { }
#endregion
}
}
<modules>
<add name="AuthModule" type="Foo.Handlers.AuthModule, Foo"/>
</modules>
Create the following control adapter to rewrite the form tag with the for the action attribute. I used this a ASP.NET 2.0 app in conjunction with the Intelligencia url rewriter. I got it from this blog post from the Gu.
Put this class in your App_Code folder:
using System.IO;
using System.Web;
using System.Web.UI;
public class FormRewriterControlAdapter : System.Web.UI.Adapters.ControlAdapter
{
protected override void Render(HtmlTextWriter writer)
{
base.Render(new RewriteFormHtmlTextWriter(writer));
}
}
public class RewriteFormHtmlTextWriter : HtmlTextWriter
{
public RewriteFormHtmlTextWriter(TextWriter writer) : base(writer)
{
base.InnerWriter = writer;
}
public RewriteFormHtmlTextWriter(HtmlTextWriter writer) : base(writer)
{
this.InnerWriter = writer.InnerWriter;
}
public override void WriteAttribute(string name, string value, bool fEncode)
{
// If the attribute we are writing is the "action" attribute, and we are not on a sub-control,
// then replace the value to write with the raw URL of the request - which ensures that we'll
// preserve the PathInfo value on postback scenarios
if ((name == "action"))
{
if (HttpContext.Current.Items["ActionAlreadyWritten"] == null)
{
// Because we are using the UrlRewriting.net HttpModule, we will use the
// Request.RawUrl property within ASP.NET to retrieve the origional URL
// before it was re-written. You'll want to change the line of code below
// if you use a different URL rewriting implementation.
value = HttpContext.Current.Request.RawUrl;
// Indicate that we've already rewritten the <form>'s action attribute to prevent
// us from rewriting a sub-control under the <form> control
HttpContext.Current.Items["ActionAlreadyWritten"] = true;
}
}
base.WriteAttribute(name, value, fEncode);
}
}
Then, create this .browser file in your App_Browsers folder:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.HtmlControls.HtmlForm" adapterType="FormRewriterControlAdapter" />
</controlAdapters>
</browser>
</browsers>
I ended up checking for existence of ReturnUrl in the Url and replacing it with RawUrl in EndRequest stage in Global.asax. This works for me for now...
This blog post helped me setting it up.
protected void Application_EndRequest(object sender, EventArgs e)
{
string redirectUrl = this.Response.RedirectLocation;
if (!this.Request.RawUrl.Contains("ReturnUrl=") && !string.IsNullOrEmpty(redirectUrl))
{
this.Response.RedirectLocation = Regex.Replace(redirectUrl, "ReturnUrl=(?'url'[^&]*)", delegate(Match m)
{
return string.Format("ReturnUrl={0}", HttpUtility.UrlEncode(this.Request.RawUrl));
}, RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
}
}
If you are using ASP.NET 3.5, use ASP.NET UrlRouting instead. But you must check the authorization manualy.
http://chriscavanagh.wordpress.com/2008/03/11/aspnet-routing-goodbye-url-rewriting/