Closed AdamDotNet closed 7 years ago
So in short, .net 4.7 breaks something related to the anti-forgery token from working in IdSvr3?
Yes, it seems anti forgery token is broken in .net 4.7; specifically, when using hybrid flow with the IE browser control in wpf. Surprisingly, implicit flow in a full browser for website login worked.
Looking at the log, I really think this will end up being an issue for Microsoft. In short, the POST to the login endpoint is not sending the .xsrf cookie for some reason (but it is sending the .SignInMessage oddly enough). It's almost as if we need logs from the embedded IE to know why.
Just FYI, I've been trying to reproduce this some more.
When I tried enacting the hybrid flow using HttpClient instead of a web browser, I noticed that the server simply wasn't sending the cookie, not that IE embedded wasn't passing it back up to the server.
Request /connect/authorize Response 302 + SignInMessage cookie Request /login Response 200 + login HTML (here's where it should also add the xsrf cookie, but isn't) Request to sign in, anti forgery token failure, etc.
So I tried to make a simpler identity server to see if it really is just .Net 4.7 on the server breaking it. I took the "WebHost (minimal)" sample and added a few of my app specific configs and... it just works!
So there are interaction effects with my app compared to a simple app. I'm guessing ideal deployment is the Identity Server bit is its own application in IIS? My company's SSO solution includes a web dashboard, and we ended up making a single MVC app with Identity server and the website as one web application. Part of that was maintaining the same host URL (so account.company.com serves both a web UI and hosts the identity solution at account.company.com/Identity, versus account.company.com and identity.company.com or something like that; I now realize though that it should be possible to do that by putting the identity application inside the main app's virtual directory/application, right?). Another part was sharing Razor layout to ensure consistency with the web portal UI and the sign on page, done by implementing a ViewService and basically pointing it to rendered Razor bytes returned from manually calling the ViewEngine. Have I committed a horrible sin against your tool by doing things this way?
It's a little hard to rip apart my web UI and identity server to see if things start working again, because of the coupled view service, but it's something I'd like to try and find out. .Net 4.7 is clearly part of it, but perhaps my app needs a refactor all the same. The plot thickens.
I have a complete explanation of the problem now.
We have requirements that include showing a different sign in page when signing in as a desktop client versus a web client. The desktop page has both the sign in fields and the registration fields; the user clicks on "already have an account" or "register" in order to sign in or create an account respectively.
Well, the register part has its own anti forgery token. The cookie name is RequestVerificationToken, spawned by using @Html.AntiForgeryToken()
in the razor file. When RequestVerificationToken is present, SA.idsrv.xsrf is not. When I remove my AntiForgeryToken, then SA.idsrv.xsrf will be present.
Because the web client sign in page uses different razor that doesn't include the register part, it just works.
All explained.
I can probably close this question soon, unless you have any suggestions. The last basic question: why does Asp.Net 4.7 choose to only send one anti forgery token header, even though the names do not collide, versus simply sending both like it did in Asp.Net 4.6.x?
The answer could be suck it up, and change my flow ensuring only one anti forgery token is present always; or remove my anti forgery token completely (seems bad); or find out where Asp.Net 4.7 is messing with my cookies.
Hmm, not clue why the Microsoft AF token dynamically shows up. Our implementation is our own and unrelated to Microsoft's. To really understand, I'd likely need to debug thru to the level you have...
Now that I know the cause, I should be able to produce a simple app I can share with you to reproduce it. But I'll have to work on it on Monday.
Code to reproduce the issue has been created.
Ensure MinimalServer is running in IIS Express, then run the unit tests. Only one test can pass at a time because either it has the MVC token but not the idsrv token, or it has the idsrv token because the MVC token is not present. You can toggle the MVC token being present by commenting out this line:
Hey Brock, first I just want to say thank you for the time you have spent on this so far and thank you for IdentityServer3 period!
This scenario probably seems pretty odd, but that's how we've been running for quite some time now. I've tried stepping through it myself and all I can tell is that by the time AuthenticationController.Login
finishes, the IOwinContext.Response.Cookies.Headers
has the right Set-Cookie
for idsrv.xsrf
and then it never reaches clients. System.Web must be eating it... I've used reflection where I could to try and understand System.Web doing cookies, and even tried forcing IdentityServer3 to use System.Web to wire up
But that was to no avail.
Have you had any time to look at this? Have you had any more ideas or luck than me? I might have to start thinking of work arounds, which up to this point has been avoid .Net 4.7... but I think I can come up with more if we really feel like making it work on 4.7 and there is no solution in this layer.
Have you considered updating to IdentityServer4 ?
Yea, prolly something changed in the bowels of System.Web under this release. Wonderful.
@leastprivilege That might indeed be a good solution, but it would be a lot of rewrite on my end to get to Asp.Net Core and friends (but ultimately that would probably be a good thing). Is there an eminent "end of life" or "deprecation" for IdentityServer3 I should be concerned about? As long as I can come up with roughly the same user experience, I think avoiding having an MVC anti forgery token on the same page as your token is probably a small enough change that I can make it work. But if v3 is dead, I have a compelling argument to give to my boss.
Well - all I am saying is that any new feature development will go into 4. We are just a two person team really.
..and your problem would also go away (plus other unforeseen things in the future). Katana is not really the ASP.NET teams's main focus anymore.
Yeah I totally understand and can sympathize that it's just you two and it's one of your older versions that doesn't run on Microsoft's currently developed platform. I'll have to consult my team!
Question / Issue
I have IdentityServer3, Nuget Version 2.6 installed on an Asp.Net MVC 5, .Net 4.6.2 app. Changing nothing other than installing KB3186539 on Windows Server 2012 R2, I was no longer able to sign into our desktop product that uses the WPF browser control (with edge meta tag, so IE 11 on my Windows 10 x64 box). The client is authorized via Hyrbrid flow, client Id/Secret. Through the IdentityServer logging and Fiddler, it looks like cookie "SA.idsrv.xsrf" (SA is my prefix I configured) is not being sent as part of submitting the username/password. Our app sends a sign out request first in order to flush cookies, then the sign in request.
Upon uninstalling KB3186539 (.Net 4.7) on the server, the app could sign in again. The MVC app was compiled for .Net 4.6.2 throughout this whole process. Full web browsers using Implicit authorization flow for signing into websites works fine, mysteriously enough.
The short story of the log file seems to be as the following:
I hope this will help out. It's always a shame when .Net breaks things.
Relevant parts of the log file (I tried to keep this slim, but 610 lines remain)