Hello,
I am attempting to develop an IIS Authentication Module using C# code (testing on Windows SBS 2011).
The sole purpose of the module is to perform authentication using a custom HTTP header.
Based on the contents of this custom header, a user is authenticated by creating a Principal and assigning it to the "User" attribute of the current HttpContext.
My current code actually works perfectly fine against a helloworld-type test web app : I send a HTTP request using the previously-mentioned custom HTTP Header, the module produces a Principal and the webapp can access it through System.Web.HttpContext.Current.User.Identity.Name and System.Web.HttpContext.Current.User.Identity.IsAuthenticated (which returns true).
Surprisingly, when using the same module for Outlook Web Access (OWA), an error is reported by OWA in the web page : "Outlook Web App didn't initialize. If the problem continues, please contact your helpdesk.", with no additional information. Windows event viewer on the server shows no message relating to this.
Information about the code
Initialization is very simple, I just attach my methods to the "AuthenticateRequest" and "EndRequest" events:
// Init (IHttpModule Implementation) public void Init(HttpApplication ctx) { // Register Events ctx.AuthenticateRequest += new EventHandler(this.Authenticate); ctx.EndRequest += new EventHandler(this.IssueAuthChallenge); }
The code for the authenticate method is as follows :
// Authenticate User public void Authenticate(Object src, EventArgs e) { // Acquire Source and Context HttpApplication app = (HttpApplication)src; HttpContext ctx = app.Context; // Acquire Client Certificate HttpClientCertificate client_cert = ctx.Request.ClientCertificate; String client_cn = client_cert.Get(ClientCert_SubjectCN); // Acquire Authentication Headers String username = ctx.Request.Headers[HttpHeader_AuthUsername]; // Drop Invalid Requests if((username == null) || (!(client_cert.IsPresent))) { return; } // Check Client Certificate CN if(client_cn != AllowedClientCN) { return; } // Check Group Membership if(!(AD.isMemberOf(ActiveDirectoryDomain, username, AuthGroup))) { return; } // Authentication Passed - Register User Principal
IPrincipal principal = new GenericPrincipal(new GenericIdentity(username), new String[] { AuthGroup });
HttpContext.Current.User = principal;
ctx.User = principal;
Thread.CurrentPrincipal = principal;}
EndRequest event is handled as follows :
// Issue Auth Challenge public void IssueAuthChallenge(Object src, EventArgs e) { // Acquire Source and Context HttpApplication app = (HttpApplication)src; HttpContext ctx = app.Context; // Issue Authentication Header ctx.Response.AddHeader(HttpHeader_AuthRequired, "Authentication Required"); // Drop WWW-Authenticate Header ctx.Response.Headers.Remove(HttpHeader_WWWAuthenticate); // Redirect to Authentication Area ctx.Response.StatusCode = HttpStatusCode_Found; ctx.Response.AddHeader(HttpHeader_Location, AuthLocation); }
Finally, here are the global definitions referenced throughout the code :
// Active Directory Domain public const String ActiveDirectoryDomain = "FOODOM"; // Allowed Client CN (Reverse-Proxy) public const String AllowedClientCN = "FooCertName"; // Authentication Authorized Group public const String AuthGroup = "FooAuthAllowed"; // Authentication Custom HTTP Header Base public const String HttpHeader_AuthBase = "X-FooAuth"; // HTTP WWW-Authenticate Header public const String HttpHeader_WWWAuthenticate = "WWW-Authenticate"; // HTTP Location Header public const String HttpHeader_Location = "Location"; // Client Certificate Fields public const String ClientCert_SubjectCN = "SUBJECTCN"; // Authentication Custom HTTP Headers public const String HttpHeader_AuthRequired = HttpHeader_AuthBase + "-Required"; public const String HttpHeader_AuthUsername = HttpHeader_AuthBase + "-Username"; // HTTP Status Codes public const int HttpStatusCode_NotAuthorized = 401; public const int HttpStatusCode_Found = 302; // Authentication Area public const String AuthLocation = "/FooAuth";
After spending many hours fiddling with the IIS settings (mostly authentication and SSL options) I simply do not understand why OWA throws an error when my test app works fine. Are there any specifics that need to be performed to allow OWA to authenticate ?
- Edited by Void.Ptr Monday, July 20, 2015 9:51 AM