using System; using System.Reflection; using System.Security.Principal; using System.Web; using System.Web.Security; namespace Neo.Afx.Security { /// /// Allows for two-Level authentication with Forms Authentication and Windows Authentication in IIS 7. /// /// See http://mvolo.com/blogs/serverside/archive/2008/02/11/IIS-7.0-Two_2D00_Level-Authentication-with-Forms-Authentication-and-Windows-Authentication.aspx /// /// public class FormsAuthModule : IHttpModule { bool _enabled; FormsAuthSettings _config; FormsAuthenticationModule _module; MethodInfo _onEnter; MethodInfo _onLeave; /////////////////////////////////////////////////////////////////////////////////////////////// // IHttpModule methods /////////////////////////////////////////////////////////////////////////////////////////////// #region Dispose /// /// Disposes of the resources (other than memory) used by the module that implements . /// public void Dispose() { _module.Dispose(); _module = null; GC.SuppressFinalize(this); } #endregion #region Init /// /// Initializes the object. /// /// The current instance. public void Init(HttpApplication app) { _module = new FormsAuthenticationModule(); using(var application = new HttpApplication()) { _module.Init(application); } var type = _module.GetType(); _onEnter = type.GetMethod("OnEnter", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(object), typeof(EventArgs) }, null); _onLeave = type.GetMethod("OnLeave", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(object), typeof(EventArgs) }, null); if((_onEnter == null) || (_onLeave == null)) { throw new Exception("Unable to get all required FormsAuthenticationModule entrypoints using reflection."); } app.AuthenticateRequest += OnAuthenticateRequest; app.PostAuthenticateRequest += OnPostAuthenticateRequest; app.EndRequest += OnEndRequest; } #endregion /////////////////////////////////////////////////////////////////////////////////////////////// // Custom event handlers methods /////////////////////////////////////////////////////////////////////////////////////////////// void OnAuthenticateRequest(object source, EventArgs e) { var application = (HttpApplication)source; var context = application.Context; _enabled = false; _config = FormsAuthSettings.GetSection(context); if(_config != null && _config.IsEnabled) { _enabled = true; _onEnter.Invoke(_module, new[] { source, e }); } } void OnEndRequest(object source, EventArgs e) { if(_enabled) { _onLeave.Invoke(_module, new[] { source, e }); } } void OnPostAuthenticateRequest(object source, EventArgs e) { var application = (HttpApplication)source; var context = application.Context; if(!_enabled && context.User == null) { var logonUserIdentity = context.Request.LogonUserIdentity; if(logonUserIdentity != null) { context.User = logonUserIdentity.IsAnonymous ? new WindowsPrincipal(WindowsIdentity.GetAnonymous()) : new WindowsPrincipal(logonUserIdentity); } } } } }