mirror of
https://github.com/etesync/android
synced 2024-11-25 17:38:13 +00:00
Update cert4android and adjust HttpClient accordingly
This commit is contained in:
parent
d64e6ba33f
commit
c26c2c5332
@ -11,15 +11,11 @@ package com.etesync.syncadapter
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.security.KeyChain
|
import android.security.KeyChain
|
||||||
import at.bitfire.cert4android.CertTlsSocketFactory
|
|
||||||
import at.bitfire.cert4android.CustomCertManager
|
import at.bitfire.cert4android.CustomCertManager
|
||||||
import com.etesync.syncadapter.log.Logger
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.ServiceDB
|
import com.etesync.syncadapter.model.ServiceDB
|
||||||
import com.etesync.syncadapter.model.Settings
|
import com.etesync.syncadapter.model.Settings
|
||||||
import okhttp3.Cache
|
import okhttp3.*
|
||||||
import okhttp3.Interceptor
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Response
|
|
||||||
import okhttp3.internal.tls.OkHostnameVerifier
|
import okhttp3.internal.tls.OkHostnameVerifier
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -32,10 +28,7 @@ import java.security.Principal
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
import javax.net.ssl.KeyManager
|
import javax.net.ssl.*
|
||||||
import javax.net.ssl.TrustManagerFactory
|
|
||||||
import javax.net.ssl.X509ExtendedKeyManager
|
|
||||||
import javax.net.ssl.X509TrustManager
|
|
||||||
import java.util.logging.Logger as LoggerType
|
import java.util.logging.Logger as LoggerType
|
||||||
|
|
||||||
class HttpClient private constructor(
|
class HttpClient private constructor(
|
||||||
@ -44,8 +37,11 @@ class HttpClient private constructor(
|
|||||||
): AutoCloseable {
|
): AutoCloseable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
/** max. size of disk cache (10 MB) */
|
||||||
|
const val DISK_CACHE_MAX_SIZE: Long = 10*1024*1024
|
||||||
|
|
||||||
/** [OkHttpClient] singleton to build all clients from */
|
/** [OkHttpClient] singleton to build all clients from */
|
||||||
val sharedClient = OkHttpClient.Builder()
|
val sharedClient: OkHttpClient = OkHttpClient.Builder()
|
||||||
// set timeouts
|
// set timeouts
|
||||||
.connectTimeout(15, TimeUnit.SECONDS)
|
.connectTimeout(15, TimeUnit.SECONDS)
|
||||||
.writeTimeout(30, TimeUnit.SECONDS)
|
.writeTimeout(30, TimeUnit.SECONDS)
|
||||||
@ -60,7 +56,9 @@ class HttpClient private constructor(
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
|
okHttpClient.cache()?.close()
|
||||||
certManager?.close()
|
certManager?.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +69,7 @@ class HttpClient private constructor(
|
|||||||
) {
|
) {
|
||||||
private var certManager: CustomCertManager? = null
|
private var certManager: CustomCertManager? = null
|
||||||
private var certificateAlias: String? = null
|
private var certificateAlias: String? = null
|
||||||
private var foreground = true
|
private var cache: Cache? = null
|
||||||
|
|
||||||
private val orig = sharedClient.newBuilder()
|
private val orig = sharedClient.newBuilder()
|
||||||
|
|
||||||
@ -103,8 +101,12 @@ class HttpClient private constructor(
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Logger.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
Logger.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
||||||
} finally {
|
} finally {
|
||||||
dbHelper.close()
|
// dbHelper.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if (BuildConfig.customCerts)
|
||||||
|
customCertManager(CustomCertManager(context, true,
|
||||||
|
!(settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES,false)), true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// use account settings for authentication
|
// use account settings for authentication
|
||||||
@ -124,19 +126,23 @@ class HttpClient private constructor(
|
|||||||
val cacheDir = File(dir, "HttpClient")
|
val cacheDir = File(dir, "HttpClient")
|
||||||
cacheDir.mkdir()
|
cacheDir.mkdir()
|
||||||
Logger.log.fine("Using disk cache: $cacheDir")
|
Logger.log.fine("Using disk cache: $cacheDir")
|
||||||
orig.cache(Cache(cacheDir, 10*1024*1024))
|
orig.cache(Cache(cacheDir, DISK_CACHE_MAX_SIZE))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun followRedirects(follow: Boolean): Builder {
|
||||||
|
orig.followRedirects(follow)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun customCertManager(manager: CustomCertManager) {
|
fun customCertManager(manager: CustomCertManager) {
|
||||||
certManager = manager
|
certManager = manager
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setForeground(foreground: Boolean): Builder {
|
fun setForeground(foreground: Boolean): Builder {
|
||||||
this.foreground = foreground
|
certManager?.appInForeground = foreground
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,16 +178,6 @@ class HttpClient private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun build(): HttpClient {
|
fun build(): HttpClient {
|
||||||
//if (BuildConfig.customCerts)
|
|
||||||
context?.let {
|
|
||||||
val dbHelper = ServiceDB.OpenHelper(context)
|
|
||||||
val settings = Settings(dbHelper.readableDatabase)
|
|
||||||
|
|
||||||
// Only make it interactive if app is in foreground
|
|
||||||
customCertManager(CustomCertManager(context, foreground, !settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false), foreground))
|
|
||||||
dbHelper.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
val trustManager = certManager ?: {
|
val trustManager = certManager ?: {
|
||||||
val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||||
factory.init(null as KeyStore?)
|
factory.init(null as KeyStore?)
|
||||||
@ -192,14 +188,14 @@ class HttpClient private constructor(
|
|||||||
?: OkHostnameVerifier.INSTANCE
|
?: OkHostnameVerifier.INSTANCE
|
||||||
|
|
||||||
var keyManager: KeyManager? = null
|
var keyManager: KeyManager? = null
|
||||||
try {
|
certificateAlias?.let { alias ->
|
||||||
certificateAlias?.let { alias ->
|
try {
|
||||||
val context = requireNotNull(context)
|
val context = requireNotNull(context)
|
||||||
|
|
||||||
// get client certificate and private key
|
// get provider certificate and private key
|
||||||
val certs = KeyChain.getCertificateChain(context, alias) ?: return@let
|
val certs = KeyChain.getCertificateChain(context, alias) ?: return@let
|
||||||
val key = KeyChain.getPrivateKey(context, alias) ?: return@let
|
val key = KeyChain.getPrivateKey(context, alias) ?: return@let
|
||||||
logger.fine("Using client certificate $alias for authentication (chain length: ${certs.size})")
|
logger.fine("Using provider certificate $alias for authentication (chain length: ${certs.size})")
|
||||||
|
|
||||||
// create Android KeyStore (performs key operations without revealing secret data to DAVx5)
|
// create Android KeyStore (performs key operations without revealing secret data to DAVx5)
|
||||||
val keyStore = KeyStore.getInstance("AndroidKeyStore")
|
val keyStore = KeyStore.getInstance("AndroidKeyStore")
|
||||||
@ -222,12 +218,21 @@ class HttpClient private constructor(
|
|||||||
override fun getPrivateKey(forAlias: String?) =
|
override fun getPrivateKey(forAlias: String?) =
|
||||||
key.takeIf { forAlias == alias }
|
key.takeIf { forAlias == alias }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTTP/2 doesn't support client certificates (yet)
|
||||||
|
// see https://tools.ietf.org/html/draft-ietf-httpbis-http2-secondary-certs-04
|
||||||
|
orig.protocols(listOf(Protocol.HTTP_1_1))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.log(Level.SEVERE, "Couldn't set up provider certificate authentication", e)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
logger.log(Level.SEVERE, "Couldn't set up client certificate authentication", e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
orig.sslSocketFactory(CertTlsSocketFactory(keyManager, trustManager), trustManager)
|
val sslContext = SSLContext.getInstance("TLS")
|
||||||
|
sslContext.init(
|
||||||
|
if (keyManager != null) arrayOf(keyManager) else null,
|
||||||
|
arrayOf(trustManager),
|
||||||
|
null)
|
||||||
|
orig.sslSocketFactory(sslContext.socketFactory, trustManager)
|
||||||
orig.hostnameVerifier(hostnameVerifier)
|
orig.hostnameVerifier(hostnameVerifier)
|
||||||
|
|
||||||
return HttpClient(orig.build(), certManager)
|
return HttpClient(orig.build(), certManager)
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit f57a8ee9b11a74ca48c067b42dc0411259c567c8
|
Subproject commit 0a451ad044ff50b488135cb91207d5a9a071c3b6
|
Loading…
Reference in New Issue
Block a user