diff --git a/src/main/java/com/aliyun/tea/okhttp/OkHttpClientBuilder.java b/src/main/java/com/aliyun/tea/okhttp/OkHttpClientBuilder.java index 95042a2..ab4ab51 100644 --- a/src/main/java/com/aliyun/tea/okhttp/OkHttpClientBuilder.java +++ b/src/main/java/com/aliyun/tea/okhttp/OkHttpClientBuilder.java @@ -4,7 +4,7 @@ import com.aliyun.tea.TeaException; import com.aliyun.tea.okhttp.interceptors.SocksProxyAuthInterceptor; import com.aliyun.tea.utils.StringUtils; -import com.aliyun.tea.utils.TrueHostnameVerifier; +import com.aliyun.tea.utils.DefaultHostnameVerifier; import com.aliyun.tea.utils.X509TrustManagerImp; import okhttp3.*; import okhttp3.Authenticator; @@ -87,11 +87,11 @@ public OkHttpClientBuilder connectionPool(Map map) { public OkHttpClientBuilder certificate(Map map) { try { if (null != map.get("ignoreSSL") && Boolean.parseBoolean(String.valueOf(map.get("ignoreSSL")))) { - X509TrustManager compositeX509TrustManager = new X509TrustManagerImp(); + X509TrustManager compositeX509TrustManager = new X509TrustManagerImp(true); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{compositeX509TrustManager}, new java.security.SecureRandom()); this.builder.sslSocketFactory(sslContext.getSocketFactory(), compositeX509TrustManager). - hostnameVerifier(new TrueHostnameVerifier()); + hostnameVerifier(DefaultHostnameVerifier.getInstance(true)); } else if (!StringUtils.isEmpty(map.get("ca"))) { SSLContext sslContext = SSLContext.getInstance("TLS"); KeyManagerFactory keyManagerFactory = null; diff --git a/src/main/java/com/aliyun/tea/utils/DefaultHostnameVerifier.java b/src/main/java/com/aliyun/tea/utils/DefaultHostnameVerifier.java new file mode 100644 index 0000000..6a59f58 --- /dev/null +++ b/src/main/java/com/aliyun/tea/utils/DefaultHostnameVerifier.java @@ -0,0 +1,29 @@ +package com.aliyun.tea.utils; + +import okhttp3.internal.tls.OkHostnameVerifier; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; + +public class DefaultHostnameVerifier implements HostnameVerifier { + private final boolean ignoreSSLCert; + private static final HostnameVerifier NOOP_INSTANCE = new DefaultHostnameVerifier(true); + private static final HostnameVerifier DEFAULT_INSTANCE = OkHostnameVerifier.INSTANCE; + + private DefaultHostnameVerifier(boolean ignoreSSLCert) { + this.ignoreSSLCert = ignoreSSLCert; + } + + public static HostnameVerifier getInstance(boolean ignoreSSLCert) { + if (ignoreSSLCert) { + return NOOP_INSTANCE; + } else { + return DEFAULT_INSTANCE; + } + } + + @Override + public boolean verify(String s, SSLSession sslSession) { + return ignoreSSLCert; + } +} diff --git a/src/main/java/com/aliyun/tea/utils/TrueHostnameVerifier.java b/src/main/java/com/aliyun/tea/utils/TrueHostnameVerifier.java deleted file mode 100644 index c2d473f..0000000 --- a/src/main/java/com/aliyun/tea/utils/TrueHostnameVerifier.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.aliyun.tea.utils; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLSession; - -public class TrueHostnameVerifier implements HostnameVerifier { - @Override - public boolean verify(String s, SSLSession sslSession) { - return true; - } -} diff --git a/src/main/java/com/aliyun/tea/utils/X509TrustManagerImp.java b/src/main/java/com/aliyun/tea/utils/X509TrustManagerImp.java index 2e2e056..03fe4b5 100644 --- a/src/main/java/com/aliyun/tea/utils/X509TrustManagerImp.java +++ b/src/main/java/com/aliyun/tea/utils/X509TrustManagerImp.java @@ -1,19 +1,57 @@ package com.aliyun.tea.utils; import javax.net.ssl.X509TrustManager; +import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; public class X509TrustManagerImp implements X509TrustManager { + private List trustManagers = new ArrayList(); + + private boolean ignoreSSLCert = false; + + public boolean isIgnoreSSLCert() { + return ignoreSSLCert; + } + + public X509TrustManagerImp(boolean ignoreSSLCert) { + this.ignoreSSLCert = ignoreSSLCert; + } + + public X509TrustManagerImp(List trustManagers) { + this.trustManagers = trustManagers; + } + @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) { + public void checkClientTrusted(X509Certificate[] chain, String authType) { + // do nothing } @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) { + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + if (this.ignoreSSLCert) { + return; + } + for (X509TrustManager trustManager : this.trustManagers) { + try { + trustManager.checkServerTrusted(chain, authType); + return; // someone trusts them. success! + } catch (CertificateException e) { + // maybe someone else will trust them + } + } + throw new CertificateException("None of the TrustManagers trust this certificate chain"); } @Override public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; + List certificates = new ArrayList(); + for (X509TrustManager trustManager : this.trustManagers) { + certificates.addAll(Arrays.asList(trustManager.getAcceptedIssuers())); + } + X509Certificate[] certificatesArray = new X509Certificate[certificates.size()]; + return certificates.toArray(certificatesArray); } } diff --git a/src/test/java/com/aliyun/tea/okhttp/OkHttpClientBuilderTest.java b/src/test/java/com/aliyun/tea/okhttp/OkHttpClientBuilderTest.java index 7d403fe..293076f 100644 --- a/src/test/java/com/aliyun/tea/okhttp/OkHttpClientBuilderTest.java +++ b/src/test/java/com/aliyun/tea/okhttp/OkHttpClientBuilderTest.java @@ -1,7 +1,7 @@ package com.aliyun.tea.okhttp; import com.aliyun.tea.TeaException; -import com.aliyun.tea.utils.TrueHostnameVerifier; +import com.aliyun.tea.utils.DefaultHostnameVerifier; import okhttp3.OkHttpClient; import okhttp3.Protocol; import org.junit.Assert; @@ -103,7 +103,7 @@ public void certificateTest() throws IOException { OkHttpClientBuilder builder = new OkHttpClientBuilder().certificate(map); OkHttpClient client = builder.buildOkHttpClient(); - Assert.assertFalse(client.hostnameVerifier() instanceof TrueHostnameVerifier); + Assert.assertFalse(client.hostnameVerifier() instanceof DefaultHostnameVerifier); Assert.assertNotNull(client.sslSocketFactory()); map.put("key", null); diff --git a/src/test/java/com/aliyun/tea/utils/TrueHostnameVerifierTest.java b/src/test/java/com/aliyun/tea/utils/TrueHostnameVerifierTest.java index fbd2130..0718daa 100644 --- a/src/test/java/com/aliyun/tea/utils/TrueHostnameVerifierTest.java +++ b/src/test/java/com/aliyun/tea/utils/TrueHostnameVerifierTest.java @@ -3,15 +3,22 @@ import org.junit.Assert; import org.junit.Test; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSession; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; public class TrueHostnameVerifierTest { @Test - public void trueHostnameVerifierTest(){ - TrueHostnameVerifier trueHostnameVerifier = new TrueHostnameVerifier(); + public void trueHostnameVerifierTest() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException { + HostnameVerifier trueHostnameVerifier = DefaultHostnameVerifier.getInstance(true); SSLSession sslSession = null; - trueHostnameVerifier.verify("authType",sslSession); - Assert.assertTrue(trueHostnameVerifier.verify(null,null)); + Assert.assertTrue(trueHostnameVerifier.verify("authType", sslSession)); + Assert.assertTrue(trueHostnameVerifier.verify(null, null)); + Constructor constructor = DefaultHostnameVerifier.class.getDeclaredConstructor(boolean.class); + constructor.setAccessible(true); + DefaultHostnameVerifier hostnameVerifier = constructor.newInstance(false); + Assert.assertFalse(hostnameVerifier.verify(null, null)); } } diff --git a/src/test/java/com/aliyun/tea/utils/X509TrustManagerImpTest.java b/src/test/java/com/aliyun/tea/utils/X509TrustManagerImpTest.java index 91d8f3b..26bfe01 100644 --- a/src/test/java/com/aliyun/tea/utils/X509TrustManagerImpTest.java +++ b/src/test/java/com/aliyun/tea/utils/X509TrustManagerImpTest.java @@ -1,34 +1,106 @@ package com.aliyun.tea.utils; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import javax.net.ssl.X509TrustManager; +import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; public class X509TrustManagerImpTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void getSetIgnoreSSLCert() { + X509TrustManagerImp trustManager = new X509TrustManagerImp(Collections.emptyList()); + Assert.assertFalse(trustManager.isIgnoreSSLCert()); + trustManager = new X509TrustManagerImp(true); + Assert.assertTrue(trustManager.isIgnoreSSLCert()); + } + @Test - public void testCheckClientTrusted(){ + public void testCheckClientTrusted() { try { - X509TrustManagerImp trustManagerImp = new X509TrustManagerImp(); - trustManagerImp.checkClientTrusted(new X509Certificate[0],"authType"); - }catch (Exception e){ + X509TrustManagerImp trustManagerImp = new X509TrustManagerImp(Collections.emptyList()); + trustManagerImp.checkClientTrusted(new X509Certificate[0], "authType"); + } catch (Exception e) { Assert.fail(); } } + @Test - public void testCheckServerTrusted(){ + public void testCheckServerTrustedAndIgnoreSSLCert() { + try { + X509TrustManagerImp trustManager = new X509TrustManagerImp(true); + trustManager.checkServerTrusted(new X509Certificate[0], "authType"); + } catch (Exception e) { + Assert.fail(); + } + try { - X509TrustManagerImp trustManagerImp = new X509TrustManagerImp(); - trustManagerImp.checkServerTrusted(new X509Certificate[0],"authType"); - }catch (Exception e){ + X509TrustManagerImp trustManagerImp = new X509TrustManagerImp(Collections.emptyList()); + trustManagerImp.checkServerTrusted(new X509Certificate[0], "authType"); Assert.fail(); + } catch (Exception e) { + Assert.assertEquals("None of the TrustManagers trust this certificate chain", e.getMessage()); } + } + + @Test + public void testCheckServerTrustedSucceedTwice() { + try { + final X509TrustManager trustManager0 = mock(X509TrustManager.class); + doThrow(CertificateException.class).when(trustManager0).checkServerTrusted(any(X509Certificate[].class), anyString()); + final X509TrustManager trustManager1 = mock(X509TrustManager.class); + doNothing().when(trustManager0).checkServerTrusted(any(X509Certificate[].class), anyString()); + List trustManagerList = new ArrayList(); + trustManagerList.add(trustManager0); + trustManagerList.add(trustManager1); + X509TrustManagerImp trustManager = new X509TrustManagerImp(trustManagerList); + trustManager.checkServerTrusted(new X509Certificate[0], "authType"); + } catch (Exception e) { + Assert.fail(); + } + + } + + @Test + public void testCheckServerTrustedFailed() throws CertificateException { + thrown.expect(CertificateException.class); + final X509TrustManager trustManager0 = mock(X509TrustManager.class); + doThrow(CertificateException.class).when(trustManager0).checkServerTrusted(any(X509Certificate[].class), anyString()); + List trustManagerList = new ArrayList(); + trustManagerList.add(trustManager0); + X509TrustManagerImp trustManager = new X509TrustManagerImp(trustManagerList); + trustManager.checkServerTrusted(new X509Certificate[0], "authType"); + } + @Test - public void testGetAcceptedIssuers(){ - X509TrustManagerImp trustManagerImp = new X509TrustManagerImp(); + public void testGetAcceptedIssuers() { + X509TrustManagerImp trustManagerImp = new X509TrustManagerImp(Collections.emptyList()); trustManagerImp.getAcceptedIssuers(); X509Certificate[] res = trustManagerImp.getAcceptedIssuers(); Assert.assertEquals(0, res.length); + final X509TrustManager trustManager0 = mock(X509TrustManager.class); + X509Certificate certificate = mock(X509Certificate.class); + when(trustManager0.getAcceptedIssuers()).thenReturn(new X509Certificate[]{certificate}); + List trustManagerList = new ArrayList(); + trustManagerList.add(trustManager0); + X509TrustManagerImp trustManager = new X509TrustManagerImp(trustManagerList); + res = trustManager.getAcceptedIssuers(); + Assert.assertEquals(1, res.length); + Assert.assertEquals(certificate, res[0]); } }