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> <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>
<data name="ID0334" xml:space="preserve"> <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>
<data name="ID0335" xml:space="preserve"> <data name="ID0335" xml:space="preserve">
<value>The username cannot be null or empty.</value> <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.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Text.Json;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers; using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers.Userinfo;
using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants; using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants;
namespace OpenIddict.Client.WebIntegration; namespace OpenIddict.Client.WebIntegration;
@ -19,7 +21,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/* /*
* Userinfo request preparation: * Userinfo request preparation:
*/ */
AttachNonStandardFieldParameter.Descriptor, AttachAdditionalParameters.Descriptor,
/* /*
* Userinfo response extraction: * Userinfo response extraction:
@ -27,16 +29,16 @@ public static partial class OpenIddictClientWebIntegrationHandlers
UnwrapUserinfoResponse.Descriptor); UnwrapUserinfoResponse.Descriptor);
/// <summary> /// <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> /// </summary>
public class AttachNonStandardFieldParameter : IOpenIddictClientHandler<PrepareUserinfoRequestContext> public class AttachAdditionalParameters : IOpenIddictClientHandler<PrepareUserinfoRequestContext>
{ {
/// <summary> /// <summary>
/// Gets the default descriptor definition assigned to this handler. /// Gets the default descriptor definition assigned to this handler.
/// </summary> /// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; } public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserinfoRequestContext>() = OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserinfoRequestContext>()
.UseSingletonHandler<AttachNonStandardFieldParameter>() .UseSingletonHandler<AttachAdditionalParameters>()
.SetOrder(PrepareGetHttpRequest<PrepareUserinfoRequestContext>.Descriptor.Order - 500) .SetOrder(PrepareGetHttpRequest<PrepareUserinfoRequestContext>.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn) .SetType(OpenIddictClientHandlerType.BuiltIn)
.Build(); .Build();
@ -51,15 +53,13 @@ public static partial class OpenIddictClientWebIntegrationHandlers
Debug.Assert(context.Request is not null, SR.GetResourceString(SR.ID4008)); 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) if (context.Registration.ProviderName is Providers.Twitter)
{ {
var options = context.Registration.GetTwitterOptions(); 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["expansions"] = string.Join(",", options.Expansions);
context.Request["tweet.fields"] = string.Join(",", options.TweetFields); context.Request["tweet.fields"] = string.Join(",", options.TweetFields);
context.Request["user.fields"] = string.Join(",", options.UserFields); 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 // 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. // 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; return default;
} }
} }

Loading…
Cancel
Save