5
5
using Microsoft . Extensions . Configuration ;
6
6
using Microsoft . Extensions . DependencyInjection ;
7
7
using Microsoft . Extensions . Hosting ;
8
+ using Microsoft . Extensions . Logging ;
8
9
using Microsoft . Extensions . Options ;
9
10
using NSubstitute ;
10
11
using Xunit ;
@@ -30,10 +31,6 @@ public async Task OptionsPatternReturnsCachedValue()
30
31
31
32
var services = CreateServices ( ( gs , environment , config ) =>
32
33
{
33
- gs . SelfHosted = true ;
34
-
35
- environment . EnvironmentName = "Development" ;
36
-
37
34
config [ "X509ChainOptions:AdditionalCustomTrustCertificatesDirectory" ] = tempDir . FullName ;
38
35
} ) ;
39
36
@@ -69,8 +66,6 @@ public async Task DoesNotProvideCustomCallbackOnCloud()
69
66
{
70
67
gs . SelfHosted = false ;
71
68
72
- environment . EnvironmentName = "Development" ;
73
-
74
69
config [ "X509ChainOptions:AdditionalCustomTrustCertificatesDirectory" ] = tempDir . FullName ;
75
70
} ) ;
76
71
@@ -85,12 +80,8 @@ public async Task ManuallyAddingOptionsTakesPrecedence()
85
80
var tempCert = Path . Combine ( tempDir . FullName , "test.crt" ) ;
86
81
await File . WriteAllBytesAsync ( tempCert , CreateSelfSignedCert ( "localhost" ) . Export ( X509ContentType . Cert ) ) ;
87
82
88
- var options = CreateOptions ( ( gs , environment , config ) =>
83
+ var services = CreateServices ( ( gs , environment , config ) =>
89
84
{
90
- gs . SelfHosted = false ;
91
-
92
- environment . EnvironmentName = "Development" ;
93
-
94
85
config [ "X509ChainOptions:AdditionalCustomTrustCertificatesDirectory" ] = tempDir . FullName ;
95
86
} , services =>
96
87
{
@@ -100,9 +91,95 @@ public async Task ManuallyAddingOptionsTakesPrecedence()
100
91
} ) ;
101
92
} ) ;
102
93
94
+ var options = services . GetRequiredService < IOptions < X509ChainOptions > > ( ) . Value ;
95
+
103
96
Assert . True ( options . TryGetCustomRemoteCertificateValidationCallback ( out var callback ) ) ;
104
97
var cert = Assert . Single ( options . AdditionalCustomTrustCertificates ) ;
105
98
Assert . Equal ( "CN=example.com" , cert . Subject ) ;
99
+
100
+ var fakeLogCollector = services . GetFakeLogCollector ( ) ;
101
+
102
+ Assert . Contains ( fakeLogCollector . GetSnapshot ( ) ,
103
+ r => r . Message == $ "Additional custom trust certificates were added directly, skipping loading them from '{ tempDir } '") ;
104
+ }
105
+
106
+ [ Fact ]
107
+ public void NullCustomDirectory_SkipsTryingToLoad ( )
108
+ {
109
+ var services = CreateServices ( ( gs , environment , config ) =>
110
+ {
111
+ config [ "X509ChainOptions:AdditionalCustomTrustCertificatesDirectory" ] = null ;
112
+ } ) ;
113
+
114
+ var options = services . GetRequiredService < IOptions < X509ChainOptions > > ( ) . Value ;
115
+
116
+ Assert . False ( options . TryGetCustomRemoteCertificateValidationCallback ( out _ ) ) ;
117
+ }
118
+
119
+ [ Theory ]
120
+ [ InlineData ( "Development" , LogLevel . Debug ) ]
121
+ [ InlineData ( "Production" , LogLevel . Warning ) ]
122
+ public void CustomDirectoryDoesNotExist_Logs ( string environment , LogLevel logLevel )
123
+ {
124
+ var fakeDir = "/fake/dir/that/does/not/exist" ;
125
+ var services = CreateServices ( ( gs , hostEnvironment , config ) =>
126
+ {
127
+ hostEnvironment . EnvironmentName = environment ;
128
+
129
+ config [ "X509ChainOptions:AdditionalCustomTrustCertificatesDirectory" ] = fakeDir ;
130
+ } ) ;
131
+
132
+ var options = services . GetRequiredService < IOptions < X509ChainOptions > > ( ) . Value ;
133
+
134
+ Assert . False ( options . TryGetCustomRemoteCertificateValidationCallback ( out _ ) ) ;
135
+
136
+ var fakeLogCollector = services . GetFakeLogCollector ( ) ;
137
+
138
+ Assert . Contains ( fakeLogCollector . GetSnapshot ( ) ,
139
+ r => r . Message == $ "An additional custom trust certificate directory was given '{ fakeDir } ' but that directory does not exist."
140
+ && r . Level == logLevel
141
+ ) ;
142
+ }
143
+
144
+ [ Fact ]
145
+ public async Task NamedOptions_NotConfiguredAsync ( )
146
+ {
147
+ // To help make sure this fails for the right reason we should add certs to the directory
148
+ var tempDir = Directory . CreateTempSubdirectory ( "certs" ) ;
149
+
150
+ var tempCert = Path . Combine ( tempDir . FullName , "test.crt" ) ;
151
+ await File . WriteAllBytesAsync ( tempCert , CreateSelfSignedCert ( "localhost" ) . Export ( X509ContentType . Cert ) ) ;
152
+
153
+ var services = CreateServices ( ( gs , environment , config ) =>
154
+ {
155
+ config [ "X509ChainOptions:AdditionalCustomTrustCertificatesDirectory" ] = tempDir . FullName ;
156
+ } ) ;
157
+
158
+ var options = services . GetRequiredService < IOptionsMonitor < X509ChainOptions > > ( ) ;
159
+
160
+ var namedOptions = options . Get ( "SomeName" ) ;
161
+
162
+ Assert . Null ( namedOptions . AdditionalCustomTrustCertificates ) ;
163
+ }
164
+
165
+ [ Fact ]
166
+ public void CustomLocation_NoCertificates_Logs ( )
167
+ {
168
+ var tempDir = Directory . CreateTempSubdirectory ( "certs" ) ;
169
+ var services = CreateServices ( ( gs , hostEnvironment , config ) =>
170
+ {
171
+ config [ "X509ChainOptions:AdditionalCustomTrustCertificatesDirectory" ] = tempDir . FullName ;
172
+ } ) ;
173
+
174
+ var options = services . GetRequiredService < IOptions < X509ChainOptions > > ( ) . Value ;
175
+
176
+ Assert . False ( options . TryGetCustomRemoteCertificateValidationCallback ( out _ ) ) ;
177
+
178
+ var fakeLogCollector = services . GetFakeLogCollector ( ) ;
179
+
180
+ Assert . Contains ( fakeLogCollector . GetSnapshot ( ) ,
181
+ r => r . Message == $ "No additional custom trust certificates were found in '{ tempDir . FullName } '"
182
+ ) ;
106
183
}
107
184
108
185
private static X509ChainOptions CreateOptions ( Action < GlobalSettings , IHostEnvironment , Dictionary < string , string > > configure , Action < IServiceCollection > ? after = null )
@@ -113,13 +190,23 @@ private static X509ChainOptions CreateOptions(Action<GlobalSettings, IHostEnviro
113
190
114
191
private static IServiceProvider CreateServices ( Action < GlobalSettings , IHostEnvironment , Dictionary < string , string > > configure , Action < IServiceCollection > ? after = null )
115
192
{
116
- var globalSettings = new GlobalSettings ( ) ;
193
+ var globalSettings = new GlobalSettings
194
+ {
195
+ // A solid default for these tests as these settings aren't allowed to work in cloud.
196
+ SelfHosted = true ,
197
+ } ;
117
198
var hostEnvironment = Substitute . For < IHostEnvironment > ( ) ;
199
+ hostEnvironment . EnvironmentName = "Development" ;
118
200
var config = new Dictionary < string , string > ( ) ;
119
201
120
202
configure ( globalSettings , hostEnvironment , config ) ;
121
203
122
204
var services = new ServiceCollection ( ) ;
205
+ services . AddLogging ( logging =>
206
+ {
207
+ logging . SetMinimumLevel ( LogLevel . Debug ) ;
208
+ logging . AddFakeLogging ( ) ;
209
+ } ) ;
123
210
services . AddSingleton ( globalSettings ) ;
124
211
services . AddSingleton ( hostEnvironment ) ;
125
212
services . AddSingleton < IConfiguration > (
0 commit comments