Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

A dynamic RequireSsl Attribute for ASP.NET MVC


:P
On this page:

sslIn most of my Web applications I’m finding that I need to handle SSL activation dynamically rather than statically. IOW, depending on the environment that I’m running in I need to specify whether I want to enforce SSL or not. Specifically during development I typically want to run with SSL disabled and at runtime on my live server I want to force it on. On a staging server typically I don’t want to run SSL unless I have access to a configured certificate.

Typically there’s little reason to run SSL locally on development machines, and it certainly isn’t configured by default. Although IIS makes it pretty easy to create machine certificates these days, it’s still not quite automatic for SSL to ‘just work’ out of the box. I find especially in multi-developer environments or for staging and testing servers adding certificates is often a causing a problem or adding extra work that doesn’t really add any value on a non-production machine.

For these reasons I like to use a configuration switch to turn SSL on and off at runtime based on a configuration setting.

SSL and MVC

ASP.NET MVC provides the [RequireHttps] attribute that you can slap on a controller or controller method and which forces the affected requests to SSL. This works fine for static situations if you want to force a controller or method to SSL, but it’s on or off and you have to change code in order to change the value.

It’s easy enough to use: You simply apply the attribute to a control or individual controller methods and off you go.

Here’s what this looks like on a controller:

[RequireHttps]
public class AccountController : AppBaseController

You can also assign [RequireHttps] to a method – if you don’t have it on the controller – to force individual methods to be accessed via SSL.

[RequireHttps]
public ActionResult Login(string redirectUrl)  {…}

For example, this can be useful if you have a login API and you only want to protect your login pages or certain order pages in an online store etc. Personally, if I have a certificate on my site – these days I prefer to simply run the entire site in SSL since it’s more secure and also cleaner simply leaving all urls consistently in SSL rather than switching back and forth which can result in different urls that sometimes show up in SSL and sometimes now (because once you go to URL and then navigate to a non-SSL required URL you stay in SSL).

The implementation of this attribute is super simple – you can check out the code here on GitHub. Basically all this method does is check to see if the request is on a secure connection and if it isn’t, switch the URL to https by munging request URI and then redirecting to the same page with the new URL. It’s important to note that the attribute only works with GET requests, which makes sense, since a redirect cannot pass any POST content to the redirected page.

Working around [RequireHttps]

Because [RequireHttps] is an attribute it requires constant values as parameters, and there’s no option to dynamically determine whether the controller should run SSL or not. So it’s really all or nothing and a manual code change to flip behavior, which is not super useful if you want to parameterize SSL operation with a configuration switch or some other mechanism.

To get around the static setting in RequireHttps in the past I have simply created a custom attribute that overrides the RequireHttpsAttribute behavior, by subclassing it and creating my own attribute. I then handle the default constructor’s code and load a setting from within the application from a configuration store – in this case a simple configuration setting on a config class.

Here’s what this custom attribute looks like:

public class RequireHttpsWithFlagAttribute : RequireHttpsAttribute
{
    public bool RequireSsl { get; set; }
    
    public RequireHttsWithFlagAttribute()
    {
        // Assign from App specific configuration object
        RequireSsl = App.Configuration.RequireSsl;
    }

    public RequireHttpsWithFlagAttribute(bool requireSsl)
    {
        RequireSsl = requireSsl;
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext != null &&
            RequireSsl &&
            !filterContext.HttpContext.Request.IsSecureConnection)
        {
            HandleNonHttpsRequest(filterContext);
        }
    }
}

The key line in this subclassed version is the default constructor which overrides the RequireSsl flag with a configuration value which comes from my web.config file. Here I’m using the West Wind Application Configuration class to hold and retrieve my value, but the value could really come from anywhere as long as it’s globally available. In this case the App.Configuration is a static class so I can globally access it here in the attribute. You could use an AppSettings key or whatever else works for you for configuration.

This code also overrides the OnAuthorization call, duplicating the original functionality but adding in the RequireSsl flag setting as well into the filter condition.

Once this attribute has been created I can access it on a controller class or Action method just as I normally would do with [RequireHttps]:

[RequireHttpsWithFlag]
public class AccountController : AppBaseController    

Because I use the default constructor, the attribute assigns the value from the configuration and that’s it – I’m in business with my dynamic value. You can also explicitly pass true or false to this attribute to enable and disable SSL behavior, which is nice for explicitly setting and removing SSL from requests.

Attributes are not Dynamic

This custom implementation works, but it’s a a drag to have to create this class for every project, since this code hardcodes my configuration setting. It works but it’s not generic.

It’d be nice if I could do something like (does not work!):

[RequireHttpsWithFlag(App.Configuration.RequireSsl)]

But as you can see by the red highlighting from Visual Studio, that doesn’t work. Other things that would be nice to pass here might be a delegate or lamda expression that could be called. But none of that works because only constant expressions are allowed.

If you try to use the above you get an error:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

Attributes require that values bound to the attribute parameters are a constant expression that can’t change at runtime. Part of the reason for this is that Attributes were primarily meant for MetaData and that meta data might be queried outside of a dynamic runtime environment. Without an application running dynamic values would fail but constant static values are always going to be available and work.

