Today I’ve pushed the next version of Hangfire project that allows to process background jobs inside ASP.NET applications in a reliable way.

Although this release contains only one new feature that is visible for all users (security improvements), it brings Hangfire closer than ever to the version 1.0. But let’s see the new changes.

Note. The conceptual part of the following information is correct, but implementation details changed since version 1.0. Please, see the documentation instead of relying this information.

Remote requests are denied by default

Hangfire has integrated monitoring system that shows you information about background jobs and acts as an ASP.NET’s IHttpHandler. Registration is performed by automatically changing the web.config file during the installation of the Hangfire.Web package (it is a dependency of Hangfire bootstrap package) by NuGet Package Manager.

This HTTP handler displays the internals of your application. Furthermore it offers to interact with this internal state: background jobs can be retried, possibly removed, scheduled earlier than necessary and so on. What if it become available for malicious users? It is hard to guess the actual consequences for a wide range of applications, but it is simple to understand that this behavior is highly undesirable.

The automatics greatly simplifies the installation process, but performs it on the quiet, making it simple to overlook that Monitor handler is ever exist or requires additional set-up. So, it is required to provide strong rules that work by default.

To solve this problem, we need to authorize users. ASP.NET applications have authorization feature by default, that is based on user names or their roles. But it is impossible to guess what user names and roles uses your ASP.NET application (if your application uses them at all). So, we need more simple solution.

The simplest solution is to block all remote requests by default using the Request.IsLocal property. Local requests are accepted as usually, and this decision does not bring problems for application developers. Another libraries, such as Elmah or Glimpse are also using this authorization policy by default.

The policy can be configured from the appSettings section of web.config file – I don’t want to introduce separate configuration section for a single setting.

Disable remote access to Hangfire Monitor (by default):

<appSettings>
  <!-- You can also remove this line to keep the default settings -->
  <add key="hangfire:EnableRemoteMonitorAccess" value="false"/>
  ...
</appSettings>

Enable remote access to Hangfire Monitor:

<appSettings>
  <add key="hangfire:EnableRemoteMonitorAccess" value="true"/>
  ...
</appSettings>

Granting or denying access via ASP.NET authorization

Remote Monitor access policy is good. But once your application is deployed to production environment, you need to be able to access Monitor, otherwise it is useless.

Elmah library author and contributors conducted a deep investigation on a topic and proposed the solution to provide use ASP.NET authorization for such registered handlers:

  1. The handler registrations need to be moved under the location tag. Having them outside does not secure access sufficiently.
  2. The location element’s path attribute carries the same value as the path attribute of the handler registrations. Unfortunately, it has to be repeated so if you change one, the others must be updated to match.
  3. The authorization element is where the authorization rules go and where you will want to selectively grant access.

So, starting from this version, Hangfire Monitor HTTP handler is registered under the location tag:

<location path="hangfire.axd" inheritInChildApplications="false">
  <system.web>
    <authorization>
      <deny users="*" />  
    </authorization>
  </system.web>
  <system.webServer>
    <handlers>
      <add name="Hangfire" path="hangfire.axd" verb="*" type="Hangfire.Web.HangfirePageFactory, Hangfire.Web" />
    </handlers>
  </system.webServer>
</location>

The configuration example above denies access to all users, but that is a good starting point. You will probably want to add rules that allow access to only specific users and/or roles. For example, you might have a role for administrators and developers called admin and dev, respectively. To allow users that are members of either role, you could configure the authorization section above as follows:

<authorization>  
  <allow roles="admin" />  
  <allow roles="dev" />  
  <deny users="*" />  
</authorization>

But to enable these rules, you need to set-up ASP.NET Authentication using, for example, the new and shining ASP.NET Identity project.

Moving closer to 1.0

This version contains 300+ new unit tests, their total number is 550, and the test coverage of Hangfire.Core.dll is 99%. Although this does not say that Hangfire is 100% bug-free, this is an indicator of the fact that the most code is tested and it is fully unit testable. New features can be added much faster. To do this, I’ve completely rewritten the Server subsystem that resulted in a more clean application model.

Full unit testability was one of the goals I wanted to achieve, and the fact that it requires a lot of breaking changes stopped me even to think about production-ready version. I want to use semantic versioning and do not want to have Hangfire 28.0 in a few months.

Now I’ve started to think about production readiness, but I need a lot of feedback to give any stability guarantees.

Recently I’ve launched a new forum for Hangfire to replace unnoying (for me) Google Groups – https://discuss.hangfire.io. It is modern, clean and easy to use, based on Discourse. So, have ideas or problems? Let’s discuss!

Subscribe to monthly updates

Subscribe to receive monthly blog updates. Very low traffic, you are able to unsubscribe at any time.

Comments