From 4d27b50cb520948e7f9f653f26ae64dd6279f791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Sat, 26 Nov 2022 07:11:21 +0100 Subject: [PATCH] Add Trakt to the list of supported providers --- ...ctClientWebIntegrationHandlers.Userinfo.cs | 56 +++++++++++++++++-- .../OpenIddictClientWebIntegrationHandlers.cs | 26 ++++++--- ...penIddictClientWebIntegrationProviders.xml | 8 +++ 3 files changed, 77 insertions(+), 13 deletions(-) diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs index 7349d8e7..5b13013e 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs +++ b/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.SystemNetHttp.OpenIddictClientSystemNetHttpHandlerFilters; +using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers; using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers.Userinfo; using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants; @@ -21,6 +22,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers /* * Userinfo request preparation: */ + AttachRequestHeaders.Descriptor, AttachAccessTokenParameter.Descriptor, /* @@ -28,6 +30,50 @@ public static partial class OpenIddictClientWebIntegrationHandlers */ UnwrapUserinfoResponse.Descriptor); + /// + /// Contains the logic responsible for attaching additional + /// headers to the request for the providers that require it. + /// + public sealed class AttachRequestHeaders : IOpenIddictClientHandler + { + /// + /// Gets the default descriptor definition assigned to this handler. + /// + public static OpenIddictClientHandlerDescriptor Descriptor { get; } + = OpenIddictClientHandlerDescriptor.CreateBuilder() + .AddFilter() + .UseSingletonHandler() + .SetOrder(AttachUserAgentHeader.Descriptor.Order + 250) + .SetType(OpenIddictClientHandlerType.BuiltIn) + .Build(); + + /// + 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)); + + // Trakt requires sending both an API key (which is always the client identifier) and an API version + // (which is statically set to the last version known to be supported by the OpenIddict integration). + if (context.Registration.ProviderName is Providers.Trakt) + { + var options = context.Registration.GetTraktOptions(); + + request.Headers.Add("trakt-api-key", options.ClientId); + request.Headers.Add("trakt-api-version", "2"); + } + + return default; + } + } + /// /// Contains the logic responsible for attaching the access token /// parameter to the request for the providers that require it. @@ -62,11 +108,13 @@ public static partial class OpenIddictClientWebIntegrationHandlers // 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.Deezer or Providers.StackExchange) + (context.Request.AccessToken, request.Headers.Authorization) = context.Registration.ProviderName switch { - context.Request.AccessToken = request.Headers.Authorization?.Parameter; - request.Headers.Authorization = null; - } + Providers.Deezer or Providers.StackExchange + => (request.Headers.Authorization?.Parameter, null), + + _ => (context.Request.AccessToken, request.Headers.Authorization) + }; return default; } diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs index 205cd171..6419a409 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs @@ -238,13 +238,15 @@ public static partial class OpenIddictClientWebIntegrationHandlers // of the authorization requests, the value persisted in the state token principal // MUST be replaced to include the state token received by the redirection endpoint. - if (context.Registration.ProviderName is Providers.Deezer) + context.TokenRequest.RedirectUri = context.Registration.ProviderName switch { - context.TokenRequest.RedirectUri = OpenIddictHelpers.AddQueryStringParameter( + Providers.Deezer => OpenIddictHelpers.AddQueryStringParameter( address: new Uri(context.TokenRequest.RedirectUri, UriKind.Absolute), name: Parameters.State, - value: context.StateToken).AbsoluteUri; - } + value: context.StateToken).AbsoluteUri, + + _ => context.TokenRequest.RedirectUri + }; return default; } @@ -338,6 +340,12 @@ public static partial class OpenIddictClientWebIntegrationHandlers context.UserinfoRequest["site"] = options.Site; } + // Trakt allows retrieving additional user details via the "extended" parameter. + else if (context.Registration.ProviderName is Providers.Trakt) + { + context.UserinfoRequest["extended"] = "full"; + } + // 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. @@ -471,15 +479,15 @@ public static partial class OpenIddictClientWebIntegrationHandlers // Note: this workaround only works for providers that allow dynamic // redirection URIs and implement a relaxed validation policy logic. - if (context.Registration.ProviderName is Providers.Deezer) + (context.Request.RedirectUri, context.Request.State) = context.Registration.ProviderName switch { - context.Request.RedirectUri = OpenIddictHelpers.AddQueryStringParameter( + Providers.Deezer => (OpenIddictHelpers.AddQueryStringParameter( address: new Uri(context.RedirectUri, UriKind.Absolute), name: Parameters.State, - value: context.Request.State).AbsoluteUri; + value: context.Request.State).AbsoluteUri, null), - context.Request.State = null; - } + _ => (context.Request.RedirectUri, context.Request.State) + }; return default; } diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml index b8075c98..cb24f5b9 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml @@ -138,6 +138,14 @@ Description="The site specified in userinfo requests (by default, 'stackoverflow')" /> + + + + + +