Browse Source

Add StackExchange support

pull/1532/head
Kévin Chalet 4 years ago
parent
commit
6a86b45ddc
  1. 54
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs
  2. 10
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
  3. 14
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml

54
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs

@ -8,6 +8,7 @@ using System.Collections.Immutable;
using System.Diagnostics;
using System.Text.Json;
using static OpenIddict.Client.OpenIddictClientHandlers.Userinfo;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers.Userinfo;
using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants;
namespace OpenIddict.Client.WebIntegration;
@ -17,11 +18,59 @@ public static partial class OpenIddictClientWebIntegrationHandlers
public static class Userinfo
{
public static ImmutableArray<OpenIddictClientHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create(
/*
* Userinfo request preparation:
*/
AttachAccessTokenParameter.Descriptor,
/*
* Userinfo response extraction:
*/
UnwrapUserinfoResponse.Descriptor);
/// <summary>
/// Contains the logic responsible for attaching the access token
/// parameter to the request for the providers that require it.
/// </summary>
public class AttachAccessTokenParameter : IOpenIddictClientHandler<PrepareUserinfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserinfoRequestContext>()
.UseSingletonHandler<AttachAccessTokenParameter>()
.SetOrder(AttachBearerAccessToken.Descriptor.Order + 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(PrepareUserinfoRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
// This handler only applies to System.Net.Http requests. If the HTTP request cannot be resolved,
// this may indicate that the request was incorrectly processed by another client stack.
var request = context.Transaction.GetHttpRequestMessage() ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0173));
// By default, OpenIddict sends the access token as part of the Authorization header
// using the Bearer authentication scheme. Some providers don't support this method
// and require sending the access token as part of the userinfo request payload.
if (context.Registration.ProviderName is Providers.StackExchange)
{
context.Request.AccessToken = request.Headers.Authorization?.Parameter;
request.Headers.Authorization = null;
}
return default;
}
}
/// <summary>
/// Contains the logic responsible for extracting the userinfo response
/// from nested JSON nodes (e.g "data") for the providers that require it.
@ -55,6 +104,11 @@ public static partial class OpenIddictClientWebIntegrationHandlers
context.Response = context.Registration.ProviderName switch
{
// StackExchange returns an "items" array containing a single element.
Providers.StackExchange => (JsonElement) context.Response["items"]
is { ValueKind: JsonValueKind.Array } element && element.GetArrayLength() is 1 ?
new(element[0]) : throw new InvalidOperationException(SR.FormatID0334("items")),
// Twitter returns a nested "data" object.
Providers.Twitter => (JsonElement) context.Response["data"]
is { ValueKind: JsonValueKind.Object } element ?

10
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs

@ -148,7 +148,15 @@ public static partial class OpenIddictClientWebIntegrationHandlers
Debug.Assert(context.UserinfoRequest is not null, SR.GetResourceString(SR.ID4008));
if (context.Registration.ProviderName is Providers.Twitter)
if (context.Registration.ProviderName is Providers.StackExchange)
{
var options = context.Registration.GetStackExchangeOptions();
context.UserinfoRequest["key"] = options.ApplicationKey;
context.UserinfoRequest["site"] = options.Site;
}
else if (context.Registration.ProviderName is Providers.Twitter)
{
var options = context.Registration.GetTwitterOptions();

14
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml

@ -58,6 +58,20 @@
</Environment>
</Provider>
<Provider Name="StackExchange" Documentation="https://api.stackexchange.com/docs/authentication">
<Environment Issuer="https://api.stackexchange.com/">
<Configuration AuthorizationEndpoint="https://stackoverflow.com/oauth"
TokenEndpoint="https://stackoverflow.com/oauth/access_token/json"
UserinfoEndpoint="https://api.stackexchange.com/2.3/me" />
</Environment>
<Setting PropertyName="ApplicationKey" ParameterName="key" Type="String" Required="true"
Description="The application key used to communicate with the StackExchange API" />
<Setting PropertyName="Site" ParameterName="site" Type="String" Required="true" DefaultValue="stackoverflow"
Description="The site specified in userinfo requests (by default, 'stackoverflow')" />
</Provider>
<Provider Name="Twitter" Documentation="https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code">
<Environment Issuer="https://twitter.com/">
<Configuration AuthorizationEndpoint="https://twitter.com/i/oauth2/authorize"

Loading…
Cancel
Save