Mixing Forms Based and Windows Authentication In ASP.NET
To start off this blog with some usefull information, I´m going to explain how to develop an ASP.NET 2.0 web application which has both forms authentication and Windows authentication enabled.
Let’s say we’re developing a web application which will be running on our local intranet. There’s a pretty good chance that same intranet will have a domain and thus a domain server, which in this case will be a Microsoft Active Directory. Now, after our user has logged in to his (or her) computer, we don’t want to bother him with credentials any more. He provided the correct password to get into the machine, so he’s trusted from that point on.
So far, so good: ASP.NET has Windows based authentication which allows us to use the current Windows account logged onto the computer. Works great in IE since IE is going to send those credentials by itself (and if it isn’t; add the site to your ‘trusted sites’ zone), a little less great in other browsers such as FireFox; those will still provide a login box but the user may enter his normal AD credentials and log in anyway.
For more information about setting up a web application for Windows authentication; please check out Scott Guthrie’s recipe for that.
Now we’ll take it one step further and make our application available online so our users can log in from their own homes. But hey; the Windows account is probably not a user in our Active Directory, so authentication will fail, right? Okay no problem: the login box will pop-up and ask our user for proper authentication. After providing this all is well again, at least from a logging-in point of view.
Okay, so what’s the actual problem here you might wonder. Well, I didn’t really want to use those ugly pop-up boxes asking for authentication; so that’s where Forms Authentication comes in bringing a few problems with it. Why? Because ASP.NET doesn’t support mixed mode authentication so we’ll have to provide a way to do this ourselves.
There are some solutions for this problem mentioned here, here and here. They seem to revolve around a few things like global.asax functions and placing (custom) authentication cookies. But guess what: all of that work isn’t necessary! I got it working by combining standard ASP.NET authentication and IIS features and a very small piece of code! Neat right? So let’s dive into the steps I’ve taken!
1. Set up your application for working with forms based authentication. You can do that by including the <authenticationmode=“Forms“> tag in the system.web section of your Web.config file; check out 15 seconds for more info.
2. Deny access to your web application for anonymous users by including
In the system.web section of your Web.config file.
3. Create 3 files: Login.aspx, WebLogin.aspx, WinLogin.aspx. These will be the only 3 files which can be accessed without any credentials. You can allow anonymous access through your Web.config like this:
The Login.aspx file will have anonymous access enabled by default.
4. The login.aspx file will serve all incoming authentication requests by default. The page actually requested will be added to the URL in the ReturnUrl request parameter. Now, we have to redirect the authentication request based on some conditions:
– Internal users user IE will be redirected to WinLogin.aspx
– External or non-IE users will be redirected to WebLogin.aspx
The following code (placed in the codebehind file of Login.aspx) is enough to check if the user is on our local domain (via IP) and is using IE or not. There’s probably a nicer way of checking the IP, but this does the trick.
protected void Page_Init(object sender, EventArgs e)
string userIP = Request.UserHostAddress;
string serverIP = Request.ServerVariables[“LOCAL_ADDR”];
userIP = userIP.Substring(0, userIP.LastIndexOf(‘.’));
serverIP = serverIP.Substring(0, serverIP.LastIndexOf(‘.’));
// only redirect to WinLogin.aspx if user is internal & IE
if (userIP.Equals(serverIP) && Request.Browser.IsBrowser(“ie”))
The actual Login.aspx file itself can remain empty, because the user will be transferred to another page before its output anyway; though you might want to put in some kind of redirecting message just in case.
5. The WebLogin.aspx page will be set up as a usual forms authentication page, having a Login control and maybe a ValidationSummary control for listing possible errors. The only thing you have to do is make sure the user is redirected to the correct page after logging in. That’s done in the LoggedIn event of the Login control:
protected void _Login_LoggedIn(object sender, EventArgs e)
string ReturnUrl = (Request.Params[“ReturnUrl”] != null) ?
Request.Params[“ReturnUrl”] : FormsAuthentication.DefaultUrl;
// redirect user to the correct page; don’t use Server.Transfer because
the identity won’t be set yet
Off course you could implement your own authentication method for checking the users credentials, but that’s up to you; default behavior worked just fine for me.
6. Now for the WinLogin.aspx file. Firstly, we need to make sure IE is going to send us the username of the user logged onto the computer. That’s achieved by editing the security settings in IIS for only the WinLogin.aspx file, not the entire site! Disable all access methods except ‘Integrated Windows Security’ because they won’t be needed for this file.
Now the only thing we have to do is to convert the username into a valid authentication ticket. Fortunately ASP.NET is going to do that for us with a single method we can call:
protected void Page_Init(object sender, EventArgs e)
string userName = this.Request.ServerVariables[“LOGON_USER”];
userName = userName.Substring(userName.LastIndexOf(‘\\’) + 1);
FormsAuthentication.RedirectFromLoginPage(userName, true, “/”);
As you can see I strip the domain prefix because I use SAMAccountName for the userNameAttribute property of my provider, but if you don’t (by default you don’t), just leave the domain attached.
7. No wait… there is no 7! That’s it!
So there you have it, some quite simple steps which enable you to set up a mixed mode authentication, handling internal and external users as well as different browser types quite nicely. It’s all based on out-of-the-box functionality, so you can just use the standard MembershipProvider and RoleProvider classes available in ASP.NET. For question or comments, please use the reactions to this blog post.
PS: I have quickly tested this method to make sure it actually works. I found out the Windows identification and impersonations works really great on Windows 2003 Server, but I did have some difficulties running it on my local Windows XP computer. So watch out for that and when you have a solution: please post it in the reactions section.