Skip to content
This repository has been archived by the owner on Nov 22, 2018. It is now read-only.

Cookie header request example #83

Closed
Basewq opened this issue May 25, 2016 · 15 comments
Closed

Cookie header request example #83

Basewq opened this issue May 25, 2016 · 15 comments
Labels
Milestone

Comments

@Basewq
Copy link

Basewq commented May 25, 2016

I looked at the AntiforgerySample but I'm still confused how this works in an Angular SPA environment (where the majority of [ValidateAntiforgeryToken] is declared on the backend WebApi in my project).
I have followed the same as the sample, but I will also note I have added Identity, which I think also adds the Antiforgery service for itself(?).

I have done a login page and a logoff page, where the cshtmls are 'dumb' and I have HttpPost methods LogIn and LogOff [ValidateAntiforgeryToken] as WebApi methods that the angular controller calls.
The first time it generates the token and I can successfully log on in the Login page.
However, any subsequent WebApi calls that have [ValidateAntiforgeryToken] (eg. my LogOff WebApi method), I keep getting The provided antiforgery token was meant for a different claims-based user than the current user.
Looking at Fiddler, I see 3 cookie tokens sent on request (each with different values):
.AspNetCore.Antiforgery.xxxx
.AspNetCore.Identity.Application
XSRF-TOKEN

Am I missing something in my case? Do I need to override how the validation is working?

@rynowak
Copy link
Member

rynowak commented May 25, 2016

You'll need to send the client a new tokenset when they log in. The tokenset always has some embedded data that identifies the user. When the user is anonymous we just use a random token. When the user is logged in, we generate the token set based on their claims.

Our XSRF system uses two tokens. One of them goes in the .AspNetCore.Antiforgery.xxxx cookie, and will be automatically sent back by the browser. The other one can go in either form data for the request headers.

I looked at the AntiforgerySample but I'm still confused how this works in an Angular SPA environment

Angular's docs explain this in more details https://docs.angularjs.org/api/ng/service/$http (ctrl+F for XSRF-TOKEN) - but basically when Angular sees a cookie with the name XSRF-TOKEN it will send the value of that cookie back with all ajax requests it does in the header value X-XSRF-TOKEN.

So the XSRF-TOKEN value is only used to send one of the tokens to the client. ASP.NET will never read or validate the XSRF-TOKEN cookie. Notice that setting this cookie value is part of the sample, and isn't done by any ASP.NET infrastructure.

The .AspNetCore.Antiforgery.xxxx cookie is what we're looking for, we're going to validate this value in combination with the value of the header X-XSRF-TOKEN.

The .AspNetCore.Identity.Application is the cookie that carries your identification token and as is only used by Identity.

@rynowak
Copy link
Member

rynowak commented May 25, 2016

/cc @blowdart in case he wants to add anything

@Basewq
Copy link
Author

Basewq commented May 25, 2016

Thanks @rynowak, it's a bit clearer now.
It looks like in my project my Identity authentication isn't persisting (for different reasons) so it doesn't create the correct token set. I think once I figure that out the tokens should behave properly.

@rynowak
Copy link
Member

rynowak commented May 25, 2016

Are you generating the new token set as part of the response right when the user logs in?

You might need to add a call to AuthenticateAsync if you're doing that, because I know Antiforgery uses the principal on HttpContext. https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Core/Authorization/AuthorizeFilter.cs#L55

/cc @HaoK

@Basewq
Copy link
Author

Basewq commented May 25, 2016

No I'm not. I'm using ui-router to change pages, so I thought it'll be recreated in the middleware section.
Debugging the code I see the middleware doesn't have the authenticated principal, however I think it's because it's still thinking it's part of the original http context (or something like that...). I think this is an issue with my code with angular rather than a fault with antiforgery or asp.

@Basewq
Copy link
Author

Basewq commented May 25, 2016

EDIT: Ok problem still exists. I've been messing with AutoValidateAntiforgeryTokenAttribute, then tricked myself thinking it was fixed when I disabled it.

ORIGINAL POST:
Ok, no problem anymore. I did not realize the custom UserStore I was using was a factor in the Identity issue. I was missing an IUserSecurityStampStore interface implementation otherwise it was logging me out immediately after signing in, and so the token was recreated for an unauthenticated user.

@HaoK
Copy link
Member

HaoK commented May 25, 2016

You can also try explicitly disabling the cookie security stamp validation to confirm that it isn't the issue by removing the OnValidatePrincipal that is added by default:

IdentityOptions.Cookies.ApplicationCookie
                Events = new CookieAuthenticationEvents
                {
                    OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
                }
            };

@Basewq
Copy link
Author

Basewq commented May 25, 2016

@HaoK Sorry, I'm not quite sure what you're saying.
I set a dummy func in place of the OnValidatePrincipal since you can't null it. It appears CookieValidatePrincipalContext.Pricipal has the authenticated user, but the CookieValidatePrincipalContext.HttpContext.User does not.
Does this say something?

@HaoK
Copy link
Member

HaoK commented May 25, 2016

Have you tried turning on logging and seeing if any interesting failures come out?
In general if CookieValidatePrincipalContext has the authenticated user, and you successfully remove the Validation, it should flow through.

Is AutomaticAuthenticate set to true for your cookies?

@Basewq
Copy link
Author

Basewq commented May 25, 2016

I've got logging on Debug level.
Other than the already mentioned The provided antiforgery token was meant for a different claims-based user than the current user. there's no failures.
Not sure if HttpContext.User merged via AutomaticAuthentication from authenticationScheme: "Identity.Application". counts as interesting?

I haven't set AutomaticAuthenticate, but I'll try setting it. Note that I didn't try any of these cookies settings since I didn't see them in the Sample.

EDIT: OK, so AutomaticAuthenticate = true hasn't changed anything.

@HaoK
Copy link
Member

HaoK commented May 25, 2016

Okay sounds like this is really an antiforgery issue.

@rynowak
Copy link
Member

rynowak commented May 25, 2016

@HaoK he needs to update the principal after login so that AF will generate the right token. GetAndStoreTokens doesn't let you provide a principal

In a normal MVC non-ajax flow you'd get redirected after login so the next request which is a GET generates a new token because you have the updated logged-in principal.

@kichalla - you were interested in this, want to see if you can come up with a quick sample or retrofit this on the current sample?

@Basewq
Copy link
Author

Basewq commented May 25, 2016

Thanks for everyone's help. It seems I made a grave error.
I just needed to move the middleware code after app.UseIdentity(); in Startup.Configure.
Having it after UseIdentity meant the Identity would set the authenticated principal for the middleware to use.
I'm double checking to make sure this is correct and I didn't accidentally disable something!

@rynowak
Copy link
Member

rynowak commented May 25, 2016

Yeah that would do it! Seems right to me. Glad we we able to help.

@Basewq
Copy link
Author

Basewq commented May 25, 2016

Great. It's working. Thanks again everyone!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants