1- using System . Globalization ;
2- using System . Security . Cryptography ;
3- using System . Security . Cryptography . X509Certificates ;
41using DotPulsar ;
52using DotPulsar . Abstractions ;
63using Microsoft . Extensions . Configuration ;
@@ -12,6 +9,16 @@ namespace Microsoft.Extensions.DependencyInjection;
129
1310public static class PulsarServiceCollectionExtensions
1411{
12+ public static IServiceCollection AddPulsarOptions ( this IServiceCollection services , string sectionName = PulsarClientOptions . SectionName ) {
13+ services . AddOptions < PulsarClientOptions > ( ) . BindConfiguration ( sectionName ) ;
14+ return services ;
15+ }
16+
17+ public static IServiceCollection AddPulsarOptions ( this IServiceCollection services , IConfigurationSection pulsarSection ) {
18+ services . AddOptions < PulsarClientOptions > ( ) . Bind ( pulsarSection ) ;
19+ return services ;
20+ }
21+
1522 public static IServiceCollection AddPulsarClient ( this IServiceCollection services , IPulsarClient pulsarClient ) {
1623 services . TryAddSingleton ( pulsarClient ) ;
1724 return services ;
@@ -22,29 +29,18 @@ public static IServiceCollection AddPulsarClient(this IServiceCollection service
2229 return services ;
2330 }
2431
25- public static IServiceCollection AddPulsarClient ( this IServiceCollection services , IPulsarClientBuilder pulsarClientBuilder ) {
26- ArgumentNullException . ThrowIfNull ( pulsarClientBuilder ) ;
27- return AddPulsarClient ( services , pulsarClientBuilder . Build ( ) ) ;
28- }
29-
30- public static IServiceCollection AddPulsarClient ( this IServiceCollection services ) {
31- services . AddOptions < PulsarClientOptions > ( ) . Configure < IConfiguration > ( static ( opts , config ) => BindOptions ( opts , config . GetSection ( "Pulsar" ) ) ) ;
32- return AddPulsarClient ( services , static ( sp , builder ) => {
33- var options = sp . GetRequiredService < IOptions < PulsarClientOptions > > ( ) . Value ;
34- options . Apply ( builder ) ;
32+ public static IServiceCollection AddPulsarClient ( this IServiceCollection services , PulsarClientOptions ? options = null ) {
33+ return AddPulsarClient ( services , ( sp , builder ) => {
34+ if ( options == null ) {
35+ options = sp . GetService < IOptions < PulsarClientOptions > > ( ) ? . Value ;
36+ }
37+ builder . Configure ( options ) ;
3538 } ) ;
3639 }
3740
38- public static IServiceCollection AddPulsarClient ( this IServiceCollection services , IConfigurationSection pulsarSection ) {
39- return AddPulsarClient ( services , opts => BindOptions ( opts , pulsarSection ) ) ;
40- }
41-
4241 public static IServiceCollection AddPulsarClient ( this IServiceCollection services , Action < PulsarClientOptions > configure ) {
4342 services . AddOptions < PulsarClientOptions > ( ) . Configure ( configure ) ;
44- return AddPulsarClient ( services , static ( sp , builder ) => {
45- var options = sp . GetRequiredService < IOptions < PulsarClientOptions > > ( ) . Value ;
46- options . Apply ( builder ) ;
47- } ) ;
43+ return AddPulsarClient ( services ) ;
4844 }
4945
5046 public static IServiceCollection AddPulsarClient ( this IServiceCollection services , Action < IPulsarClientBuilder > configure ) {
@@ -60,112 +56,9 @@ public static IServiceCollection AddPulsarClient(this IServiceCollection service
6056 } ) ;
6157 }
6258
63- private static void BindOptions ( this PulsarClientOptions options , IConfiguration configuration ) {
64- configuration . Bind ( options ) ;
65-
66- options . AuthenticateUsingClientCertificate = BindCertificate ( configuration . GetSection ( nameof ( PulsarClientOptions . AuthenticateUsingClientCertificate ) ) ) ;
67- options . TrustedCertificateAuthority = BindCertificate ( configuration . GetSection ( nameof ( PulsarClientOptions . TrustedCertificateAuthority ) ) ) ;
68-
69- static X509Certificate2 ? BindCertificate ( IConfigurationSection configSection ) => new CertificateConfig ( configSection ) . LoadCertificate ( ) ;
70- }
71-
72- // Inspired from https://github.com/dotnet/aspnetcore/blob/449abac6f1ca12fa0ad557a872c219fcdfae09f3/src/Servers/Kestrel/Core/src/Internal/Certificates/CertificateConfigLoader.cs#L13
73- private sealed class CertificateConfig
74- {
75- public CertificateConfig ( IConfiguration configSection ) {
76- Path = configSection [ nameof ( Path ) ] ;
77- KeyPath = configSection [ nameof ( KeyPath ) ] ;
78- Password = configSection [ nameof ( Password ) ] ;
79- }
80-
81- public string ? Path {
82- get ;
83- init ;
84- }
85-
86- public string ? KeyPath {
87- get ;
88- init ;
89- }
90-
91- public string ? Password {
92- get ;
93- init ;
94- }
95-
96- public X509Certificate2 ? LoadCertificate ( ) {
97- if ( ! string . IsNullOrEmpty ( Path ) ) {
98- var fullChain = new X509Certificate2Collection ( ) ;
99- fullChain . ImportFromPemFile ( Path ) ;
100-
101- if ( KeyPath != null ) {
102- #pragma warning disable CA2000
103- var certificate = new X509Certificate2 ( Path ) ;
104- #pragma warning restore CA2000
105- try {
106- certificate = LoadCertificateKey ( certificate , KeyPath , Password ) ;
107- } catch {
108- certificate . Dispose ( ) ;
109- throw ;
110- }
111-
112- if ( OperatingSystem . IsWindows ( ) ) {
113- try {
114- certificate = PersistKey ( certificate ) ;
115- } catch {
116- certificate . Dispose ( ) ;
117- throw ;
118- }
119- }
120- return certificate ;
121- }
122-
123- return new X509Certificate2 ( Path , Password ) ;
124- }
125-
126- return null ;
127-
128- static X509Certificate2 LoadCertificateKey ( X509Certificate2 certificate , string keyPath , string ? password ) {
129- const string RSAOid = "1.2.840.113549.1.1.1" ;
130- const string DSAOid = "1.2.840.10040.4.1" ;
131- const string ECDsaOid = "1.2.840.10045.2.1" ;
132-
133- var keyText = File . ReadAllText ( keyPath ) ;
134- switch ( certificate . PublicKey . Oid . Value ) {
135- case RSAOid : {
136- using var rsa = RSA . Create ( ) ;
137- ImportKeyFromFile ( rsa , keyText , password ) ;
138- return certificate . CopyWithPrivateKey ( rsa ) ;
139- }
140- case ECDsaOid : {
141- using var ecdsa = ECDsa . Create ( ) ;
142- ImportKeyFromFile ( ecdsa , keyText , password ) ;
143- return certificate . CopyWithPrivateKey ( ecdsa ) ;
144- }
145- case DSAOid : {
146- using var dsa = DSA . Create ( ) ;
147- ImportKeyFromFile ( dsa , keyText , password ) ;
148- return certificate . CopyWithPrivateKey ( dsa ) ;
149- }
150- default :
151- throw new InvalidOperationException ( string . Format ( CultureInfo . InvariantCulture , "Unknown algorithm for certificate with public key type '{0}'" , certificate . PublicKey . Oid . Value ) ) ;
152- }
153- }
154-
155- static void ImportKeyFromFile ( AsymmetricAlgorithm asymmetricAlgorithm , string keyText , string ? password ) {
156- if ( password == null ) {
157- asymmetricAlgorithm . ImportFromPem ( keyText ) ;
158- } else {
159- asymmetricAlgorithm . ImportFromEncryptedPem ( keyText , password ) ;
160- }
161- }
162-
163- static X509Certificate2 PersistKey ( X509Certificate2 fullCertificate ) {
164- // We need to force the key to be persisted.
165- // See https://github.com/dotnet/runtime/issues/23749
166- var certificateBytes = fullCertificate . Export ( X509ContentType . Pkcs12 , "" ) ;
167- return new X509Certificate2 ( certificateBytes , "" , X509KeyStorageFlags . DefaultKeySet ) ;
168- }
169- }
59+ public static IPulsarClientBuilder Configure ( this IPulsarClientBuilder pulsarClientBuilder , PulsarClientOptions ? options ) {
60+ ArgumentNullException . ThrowIfNull ( pulsarClientBuilder ) ;
61+ options ? . Apply ( pulsarClientBuilder ) ;
62+ return pulsarClientBuilder ;
17063 }
17164}
0 commit comments