1515 */
1616package com .marklogic .client .test ;
1717
18+ import static org .junit .Assert .assertArrayEquals ;
1819import static org .junit .Assert .assertEquals ;
20+ import static org .mockito .Mockito .mock ;
21+ import static org .mockito .Mockito .when ;
1922
2023import javax .net .ssl .SSLContext ;
24+ import javax .net .ssl .SSLException ;
2125import javax .net .ssl .TrustManager ;
2226import javax .net .ssl .X509TrustManager ;
27+ import javax .security .auth .x500 .X500Principal ;
2328import java .security .KeyManagementException ;
2429import java .security .NoSuchAlgorithmException ;
30+ import java .security .cert .CertificateParsingException ;
2531import java .security .cert .X509Certificate ;
26-
32+ import java .util .ArrayList ;
33+ import java .util .Arrays ;
34+ import java .util .Collection ;
35+ import java .util .List ;
36+ import java .util .concurrent .atomic .AtomicReference ;
2737import org .junit .Test ;
2838
2939import com .marklogic .client .DatabaseClient ;
3242import com .marklogic .client .DatabaseClientFactory .SSLHostnameVerifier ;
3343import com .marklogic .client .document .TextDocumentManager ;
3444import com .marklogic .client .io .StringHandle ;
45+ import com .marklogic .client .impl .OkHttpServices ;
3546
3647public class SSLTest {
3748 @ Test
3849 public void testSSLAuth () throws NoSuchAlgorithmException , KeyManagementException {
3950
40- // create a trust manager
41- // (note: a real application should verify certificates)
42- TrustManager naiveTrustMgr = new X509TrustManager () {
43- @ Override
44- public void checkClientTrusted (X509Certificate [] chain , String authType ) {
45- }
46- @ Override
47- public void checkServerTrusted (X509Certificate [] chain , String authType ) {
48- }
49- @ Override
50- public X509Certificate [] getAcceptedIssuers () {
51- return new X509Certificate [0 ];
52- }
53- };
54-
5551 // create an SSL context
5652 SSLContext sslContext = SSLContext .getInstance ("SSLv3" );
57- sslContext .init (null , new TrustManager [] { naiveTrustMgr }, null );
53+ sslContext .init (null , new TrustManager [] { mock ( X509TrustManager . class ) }, null );
5854
5955 // create the client
6056 DatabaseClient client = DatabaseClientFactory .newClient (Common .HOST , Common .PORT ,
61- "MyFooUser" , "x" , Authentication .DIGEST , sslContext , SSLHostnameVerifier .ANY );
62-
57+ "MyFooUser" , "x" , Authentication .DIGEST , sslContext , SSLHostnameVerifier .ANY );
6358
6459 String expectedException = "com.marklogic.client.MarkLogicIOException: " +
6560 "javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?" ;
@@ -79,6 +74,66 @@ public X509Certificate[] getAcceptedIssuers() {
7974 exception = e .toString ();
8075 }
8176 assertEquals (expectedException , exception );
77+ }
78+
79+ private static class SSLTestServices extends OkHttpServices {
80+ static class SSLTestHostnameVerifierAdapter extends SSLTestServices .HostnameVerifierAdapter {
81+ SSLTestHostnameVerifierAdapter (SSLHostnameVerifier hostnameVerifier ) {
82+ super (hostnameVerifier );
83+ }
84+ }
85+ }
86+
87+ @ Test
88+ public void testHostnameVerifier () throws SSLException , CertificateParsingException {
89+ // three things our SSLHostnameVerifier will capture
90+ final AtomicReference <String > capturedHost = new AtomicReference <String >();
91+ final AtomicReference <String []> capturedCNs = new AtomicReference <String []>();
92+ final AtomicReference <String []> capturedSAs = new AtomicReference <String []>();
93+
94+ // this adapter is an SSLHostnameVerifier we'd normally pass to withSSLHostnameVerifier
95+ SSLHostnameVerifier verifier = new SSLHostnameVerifier () {
96+ public void verify (String host , String [] cns , String [] alts ) {
97+ capturedHost .set (host );
98+ capturedCNs .set (cns );
99+ capturedSAs .set (alts );
100+ }
101+ };
102+ // rather than attempt a real SSL connection, let's just test the implementation
103+ // with some mocks
104+ SSLTestServices .SSLTestHostnameVerifierAdapter adapter = new SSLTestServices .SSLTestHostnameVerifierAdapter (verifier );
105+
106+ // three things we'll pass and expect we can capture when verify is called
107+ String passedHost = "somehost" ;
108+ String [] passedCns = new String [] {"\u82b1 \u5b50 .co.jp" , "bar.com" , "foo.com" };
109+ String [] passedSas = new String [] {"a.foo.com" , "104.198.163.83" , "a.bar.com" , "\u82b1 \u5b50 .co.jp" };
110+ // throw some extra information in like a real SSL cert would have
111+ // but what we're really wanting here are the CNs (common names)
112+ X500Principal principal = new X500Principal ("C=US, ST=California, L=San Carlos, O=API Team, OU=test certificates, " +
113+ "CN=" + passedCns [2 ] + ", CN=" + passedCns [1 ] + ", CN=" + passedCns [0 ]);
114+ X509Certificate cert = mock (X509Certificate .class );
115+ when (cert .getSubjectX500Principal ()).thenReturn (principal );
116+
117+ int type_dnsName = 2 ;
118+ int type_ipAddress = 7 ;
119+ // subject alts come out as a Collection of 2-entry lists where the first entry
120+ // is the Integer type and the second entry is the value
121+ // if the entry is 2 it's a DNS or 7 then it's an IP address
122+ // according to https://docs.oracle.com/javase/8/docs/api/java/security/cert/X509Certificate.html#getSubjectAlternativeNames--
123+ Collection <List <?>> listSas = new ArrayList <List <?>>();
124+ listSas .add (Arrays .asList (new Object [] {new Integer (type_dnsName ), passedSas [0 ]}));
125+ listSas .add (Arrays .asList (new Object [] {new Integer (type_ipAddress ), passedSas [1 ]}));
126+ listSas .add (Arrays .asList (new Object [] {new Integer (type_dnsName ), passedSas [2 ]}));
127+ listSas .add (Arrays .asList (new Object [] {new Integer (type_dnsName ), passedSas [3 ]}));
128+ when (cert .getSubjectAlternativeNames ()).thenReturn (listSas );
129+
130+ // now that we have the cert all mocked with common names and subject alts, call the
131+ // implementation method HostnameVerifierAdapter.verify to make sure it calls
132+ // SSLHostnameVerifier.verify(String, String[], String[]) with the expected hostname, cns, and subjectAlts
133+ adapter .verify (passedHost , cert );
82134
135+ assertEquals (passedHost , capturedHost .get ());
136+ assertArrayEquals (passedCns , capturedCNs .get ());
137+ assertArrayEquals (passedSas , capturedSAs .get ());
83138 }
84139}
0 commit comments