diff --git a/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs b/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs index c68a0f97..799381b8 100644 --- a/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs +++ b/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs @@ -46,6 +46,7 @@ namespace OpenIddict.Client.WebIntegration.Generators static string GenerateBuilderMethods(XDocument document) { var template = Template.Parse(@"#nullable enable +#pragma warning disable CS0618 using System.ComponentModel; using System.Diagnostics.CodeAnalysis; @@ -284,6 +285,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// /// {{ setting.description | string.capitalize }}. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Add{{ setting.property_name }}(params {{ setting.clr_type }}[] {{ setting.parameter_name }}) { if ({{ setting.parameter_name }} is null) @@ -299,6 +303,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// /// {{ setting.description | string.capitalize }}. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(ECDsaSecurityKey {{ setting.parameter_name }}) { if ({{ setting.parameter_name }} is null) @@ -322,6 +329,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// The PEM-encoded Elliptic Curve Digital Signature Algorithm (ECDSA) signing key. /// /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(string key) => Set{{ setting.property_name }}(key.AsMemory()); @@ -332,6 +342,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// The PEM-encoded Elliptic Curve Digital Signature Algorithm (ECDSA) signing key. /// /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(ReadOnlyMemory key) => Set{{ setting.property_name }}(key.Span); @@ -342,6 +355,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// The PEM-encoded Elliptic Curve Digital Signature Algorithm (ECDSA) signing key. /// /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(ReadOnlySpan key) { if (key.IsEmpty) @@ -372,6 +388,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// /// {{ setting.description | string.capitalize }}. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(Uri {{ setting.parameter_name }}) { if ({{ setting.parameter_name }} is null) @@ -392,6 +411,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// /// {{ setting.description | string.capitalize }}. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(string {{ setting.parameter_name }}) { if (string.IsNullOrEmpty({{ setting.parameter_name }})) @@ -407,6 +429,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// /// {{ setting.description | string.capitalize }}. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(X509Certificate2 {{ setting.parameter_name }}) { if ({{ setting.parameter_name }} is null) @@ -429,6 +454,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// The name of the embedded resource. /// The password used to open the certificate. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(Assembly assembly, string resource, string? password) #if SUPPORTS_EPHEMERAL_KEY_SETS // Note: ephemeral key sets are currently not supported on macOS. @@ -447,6 +475,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// The password used to open the certificate. /// An enumeration of flags indicating how and where to store the private key of the certificate. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}( Assembly assembly, string resource, string? password, X509KeyStorageFlags flags) @@ -473,6 +504,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// The stream containing the certificate. /// The password used to open the certificate. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(Stream stream, string? password) #if SUPPORTS_EPHEMERAL_KEY_SETS // Note: ephemeral key sets are currently not supported on macOS. @@ -493,6 +527,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// to store the private key of the certificate. /// /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(Stream stream, string? password, X509KeyStorageFlags flags) { if (stream is null) @@ -511,6 +548,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// /// The thumbprint of the certificate used to identify it in the X.509 store. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(string thumbprint) { if (string.IsNullOrEmpty(thumbprint)) @@ -541,6 +581,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// The name of the X.509 store. /// The location of the X.509 store. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}(string thumbprint, StoreName name, StoreLocation location) { if (string.IsNullOrEmpty(thumbprint)) @@ -562,6 +605,9 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder /// /// {{ setting.description | string.capitalize }}. /// The instance. + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} public {{ provider.name }} Set{{ setting.property_name }}({{ setting.clr_type }} {{ setting.parameter_name }}) { if ({{ setting.parameter_name }} is null) @@ -611,6 +657,8 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder ParameterName = (string) setting.Attribute("ParameterName"), Collection = (bool?) setting.Attribute("Collection") ?? false, + Obsolete = (bool?) setting.Attribute("Obsolete") ?? false, + Description = (string) setting.Attribute("Description") is string description ? char.ToLower(description[0], CultureInfo.GetCultureInfo("en-US")) + description[1..] : null, ClrType = (string) setting.Attribute("Type") switch @@ -687,6 +735,7 @@ public static partial class OpenIddictClientWebIntegrationConstants static string GenerateConfigurationClasses(XDocument document) { var template = Template.Parse(@"#nullable enable +#pragma warning disable CS0618 using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -1155,6 +1204,9 @@ public sealed partial class OpenIddictClientWebIntegrationOptions /// /// Gets or sets {{ setting.description }}. /// + {{~ if setting.obsolete ~}} + [Obsolete(""This option is no longer supported and will be removed in a future version."")] + {{~ end ~}} {{~ if setting.collection ~}} public HashSet<{{ setting.clr_type }}> {{ setting.property_name }} { get; } = new(); {{~ else ~}} @@ -1179,6 +1231,8 @@ public sealed partial class OpenIddictClientWebIntegrationOptions PropertyName = (string) setting.Attribute("PropertyName"), Collection = (bool?) setting.Attribute("Collection") ?? false, + Obsolete = (bool?) setting.Attribute("Obsolete") ?? false, + Description = (string) setting.Attribute("Description") is string description ? char.ToLower(description[0], CultureInfo.GetCultureInfo("en-US")) + description[1..] : null, ClrType = (string) setting.Attribute("Type") switch diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs index 93a2c1ef..7a2c3094 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs @@ -101,7 +101,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers // authorization code or implicit flows). To work around that, the list of supported grant // types is amended to include the known supported types for the providers that require it. - if (context.Registration.ProviderName is Providers.Apple or Providers.QuickBooksOnline) + if (context.Registration.ProviderName is Providers.Apple or Providers.LinkedIn or Providers.QuickBooksOnline) { context.Configuration.GrantTypesSupported.Add(GrantTypes.AuthorizationCode); context.Configuration.GrantTypesSupported.Add(GrantTypes.RefreshToken); @@ -278,6 +278,16 @@ public static partial class OpenIddictClientWebIntegrationHandlers ClientAuthenticationMethods.PrivateKeyJwt); } + // LinkedIn doesn't support sending the client credentials using basic authentication but + // doesn't return a "token_endpoint_auth_methods_supported" node containing alternative + // authentication methods, making basic authentication the default authentication method. + // To work around this compliance issue, "client_secret_post" is manually added here. + else if (context.Registration.ProviderName is Providers.LinkedIn) + { + context.Configuration.TokenEndpointAuthMethodsSupported.Add( + ClientAuthenticationMethods.ClientSecretPost); + } + return default; } } diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs index ffe5bb28..a10e8103 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs @@ -60,6 +60,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers /// public static OpenIddictClientHandlerDescriptor Descriptor { get; } = OpenIddictClientHandlerDescriptor.CreateBuilder() + .AddFilter() .UseSingletonHandler() .SetOrder(HandleFrontchannelErrorResponse.Descriptor.Order - 500) .SetType(OpenIddictClientHandlerType.BuiltIn) @@ -394,7 +395,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers context.DisableBackchannelIdentityTokenNonceValidation = context.Registration.ProviderName switch { // These providers don't include the nonce in their identity tokens: - Providers.Asana or Providers.Dropbox or Providers.QuickBooksOnline => true, + Providers.Asana or Providers.Dropbox or Providers.LinkedIn or Providers.QuickBooksOnline => true, _ => context.DisableBackchannelIdentityTokenNonceValidation }; @@ -582,16 +583,6 @@ public static partial class OpenIddictClientWebIntegrationHandlers context.UserinfoRequest["fields"] = string.Join(",", options.Fields); } - // By default, LinkedIn returns all the basic fields except the profile image. - // To retrieve the profile image, a projection parameter must be sent with - // all the parameters that should be returned from the userinfo endpoint. - else if (context.Registration.ProviderName is Providers.LinkedIn) - { - var options = context.Registration.GetLinkedInOptions(); - - context.UserinfoRequest["projection"] = string.Concat("(", string.Join(",", options.Fields), ")"); - } - // Patreon 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. diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml index 8043df3d..ec96a20a 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml @@ -414,8 +414,7 @@ @@ -450,25 +449,16 @@ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ --> - - - - - - - + + - + - diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xsd b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xsd index 771bca7c..492b6e18 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xsd +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xsd @@ -398,6 +398,16 @@ + + + A boolean indicating whether the setting is obsolete. + + + + + + + The setting type.