X

Enable https on ASP.NET MVC 2 & 3, through Filters and web.config

ASP.NET-MVC

To enable https on asp.net mvc, one can use the [RequireHttps] attribute on the base controller if you are using a base controller

[RequireHttps]
public class BaseController: Controller

But what if you want to give an option to the installer or the client to enable it in web.config, the easy way to do it for asp mvc2 is to create your own property like code below: (Please note: I am using protected virtual to override stuff for testing, its not one of the best things but it works in breaking dependency and its quick, so that I dont have to mock httpcontext, configuration manager etc etc, I could use an IoC but would make it more complicated for the reader but feel free to use one)

namespace MyWebMvc.Attributes
{
    public class MyRequireSslAttribute : RequireHttpsAttribute
    {
        private const string EnableSslKey = "EnableSSL";

        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if(filterContext == null)
                throw new ArgumentException("filterContext");

            if (!IsHttpContextNull(filterContext) && !IsEnableSsl())
            {
                return;
            }

            BaseOnAuthorization(filterContext);            
        }

        protected virtual void BaseOnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
        }

        protected virtual bool IsHttpContextNull(AuthorizationContext filterContext)
        {
            return filterContext.HttpContext == null;
        }

        protected virtual bool IsEnableSsl()
        {
            var enableSsl = HttpRuntime.Cache.Get(EnableSslKey);

            if(enableSsl == null)
            {
                var configEnableSsl = ConfigurationManager.AppSettings[EnableSslKey] ?? string.Empty;

                if(string.IsNullOrEmpty(configEnableSsl))
                {
                    HttpRuntime.Cache.Insert(EnableSslKey, false);
                    return false;
                }
                
                if(configEnableSsl.ToLower() != "true")
                {
                    HttpRuntime.Cache.Insert(EnableSslKey, false);
                    return false;
                }

                HttpRuntime.Cache.Insert(EnableSslKey, true);
                return true;
            }

            var isEnableSsl = false;
            bool.TryParse(enableSsl.ToString(), out isEnableSsl);            

            return isEnableSsl;
        }
    }

Here is the unit test for it, I am using a stub class to override the things I want for testing

using System;
using System.Web.Mvc;
using NUnit.Framework;
using MyWebMvc.Attributes;

namespace MyWebMvc.Tests.Attributes
{
    [TestFixture]
    public class MyRequireSslAttributeTests
    {
     
        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void OnAuthorization_ThrowException_WhenFilterIsNull()
        {
            var attr = new MyRequireSslAttribute();

            attr.OnAuthorization(null);
        }


        [Test]
        public void OnAuthorization_IsEnableFalse_BaseValidationWasNotCalled()
        {
            var attr = new StubMyRequireSslAttribute {EnableSsl = false, HttpContextBool = false};

            var context = new AuthorizationContext();         
   
            attr.OnAuthorization(context);

            Assert.That(attr.BaseWasCalled, Is.False);

        }

        [Test]
        public void OnAuthorization_HttpContextNullTrue_BaseValidationWasCalled()
        {
            var attr = new StubMyRequireSslAttribute { EnableSsl = false, HttpContextBool = true };

            var context = new AuthorizationContext();

            attr.OnAuthorization(context);

            Assert.That(attr.BaseWasCalled, Is.True);

        }


        [Test]
        public void OnAuthorization_HttpContextNullTrueIsEnableTrue_BaseValidationWasCalled()
        {
            var attr = new StubMyRequireSslAttribute { EnableSsl = true, HttpContextBool = true };

            var context = new AuthorizationContext();

            attr.OnAuthorization(context);

            Assert.That(attr.BaseWasCalled, Is.True);

        }


        [Test]
        public void OnAuthorization_IsEnableTrue_BaseValidationIsCalled()
        {
            var attr = new StubMyRequireSslAttribute { EnableSsl = true, HttpContextBool = false };

            var context = new AuthorizationContext();

            attr.OnAuthorization(context);

            Assert.That(attr.BaseWasCalled, Is.True);
        }

    }


    public class StubMyRequireSslAttribute : MyRequireSslAttribute
    {
        public bool EnableSsl { get; set; }
        public bool HttpContextBool { get; set; }
        public bool BaseWasCalled { get; set; }

        protected override bool IsHttpContextNull(AuthorizationContext filterContext)
        {
            return HttpContextBool;
        }

        protected override bool IsEnableSsl()
        {
            return EnableSsl;
        }

        protected override void BaseOnAuthorization(AuthorizationContext filterContext)
        {
            BaseWasCalled = true;
        }
    }
}

Now in your web.config you can add a key value pair like


And last if you are using Asp.Net Mvc3 life is way easier, one can just use in their Global.ascx file to add the filter

public static void RegisterGlobalFilters(GlobalFilterCollection filters) {

     //get configuration and add the attribute if needed
    filters.Add(new MyRequireHttpsAttribute()); 
 
}

Lastly you would add it to your BaseController

[MyRequireSsl]
public class BaseController: Controller
Taswar Bhatti:
Related Post