Tuesday, June 26, 2007

Dual (or Mixed) Mode Authentication with ASP.NET

On my current project, I was faced with the requirement to allow user logged-in on a the same domain as the server where the web application would run to use Integrated authentication, while at the same time supporting forms-based logins for users who did not have domain accounts. Users will always be directed to the same landing page when they are properly logged in.

I'm not going to explain why this work, or how it works, just what I did. I believe this solution is the simplest one you'll find if your requirements are the same as the above. This is not a general solution by any means, given the assumptions I am making.

Here's the basic idea. You're application will be configured to use Forms-based Authentication. You'll implement some strategy for determining if the request is coming from a domain user, if so you'll redirect them to a page that leverages Integrated authentication in IIS, otherwise they'll just do a normal form-based login. The Integrated authentication page will simply issue a Forms-based authentication ticket (via the ASP.NET FormsAuthentication API) and redirect the user to the landing page. Once you have an authenticated user, in either scenario, you will map that user to a logical (business-layer) User object in your application.

Essentially, you need to decouple your authentication mechanism from the logical user that you track in your application. Note that this does not preclue you from using the default Profile provider, since you are still issuing a Forms Auth ticket.

Here's what I did, specifically.

  1. Configure the web.config to use Forms-based authentication.
  2. Create a sub-folder called "Auth" and configure a web.config there to allow anonymous access to all files in that directory. This is crucial.
  3. Create two pages in the Auth directory: WebLogin.aspx and WinLogin.aspx.
  4. Configure the root web.config to use "~/Auth/WebLogin.aspx" for the forms authentication url.
  5. Build WebLogin.aspx as a normal forms authentication page, but add code to the Load event handler to check the IP address of the incoming request. If it is a domain user, redirect them to the WinLogin.aspx.
  6. In IIS, disable anonymous authentication and enable Integrated Windows authentication for the WinLogin.aspx page.
  7. In the Load event handler for the WinLogin.aspx, create a Forms Auth ticket for the logged in user.
That's the basic idea. You can use the Profile object for some light personalization, but if you need to do any auditing or authorization, you'll want to have a logical user object that you construct using either a Guid (Forms authentication) or a SID (Windows authentication).

At some point I will update the blog with a detailed implementation guide. For now, I hope this sets someone on the right track. For me, the conceptual block-buster was realizing I could make a proactive choice about how to authenticate the user, using their IP address.