55using System . Linq ;
66using System . Net ;
77using System . Net . Http ;
8+ using System . Net . Security ;
9+ using System . Net . Sockets ;
10+ using System . Security . Cryptography . X509Certificates ;
811using System . Text ;
912using System . Threading . Tasks ;
1013using System . Web ;
@@ -13,15 +16,14 @@ namespace AzFappDebugger.Tests
1316{
1417 internal class OutboundConnectivityTests
1518 {
16- private static IDictionary < string , string > _environmentVariablesDictionary = null ;
19+ private IDictionary < string , string > _environmentVariablesDictionary = null ;
20+ private HttpClient _defaultHttpClient ;
1721
18- private HttpClient _httpClient = null ;
19-
20- internal OutboundConnectivityTests ( IDictionary < string , string > environmentVariablesDictionary , HttpClient httpClient )
22+ internal OutboundConnectivityTests ( IDictionary < string , string > environmentVariablesDictionary , HttpClient defaultHttpClient )
2123 {
2224
2325 _environmentVariablesDictionary = environmentVariablesDictionary ;
24- _httpClient = httpClient ;
26+ _defaultHttpClient = defaultHttpClient ;
2527 }
2628
2729
@@ -44,9 +46,10 @@ internal async Task<string> RunAllTestsAsHtmlOutputAsync()
4446 {
4547 output += HtmlBrandingHelper . GetStandardTableRow ( "Integrated vNET" , $ "<code>{ configItemValue } </code>") ;
4648 }
47- else {
49+ else
50+ {
4851 output += HtmlBrandingHelper . GetStandardTableRow ( "Integrated vNET" , $ "<span class=\" badge text-bg-danger\" >No vNET integration</span><br>" +
49- $ "The application is not integrated with any vNET.") ;
52+ $ "The application is not integrated with any vNET.") ;
5053 }
5154
5255
@@ -62,71 +65,108 @@ internal async Task<string> RunAllTestsAsHtmlOutputAsync()
6265
6366 output += $ "<h3>Connectivity tests</h3>";
6467
65- if ( _httpClient != null )
66- {
68+ string httpClientUrlToResolve = string . Empty ;
6769
68- string httpClientUrlToResolve = string . Empty ;
69-
70- output += $ "<h4>HttpClient test</h4> <small>";
71- output += HtmlBrandingHelper . GetBootstrapWhatItMeans ( "OutboundConnectivityHttpClient" ,
72- $ "<p>This test performs HTTP request via outbound connectivity of the application to hostname specified in <code>{ Constants . TEST_HTTPCLIENT_RESOLVE_URL_VARIABLE } </code> configuration variable.</p>", false , false , "Test description" ) ;
73- output += "</small>" ;
70+ output += $ "<h4>HttpClient test</h4> <small>";
71+ output += HtmlBrandingHelper . GetBootstrapWhatItMeans ( "OutboundConnectivityHttpClient" ,
72+ $ "<p>This test performs HTTP request via outbound connectivity of the application to hostname specified in <code>{ Constants . TEST_HTTPCLIENT_RESOLVE_URL_VARIABLE } </code> configuration variable.</p>", false , false , "Test description" ) ;
73+ output += "</small>" ;
7474
7575
76- _environmentVariablesDictionary . TryGetValue ( Constants . TEST_HTTPCLIENT_RESOLVE_URL_VARIABLE , out httpClientUrlToResolve ) ;
76+ _environmentVariablesDictionary . TryGetValue ( Constants . TEST_HTTPCLIENT_RESOLVE_URL_VARIABLE , out httpClientUrlToResolve ) ;
7777
78- if ( ! string . IsNullOrWhiteSpace ( httpClientUrlToResolve ) )
78+ if ( ! string . IsNullOrWhiteSpace ( httpClientUrlToResolve ) && _defaultHttpClient != null )
79+ {
80+ output += "<table class=\" table\" >" ;
81+ string testResult = "" ;
82+ try
7983 {
80- output += "<table class=\" table\" >" ;
81- string testResult = "" ;
82- try
83- {
84- var content = await _httpClient . GetStringAsync ( httpClientUrlToResolve ) ;
85- testResult = $ "<span class=\" badge text-bg-success\" >OK</span><br><code>{ HttpUtility . HtmlEncode ( content ) } </code>";
86- }
87- catch ( Exception e )
88- {
89- testResult = "<span class=\" badge text-bg-danger\" >QUERY FAILED</span><br> " + e . Message + "<br>" + ( e . InnerException != null ? e . InnerException . Message : "" ) ;
90- }
91- finally
92- {
93- output += HtmlBrandingHelper . GetStandardTableRow ( $ "{ httpClientUrlToResolve } ", testResult ) ;
94- }
84+ var httpClientUrlToResolveUri = new Uri ( httpClientUrlToResolve ) ;
85+ var content = await _defaultHttpClient . GetAsync ( httpClientUrlToResolveUri ) ;
86+ content . EnsureSuccessStatusCode ( ) ;
87+ string text = await content . Content . ReadAsStringAsync ( ) ;
9588
96- output += "</table>" ;
97- }
9889
90+ testResult = $ "<span class=\" badge text-bg-success\" >OK</span> { ( int ) content . StatusCode } { content . StatusCode } <br><br>";
9991
100- if ( ! string . IsNullOrWhiteSpace ( Constants . MY_IP_ADDRESS_EXTERNAL_SERVICE_URL ) )
101- {
102- output += $ "<h4>My outbound IP address</h4> <small>";
103- output += HtmlBrandingHelper . GetBootstrapWhatItMeans ( "OutboundConnectivityExternalIp" ,
104- $ "<p>This test performs a HTTP request to external service, which returns a IP address of HTTP request.</p>", false , false , "Test description" ) ;
105- output += "</small>" ;
10692
107- output += "<table class= \" table \" >" ;
108- string testResult = " ";
93+ testResult += $ "<strong>Connection details</strong><br>" +
94+ $ "Protocol: <code>HTTP { content . Version } </code><br> ";
10995 try
11096 {
111- var content = await _httpClient . GetStringAsync ( Constants . MY_IP_ADDRESS_EXTERNAL_SERVICE_URL ) ;
112- testResult = $ "<code>{ HttpUtility . HtmlEncode ( content ) } </code>";
113- }
114- catch ( Exception e )
115- {
116- testResult = "<span class=\" badge text-bg-danger\" >QUERY FAILED</span><br> " + e . InnerException . Message ;
97+ RemoteCertificateValidationCallback certCallback = ( _ , _ , _ , _ ) => true ;
98+ using var client = new TcpClient ( httpClientUrlToResolveUri . Host , httpClientUrlToResolveUri . Port ) ;
99+ using var sslStream = new SslStream ( client . GetStream ( ) , true , certCallback ) ;
100+ await sslStream . AuthenticateAsClientAsync ( httpClientUrlToResolveUri . Host ) ;
101+ var serverCertificate = sslStream . RemoteCertificate ;
102+ var certificate = new X509Certificate2 ( serverCertificate ) ;
103+
104+ if ( certificate != null )
105+ {
106+ testResult += $ "Security protocol: <code>{ HtmlBrandingHelper . NiceTlsProtocol ( sslStream . SslProtocol ) } </code><br>" +
107+ $ "Negotiated cipher: <code>{ sslStream . NegotiatedCipherSuite } </code><br><br>";
108+
109+ testResult += $ "<strong>Certificate</strong><br>" +
110+ $ "Subject: <code>{ certificate . Subject } </code><br>" +
111+ $ "Issuer: <code>{ certificate . Issuer } </code><br>" +
112+ $ "Valid from: <code>{ certificate . GetEffectiveDateString ( ) } </code><br>" +
113+ $ "Expires on: <code>{ certificate . GetExpirationDateString ( ) } </code><br>" +
114+ $ "Thumbprint: <code>{ certificate . Thumbprint } </code><br><br>"
115+ ;
116+ }
117117 }
118- finally
118+ catch ( Exception ee )
119119 {
120- output += HtmlBrandingHelper . GetStandardTableRow ( $ "My IP address", testResult ) ;
120+ testResult += $ "<i>Connection is not secured</i><br><br>";
121+
121122 }
122123
123- output += "</table>" ;
124+ testResult += $ "<strong>Body:</strong><br>" +
125+ $ "<code>{ HttpUtility . HtmlEncode ( HtmlBrandingHelper . NormalizeLength ( text , 1000 ) ) } </code>";
124126 }
127+ catch ( Exception e )
128+ {
129+ testResult = "<span class=\" badge text-bg-danger\" >QUERY FAILED</span><br> " + e . Message + "<br>" + ( e . InnerException != null ? e . InnerException . Message : "" ) ;
130+ }
131+ finally
132+ {
133+ output += HtmlBrandingHelper . GetStandardTableRow ( $ "{ httpClientUrlToResolve } ", testResult ) ;
134+ }
135+
125136
137+ output += "</table>" ;
138+ }
139+ else
140+ {
141+ output += $ "<div class='callout callout-warning'>No valid <code>{ Constants . TEST_HTTPCLIENT_RESOLVE_URL_VARIABLE } </code> variable defined, test has been skipped.</div>";
126142 }
127143
128144
145+ if ( ! string . IsNullOrWhiteSpace ( Constants . MY_IP_ADDRESS_EXTERNAL_SERVICE_URL ) && _defaultHttpClient != null )
146+ {
147+ output += $ "<h4>My outbound IP address</h4> <small>";
148+ output += HtmlBrandingHelper . GetBootstrapWhatItMeans ( "OutboundConnectivityExternalIp" ,
149+ $ "<p>This test performs a HTTP request to external service, which returns a IP address of HTTP request.</p>", false , false , "Test description" ) ;
150+ output += "</small>" ;
129151
152+ output += "<table class=\" table\" >" ;
153+ string testResult = "" ;
154+ try
155+ {
156+ var content = await _defaultHttpClient . GetStringAsync ( Constants . MY_IP_ADDRESS_EXTERNAL_SERVICE_URL ) ;
157+ testResult = $ "<code>{ HttpUtility . HtmlEncode ( content ) } </code>";
158+ }
159+ catch ( Exception e )
160+ {
161+ testResult = "<span class=\" badge text-bg-danger\" >QUERY FAILED</span><br> " + e . InnerException . Message ;
162+ }
163+ finally
164+ {
165+ output += HtmlBrandingHelper . GetStandardTableRow ( $ "My IP address", testResult ) ;
166+ }
167+
168+ output += "</table>" ;
169+ }
130170
131171 return output ;
132172 }
0 commit comments