Last active
March 20, 2019 13:25
-
-
Save kotoMJ/e22f0469342319570770e928eaa3b8a2 to your computer and use it in GitHub Desktop.
Enable TLS 1.2 for Glide 4+ on pre-lollipop Android API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.