Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

kotlin library that can do httpS connection without certificate verification (like curl --insecure)

I need to crawl internal company site that has expired/self-signed certificate. Noone is ever going to configure valid certificate for that host, so I have to use insecure connection.

curl has --insecure flag for that purpose,

Scala finagle library has .tlsWithoutValidation() mode.

QUESTION: Is there a Kotlin library that has similar option?

UPD: so far I am using Fuel with the javish workaround found here but still searching for better ways..

fun useInsecureSSL() {

    // Create a trust manager that does not validate certificate chains
    val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
        override fun getAcceptedIssuers(): Array<X509Certificate>? = null
        override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) = Unit
        override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) = Unit
    })

    val sc = SSLContext.getInstance("SSL")
    sc.init(null, trustAllCerts, java.security.SecureRandom())
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.socketFactory)

    // Create all-trusting host name verifier
    val allHostsValid = HostnameVerifier { _, _ -> true }

    // Install the all-trusting host verifier
    HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid)
}

The above workaround works however it is too verbose and seems to set insecure mode for every connection made by my app, not only for the particular one.

like image 313
ludenus Avatar asked Nov 23 '17 16:11

ludenus


1 Answers

Fuel allows you to create your own instance of the Fuel client through the FuelManager class. The manager lets you can set your own HostnameVerifier and SSLSocketFactory and then creates a client with those configured. See https://github.com/kittinunf/Fuel/blob/1.16.0/fuel/src/main/kotlin/com/github/kittinunf/fuel/core/FuelManager.kt#L31-L43

val manager : FuelManager = FuelManager().apply {
  val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
    override fun getAcceptedIssuers(): Array<X509Certificate>? = null
    override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) = Unit
    override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) = Unit
  })

  socketFactory = SSLContext.getInstance("SSL").apply {
    init(null, trustAllCerts, java.security.SecureRandom())
  }.socketFactory

  hostnameVerifier = HostnameVerifier { _, _ -> true }
}

Then to check that only connections that goes through this custom FuelManager is untrusted and connections that don't are trusted, we do this:

val (_, untrustedResp, untrustedResult) = manager.request(Method.GET, "https://internal/company/site").response()
assert(untrustedResp.statusCode == 200)
val (bytes, _) = untrustedResult
assert(bytes != null)


val (_, trustedResp, trustedResult) = "https://internal/company/site".httpGet().response()
assert(trustedResp.statusCode != 200)
val (bytes, error) = trustedResult
assert(bytes == null)
println(error) // javax.net.ssl.SSLHandshakeException: PKIX path building failed: ...

The custom FuelManager was able to make the request successfully because it trusts all certs but for the connection that didn't use the custom manager, we can see that it returns with javax.net.ssl.SSLHandshakeException.

like image 162
Jason Yeo Avatar answered Nov 16 '22 03:11

Jason Yeo