Skip to content

Instantly share code, notes, and snippets.

@kotoMJ
Last active March 20, 2019 13:25
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kotoMJ/e22f0469342319570770e928eaa3b8a2 to your computer and use it in GitHub Desktop.
Save kotoMJ/e22f0469342319570770e928eaa3b8a2 to your computer and use it in GitHub Desktop.
Enable TLS 1.2 for Glide 4+ on pre-lollipop Android API
import android.content.Context
import android.os.Build
import com.bumptech.glide.Glide
import com.bumptech.glide.Registry
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.module.AppGlideModule
import okhttp3.ConnectionSpec
import okhttp3.OkHttpClient
import okhttp3.TlsVersion
import org.alfonz.utility.Logcat
import java.io.InputStream
import java.security.KeyStore
import java.util.*
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
/**
* Avoid following errors on pre-lollipop devices:
*
* class com.bumptech.glide.load.engine.GlideException: Failed to load resource
* Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class java.io.InputStream, REMOTE
* Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetch failed
* Cause (1 of 1): class javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb84fdb80: Failure in SSL library, usually a protocol error
* error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:741 0x96f6f926:0x00000000)
* W/Glide: Load failed for https://www.legalzoom.com/sites/legalzoom.com/files/uploaded/attorney/atty-258.jpg with size [100x100]
*/
fun enableTls12OnPreLollipop(client: OkHttpClient.Builder): OkHttpClient.Builder {
if (Build.VERSION.SDK_INT in 19..21) {
try {
val trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(null as KeyStore?)
val trustManagers = trustManagerFactory.trustManagers
if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
throw IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers))
}
val trustManager = trustManagers[0] as X509TrustManager
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
val sc = SSLContext.getInstance("TLSv1.2")
sc.init(null, null, null)
client.sslSocketFactory(Tls12SocketFactory(sc.socketFactory), trustManager)
val cs = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.build()
val specs = arrayListOf<ConnectionSpec>()
specs.add(cs)
specs.add(ConnectionSpec.COMPATIBLE_TLS)
specs.add(ConnectionSpec.CLEARTEXT)
client.connectionSpecs(specs)
} catch (exc: Throwable) {
Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc)
}
}
return client
}
/**
* Customize Glide module:
*
* Especially enable TLS12 on pre-lollipop devices.
* https://github.com/square/okhttp/issues/2372
* https://bumptech.github.io/glide/doc/getting-started.html#applications
*/
@GlideModule
class CustomGlideModule : AppGlideModule() {
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
val clientBuilder = OkHttpClient.Builder()
.followRedirects(true)
.followSslRedirects(true)
.retryOnConnectionFailure(true)
.cache(null)
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS);
val factory = OkHttpUrlLoader.Factory(enableTls12OnPreLollipop(clientBuilder).build())
registry.replace(GlideUrl::class.java, InputStream::class.java, factory)
}
}
import java.io.IOException
import java.net.InetAddress
import java.net.Socket
import java.net.UnknownHostException
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
/**
* Enables TLS v1.2 when creating SSLSockets.
*
*
* For some reason, android supports TLS v1.2 from API 16, but enables it by
* default only from API 20.
* @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
* @see SSLSocketFactory
*/
class Tls12SocketFactory(internal val delegate: SSLSocketFactory) : SSLSocketFactory() {
override fun getDefaultCipherSuites(): Array<String> {
return delegate.defaultCipherSuites
}
override fun getSupportedCipherSuites(): Array<String> {
return delegate.supportedCipherSuites
}
@Throws(IOException::class)
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket? {
return patch(delegate.createSocket(s, host, port, autoClose))
}
@Throws(IOException::class, UnknownHostException::class)
override fun createSocket(host: String, port: Int): Socket? {
return patch(delegate.createSocket(host, port))
}
@Throws(IOException::class, UnknownHostException::class)
override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket? {
return patch(delegate.createSocket(host, port, localHost, localPort))
}
@Throws(IOException::class)
override fun createSocket(host: InetAddress, port: Int): Socket? {
return patch(delegate.createSocket(host, port))
}
@Throws(IOException::class)
override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket? {
return patch(delegate.createSocket(address, port, localAddress, localPort))
}
private fun patch(s: Socket): Socket {
if (s is SSLSocket) {
s.enabledProtocols = TLS_V12_ONLY
}
return s
}
companion object {
private val TLS_V12_ONLY = arrayOf("TLSv1.2")
private val TLS_V1X = arrayOf("TLSv1.1", "TLSv1.2")
}
}
//The API is generated in the same package as the AppGlideModule and is named GlideApp by default.
//Applications can use the API by starting all loads with GlideApp.with() instead of Glide.with():
//For more details look at: https://bumptech.github.io/glide/doc/getting-started.html#applications
GlideApp.with(fragment)
.load(myUrl)
.placeholder(placeholder)
.fitCenter()
.into(imageView);
val glideRequest = GlideApp
.with(imageView.context)
.load(url)
GlideApp.with(imageView.context)
.load(url.toInt())
.circleCrop()
.into(imageView)
@KeyStarr
Copy link

KeyStarr commented Jul 11, 2018

Thanks a lot!
I wasted hours trying to combine all those solutions from okhttp git page, glide and stackoverflow.
For some reason i was unsuccessful, but you have done it properly.
Now it works!)

One thing, these lines are not used in code and therefore are useless:
val sslContext = SSLContext.getInstance("TLS") sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
(CustomGlideModule.kt, lines 44-45)

And a question:
Why are you enabling TSL v1.2 for APIs 20 and 21? In docs it said that starting from API 20 (included) TSL v1.2 is enabled by default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment