Browse Source

Tweak the logic used to unwrap nested userinfo responses to validate JsonElement.ValueKind

pull/1528/head
Kévin Chalet 4 years ago
parent
commit
62002ae042
  1. 2
      src/OpenIddict.Abstractions/OpenIddictResources.resx
  2. 33
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs

2
src/OpenIddict.Abstractions/OpenIddictResources.resx

@ -1299,7 +1299,7 @@ Alternatively, you can disable the token storage feature by calling 'services.Ad
<value>The '{0}' provider settings cannot be resolved from the event context. Make sure the provider was correctly registered using 'services.AddOpenIddict().AddClient().UseWebProviders().Add{0}()'.</value>
</data>
<data name="ID0334" xml:space="preserve">
<value>The '{0}' node cannot be extracted from the response.</value>
<value>The '{0}' node cannot be extracted from the response or is not of the expected type.</value>
</data>
<data name="ID0335" xml:space="preserve">
<value>The username cannot be null or empty.</value>

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

@ -6,7 +6,9 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Text.Json;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers.Userinfo;
using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants;
namespace OpenIddict.Client.WebIntegration;
@ -19,7 +21,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/*
* Userinfo request preparation:
*/
AttachNonStandardFieldParameter.Descriptor,
AttachAdditionalParameters.Descriptor,
/*
* Userinfo response extraction:
@ -27,16 +29,16 @@ public static partial class OpenIddictClientWebIntegrationHandlers
UnwrapUserinfoResponse.Descriptor);
/// <summary>
/// Contains the logic responsible for attaching non-standard field parameters for the providers that require it.
/// Contains the logic responsible for attaching additional parameters for the providers that require it.
/// </summary>
public class AttachNonStandardFieldParameter : IOpenIddictClientHandler<PrepareUserinfoRequestContext>
public class AttachAdditionalParameters : IOpenIddictClientHandler<PrepareUserinfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserinfoRequestContext>()
.UseSingletonHandler<AttachNonStandardFieldParameter>()
.UseSingletonHandler<AttachAdditionalParameters>()
.SetOrder(PrepareGetHttpRequest<PrepareUserinfoRequestContext>.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -51,15 +53,13 @@ public static partial class OpenIddictClientWebIntegrationHandlers
Debug.Assert(context.Request is not null, SR.GetResourceString(SR.ID4008));
// Some providers are known to limit the number of fields returned by their userinfo endpoint
// but allow returning additional information using a special parameter (generally called "fields")
// that determines what fields will be returned as part of the userinfo response. This handler is
// responsible for resolving the fields from the provider settings and attaching them to the request.
if (context.Registration.ProviderName is Providers.Twitter)
{
var options = context.Registration.GetTwitterOptions();
// Twitter limits the number of fields returned by the userinfo endpoint
// but allows returning additional information using special parameters that
// determine what fields will be returned as part of the userinfo response.
context.Request["expansions"] = string.Join(",", options.Expansions);
context.Request["tweet.fields"] = string.Join(",", options.TweetFields);
context.Request["user.fields"] = string.Join(",", options.UserFields);
@ -100,19 +100,16 @@ public static partial class OpenIddictClientWebIntegrationHandlers
// logic from mapping the parameters to CLR claims. To work around that, this handler
// is responsible for extracting the nested payload and replacing the userinfo response.
var parameter = context.Registration.ProviderName switch
context.Response = context.Registration.ProviderName switch
{
Providers.Twitter => "data",
// Twitter uses a nested object.
Providers.Twitter => (JsonElement?) context.Response["data"]
is { ValueKind: JsonValueKind.Object } element ?
new(element) : throw new InvalidOperationException(SR.FormatID0334("data")),
_ => null
_ => context.Response
};
if (!string.IsNullOrEmpty(parameter))
{
context.Response = new OpenIddictResponse(context.Response[parameter]?.GetNamedParameters() ??
throw new InvalidOperationException(SR.FormatID0334(parameter)));
}
return default;
}
}

Loading…
Cancel
Save