Of course we know that today attributes are used for a lot more than just metadata, but the restrictions are there and remain.

Note that although the attribute declaration requires constant values, however the actual attribute property data and values– once you get a hold of an attribute or internally as you run code in a custom attribute – can be modified at runtime. This means there’s hope that we can maybe work around the constant limitations.

Attribute Fakery

The ideal scenario for a custom Attribute would be that you could hook up a Delegate and call it to get values at runtime explicitly. But alas delegates are also not allowed even if pointing at static methods.

The easiest way to work around this is to use attribute parameters that are strings. So I decided we can easily create an implementation that’s a little more dynamic. I create a RequireSslAttribute class which allows for the following:

  • Explicitly specify the value for the RequireSsl (true or false)
  • Specify appSettings key name as a string
  • Specify a static method by providing a type and method name as a string

The first is pretty obvious. [RequireHttps] is either there or not but there’s no way to specify explicitly whether it’s on or off. Sometimes it’s nice to be explicit especially if you flip the switch manually from time to time.

An appSettings key is a simple and obvious choice. It’s a simple string value you can set and appSettings tends to be available anywhere. This option tries to find the specified key and looks for True or 1 as a string value. If found RequireSsl is set to true otherwise it’s false.

The last one is a bit more esoteric and a bit of a hack, but if you need to more complex logic or simply something that needs to get a value from your application, then this provides a poor emulation of a delegate. You provide a type reference and string that is the name of a static method to invoke on that type. The method should return true or false which is then assigned to RequireSsl.

Let’s take a look how to implement this:

/// <summary>
/// Allows for dynamically assigning the RequireSsl property at runtime
/// either with an explicit boolean constant, a configuration setting,
/// or a Reflection based 'delegate' 
/// </summary>
public class RequireSslAttribute : RequireHttpsAttribute
{
    public bool RequireSsl { get; set; }


    /// <summary>
    /// Default constructor forces SSL required
    /// </summary>
    public RequireSslAttribute()
    {
        RequireSsl = true;
    }

    /// <summary>
    /// Allows assignment of the SSL status via parameter
    /// </summary>
    /// <param name="requireSsl"></param>
    public RequireSslAttribute(bool requireSsl)
    {
        RequireSsl = requireSsl;
    }

    /// <summary>
    /// Allows invoking a static method at runtime to check for a 
    /// value dynamically.
    /// 
    /// Note: The method called must be a static method
    /// </summary>
    /// <param name="typeName">Fully qualified type name on which the method to call exists</param>
    /// <param name="method">Static method on this type to invoke with no parameters</param>
    public RequireSslAttribute(Type type, string method)
    {
        var mi = type.GetMethod(method, BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public);
        RequireSsl = (bool)mi.Invoke(type, null);
    }

    /// <summary>
    /// Looks for an appSetting key you specify and if it exists
    /// and is set to true or 1 which forces SSL.
    /// </summary>
    /// <param name="appSettingsKey"></param>
    public RequireSslAttribute(string appSettingsKey)
    {
        string key = ConfigurationManager.AppSettings[appSettingsKey] as string;
        RequireSsl = false;
        if (!string.IsNullOrEmpty(key))
        {
            key = key.ToLower();
            if (key == "true" || key == "1")
                RequireSsl = true;
        }
    }


    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext != null &&
            RequireSsl &&
            !filterContext.HttpContext.Request.IsSecureConnection)
        {
            HandleNonHttpsRequest(filterContext);
        }
    }
}

The implementation is similar to the non-generic version I showed earlier: I subclass RequireHttpsAttribute and override OnAuthorization. I use a RequireSsl property on the attribute to hold my ‘state’ which is set by the various constructors that implement the configuration value retrieval.

AppSettings Value

The appSettings value is probably the easiest way to use this. You can simply add a key to the <appSettings> section in web.config:

<appSettings>
  <add key="webpages:Version" value="3.0.0.0" />
  <add key="webpages:Enabled" value="true" />
  <add key="ClientValidationEnabled" value="true" />
  <add key="UnobtrusiveJavaScriptEnabled" value="false" />
  <add key="app:RequireSsl" value="True"/>
</appSettings>

And then reference that key in your [RequireSsl] attribute usage:

[RequireSsl("app:RequireSsl")]
public class AccountController : AppBaseController {…}

Notice that I like to use an app: prefix for my application specific settings to keep them easily recognizable from all the stuff that ASP.NET MVC dumps into app settings these days.

String ‘Delegate’

Personally I really don’t like to use appSettings for a number of reasons. Rather I tend to store my configuration setting in a configuration class. In order to get the value from my configuration class I can use the ‘delegate’ implementation. To use it I can create a custom static method in my application somewhere:

public class App
{

public static bool GetRequireSsl()

{ return App.Configuration.RequireSsl; }

}

In my apps I tend to have an App object that’s sort of a global ‘miscellaneous’ object. Among other things I have static configuration settings, global constants, some reusable look up lists and other stuff attached to it typically. Since the SSL delegate falls under ‘miscellaneous’ stuff this seems like a good place for hooking the method there. The method simply returns a simple configuration value from my configuration object.

