Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OAuth - Creating event for ExchangeCode #9448

Closed
wants to merge 6 commits into from

Conversation

Menighin
Copy link

@Menighin Menighin commented Apr 17, 2019

Summary of the changes

  • Created new event OnExchangeCode with default implementation it had before
  • Created OAuthExchangeCodeContext to hold properties necessary for developer to customize their own ExchangeCode instead of overriding the whole OAuthHandler.

Addresses #9092 (Use case described on the issue)

@dnfclas
Copy link

dnfclas commented Apr 17, 2019

CLA assistant check
All CLA requirements met.

@analogrelay analogrelay added the area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer label Apr 17, 2019
/// <summary>
/// Gets or sets the delegate that is invoked when the ExchangeCode method is invoked.
/// </summary>
public Func<OAuthExchangeCodeContext, Task<OAuthTokenResponse>> OnExchangeCode { get; set; } = async context =>
Copy link
Member

Choose a reason for hiding this comment

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

This is more code than is appropriate for events. Deriving from OAuthHandler is more appropriate once you need to replace this much.

Is there a more specific event that would still be useful? Like adding an event on line 45 that passed the parameters dictionary so it could be augmented? The default implementation would no-op. Would that be enough for your PKCE example?

@@ -159,42 +159,10 @@ protected override async Task<HandleRequestResult> HandleRemoteAuthenticateAsync
}
}

protected virtual async Task<OAuthTokenResponse> ExchangeCodeAsync(string code, string redirectUri)
protected virtual async Task<OAuthTokenResponse> ExchangeCodeAsync(string code, string redirectUri, AuthenticationProperties properties)
Copy link
Member

Choose a reason for hiding this comment

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

Is there a non-breaking way to add this new parameter? E.g. with a new overload?

Copy link
Author

Choose a reason for hiding this comment

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

@Tratcher hi, I was trying to make this non-breaking but I really don't see how... An overload won't work because now it is called from HandleRemoteAuthenticateAsync with the properties parameter. So to make, it non breakable I would need the new method to call the old one. And that is not possible because I would need to pass the tokenRequestParameters setted in the new method to the old one... I couldn't think of anything else, do you see a way out of this? How bad is this breaking change? n_n'

Copy link
Member

Choose a reason for hiding this comment

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

https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/search?q=ExchangeCodeAsync&unscoped_q=ExchangeCodeAsync
It would break at least 9 providers, which is enough to try to mitigate. Let's think about it while we deal with the other issue.

Copy link
Author

Choose a reason for hiding this comment

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

Ok, the first one about simply augmenting the Dictionary, I totally agree with you and I already changed it.
Will be giving some thought about how to not break it... But I don't see now how to make it without some smelly artifact...

Copy link
Contributor

Choose a reason for hiding this comment

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

@Tratcher is it possible to add a new API ExchangeCodeAsnyc(ExchangeCodeContext context)?

This would future proof us a bit. We have used this in other places.

Copy link
Member

Choose a reason for hiding this comment

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

@brentschmaltz yes, that's plausible. Either way it's a breaking change for many providers. If we added PKCE support directly we might be able to avoid this break. #9448 (comment)

Copy link
Member

@Tratcher Tratcher left a comment

Choose a reason for hiding this comment

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

Better, I added some cleanup comments. I'll follow up on the API break.

{ "client_id", Options.ClientId },
{ "redirect_uri", redirectUri },
{ "client_secret", Options.ClientSecret },
{ "code", code },
Copy link
Member

Choose a reason for hiding this comment

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

revert?

HttpContext context,
AuthenticationScheme scheme,
OAuthOptions options,
Dictionary<string, string> tokenRequestParameters)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Dictionary<string, string> tokenRequestParameters)
IDictionary<string, string> tokenRequestParameters)

/// <summary>
/// Gets the code returned by the authentication provider after user authenticates
/// </summary>
public Dictionary<string, string> TokenRequestParameters { get; }
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public Dictionary<string, string> TokenRequestParameters { get; }
public IDictionary<string, string> TokenRequestParameters { get; }

}

/// <summary>
/// Gets the code returned by the authentication provider after user authenticates
Copy link
Member

Choose a reason for hiding this comment

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

Wrong comment?

namespace Microsoft.AspNetCore.Authentication.OAuth
{
/// <summary>
/// Contains information about the exchanging code for the access token context.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/// Contains information about the exchanging code for the access token context.
/// Contains information about exchanging code for the access token context.

/// </summary>
/// <param name="context">Contains the code returned, the redirect URI and the <see cref="AuthenticationProperties"/>.</param>
/// <returns></returns>
public virtual Task ExchangeCode(OAuthExchangeCodeContext context) => OnExchangeCode(context);
Copy link
Member

Choose a reason for hiding this comment

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

PrepareCodeExchange?

Copy link
Author

Choose a reason for hiding this comment

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

I think BeforeExchangeCode is better, what you think?

@Tratcher
Copy link
Member

@PinpointTownes

So I looked at the 9 known providers that override ExchangeCode to see why.
https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/search?q=ExchangeCodeAsync&unscoped_q=ExchangeCodeAsync

Summary:
reddit: Move the clientid & secret to the auth header, optional user agent
fitbit: same as reddit
yandex: same as reddit
yahoo: same as reddit
visual studio: weird request parameter names, values
weixin: get+query
stackexchange: x-www-form-urlencoded response
yammer: weird response format
qq: get+query & form response

I'd be more willing to take the break API if I thought they could take advantage of the change and the new event. The Visual Studio provider looks like the only one that could remove it's overload and use the event instead to remap parameters. That tells me the event might not be general enough. We also might need to add first class support for some of these other scenarios.

A full half of the providers made the same customization (reddit-like), moving the client id and secret to the auth header. If we made that a first class option then they could remove their overrides.

The other providers are unique enough and mess with both the request and response so neither first classing their behavior nor the new event seem helpful.

@kevinchalet
Copy link
Contributor

@Tratcher supporting basic authentication in both the OAuth2 and OIDC handlers would be an excellent idea, since it's a common source of pain and could help cut some code in the aspnet-contrib providers.

I wonder if this event should also allow handling the code redeeming dance manually, pretty much like the OIDC handler with its AuthorizationCodeReceived event. Is there a particular reason not to align the two handlers?

@kevinchalet
Copy link
Contributor

/cc @poke @martincostello

@Tratcher
Copy link
Member

FYI we're considering first class PKCE support that would make this unnecessary. #7734

@Tratcher
Copy link
Member

Tratcher commented Jun 5, 2019

I don't know how neccissary this will be after #10928.

@Tratcher
Copy link
Member

Tratcher commented Jun 7, 2019

Please rebase on #10928 and we can see what's left.

@Tratcher
Copy link
Member

Closing this for now due to the unresolved merge conflict and design questions. We can revisit in the future.

@Tratcher Tratcher closed this Jun 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants