Back in March, I posted about creating a custom authorization filter to enable Partial SSL. While using the filter on an application I was porting to Windows Azure, I discovered a bug, which has led me to revisit my implementation. Here is the original code.
1: public class RequireSslFilter:AuthorizeAttribute
2: {
3: protected override bool AuthorizeCore(HttpContextBase httpContext)
4: {
5: if (httpContext.Request.IsLocal == false && httpContext.Request.IsSecureConnection == false)
6: httpContext.Response.Redirect(httpContext.Request.Url.ToString().ToLower().Replace("http", "https"));
7:
8: return base.AuthorizeCore(httpContext);
9: }
10: }
As you can see, I’m calling base.AuthorizeCore at the end, which is what you usually do when overriding a method. However, since the purpose of he Authorize Filter is to, well authorize, the call to base.AuthorizeCore will return false if the user is not authenticated. This is a problem because you might not be authenticated at the time that this filter runs.
The reason I chose to use the Authorize Filter, is because it’s called before any other filter, as explained by Phill Haack. At first I thought about removing the call to the base.AuthorzieCore, but that seemed more like a hack, then a correct solution. Digging deeper, I discovered that the AuthorizeAttribute that I am inheriting from, implements the IAuthorizeFilter, which requires you implement the OnAuthorization method. So instead of inheriting from AuthorizeAttribute, I could just implement IAuthorizeFilter.
However, someone already did it for me. In the Asp.Net MVC futures project, released with the Asp.Net MVC RTM source, there is a RequireSSL attribute ready to use. The future’s project has more functionality then mine, allowing for the option to redirect or throw an exception. It’s nice to see I was on the right track at least.
RequireSSL Attribute from Asp.Net MVC Futures:
1: public void OnAuthorization(AuthorizationContext filterContext) {
2: if (filterContext == null) {
3: throw new ArgumentNullException("filterContext");
4: }
5:
6: if (!filterContext.HttpContext.Request.IsSecureConnection) {
7: // request is not SSL-protected, so throw or redirect
8: if (Redirect) {
9: // form new URL
10: UriBuilder builder = new UriBuilder() {
11: Scheme = "https",
12: Host = filterContext.HttpContext.Request.Url.Host,
13: // use the RawUrl since it works with URL Rewriting
14: Path = filterContext.HttpContext.Request.RawUrl
15: };
16: filterContext.Result = new RedirectResult(builder.ToString());
17: }
18: else {
19: throw new HttpException((int)HttpStatusCode.Forbidden, MvcResources.RequireSslAttribute_MustUseSsl);
20: }
21: }
22: }
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.