More Forms and Windows Security in ASP.NET
Ryan Dunn and I have been having a dialog on the ASP.NET Forums about my recent article on Mixing Forms and Windows Security in ASP.NET. He has another technique that attempts to do something similar here on GotDotNet and he very much disagrees that my solution is sufficient. Basically, my solution only demos how to combine Forms and Windows Authentication to automatically capture an Intranet user's name. His method instead combines Forms and Windows Authorization by creating a WindowsPrincipal that roles can be checked against. I apologize if someone thinks I've misled them since my article did not go all the way and illustrate the combined Authorization also, so I'm attaching the small amount of code, based on Ryan's work, that will create the WindowsPrincipal and complete the example.
Please also note that Ryan's technique is not at all sufficient, and is thus very misleading, since it does not actually do any real Windows Authentication! It makes an assumption that all users within a certain IP address range are valid users -- which is not at all true if your network allows visitors to plug into the network and access the Intranet. This means that visitors will automatically get access to your applications that use this technique and don't then check for an additional role. It will also actually prevent such visitors from ever logging in with the alternative custom login form to prove they have the roles in the custom scenario you worked hard to create. So, here's the necessary code, not very “clean” since its just a quick example, to complete my technique by creating a real WindowsPrincipal for Windows users:
Change the entirety of WinLogin.aspx's Page_Load method to:
IServiceProvider service = (IServiceProvider) this.Context;
HttpWorkerRequest request = (HttpWorkerRequest) service.GetService(typeof(HttpWorkerRequest));
this.Response.Cookies.Add(new HttpCookie("UserToken", request.GetUserToken().ToString()));
string userName = this.Request.ServerVariables["LOGON_USER"];
FormsAuthentication.RedirectFromLoginPage(userName, false);
Then add the following to the Global.asax's Application_AuthenticateRequest:
else if (this.Request.Cookies["UserToken"] != null) {
string token = this.Request.Cookies["UserToken"].Value;
IntPtr userToken = new IntPtr(int.Parse(token));
WindowsIdentity identity = new WindowsIdentity(userToken,
"NTLM", WindowsAccountType.Normal, true);
HttpContext.Current.User = new WindowsPrincipal(identity);
}
You can make this “cleaner” (i.e. more secure) by including the userToken into the FormsAuthentication cookie's UserData so that it gets encrypted, instead of being a separate cookie as I've done here.