1+ package com.coder.gateway.util
2+
3+ import io.mockk.Runs
4+ import io.mockk.every
5+ import io.mockk.just
6+ import io.mockk.mockk
7+ import io.mockk.verify
8+ import java.net.InetAddress
9+ import java.net.Socket
10+ import javax.net.ssl.SSLParameters
11+ import javax.net.ssl.SSLSocket
12+ import javax.net.ssl.SSLSocketFactory
13+ import kotlin.test.Test
14+ import kotlin.test.assertEquals
15+ import kotlin.test.assertNotNull
16+ import kotlin.test.assertSame
17+
18+
19+ class AlternateNameSSLSocketFactoryTest {
20+
21+ @Test
22+ fun `createSocket with no parameters should customize socket with alternate name` () {
23+ // Given
24+ val mockFactory = mockk<SSLSocketFactory >()
25+ val mockSocket = mockk<SSLSocket >(relaxed = true )
26+ val mockParams = mockk<SSLParameters >(relaxed = true )
27+
28+ every { mockFactory.createSocket() } returns mockSocket
29+ every { mockSocket.sslParameters } returns mockParams
30+ every { mockSocket.sslParameters = any() } just Runs
31+
32+ val alternateFactory = AlternateNameSSLSocketFactory (mockFactory, " alternate.example.com" )
33+
34+ // When
35+ val result = alternateFactory.createSocket()
36+
37+ // Then
38+ verify { mockSocket.sslParameters = any() }
39+ assertSame(mockSocket, result)
40+ }
41+
42+ @Test
43+ fun `createSocket with host and port should customize socket with alternate name` () {
44+ // Given
45+ val mockFactory = mockk<SSLSocketFactory >()
46+ val mockSocket = mockk<SSLSocket >(relaxed = true )
47+ val mockParams = mockk<SSLParameters >(relaxed = true )
48+
49+ every { mockFactory.createSocket(" original.com" , 443 ) } returns mockSocket
50+ every { mockSocket.sslParameters } returns mockParams
51+ every { mockSocket.sslParameters = any() } just Runs
52+
53+ val alternateFactory = AlternateNameSSLSocketFactory (mockFactory, " alternate.example.com" )
54+
55+ // When
56+ val result = alternateFactory.createSocket(" original.com" , 443 )
57+
58+ // Then
59+ verify { mockSocket.sslParameters = any() }
60+ assertSame(mockSocket, result)
61+ }
62+
63+ @Test
64+ fun `createSocket with host port and local address should customize socket` () {
65+ // Given
66+ val mockFactory = mockk<SSLSocketFactory >()
67+ val mockSocket = mockk<SSLSocket >(relaxed = true )
68+ val mockParams = mockk<SSLParameters >(relaxed = true )
69+ val localHost = mockk<InetAddress >()
70+
71+ every { mockFactory.createSocket(" original.com" , 443 , localHost, 8080 ) } returns mockSocket
72+ every { mockSocket.sslParameters } returns mockParams
73+ every { mockSocket.sslParameters = any() } just Runs
74+
75+ val alternateFactory = AlternateNameSSLSocketFactory (mockFactory, " alternate.example.com" )
76+
77+ // When
78+ val result = alternateFactory.createSocket(" original.com" , 443 , localHost, 8080 )
79+
80+ // Then
81+ verify { mockSocket.sslParameters = any() }
82+ assertSame(mockSocket, result)
83+ }
84+
85+ @Test
86+ fun `createSocket with InetAddress should customize socket with alternate name` () {
87+ // Given
88+ val mockFactory = mockk<SSLSocketFactory >()
89+ val mockSocket = mockk<SSLSocket >(relaxed = true )
90+ val mockParams = mockk<SSLParameters >(relaxed = true )
91+ val address = mockk<InetAddress >()
92+
93+ every { mockFactory.createSocket(address, 443 ) } returns mockSocket
94+ every { mockSocket.sslParameters } returns mockParams
95+ every { mockSocket.sslParameters = any() } just Runs
96+
97+ val alternateFactory = AlternateNameSSLSocketFactory (mockFactory, " alternate.example.com" )
98+
99+ // When
100+ val result = alternateFactory.createSocket(address, 443 )
101+
102+ // Then
103+ verify { mockSocket.sslParameters = any() }
104+ assertSame(mockSocket, result)
105+ }
106+
107+ @Test
108+ fun `createSocket with InetAddress and local address should customize socket` () {
109+ // Given
110+ val mockFactory = mockk<SSLSocketFactory >()
111+ val mockSocket = mockk<SSLSocket >(relaxed = true )
112+ val mockParams = mockk<SSLParameters >(relaxed = true )
113+ val address = mockk<InetAddress >()
114+ val localAddress = mockk<InetAddress >()
115+
116+ every { mockFactory.createSocket(address, 443 , localAddress, 8080 ) } returns mockSocket
117+ every { mockSocket.sslParameters } returns mockParams
118+ every { mockSocket.sslParameters = any() } just Runs
119+
120+ val alternateFactory = AlternateNameSSLSocketFactory (mockFactory, " alternate.example.com" )
121+
122+ // When
123+ val result = alternateFactory.createSocket(address, 443 , localAddress, 8080 )
124+
125+ // Then
126+ verify { mockSocket.sslParameters = any() }
127+ assertSame(mockSocket, result)
128+ }
129+
130+ @Test
131+ fun `createSocket with existing socket should customize socket with alternate name` () {
132+ // Given
133+ val mockFactory = mockk<SSLSocketFactory >()
134+ val mockSSLSocket = mockk<SSLSocket >(relaxed = true )
135+ val mockParams = mockk<SSLParameters >(relaxed = true )
136+ val existingSocket = mockk<Socket >()
137+
138+ every { mockFactory.createSocket(existingSocket, " original.com" , 443 , true ) } returns mockSSLSocket
139+ every { mockSSLSocket.sslParameters } returns mockParams
140+ every { mockSSLSocket.sslParameters = any() } just Runs
141+
142+ val alternateFactory = AlternateNameSSLSocketFactory (mockFactory, " alternate.example.com" )
143+
144+ // When
145+ val result = alternateFactory.createSocket(existingSocket, " original.com" , 443 , true )
146+
147+ // Then
148+ verify { mockSSLSocket.sslParameters = any() }
149+ assertSame(mockSSLSocket, result)
150+ }
151+
152+ @Test
153+ fun `customizeSocket should set SNI hostname to alternate name for valid hostname` () {
154+ // Given
155+ val mockFactory = mockk<SSLSocketFactory >()
156+ val mockSocket = mockk<SSLSocket >(relaxed = true )
157+ val mockParams = mockk<SSLParameters >(relaxed = true )
158+
159+ every { mockFactory.createSocket() } returns mockSocket
160+ every { mockSocket.sslParameters } returns mockParams
161+ every { mockSocket.sslParameters = any() } just Runs
162+
163+ val alternateFactory = AlternateNameSSLSocketFactory (mockFactory, " valid-hostname.example.com" )
164+
165+ // When & Then - This should work without throwing an exception
166+ assertNotNull(alternateFactory.createSocket())
167+ verify { mockSocket.sslParameters = any() }
168+ }
169+
170+ @Test
171+ fun `customizeSocket should NOT throw IllegalArgumentException for hostname with underscore` () {
172+ // Given
173+ val mockFactory = mockk<SSLSocketFactory >()
174+ val mockSocket = mockk<SSLSocket >(relaxed = true )
175+ val mockParams = mockk<SSLParameters >(relaxed = true )
176+
177+ every { mockFactory.createSocket() } returns mockSocket
178+ every { mockSocket.sslParameters } returns mockParams
179+ every { mockSocket.sslParameters = any() } just Runs
180+
181+ val alternateFactory = AlternateNameSSLSocketFactory (mockFactory, " non_compliant_hostname.example.com" )
182+
183+ // When & Then - This should work without throwing an exception
184+ assertNotNull(alternateFactory.createSocket())
185+ verify { mockSocket.sslParameters = any() }
186+ assertEquals(0 , mockSocket.sslParameters.serverNames.size)
187+ }
188+
189+ @Test
190+ fun `createSocket should work with valid international domain names` () {
191+ // Given
192+ val mockFactory = mockk<SSLSocketFactory >()
193+ val mockSocket = mockk<SSLSocket >(relaxed = true )
194+ val mockParams = mockk<SSLParameters >(relaxed = true )
195+
196+ every { mockFactory.createSocket() } returns mockSocket
197+ every { mockSocket.sslParameters } returns mockParams
198+ every { mockSocket.sslParameters = any() } just Runs
199+
200+ val alternateFactory = AlternateNameSSLSocketFactory (mockFactory, " test-server.example.com" )
201+
202+ // When & Then - This should work as hyphens are valid
203+ assertNotNull(alternateFactory.createSocket())
204+ verify { mockSocket.sslParameters = any() }
205+ }
206+
207+ private fun createMockSSLSocketFactory (): SSLSocketFactory {
208+ val mockFactory = mockk<SSLSocketFactory >()
209+ val mockSocket = mockk<SSLSocket >(relaxed = true )
210+ val mockParams = mockk<SSLParameters >(relaxed = true )
211+
212+ // Setup default behavior
213+ every { mockFactory.defaultCipherSuites } returns arrayOf(" TLS_AES_256_GCM_SHA384" )
214+ every { mockFactory.supportedCipherSuites } returns arrayOf(" TLS_AES_256_GCM_SHA384" , " TLS_AES_128_GCM_SHA256" )
215+
216+ // Make all createSocket methods return our mock socket
217+ every { mockFactory.createSocket() } returns mockSocket
218+ every { mockFactory.createSocket(any<String >(), any<Int >()) } returns mockSocket
219+ every { mockFactory.createSocket(any<String >(), any<Int >(), any<InetAddress >(), any<Int >()) } returns mockSocket
220+ every { mockFactory.createSocket(any<InetAddress >(), any<Int >()) } returns mockSocket
221+ every {
222+ mockFactory.createSocket(
223+ any<InetAddress >(),
224+ any<Int >(),
225+ any<InetAddress >(),
226+ any<Int >()
227+ )
228+ } returns mockSocket
229+ every { mockFactory.createSocket(any<Socket >(), any<String >(), any<Int >(), any<Boolean >()) } returns mockSocket
230+
231+ // Setup SSL parameters
232+ every { mockSocket.sslParameters } returns mockParams
233+ every { mockSocket.sslParameters = any() } just Runs
234+
235+ return mockFactory
236+ }
237+ }
0 commit comments