Skip to content

Commit 884ba6d

Browse files
authored
Fall back to OkHostnameVerifier for default SSL verification (#1043)
* Add failing test for hostname verifier fallback When allowedHostnames is configured, the custom hostname verifier doesn't fall back to default OkHttp verification. This breaks SSL verification for sites using wildcard/SAN certificates. The test demonstrates that after configuring an allowed hostname override, requests to other valid SSL sites (google.com) fail with SSL errors instead of succeeding. * Fall back to OkHostnameVerifier for default SSL verification The custom WpRequestExecutorHostnameVerifier now falls back to OkHostnameVerifier when the hostname is not in the allowlist. This ensures proper handling of wildcard certificates and SANs while still allowing custom hostname overrides. Changes: - Import OkHostnameVerifier from okhttp3.internal.tls - Check custom allowlist first, then fall back to default verification - Remove conditional verifier application (always use our verifier)
1 parent 691cb72 commit 884ba6d

File tree

2 files changed

+35
-8
lines changed

2 files changed

+35
-8
lines changed

native/kotlin/api/kotlin/src/integrationTest/kotlin/ApiUrlDiscoveryTest.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,31 @@ class ApiUrlDiscoveryTest {
297297
)
298298
}
299299

300+
@Test
301+
fun testAllowedHostnamesDoesNotBreakValidSites() = runTest {
302+
val httpClient = WpHttpClient.DefaultHttpClient(emptyList())
303+
val executor = WpRequestExecutor(httpClient)
304+
val loginClient = WpLoginClient(requestExecutor = executor)
305+
306+
// First, configure an allowed hostname override for a specific cert/hostname pair
307+
httpClient.addAllowedAlternativeNamesForHostname(
308+
"vanilla.wpmt.co",
309+
listOf("wordpress-1315525-4803651.cloudwaysapps.com")
310+
)
311+
312+
// The override should work
313+
assertEquals(
314+
"https://vanilla.wpmt.co/wp-admin/authorize-application.php",
315+
loginClient.apiDiscovery("https://wordpress-1315525-4803651.cloudwaysapps.com")
316+
.assertSuccess().applicationPasswordsAuthenticationUrl.url()
317+
)
318+
319+
// Other valid SSL sites should still work via fallback to default hostname verification.
320+
// google.com uses wildcard/SAN certificates which require proper OkHttp verification.
321+
val reason = loginClient.apiDiscovery("https://google.com").assertFailureFindApiRoot()
322+
assertInstanceOf(FindApiRootFailure.ProbablyNotAWordPressSite::class.java, reason)
323+
}
324+
300325
@Test
301326
fun testCustomOkHttpClient() = runTest {
302327
val executor =

native/kotlin/api/kotlin/src/main/kotlin/rs/wordpress/api/kotlin/WpHttpClient.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package rs.wordpress.api.kotlin
22

33
import okhttp3.Interceptor
44
import okhttp3.OkHttpClient
5+
import okhttp3.internal.tls.OkHostnameVerifier
56
import javax.net.ssl.HostnameVerifier
67
import javax.net.ssl.SSLSession
78

@@ -25,9 +26,7 @@ sealed class WpHttpClient {
2526
private fun buildClient(): OkHttpClient {
2627
return OkHttpClient.Builder().apply {
2728
this@DefaultHttpClient.interceptors.forEach { addInterceptor(it) }
28-
if (allowedHostnames.isNotEmpty()) {
29-
hostnameVerifier(WpRequestExecutorHostnameVerifier(allowedHostnames))
30-
}
29+
hostnameVerifier(WpRequestExecutorHostnameVerifier(allowedHostnames))
3130
}.build()
3231
}
3332

@@ -41,9 +40,12 @@ sealed class WpHttpClient {
4140

4241
private class WpRequestExecutorHostnameVerifier(private val allowedHostnames: Map<String, List<String>>) :
4342
HostnameVerifier {
44-
override fun verify(hostname: String?, session: SSLSession?): Boolean =
45-
session?.let {
46-
val peerPrincipalName = it.peerPrincipal.name.replace("CN=", "")
47-
peerPrincipalName == hostname || allowedHostnames[peerPrincipalName]?.contains(hostname) ?: false
48-
} ?: false
43+
override fun verify(hostname: String?, session: SSLSession?): Boolean {
44+
if (hostname == null || session == null) return false
45+
46+
// Check our custom allowlist first, then fall back to default OkHttp verification
47+
val peerPrincipalName = session.peerPrincipal.name.replace("CN=", "")
48+
val customMatch = allowedHostnames[peerPrincipalName]?.contains(hostname) ?: false
49+
return customMatch || OkHostnameVerifier.verify(hostname, session)
50+
}
4951
}

0 commit comments

Comments
 (0)