1
+ using Microsoft . AspNetCore . Mvc ;
2
+ using Microsoft . AspNetCore . Server . HttpSys ;
3
+
4
+ var builder = WebApplication . CreateBuilder ( args ) ;
5
+ builder . Logging . ClearProviders ( ) ;
6
+
7
+ var writeCertValidationEventsToConsole = bool . TryParse ( builder . Configuration [ "certValidationConsoleEnabled" ] , out var certValidationConsoleEnabled ) && certValidationConsoleEnabled ;
8
+ var statsEnabled = bool . TryParse ( builder . Configuration [ "statsEnabled" ] , out var connectionStatsEnabledConfig ) && connectionStatsEnabledConfig ;
9
+ var mTlsEnabled = bool . TryParse ( builder . Configuration [ "mTLS" ] , out var mTlsEnabledConfig ) && mTlsEnabledConfig ;
10
+ var listeningEndpoints = builder . Configuration [ "urls" ] ?? "https://localhost:5000/" ;
11
+
12
+ #pragma warning disable CA1416 // Can be launched only on Windows (HttpSys)
13
+ builder . WebHost . UseHttpSys ( options =>
14
+ {
15
+ // meaning client can send a certificate, but it can be explicitly requested by server as well (renegotiation)
16
+ options . ClientCertificateMethod = ClientCertificateMethod . AllowRenegotation ;
17
+ } ) ;
18
+ #pragma warning restore CA1416 // Can be launched only on Windows (HttpSys)
19
+
20
+ var app = builder . Build ( ) ;
21
+
22
+ app . MapGet ( "/hello-world" , ( ) =>
23
+ {
24
+ return Results . Ok ( "Hello World!" ) ;
25
+ } ) ;
26
+
27
+ var connectionIds = new HashSet < string > ( ) ;
28
+ var fetchedCertsCounter = 0 ;
29
+
30
+ if ( statsEnabled )
31
+ {
32
+ Console . WriteLine ( "Registered stats middleware" ) ;
33
+ app . Use ( async ( context , next ) =>
34
+ {
35
+ connectionIds . Add ( context . Connection . Id ) ;
36
+ Console . WriteLine ( $ "[stats] unique connections established: { connectionIds . Count } ; fetched certificates: { fetchedCertsCounter } ") ;
37
+
38
+ await next ( ) ;
39
+ } ) ;
40
+ }
41
+
42
+ if ( mTlsEnabled )
43
+ {
44
+ // this is an http.sys middleware to get a cert
45
+ Console . WriteLine ( "Registered client cert validation middleware" ) ;
46
+
47
+ app . Use ( async ( context , next ) => {
48
+ var clientCert = context . Connection . ClientCertificate ;
49
+ if ( clientCert is null )
50
+ {
51
+ if ( writeCertValidationEventsToConsole )
52
+ {
53
+ Console . WriteLine ( $ "No client certificate provided. Fetching for connection { context . Connection . Id } ") ;
54
+ }
55
+
56
+ clientCert = await context . Connection . GetClientCertificateAsync ( CancellationToken . None ) ;
57
+ Interlocked . Increment ( ref fetchedCertsCounter ) ;
58
+ }
59
+ else
60
+ {
61
+ if ( writeCertValidationEventsToConsole )
62
+ {
63
+ Console . WriteLine ( $ "client certificate ({ clientCert . Thumbprint } ) already exists on the connection { context . Connection . Id } ") ;
64
+ }
65
+ }
66
+
67
+ // we have a client cert here, and lets imagine we do the validation here
68
+ // if (clientCert.Thumbprint != "1234567890") throw new NotImplementedException();
69
+
70
+ await next ( ) ;
71
+ } ) ;
72
+ }
73
+
74
+ await app . StartAsync ( ) ;
75
+ Console . WriteLine ( "Application Info:" ) ;
76
+ if ( mTlsEnabled )
77
+ {
78
+ Console . WriteLine ( $ "\t mTLS is enabled (client cert is required)") ;
79
+ }
80
+ if ( writeCertValidationEventsToConsole )
81
+ {
82
+ Console . WriteLine ( $ "\t enabled logging certificate validation events to console") ;
83
+ }
84
+ if ( statsEnabled )
85
+ {
86
+ Console . WriteLine ( $ "\t enabled logging stats to console") ;
87
+ }
88
+ Console . WriteLine ( $ "\t listening endpoints: { listeningEndpoints } ") ;
89
+ Console . WriteLine ( "--------------------------------" ) ;
90
+
91
+ Console . WriteLine ( "Application started." ) ;
92
+ await app . WaitForShutdownAsync ( ) ;
0 commit comments