/* * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) * See https://github.com/openiddict/openiddict-core for more information concerning * the license and the contributors participating to this project. */ using System.ComponentModel; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Mail; using System.Reflection; using System.Security.Cryptography.X509Certificates; using OpenIddict.Client; using OpenIddict.Client.SystemNetHttp; using Polly; namespace Microsoft.Extensions.DependencyInjection; /// /// Exposes the necessary methods required to configure the OpenIddict client/System.Net.Http integration. /// public sealed class OpenIddictClientSystemNetHttpBuilder { /// /// Initializes a new instance of . /// /// The services collection. public OpenIddictClientSystemNetHttpBuilder(IServiceCollection services) => Services = services ?? throw new ArgumentNullException(nameof(services)); /// /// Gets the services collection. /// [EditorBrowsable(EditorBrowsableState.Never)] public IServiceCollection Services { get; } /// /// Amends the default OpenIddict client/System.Net.Http configuration. /// /// The delegate used to configure the OpenIddict options. /// This extension can be safely called multiple times. /// The instance. public OpenIddictClientSystemNetHttpBuilder Configure(Action configuration) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } Services.Configure(configuration); return this; } /// /// Configures the used by the OpenIddict client/System.Net.Http integration. /// /// /// Note: customizations configured using this method apply to all client registrations. /// /// The delegate used to configure the . /// The instance. [EditorBrowsable(EditorBrowsableState.Advanced)] public OpenIddictClientSystemNetHttpBuilder ConfigureHttpClient(Action configuration) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } return ConfigureHttpClient((registration, client) => configuration(client)); } /// /// Configures the used by the OpenIddict client/System.Net.Http integration. /// /// /// Note: customizations configured using this method only apply /// to client registrations that use the specified provider name. /// /// The provider name, to which the customizations are applied. /// The delegate used to configure the . /// The instance. [EditorBrowsable(EditorBrowsableState.Advanced)] public OpenIddictClientSystemNetHttpBuilder ConfigureHttpClient(string provider, Action configuration) { if (string.IsNullOrEmpty(provider)) { throw new ArgumentException(SR.FormatID0366(nameof(provider)), nameof(provider)); } if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } return ConfigureHttpClient((registration, client) => { if (string.Equals(registration.ProviderName, provider, StringComparison.Ordinal)) { configuration(client); } }); } /// /// Configures the used by the OpenIddict client/System.Net.Http integration. /// /// /// Note: customizations configured using this method apply to all client registrations, but the /// configuration delegate can restrict the applied customizations to specific instances. /// /// The delegate used to configure the . /// The instance. [EditorBrowsable(EditorBrowsableState.Advanced)] public OpenIddictClientSystemNetHttpBuilder ConfigureHttpClient(Action configuration) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } return Configure(options => options.HttpClientActions.Add(configuration)); } /// /// Configures the used by the OpenIddict client/System.Net.Http integration. /// /// /// Note: customizations configured using this method apply to all client registrations. /// /// The delegate used to configure the . /// The instance. [EditorBrowsable(EditorBrowsableState.Advanced)] public OpenIddictClientSystemNetHttpBuilder ConfigureHttpClientHandler(Action configuration) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } return ConfigureHttpClientHandler((registration, handler) => configuration(handler)); } /// /// Configures the used by the OpenIddict client/System.Net.Http integration. /// /// /// Note: customizations configured using this method only apply /// to client registrations that use the specified provider name. /// /// The provider name, to which the customizations are applied. /// The delegate used to configure the . /// The instance. [EditorBrowsable(EditorBrowsableState.Advanced)] public OpenIddictClientSystemNetHttpBuilder ConfigureHttpClientHandler(string provider, Action configuration) { if (string.IsNullOrEmpty(provider)) { throw new ArgumentException(SR.FormatID0366(nameof(provider)), nameof(provider)); } if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } return ConfigureHttpClientHandler((registration, handler) => { if (string.Equals(registration.ProviderName, provider, StringComparison.Ordinal)) { configuration(handler); } }); } /// /// Configures the used by the OpenIddict client/System.Net.Http integration. /// /// /// Note: customizations configured using this method apply to all client registrations, but the /// configuration delegate can restrict the applied customizations to specific instances. /// /// The delegate used to configure the . /// The instance. [EditorBrowsable(EditorBrowsableState.Advanced)] public OpenIddictClientSystemNetHttpBuilder ConfigureHttpClientHandler( Action configuration) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } return Configure(options => options.HttpClientHandlerActions.Add(configuration)); } /// /// Sets the contact address used in the "From" header that is attached /// to the backchannel HTTP requests sent to the authorization server. /// /// The mail address. /// The instance. public OpenIddictClientSystemNetHttpBuilder SetContactAddress(MailAddress address) { if (address is null) { throw new ArgumentNullException(nameof(address)); } return Configure(options => options.ContactAddress = address); } /// /// Sets the contact address used in the "From" header that is attached /// to the backchannel HTTP requests sent to the authorization server. /// /// The mail address. /// The instance. public OpenIddictClientSystemNetHttpBuilder SetContactAddress(string address) { if (string.IsNullOrEmpty(address)) { throw new ArgumentException(SR.FormatID0366(nameof(address)), nameof(address)); } return SetContactAddress(new MailAddress(address)); } /// /// Replaces the default HTTP error policy used by the OpenIddict client services. /// /// The HTTP Polly error policy. /// The instance. public OpenIddictClientSystemNetHttpBuilder SetHttpErrorPolicy(IAsyncPolicy policy) { if (policy is null) { throw new ArgumentNullException(nameof(policy)); } return Configure(options => options.HttpErrorPolicy = policy); } #if SUPPORTS_HTTP_CLIENT_RESILIENCE /// /// Replaces the default HTTP resilience pipeline used by the OpenIddict client services. /// /// /// The delegate used to configure the . /// /// /// Note: this option has no effect when an HTTP error policy was explicitly configured /// using . /// /// The instance. public OpenIddictClientSystemNetHttpBuilder SetHttpResiliencePipeline( Action> configuration) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } var builder = new ResiliencePipelineBuilder(); configuration(builder); return SetHttpResiliencePipeline(builder.Build()); } /// /// Replaces the default HTTP resilience pipeline used by the OpenIddict client services. /// /// The HTTP resilience pipeline. /// /// Note: this option has no effect when an HTTP error policy was explicitly configured /// using . /// /// The instance. public OpenIddictClientSystemNetHttpBuilder SetHttpResiliencePipeline(ResiliencePipeline pipeline) { if (pipeline is null) { throw new ArgumentNullException(nameof(pipeline)); } return Configure(options => options.HttpResiliencePipeline = pipeline); } #endif /// /// Sets the product information used in the "User-Agent" header that is attached /// to the backchannel HTTP requests sent to the authorization server. /// /// The product information. /// The instance. public OpenIddictClientSystemNetHttpBuilder SetProductInformation(ProductInfoHeaderValue information) { if (information is null) { throw new ArgumentNullException(nameof(information)); } return Configure(options => options.ProductInformation = information); } /// /// Sets the product information used in the "User-Agent" header that is attached /// to the backchannel HTTP requests sent to the authorization server. /// /// The product name. /// The product version. /// The instance. public OpenIddictClientSystemNetHttpBuilder SetProductInformation(string name, string? version) { if (string.IsNullOrEmpty(name)) { throw new ArgumentException(SR.GetResourceString(SR.ID0345), nameof(name)); } return SetProductInformation(new ProductInfoHeaderValue(name, version)); } /// /// Sets the product information used in the user agent header that is attached /// to the backchannel HTTP requests sent to the authorization server based /// on the identity of the specified .NET assembly (name and version). /// /// The assembly from which the product information is created. /// The instance. public OpenIddictClientSystemNetHttpBuilder SetProductInformation(Assembly assembly) { if (assembly is null) { throw new ArgumentNullException(nameof(assembly)); } return SetProductInformation(new ProductInfoHeaderValue( productName: assembly.GetName().Name!, productVersion: assembly.GetName().Version!.ToString())); } /// /// Sets the delegate called by OpenIddict when trying to resolve the self-signed /// TLS client authentication certificate that will be used for OAuth 2.0 /// mTLS-based client authentication (self_signed_tls_client_auth), if applicable. /// /// The selector delegate. /// /// If no value is explicitly set, OpenIddict automatically tries to resolve the /// X.509 certificate from the signing credentials attached to the client registration /// (in this case, the X.509 certificate MUST include the digital signature and /// client authentication key usages to be automatically selected by OpenIddict). /// /// The instance. public OpenIddictClientSystemNetHttpBuilder SetSelfSignedTlsClientAuthenticationCertificateSelector( Func selector) { if (selector is null) { throw new ArgumentNullException(nameof(selector)); } return Configure(options => options.SelfSignedTlsClientAuthenticationCertificateSelector = selector); } /// /// Sets the delegate called by OpenIddict when trying to resolve the /// TLS client authentication certificate that will be used for OAuth 2.0 /// mTLS-based client authentication (tls_client_auth), if applicable. /// /// The selector delegate. /// /// If no value is explicitly set, OpenIddict automatically tries to resolve the /// X.509 certificate from the signing credentials attached to the client registration /// (in this case, the X.509 certificate MUST include the digital signature and /// client authentication key usages to be automatically selected by OpenIddict). /// /// The instance. public OpenIddictClientSystemNetHttpBuilder SetTlsClientAuthenticationCertificateSelector( Func selector) { if (selector is null) { throw new ArgumentNullException(nameof(selector)); } return Configure(options => options.TlsClientAuthenticationCertificateSelector = selector); } /// [EditorBrowsable(EditorBrowsableState.Never)] public override bool Equals(object? obj) => base.Equals(obj); /// [EditorBrowsable(EditorBrowsableState.Never)] public override int GetHashCode() => base.GetHashCode(); /// [EditorBrowsable(EditorBrowsableState.Never)] public override string? ToString() => base.ToString(); }