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.

Published Monday, February 02, 2004 9:54 AM by PaulWilson

Comments

# re: Mixing Forms and Windows Security in ASP.NET

Monday, February 02, 2004 9:55 AM by TrackBack

# re: More Forms and Windows Security in ASP.NET

Thanks for the update to an already nice job.

Monday, February 02, 2004 3:54 PM by Tom

# More Forms and Windows Security in ASP.NET

Monday, February 02, 2004 9:25 PM by TrackBack

# More Forms and Windows Security in ASP.NET

Monday, February 02, 2004 9:26 PM by TrackBack

# Using Forms Authentication with Windows Authentication (

Using Forms Authentication with Windows Authentication (

Friday, November 05, 2004 2:55 PM by TrackBack

# Using Forms Authentication with Windows Authentication (

Thursday, March 10, 2005 8:59 AM by TrackBack

# Using Forms Authentication with Windows Authentication (

Thursday, March 10, 2005 9:31 AM by TrackBack

# re: Forms and Windows Security in ASP.NET

Paul, Really nice article on MSDN. However due to my lack of exposure in httpContext / identity area I am not able to "plug in" returnUrl in redirectFromLogin method. what code exactly should be written in global.asax, what should go in webLogin.aspx.cs? how can I store a querystring["ReturnUrl"] even before page_load of winLogin.aspx? Could you give a brief idea?

Friday, July 14, 2006 1:48 PM by AG

# re: More Forms and Windows Security in ASP.NET

Have you not looked at the code in the download that accompanies the article? If the download isn't working for you then you'll need to contact me directly via email so that I can send you the code. Thanks, Paul Wilson

Friday, July 14, 2006 1:53 PM by PaulWilson

# re: More Forms and Windows Security in ASP.NET

Paul, I just download the code, compile it and push it on an IIS6 server in domain. I followed the differents configuration instructions. And put the redirect401.htm file in the custom erors of winlogin.aspx. From a domain computer, it works fine, i have my domain user. But outside of the domain, the windows authentication dialog shows up. If i hit cancel i am then redirected to the weblogin.aspx. So the question is how to get rid of the windows authentication form ? Any idea ?

Friday, August 25, 2006 10:30 AM by Jean Marie

# re: More Forms and Windows Security in ASP.NET

Its a browser configuration option if you have that issue -- its not something you can get rid of just in code.  I believe the details involved changing the security zone for that url to be intranet instead of internet, but I can't recall completely.  I never experienced this in my tests, nor did the tester at MS, or we would have mentioned it, but since then its been apparent that lots of people do have this issue.  Making a client browser change may make this unworkable for most people, and that's fair enough, as this really was just a hack of last resort and not something I wanted to do.

Friday, August 25, 2006 2:01 PM by PaulWilson

# re: More Forms and Windows Security in ASP.NET

Hello,

Thanks for your article and code. However, I have been unable to get your technique of storing user tokens in cookies and then recreating windowsidentities from them on later requests to work. Is this technique platform specific? (IIS X, WindowsXX) I'm beginning to think it's not possible to store the token alone in order to recreate the WindowsIdentity. The symptoms are rather interesting. I pull the token out on the loading of winlogin.aspx, and store the token in the forms auth cookie. I also go ahead and store the token in a Session variable and also create the WindowsPrincipal object from the token and store it in Session scope. Recasting the WindowsIdentity from the Session scope works perfectly. However, recreating the WindowsIdentity from the token (whether its in Session or FormsAuth cookie) is problematic. The first request seems to always return the WindowsIdentity related to the IUSR_XXX account. Then on subsequent requests (perhaps reauths) it will return the ASPNET account. Then, it will invariably return a "Invalid token for impersonation - it cannot be duplicated. " error when trying to create the WindowsIdentity from the stored token. Debugging the tokens they appear to simply be four digit integers... any idea what their lifespan is? I can't imagine it could be relied on to remain static for the lifespan of the forms auth cookie... I also used your stock code along with your above code and experienced the same issues. Have you successfully used this technique in production? Thanks.

Tuesday, November 21, 2006 2:25 PM by Ryan

# re: More Forms and Windows Security in ASP.NET

Hi Ryan:

The technique presented in the article does NOT recreate Windows identities, so I believe there is a misunderstanding of intent.  Instead, the goal of the article is to show how you can grab the Windows name of the user, if it exists and the browser is setup properly, while still presenting the typical login form otherwise.  In all cases though, the result is ASP.NET Forms security since in the end the ASP.NET infrastructure forces you into one and only one model.  If you actually need Windows identities then you will not be able to combine it with ASP.NET Forms in the same "app" -- you can however create two different "apps" with the same code base with one configured as ASP.NET Forms and one with Windows identities.

Thanks, Paul Wilson

Tuesday, November 21, 2006 2:40 PM by PaulWilson

# re: More Forms and Windows Security in ASP.NET

Hi Paul. I understand your intent in your original article. And it works well which I applaud you for. However, your followup code in this blog post certainly does try to recreate Windows identities for users that previously authenticated via Windows authentication does it not? It is with this followup work that I am having difficulty implementing. You basically store the user's token in a cookie and then use that token to recreate a WindowsPrincipal object in order to populate the Context.Current.User object on subsequent requests. Wasn't the intention there to recreate that user's WindowsIdentity for role checks and try to get the best of both worlds of authentication? I understand it was just a quick example which was probably not thoroughly tested and not included in your original article, which is why I was wondering if you ever used this followup technique in a production environment or ran into the issues I 'm encountering. I apologize if I still misunderstand your intention here. Thanks again.

Tuesday, November 21, 2006 2:59 PM by Ryan

# re: More Forms and Windows Security in ASP.NET

Hi Ryan:

Ah, my apologies as I totally forgot this post was not about my article in any real sense.  So to answer your question, I certainly did not ever use this sample code beyond what was most likely a minimal test, so there may very well be issues that I did not ever notice.

Also, as I've said many times in emails, and I'm pretty sure a couple of places publicly over time too, I was never really happy with any of this.  I was forced to find a combined solution by a manager that refused to listen to  my protests.  Those reasons included that these types of hacks are very brittle -- they require odd IIS settings and even specific browser settings.  The alternatives of just accepting either everyone login, or two separate "apps" with the same codebase that are configured differently, are more than adequate in my opinion.  So why did I write an article that I didn't really like?  Because in the process of doing what I was made to do, I discovered that many others were in similar situations, so I thought it would make a good article.  Anyhow, while I did quite a bit of work and testing to get the main concept in the article, I've never spent any time on this since then -- other than responding to emails which tend to either be "this works great" or "this doesn't work".  :)

Good luck, Paul Wilson

Tuesday, November 21, 2006 3:17 PM by PaulWilson

Leave a Comment

(required) 
(required) 
(optional)
(required)