1919 */
2020package org .sonarsource .scanner .lib .internal ;
2121
22- import java . io . FileInputStream ;
22+ import com . github . tomakehurst . wiremock . junit5 . WireMockExtension ;
2323import java .io .IOException ;
2424import java .net .URISyntaxException ;
25+ import java .net .URL ;
2526import java .nio .file .Path ;
2627import java .nio .file .Paths ;
27- import java .security .KeyStore ;
28- import java .security .SecureRandom ;
29- import javax .net .ssl .KeyManagerFactory ;
30- import javax .net .ssl .SSLContext ;
3128import javax .net .ssl .SSLHandshakeException ;
32- import javax .net .ssl .TrustManagerFactory ;
3329import okhttp3 .OkHttpClient ;
3430import okhttp3 .Request ;
3531import okhttp3 .Response ;
36- import okhttp3 .mockwebserver .Dispatcher ;
37- import okhttp3 .mockwebserver .MockResponse ;
38- import okhttp3 .mockwebserver .MockWebServer ;
39- import okhttp3 .mockwebserver .RecordedRequest ;
40- import org .junit .After ;
41- import org .junit .Rule ;
42- import org .junit .Test ;
43- import org .junit .experimental .theories .Theory ;
44- import org .junit .rules .ExpectedException ;
32+ import org .junit .jupiter .api .AfterEach ;
33+ import org .junit .jupiter .api .BeforeEach ;
34+ import org .junit .jupiter .api .Test ;
35+ import org .junit .jupiter .api .extension .RegisterExtension ;
4536import org .sonarsource .scanner .lib .internal .cache .Logger ;
4637
47- import static java .lang .String .format ;
38+ import static com .github .tomakehurst .wiremock .client .WireMock .anyUrl ;
39+ import static com .github .tomakehurst .wiremock .client .WireMock .get ;
40+ import static com .github .tomakehurst .wiremock .client .WireMock .matching ;
41+ import static com .github .tomakehurst .wiremock .client .WireMock .ok ;
42+ import static com .github .tomakehurst .wiremock .core .WireMockConfiguration .wireMockConfig ;
43+ import static java .util .Objects .requireNonNull ;
4844import static org .assertj .core .api .Assertions .assertThat ;
4945import static org .assertj .core .api .Assertions .assertThatThrownBy ;
46+ import static org .junit .Assert .assertThrows ;
5047import static org .junit .Assert .fail ;
5148import static org .mockito .Mockito .mock ;
5249
53- public class OkHttpClientFactoryTest {
50+ class OkHttpClientFactoryTest {
5451
5552 private static final String KEYSTORE_CLIENT_WITH_CA = "/client-with-ca.p12" ;
5653 private static final String CLIENT_WITH_CA_KEYSTORE_PASSWORD = "pwdClientCAP12" ;
@@ -64,56 +61,76 @@ public class OkHttpClientFactoryTest {
6461 private static final String SONAR_WS_TIMEOUT = "sonar.ws.timeout" ;
6562 private static final String COOKIE = "BIGipServerpool_sonarqube.example.com_8443=123456789.12345.0000" ;
6663
67- @ Rule
68- public ExpectedException expectedException = ExpectedException .none ();
64+ @ RegisterExtension
65+ static WireMockExtension sonarqubeMock = WireMockExtension .newInstance ()
66+ .options (wireMockConfig ().dynamicHttpsPort ().httpDisabled (true ).globalTemplating (true )
67+ .keystoreType ("pkcs12" )
68+ .keystorePath (toPath (requireNonNull (OkHttpClientFactoryTest .class .getResource (SERVER_KEYSTORE_FILE ))).toString ())
69+ .keystorePassword (SERVER_KEYSTORE_PASSWORD )
70+ .keyManagerPassword (SERVER_KEYSTORE_PASSWORD ))
71+ .build ();
72+
73+ @ BeforeEach
74+ void mockServerResponses () {
75+ sonarqubeMock .stubFor (get (anyUrl ()).withHeader ("Cookie" , matching (".*" )).atPriority (1 )
76+ .willReturn (ok ("OK\n {{request.headers.Cookie}}" )));
77+ sonarqubeMock .stubFor (get (anyUrl ()).atPriority (2 )
78+ .willReturn (ok ("OK" ).withHeader ("Set-Cookie" , COOKIE )));
79+ }
6980
70- @ After
81+ @ AfterEach
7182 public void cleanSystemProperty () {
7283 System .clearProperty (SONAR_WS_TIMEOUT );
7384 }
7485
7586 @ Test
76- public void support_custom_timeouts () {
87+ void support_custom_timeouts () {
7788 int readTimeoutSec = 2000 ;
7889 System .setProperty (SONAR_WS_TIMEOUT , String .valueOf (readTimeoutSec ));
7990
80- Logger logger = mock (Logger .class );
8191 OkHttpClient underTest = OkHttpClientFactory .create (logger );
8292
8393 assertThat (underTest .readTimeoutMillis ()).isEqualTo (readTimeoutSec * 1000 );
8494 }
8595
8696 @ Test
87- public void support_custom_timeouts_throws_exception_on_non_number () {
97+ void support_custom_timeouts_throws_exception_on_non_number () {
8898 System .setProperty (SONAR_WS_TIMEOUT , "fail" );
8999
90- Logger logger = mock (Logger .class );
91100 assertThatThrownBy (() -> OkHttpClientFactory .create (logger )).isInstanceOf (NumberFormatException .class );
92101 }
93102
94103 @ Test
95- public void test_with_external_http_server () throws IOException {
104+ void test_with_external_http_server () throws IOException {
96105 Response response = call ("http://www.google.com" );
97106 assertThat (response .code ()).isEqualTo (200 );
98107 assertThat (response .body ().string ()).contains ("doctype html" );
99108 }
100109
101110 @ Test
102- public void test_with_external_https_server_with_correct_certificate () throws IOException {
111+ void test_with_external_https_server_with_correct_certificate () throws IOException {
103112 Response response = call ("https://www.google.com" );
104113 assertThat (response .code ()).isEqualTo (200 );
105114 assertThat (response .body ().string ()).contains ("doctype html" );
106115 }
107116
108- @ Theory
109- public void when_overriding_truststore_known_websites_are_failing (String clientKeyStore ) throws IOException , URISyntaxException {
117+ @ Test
118+ void when_overriding_truststore_using_ca_known_websites_are_failing () throws IOException , URISyntaxException {
119+ when_overriding_truststore_known_websites_are_failing (KEYSTORE_CLIENT_WITH_CA , CLIENT_WITH_CA_KEYSTORE_PASSWORD );
120+ }
121+
122+ @ Test
123+ void when_overriding_truststore_using_server_certificate_known_websites_are_failing () throws IOException , URISyntaxException {
124+ when_overriding_truststore_known_websites_are_failing (KEYSTORE_CLIENT_WITH_CERTIFICATE , CLIENT_WITH_CERTIFICATE_KEYSTORE_PASSWORD );
125+ }
126+
127+ public void when_overriding_truststore_known_websites_are_failing (String clientKeyStore , String keyStorePassword ) throws URISyntaxException {
110128 try {
111129 Path clientTruststore = Paths .get (getClass ().getResource (clientKeyStore ).toURI ()).toAbsolutePath ();
112130 System .setProperty ("javax.net.ssl.trustStore" , clientTruststore .toString ());
113- System .setProperty ("javax.net.ssl.trustStorePassword" , SERVER_KEYSTORE_PASSWORD );
131+ System .setProperty ("javax.net.ssl.trustStorePassword" , keyStorePassword );
114132
115- expectedException .expect (SSLHandshakeException .class );
116- call ("https://www.google.com" );
133+ assertThrows (SSLHandshakeException .class , () -> call ("https://www.google.com" ));
117134 } finally {
118135 // Ensure to not keeping this property for other tests
119136 System .clearProperty ("javax.net.ssl.trustStore" );
@@ -122,19 +139,19 @@ public void when_overriding_truststore_known_websites_are_failing(String clientK
122139 }
123140
124141 @ Test
125- public void test_with_custom_https_server_using_ca_in_truststore () throws Exception {
142+ void test_with_custom_https_server_using_ca_in_truststore () throws Exception {
126143 test_with_custom_https_server (KEYSTORE_CLIENT_WITH_CA , CLIENT_WITH_CA_KEYSTORE_PASSWORD );
127144 }
128145
129146 @ Test
130- public void test_with_custom_https_server_using_server_certificate_in_truststore () throws Exception {
147+ void test_with_custom_https_server_using_server_certificate_in_truststore () throws Exception {
131148 test_with_custom_https_server (KEYSTORE_CLIENT_WITH_CERTIFICATE , CLIENT_WITH_CERTIFICATE_KEYSTORE_PASSWORD );
132149 }
133150
134151 private void test_with_custom_https_server (String clientKeyStore , String keyStorePassword ) throws Exception {
135152 System .setProperty ("javax.net.debug" , "ssl,handshake,record" );
136- try ( MockWebServer server = buildTLSServer ()) {
137- String url = format ( "https://localhost:%d/" , server . getPort () );
153+ try {
154+ String url = sonarqubeMock . baseUrl ( );
138155
139156 // First test without any truststore is expecting to fail
140157 try {
@@ -160,18 +177,18 @@ private void test_with_custom_https_server(String clientKeyStore, String keyStor
160177 }
161178
162179 @ Test
163- public void test_with_cookie_using_ca_in_truststore () throws Exception {
180+ void test_with_cookie_using_ca_in_truststore () throws Exception {
164181 test_with_cookie (KEYSTORE_CLIENT_WITH_CA , CLIENT_WITH_CA_KEYSTORE_PASSWORD );
165182 }
166183
167184 @ Test
168- public void test_with_cookie_using_server_certificate_in_truststore () throws Exception {
185+ void test_with_cookie_using_server_certificate_in_truststore () throws Exception {
169186 test_with_cookie (KEYSTORE_CLIENT_WITH_CERTIFICATE , CLIENT_WITH_CERTIFICATE_KEYSTORE_PASSWORD );
170187 }
171188
172189 private void test_with_cookie (String clientKeyStore , String keyStorePassword ) throws Exception {
173- try ( MockWebServer server = buildTLSServer ()) {
174- String url = format ( "https://localhost:%d/" , server . getPort () );
190+ try {
191+ String url = sonarqubeMock . baseUrl ( );
175192
176193 // Add the truststore
177194 Path clientTruststore = Paths .get (getClass ().getResource (clientKeyStore ).toURI ()).toAbsolutePath ();
@@ -203,54 +220,12 @@ private static Response call(String url) throws IOException {
203220 .execute ();
204221 }
205222
206- /**
207- * Build a MockWebServer with a dispatcher always sending 200 response with OK
208- * This webserver will use respond only to https protocol
209- */
210- private MockWebServer buildTLSServer () throws Exception {
211- MockWebServer server = new MockWebServer ();
212- server .setDispatcher (new Dispatcher () {
213- @ Override
214- public MockResponse dispatch (RecordedRequest request ) {
215- String responseBody = "OK" ;
216- MockResponse response = new MockResponse ().setResponseCode (200 );
217- String cookie = request .getHeader ("Cookie" );
218- if (cookie == null || cookie .isEmpty ()) {
219- // Only set the cookie if it is not already set
220- response .addHeader ("Set-Cookie" , COOKIE );
221- } else {
222- // dump the cookie into the response body to aid in test inspection
223- responseBody += "\n Cookie: " + cookie ;
224- }
225- response .setBody (responseBody );
226- return response ;
227- }
228- });
229-
230- // JKS file storing the private key and TLS certificate
231- Path serverCertificate = Paths .get (getClass ().getResource (SERVER_KEYSTORE_FILE ).toURI ()).toAbsolutePath ();
232-
233- // Load the KeyStore
234- KeyStore serverKeyStore = KeyStore .getInstance ("pkcs12" );
235- FileInputStream stream = new FileInputStream (serverCertificate .toFile ());
236- serverKeyStore .load (stream , SERVER_KEYSTORE_PASSWORD .toCharArray ());
237-
238- // Load the KeyManager from the KeyStore
239- String kmfAlgorithm = KeyManagerFactory .getDefaultAlgorithm ();
240- KeyManagerFactory kmf = KeyManagerFactory .getInstance (kmfAlgorithm );
241- kmf .init (serverKeyStore , SERVER_KEYSTORE_PASSWORD .toCharArray ());
242-
243- // Add the "Keys" (ie. private key and TLS certificate to the TrustManager
244- TrustManagerFactory trustManagerFactory = TrustManagerFactory .getInstance (kmfAlgorithm );
245- trustManagerFactory .init (serverKeyStore );
246-
247- // Create the SocketFactory using the TrustManager so the private key and certificate
248- SSLContext sslContext = SSLContext .getInstance ("TLSv1.2" );
249- sslContext .init (kmf .getKeyManagers (), trustManagerFactory .getTrustManagers (), new SecureRandom ());
250-
251- // Let's use it for the WebServer
252- server .useHttps (sslContext .getSocketFactory (), false );
253-
254- return server ;
223+ private static Path toPath (URL url ) {
224+ try {
225+ return Paths .get (url .toURI ());
226+ } catch (URISyntaxException e ) {
227+ throw new RuntimeException (e );
228+ }
255229 }
230+
256231}
0 commit comments