Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.

Revisit OAuthAuthenticationHandler and add a new SaveTokensAsClaims option #257

Closed
wants to merge 1 commit into from
Closed

Conversation

kevinchalet
Copy link
Contributor

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 default OnGetUserInformation notification: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNet.Authentication.OAuth/OAuthAuthenticationDefaults.cs#L13

This pull request removes DefaultOnGetUserInformationAsync, moves its logic directly to OAuthAuthenticationHandler and adds a new SaveTokens property to OAuthAuthenticationOptions to decide whether tokens should be stored in ClaimsPrincipal (and in the final authentication cookie) or not, independently of the OnGetUserInformation 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

@kevinchalet
Copy link
Contributor Author

@Eilon please tell me I won't have to sign a third CLA 😄

(FYI, I submitted a PR two months ago: #168)

@@ -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))
Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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 😄

@kevinchalet kevinchalet changed the title Add a new SaveTokens options to save access and tokens directly in OAuthAuthenticationHandler Add a new SaveTokens option to save access and tokens directly in OAuthAuthenticationHandler May 14, 2015
@Eilon
Copy link
Member

Eilon commented May 14, 2015

@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!

@kevinchalet
Copy link
Contributor Author

@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)

@Eilon
Copy link
Member

Eilon commented May 14, 2015

@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/ .

@dnfclas
Copy link

dnfclas commented May 14, 2015

@PinpointTownes, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR.

Thanks, DNFBOT;

@kevinchalet
Copy link
Contributor Author

Ah. I had filed the wrong form: https://cla.dotnetfoundation.org/ (the first result on Google...)

@dnfclas thanks, dear bot 😄

@Eilon
Copy link
Member

Eilon commented May 14, 2015

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!

@kevinchalet
Copy link
Contributor Author

@Eilon wonderful, thanks!

@kevinchalet
Copy link
Contributor Author

@HaoK @Tratcher any remark concerning this PR? 😰

await Options.Notifications.GetUserInformationAsync(context);
return new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme);

await Options.Notifications.GetUserInformationAsync(notification);
Copy link
Member

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?

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

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.

@kevinchalet kevinchalet changed the title Add a new SaveTokens option to save access and tokens directly in OAuthAuthenticationHandler Add a new SaveTokens option to save tokens directly in OAuthAuthenticationHandler May 15, 2015
{
var context = new OAuthGetUserInformationContext(Context, Options, Backchannel, tokens)
var identity = new ClaimsIdentity(Options.ClaimsIssuer);
Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Member

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...

Copy link
Member

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.

@Tratcher
Copy link
Member

Possibly related: #101

@kevinchalet
Copy link
Contributor Author

@Tratcher I'm testing a new approach that merges OnAuthenticated and OnCreateTicket, as suggested. Feel free to tell me if you prefer the new design or the old one: https://github.com/PinpointTownes/Security/commit/517125d8b82ac89de1d869e4f88c949d9931032c

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;
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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?

Copy link
Contributor Author

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? 😄

Copy link
Member

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 :-)

@Tratcher
Copy link
Member

Looks good. @hoak can you check it and merge it?

@kevinchalet
Copy link
Contributor Author

@HaoK any chance you could have a look? 😄

@HaoK
Copy link
Member

HaoK commented Jun 23, 2015

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

@kevinchalet
Copy link
Contributor Author

@HaoK any chance you could share more info concerning these potential concerns? 😄

@HaoK
Copy link
Member

HaoK commented Jun 26, 2015

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 :)

@kevinchalet
Copy link
Contributor Author

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.

Ah yeah, I couldn't agree more. You'll have to convince @Tratcher though: #47 (comment) 😄

Also when you get a chance, can you rebase this against dev? I sort of blew all sorts of stuff up :)

Sure. Any idea when the CI builds including your changes will be ready? It would be easier than hacking global.json 😄

@HaoK
Copy link
Member

HaoK commented Jun 26, 2015

CI might take a day or two, you can try using the dev volatile feed which is what we use internally:
https://www.myget.org/F/aspnetvolatile/

I wouldn't recommend doing this in general, unless you like being broken...a lot :)

@HaoK
Copy link
Member

HaoK commented Jun 26, 2015

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...

@kevinchalet
Copy link
Contributor Author

@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 =>
Copy link
Contributor Author

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:

image

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).

Copy link
Member

@HaoK HaoK Jun 26, 2015 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

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.

Copy link
Member

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

Copy link
Member

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 :)

Copy link
Member

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

Copy link
Contributor Author

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 😄

@Tratcher
Copy link
Member

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.

@HaoK HaoK mentioned this pull request Jun 26, 2015
@HaoK
Copy link
Member

HaoK commented Jun 26, 2015

Ok so sounds like we have consensus to add back just the base IOAuthAuthenticationNotifications (RIP Generics and derived notifications), and use that as the pattern everywhere?

@kevinchalet
Copy link
Contributor Author

Ok so sounds like we have consensus to add back just the base IOAuthAuthenticationNotifications (RIP Generics and derived notifications), and use that as the pattern everywhere?

Yup! I haven't removed IOAuthAuthenticationNotifications, so we're fine for this PR, but we'll definitely need to fix the other providers in a future PR 😄

@kevinchalet
Copy link
Contributor Author

Rebased, squashed. I also removed the volatile feed from NuGet.Config.

@HaoK
Copy link
Member

HaoK commented Jul 1, 2015

merged 9bb8b61 thanks for grinding through this and all the rebases :)

@HaoK HaoK closed this Jul 1, 2015
@kevinchalet
Copy link
Contributor Author

@HaoK wooo, thank you for merging it! 🙇

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

Successfully merging this pull request may close these issues.

8 participants