diff --git a/samples/apache-cloudstack-client-examples/src/main/java/br/com/autonomiccs/apacheCloudStack/examples/UsernameAndPasswordAuthentication.java b/samples/apache-cloudstack-client-examples/src/main/java/br/com/autonomiccs/apacheCloudStack/examples/UsernameAndPasswordAuthentication.java index 58f2b44..637c186 100644 --- a/samples/apache-cloudstack-client-examples/src/main/java/br/com/autonomiccs/apacheCloudStack/examples/UsernameAndPasswordAuthentication.java +++ b/samples/apache-cloudstack-client-examples/src/main/java/br/com/autonomiccs/apacheCloudStack/examples/UsernameAndPasswordAuthentication.java @@ -36,9 +36,7 @@ public static void main(String[] args) { ApacheCloudStackClient apacheCloudStackClient = new ApacheCloudStackClient(cloudStackUrl, apacheCloudStackUser); apacheCloudStackClient.setValidateServerHttpsCertificate(false); - ApacheCloudStackRequest apacheCloudStackRequest = new ApacheCloudStackRequest("listUsers"); - apacheCloudStackRequest.addParameter("response", "json"); - apacheCloudStackRequest.addParameter("listall", true); + ApacheCloudStackRequest apacheCloudStackRequest = new ApacheCloudStackRequest("listHosts"); String response = apacheCloudStackClient.executeRequest(apacheCloudStackRequest); System.out.println(response); } diff --git a/src/main/java/br/com/autonomiccs/apacheCloudStack/client/ApacheCloudStackClient.java b/src/main/java/br/com/autonomiccs/apacheCloudStack/client/ApacheCloudStackClient.java index d95568d..f61ce95 100644 --- a/src/main/java/br/com/autonomiccs/apacheCloudStack/client/ApacheCloudStackClient.java +++ b/src/main/java/br/com/autonomiccs/apacheCloudStack/client/ApacheCloudStackClient.java @@ -32,6 +32,7 @@ import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -41,6 +42,11 @@ import java.util.List; import java.util.Objects; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; + import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.HmacUtils; import org.apache.commons.io.IOUtils; @@ -93,6 +99,13 @@ public class ApacheCloudStackClient { */ protected boolean validateServerHttpsCertificate = true; + /** + * This flag is highly dangerous and should never be used with production environments. + * It will accept every single SSL certificates when creating HTTPS connections. Not even the commons name will be checked. + * Therefore, it should be kept only during development phase. + */ + protected boolean acceptAllKindsOfCertificates = false; + /** * The validity time of the ACS request. * The default value is {@value #requestValidity} . @@ -330,15 +343,65 @@ protected List getParametersForLogin() { * For that we use {@link TrustSelfSignedStrategy}. */ protected SSLConnectionSocketFactory createInsecureSslFactory() { - SSLContextBuilder builder = new SSLContextBuilder(); try { + SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(new TrustSelfSignedStrategy()); - return new SSLConnectionSocketFactory(builder.build()); + SSLContext sc = builder.build(); + + if (acceptAllKindsOfCertificates) { + TrustManager[] trustAllCerts = new TrustManager[1]; + TrustManager tm = new TrustAllManager(); + trustAllCerts[0] = tm; + sc.init(null, trustAllCerts, null); + + HostnameVerifier hostnameVerifier = createInsecureHostNameVerifier(); + return new SSLConnectionSocketFactory(sc, hostnameVerifier); + } + return new SSLConnectionSocketFactory(sc); } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { throw new ApacheCloudStackClientRuntimeException(e); } } + protected HostnameVerifier createInsecureHostNameVerifier() { + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + return hostnameVerifier; + } + + /** + * This class is used when {@link ApacheCloudStackClient#acceptAllKindsOfCertificates} is set to true. + */ + @SuppressWarnings("unused") + private class TrustAllManager implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + public boolean isServerTrusted(final X509Certificate[] certs) { + return true; + } + + public boolean isClientTrusted(final X509Certificate[] certs) { + return true; + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { + return; + } + + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { + return; + } + } + /** * It retrieves the response status as a {@link String} */ @@ -472,6 +535,10 @@ public T executeRequest(ApacheCloudStackRequest request, Class clazz) { return gson.fromJson(response, clazz); } + /** + * This configuration enables or disables the HTTPS certification validation. If set to 'false', we will accept self-signed certificates. + * However, this does not mean that we accept certificates that are signed by an untrusted certificated authority. + */ public void setValidateServerHttpsCertificate(boolean validateServerHttpsCertificate) { this.validateServerHttpsCertificate = validateServerHttpsCertificate; } @@ -487,4 +554,8 @@ public void setShouldRequestsExpire(boolean shouldRequestsExpire) { public void setConnectionTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; } + + public void setAcceptAllKindsOfCertificates(boolean acceptAllKindOfCertificates) { + this.acceptAllKindsOfCertificates = acceptAllKindOfCertificates; + } } diff --git a/src/test/java/br/com/autonomiccs/apacheCloudStack/client/ApacheCloudStackClientTest.java b/src/test/java/br/com/autonomiccs/apacheCloudStack/client/ApacheCloudStackClientTest.java index 5a88bb9..5d0620d 100644 --- a/src/test/java/br/com/autonomiccs/apacheCloudStack/client/ApacheCloudStackClientTest.java +++ b/src/test/java/br/com/autonomiccs/apacheCloudStack/client/ApacheCloudStackClientTest.java @@ -21,9 +21,19 @@ */ package br.com.autonomiccs.apacheCloudStack.client; -import br.com.autonomiccs.apacheCloudStack.client.beans.ApacheCloudStackUser; -import br.com.autonomiccs.apacheCloudStack.exceptions.ApacheCloudStackClientRequestRuntimeException; -import br.com.autonomiccs.apacheCloudStack.exceptions.ApacheCloudStackClientRuntimeException; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.net.ssl.HostnameVerifier; + import org.apache.commons.lang3.time.DateUtils; import org.apache.http.Header; import org.apache.http.HeaderElement; @@ -55,16 +65,9 @@ import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import br.com.autonomiccs.apacheCloudStack.client.beans.ApacheCloudStackUser; +import br.com.autonomiccs.apacheCloudStack.exceptions.ApacheCloudStackClientRequestRuntimeException; +import br.com.autonomiccs.apacheCloudStack.exceptions.ApacheCloudStackClientRuntimeException; @RunWith(MockitoJUnitRunner.class) public class ApacheCloudStackClientTest { @@ -156,21 +159,35 @@ public void createRequestConfigCustomValueTest() { } @Test - public void createHttpClientTestValidateServerHttpsCertificateTrue() { - configureExecuteAndVerifyTestForCreateHttpClient(true, 0); + public void createHttpClientTestValidateServerHttpsCertificateTrueAndTotalInsecureFalse() { + configureExecuteAndVerifyTestForCreateHttpClient(true, 0, false, 0); + } + + @Test + public void createHttpClientTestValidateServerHttpsCertificateTrueAndTotalInsecureTrue() { + configureExecuteAndVerifyTestForCreateHttpClient(true, 0, true, 0); } @Test - public void createHttpClientTestValidateServerHttpsCertificateFalse() { - configureExecuteAndVerifyTestForCreateHttpClient(false, 1); + public void createHttpClientTestValidateServerHttpsCertificateFalseAndTotalInsecureFalse() { + configureExecuteAndVerifyTestForCreateHttpClient(false, 1, false, 0); } - private void configureExecuteAndVerifyTestForCreateHttpClient(boolean shouldVerifyServerCertificates, int numberOfCreateUnsecureSslFactoryCalls) { + @Test + public void createHttpClientTestValidateServerHttpsCertificateFalseAndTotalInsecureTrue() { + configureExecuteAndVerifyTestForCreateHttpClient(false, 1, true, 1); + } + + private void configureExecuteAndVerifyTestForCreateHttpClient(boolean shouldVerifyServerCertificates, int numberOfCreateUnsecureSslFactoryCalls, boolean totalInsecure, + int expectedCallForInsecureHostNameCheck) { apacheCloudStackClient.validateServerHttpsCertificate = shouldVerifyServerCertificates; + apacheCloudStackClient.acceptAllKindsOfCertificates = totalInsecure; + CloseableHttpClient httpClient = apacheCloudStackClient.createHttpClient(); Assert.assertNotNull(httpClient); Mockito.verify(apacheCloudStackClient, Mockito.times(1)).createRequestConfig(); + Mockito.verify(apacheCloudStackClient, Mockito.times(expectedCallForInsecureHostNameCheck)).createInsecureHostNameVerifier(); Mockito.verify(apacheCloudStackClient, Mockito.times(numberOfCreateUnsecureSslFactoryCalls)).createInsecureSslFactory(); } @@ -626,4 +643,13 @@ public void createExpirationDateTest() { Mockito.verify(apacheCloudStackClient).getExpirationDate(); } + + @Test + public void createInsecureHostNameVerifierTest() { + HostnameVerifier hostNameVerifier = apacheCloudStackClient.createInsecureHostNameVerifier(); + + Assert.assertTrue(hostNameVerifier.verify("...", null)); + Assert.assertTrue(hostNameVerifier.verify("Any other thing", null)); + + } }