To hook this up to the controller I can now do this:

[RequireSsl(typeof(App), "GetRequireSsl")]
public class AccountController : AppBaseController

The ‘delegate’ implementation uses reflection trying to invoke the method on the static type by using GetMethod() and invoking the static method directly. This is where ‘magic strings’ comes in – if the method is mistyped or has an error your code will blow up. This is pretty hacky, but I found this useful to hook up to arbitrary application logic without having to always add a custom Attribute to each project.

And voila we now have a lot more options for dynamically setting our SSL options at runtime.

RequireSsl fires only once per Controller/Method

While playing around with this I noticed that RequireSslAttribute is only called once for each controller or method that it’s attached to per Application domain life time. It appears that the attribute is instantiated once and then cached for further usage so the constructors only fire once for each controller/method. This means that although the delegate implementation uses Reflection performance is not an issue since there’s only one invocation per attribute usage.

Apply to Attributes in  General

The lack of dynamic assignment to attributes is something that I’ve often struggled with and the concepts described here can be used for other attributes as well. Essentially you can always create custom attributes that take in string parameters and then either read values from configuration or allow some sort of delegate process to call off and read additional information at runtime as I’ve done with the ‘delegate’ implementation. There are lots of use cases for this and I’m pretty sure I’ll use this for other attributes in the future.

Resources

Posted in ASP.NET  MVC  Security  

The Voices of Reason


 

Joshua Kincaid
June 18, 2014

# re: A dynamic RequireSsl Attribute for ASP.NET MVC

What is stopping you from using a IOC Container in your attribute constructors and resolve a interface to a concrete implementation that knows how to access you configuration settings. In this way you could store the settings anywhere.

Diego Mijelshon
June 18, 2014

# re: A dynamic RequireSsl Attribute for ASP.NET MVC

Interesting approach. For a simpler site-wide configurable forcing of https we are using this transform:
  <system.webServer>
    <rewrite xdt:Transform="Insert">
      <rules>
        <rule name="Force HTTPS" enabled="true">
          <match url="(.*)" ignoreCase="false" />
          <conditions>
            <add input="{HTTPS}" pattern="off" />
          </conditions>
          <action type="Redirect" url="https://{SERVER_NAME}/{R:1}" appendQueryString="true" redirectType="Found" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>

Steven
June 18, 2014

# re: A dynamic RequireSsl Attribute for ASP.NET MVC

Another option to allow more dynamic registration would be to inject the attribute with a DI framework. Containers like Ninject support lamba expressions for specifying when certain types are injected versus not injected.

kernel.BindHttpFilter<MyAttribute>(FilterScope.Controller).When(f => SomethingIsTrue());

Rick Strahl
June 18, 2014

# re: A dynamic RequireSsl Attribute for ASP.NET MVC

@Joshua, Steven - yes DI would do the trick as well, but I don't want to solely depend on IOC to have this work. Good point though - adding an injectable interface might be another good constructor to add.

@Steven - hmm, a selective injector might produce some funky behavior. You'd have to always inject in order to get consistent result me thinks.

@Diego - Excellent point about UrlRewrite. This works wonderfully if you do site wide SSL translation. I do like the idea though of having the control inside of the application to specify what gets pushed to ssl and what doesn't. Some of the things we do is have configuration that can be changed at runtime by an admin user - that'd be more difficult to do with Rewrite rules since they're not part of the application and you'd have to write out XML by hand. Definitely a good choice in some scenarios though - and it's also one of the most performant ones. Rewrite would also allow doing away with the POST limitation.

John
June 18, 2014

# re: A dynamic RequireSsl Attribute for ASP.NET MVC

My the same approcach (very similar implementation) is already used in nopCommerce

Rick Strahl
June 28, 2014

# re: A dynamic RequireSsl Attribute for ASP.NET MVC

@Steven - After the comments here I took a quick look to see what's involved in using IOC with a filter and it looks like doing IOC with a filter would be pretty tough to do *generically*.

Looking at some of the threads on StackOverflow it appears that constructor injection in general doesn't work - you need to use property injection at which point you start depending on specific IOC container dependencies to mark the property as injectable.

Has anybody done something along these lines? How would you create a generically injectable attribute that works with any IOC container for a filter?

Davide
November 14, 2014

# re: A dynamic RequireSsl Attribute for ASP.NET MVC

Hi Rick,

I used your solution modifying it a little bit to my project. I think you missed how to use a custom SSL port on development machine. After spending a few hours googling, I found out here a solution http://stackoverflow.com/questions/7104703/how-to-specify-a-different-port-with-the-requirehttps-attribute-in-mvc3. I applied a rewrite url in web.config.

Cheers,
Davide

Tim
March 22, 2015

# re: A dynamic RequireSsl Attribute for ASP.NET MVC

Hi Rick,

We use this little trick when decorating classes/methods:

#if !DEBUG
[RequireHttps]
#endif

public ActionResult MyAction()
{
...
}


For those not familiar, this uses the debug flag set up against the project configuration in Build tab. 'Define Debug constant'. You can configure whether the flag is set or not for each project build profile.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024