Search code examples
securityumbracoelmah

How to secure the ELMAH web console in Umbraco?


How can requests to /elmah.axd be limited to an Umbraco admin user.

It is my understanding that the Umbraco membership and role providers apply to Umbraco Members but not Users -- Umbraco user accounts do not appear to have a user name or role (e.g. "Admins") that could be used in the web.config like this:

<location path="elmah.axd">
  <system.web>
    <authorization>
        <allow roles="Admins" />
        <deny users="*" />
    </authorization>
  </system.web>
</location>

This is a recommended way of securing ELMAH in other ASP.Net applications.

Anyone done this in Umbraco?


Solution

  • I solved the problem by creating an HTTP module to intercept requests to elmah.axd, and authorize only Umbraco administrators to view it. Heres the module code:

    namespace MyNamespace
    {
        using System;
        using System.Configuration;
        using System.Web;
        using System.Web.Configuration;
    
        using umbraco.BusinessLogic;
    
        public class ElmahSecurityModule : IHttpModule
        {
            private HttpApplication _context;
    
            public void Dispose()
            {
            }
    
            public void Init(HttpApplication context)
            {
                this._context = context;
                this._context.BeginRequest += this.BeginRequest;
            }
    
            private void BeginRequest(object sender, EventArgs e)
            {
                var handlerPath = string.Empty;
    
                var systemWebServerSection = (HttpHandlersSection)ConfigurationManager.GetSection("system.web/httpHandlers");
    
                foreach (HttpHandlerAction handler in systemWebServerSection.Handlers)
                {
                    if (handler.Type.Trim() == "Elmah.ErrorLogPageFactory, Elmah")
                    {
                        handlerPath = handler.Path.ToLower();
                        break;
                    }
                }
    
                if (string.IsNullOrWhiteSpace(handlerPath) || !this._context.Request.Path.ToLower().Contains(handlerPath))
                {
                    return;
                }
    
                var user = User.GetCurrent();
    
                if (user != null)
                {
                    if (user.UserType.Name == "Administrators")
                    {
                        return;
                    }
                }
    
                var customErrorsSection = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");
    
                var defaultRedirect = customErrorsSection.DefaultRedirect ?? "/";
    
                this._context.Context.RewritePath(defaultRedirect);
            }
        }
    }
    

    ...and the web.config:

    <configuration>
        <system.web>
            <httpModules>
                <add name="ElmahSecurityModule" type="MyNamespace.ElmahSecurityModule" />
            </httpModules>
        </system.web>
        <system.webServer>
            <modules runAllManagedModulesForAllRequests="true">
              <add name="ElmahSecurityModule" type="MyNamespace.ElmahSecurityModule" />
            </modules>
        </system.webServer>
    </configuration>