-
Notifications
You must be signed in to change notification settings - Fork 597
Revisit OAuthAuthenticationHandler and add a new SaveTokensAsClaims option #257
Conversation
@@ -218,7 +215,7 @@ 127.0.0.1 MsSecSample.localhost.this | |||
// Deny anonymous request beyond this point. | |||
app.Use(async (context, next) => | |||
{ | |||
if (string.IsNullOrEmpty(context.User.Identity.Name)) | |||
if (context.User == null || !context.User.Identities.Any(identity => identity.IsAuthenticated)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated change, but I fixed it because the "GitHub-AccessToken" sample didn't work properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
context.User is guaranteed never to be null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah nice, I'll remove the unnecessary check then 😄
@PinpointTownes you do need to sign a .NET Foundation CLA (we just changed the projects from MS Open Tech), but this is the last CLA we plan to have! Also, this new CLA is much simpler and quicker than the previous CLA. Sorry for the hassle! |
@Eilon okay, done (indeed, it was rather quick 😄) (btw, it seems that the Contribution page has not been updated for every branch: https://github.com/aspnet/Home/blob/release/CONTRIBUTING.md#contributing-code-and-content) |
@PinpointTownes sorry that link is out-of-date... I fixed it this morning. You want to use the fully automated system at https://cla2.dotnetfoundation.org/ . |
@PinpointTownes, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR. |
Ah. I had filed the wrong form: https://cla.dotnetfoundation.org/ (the first result on Google...) @dnfclas thanks, dear bot 😄 |
Thanks! BTW I contacted the bot operators to have the CLA sites clarified as to which site is for which. Hopefully they can get that resolved soon! |
@Eilon wonderful, thanks! |
await Options.Notifications.GetUserInformationAsync(context); | ||
return new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme); | ||
|
||
await Options.Notifications.GetUserInformationAsync(notification); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this also be renamed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not necessary but yep, it would be ideal.
How about CreateTicket/OnCreateTicket?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, OnCreateTicket.
Note that the deriving providers just call OnAuthenticated, they don't call this one directly. It would be nice if we could merge the two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how to do that yet. *Authenticated
events expose strongly-typed properties that we couldn't have in the generic CreateTicket
notification.
{ | ||
var context = new OAuthGetUserInformationContext(Context, Options, Backchannel, tokens) | ||
var identity = new ClaimsIdentity(Options.ClaimsIssuer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not opposed to changing this back to AuthenticationScheme if we think that's more appropriate. We don't really use AuthenticationType for anything anymore, other than null or not for IsAuthenticated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, AuthenticationScheme
definitely sounds more appropriate, @Tratcher thinks we should use Options.ClaimsIssuer
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @Tratcher mostly was arguing consistency since I changed everything to use ClaimsIssuer. I recall that was something I questioned myself when doing it, so now is a good time to revisit to make sure we pick the most appropriate one to use...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only because that's what we changed all of the others to. That's a debate I don't want to restart in this PR. If it's out of date file a different bug.
Possibly related: #101 |
@Tratcher I'm testing a new approach that merges Regarding #101, I'll fix it in a future commit, when we're done with the general design. |
/// after a successful authentication. You can set this property to <see cref="false"/> to reduce | ||
/// the size of the final authentication cookie. | ||
/// </summary> | ||
public bool SaveTokensAsClaims { get; set; } = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this really be enabled by default? It's not needed in the default app flow, and we're already having major cookie size problems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opted for true
because it was the default behavior of OnGetUserInformationAsync
, but yeah, it's probably better to disable it by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, would it make sense to set it to true in the base options and false in the derived options? Otherwise the default behavior of the base class is an empty identity, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be a bit surprising from a configuration perspective, but as long as it is correctly documented, it shouldn't be an issue.
I'll fix that. Am I allowed to use a virtual property? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try it and we'll see :-)
Looks good. @hoak can you check it and merge it? |
@HaoK any chance you could have a look? 😄 |
Yeah I need to review it again since Lou had some potential concerns which I think we avoided but I'll need to double check |
@HaoK any chance you could share more info concerning these potential concerns? 😄 |
So he is fine with us nuking all of the derived generics/options/interfaces. His main concern is that we must keep the core INotifications interface so you can replace the workers on the options via DI. Also when you get a chance, can you rebase this against dev? I sort of blew all sorts of stuff up :) |
Ah yeah, I couldn't agree more. You'll have to convince @Tratcher though: #47 (comment) 😄
Sure. Any idea when the CI builds including your changes will be ready? It would be easier than hacking global.json 😄 |
CI might take a day or two, you can try using the dev volatile feed which is what we use internally: I wouldn't recommend doing this in general, unless you like being broken...a lot :) |
Well the status quo wins in general, its more like we have to convince @lodejard that this is the right thing to do, he felt pretty strongly against removing the interface, and if you actually agree with him, then that's 2:1 in favor of the status quo. I mostly wanted the generics gone, so I don't have a strong opinion either way on how this goes, which in practice means I'm leaning towards leaving the interface alone as well then... |
@HaoK well yeah, but the current situation is not satisfactory, as we have both patterns in the code base, which is terribly inconsistent. |
}, | ||
}; | ||
}); | ||
|
||
// Choose an authentication type | ||
app.Map("/login", signoutApp => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely not something I wanted to change, but it sounds like @HaoK's recent changes broke something here:
It seems that the redirect_uri
is now computed using the PathBase
of the handler/middleware that triggers the Challenge
call, which of course, produces an incorrect redirect_uri
(http://localhost:54540/login/signin-google
vs http://localhost:54540/signin-google
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, the middleware may need to snapshot the base address when the request first arrives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the correct url that is registered for these apps? I'm seeing errors saying: "http://localhost:54540/login/signin-google-token" did not match a registered redirect uri
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nm, I should scroll up :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to port this fix manually to a standalone so social samples actually work again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks to your fix, I can now revert this change 😄
I primarily want to reduce it from triple extensibility to just one pattern. I'm less concerned which pattern, though I do think the delegate pattern we use in OIDC is the simplest. |
Ok so sounds like we have consensus to add back just the base |
Yup! I haven't removed |
Rebased, squashed. I also removed the volatile feed from NuGet.Config. |
merged 9bb8b61 thanks for grinding through this and all the rebases :) |
@HaoK wooo, thank you for merging it! 🙇 |
In the current bits, the OAuth2 client middleware automagically saves access and refresh tokens in the
ClaimsPrincipal
it issues, but this logic disappears when you override the defaultOnGetUserInformation
notification: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNet.Authentication.OAuth/OAuthAuthenticationDefaults.cs#L13This pull request removes
DefaultOnGetUserInformationAsync
, moves its logic directly toOAuthAuthenticationHandler
and adds a newSaveTokens
property toOAuthAuthenticationOptions
to decide whether tokens should be stored inClaimsPrincipal
(and in the final authentication cookie) or not, independently of theOnGetUserInformation
notification.This will also make
OAuthAuthenticationHandler
inheritors more DRY, as they won't have to repeat the same snippet again and again: https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/blob/dev/src/AspNet.Security.OAuth.GitHub/GitHubAuthenticationHandler.cs#L52-L70/cc @HaoK @Tratcher