Use OkHttpClient with certificate to download files, and to perform wellknown request, and to get terms

This commit is contained in:
Benoit Marty 2020-06-30 11:32:14 +02:00
parent 6721e33c7e
commit ba26aee54c
14 changed files with 80 additions and 38 deletions

View file

@ -89,6 +89,7 @@ interface AuthenticationService {
* Perform a wellknown request, using the domain from the matrixId
*/
fun getWellKnownData(matrixId: String,
homeServerConnectionConfig: HomeServerConnectionConfig?,
callback: MatrixCallback<WellknownResult>): Cancelable
/**

View file

@ -215,7 +215,7 @@ internal class DefaultAuthenticationService @Inject constructor(
// Create a fake userId, for the getWellknown task
val fakeUserId = "@alice:$domain"
val wellknownResult = getWellknownTask.execute(GetWellknownTask.Params(fakeUserId))
val wellknownResult = getWellknownTask.execute(GetWellknownTask.Params(fakeUserId, homeServerConnectionConfig))
return when (wellknownResult) {
is WellknownResult.Prompt -> {
@ -327,9 +327,11 @@ internal class DefaultAuthenticationService @Inject constructor(
}
}
override fun getWellKnownData(matrixId: String, callback: MatrixCallback<WellknownResult>): Cancelable {
override fun getWellKnownData(matrixId: String,
homeServerConnectionConfig: HomeServerConnectionConfig?,
callback: MatrixCallback<WellknownResult>): Cancelable {
return getWellknownTask
.configureWith(GetWellknownTask.Params(matrixId)) {
.configureWith(GetWellknownTask.Params(matrixId, homeServerConnectionConfig)) {
this.callback = callback
}
.executeBy(taskExecutor)

View file

@ -26,6 +26,7 @@ import im.vector.matrix.android.internal.auth.data.PasswordLoginParams
import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.network.RetrofitFactory
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
import im.vector.matrix.android.internal.task.Task
import okhttp3.OkHttpClient
import javax.inject.Inject
@ -47,7 +48,8 @@ internal class DefaultDirectLoginTask @Inject constructor(
) : DirectLoginTask {
override suspend fun execute(params: DirectLoginTask.Params): Session {
val authAPI = retrofitFactory.create(okHttpClient, params.homeServerConnectionConfig.homeServerUri.toString())
val client = buildClient(params.homeServerConnectionConfig)
val authAPI = retrofitFactory.create(client, params.homeServerConnectionConfig.homeServerUri.toString())
.create(AuthAPI::class.java)
val loginParams = PasswordLoginParams.userIdentifier(params.userId, params.password, params.deviceName)
@ -58,4 +60,11 @@ internal class DefaultDirectLoginTask @Inject constructor(
return sessionCreator.createSession(credentials, params.homeServerConnectionConfig)
}
private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient {
return okHttpClient.get()
.newBuilder()
.addSocketFactory(homeServerConnectionConfig)
.build()
}
}

View file

@ -29,3 +29,7 @@ internal annotation class AuthenticatedIdentity
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
internal annotation class Unauthenticated
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
internal annotation class UnauthenticatedWithCertificate

View file

@ -35,12 +35,12 @@ internal class PinnedTrustManager(private val fingerprints: List<Fingerprint>?,
private val defaultTrustManager: X509TrustManager?) : X509TrustManager {
// Set to false to perform some test
private val USE_DEAFULT_TRUST_MANAGER = true
private val USE_DEFAULT_TRUST_MANAGER = true
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<X509Certificate>, s: String) {
try {
if (defaultTrustManager != null && USE_DEAFULT_TRUST_MANAGER) {
if (defaultTrustManager != null && USE_DEFAULT_TRUST_MANAGER) {
defaultTrustManager.checkClientTrusted(chain, s)
return
}
@ -57,7 +57,7 @@ internal class PinnedTrustManager(private val fingerprints: List<Fingerprint>?,
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<X509Certificate>, s: String) {
try {
if (defaultTrustManager != null && USE_DEAFULT_TRUST_MANAGER) {
if (defaultTrustManager != null && USE_DEFAULT_TRUST_MANAGER) {
defaultTrustManager.checkServerTrusted(chain, s)
return
}

View file

@ -26,7 +26,7 @@ import im.vector.matrix.android.internal.crypto.attachments.MXEncryptedAttachmen
import im.vector.matrix.android.internal.di.CacheDirectory
import im.vector.matrix.android.internal.di.ExternalFilesDirectory
import im.vector.matrix.android.internal.di.SessionCacheDirectory
import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.di.UnauthenticatedWithCertificate
import im.vector.matrix.android.internal.extensions.foldToCallback
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
@ -49,7 +49,7 @@ internal class DefaultFileService @Inject constructor(
@SessionCacheDirectory
private val sessionCacheDirectory: File,
private val contentUrlResolver: ContentUrlResolver,
@Unauthenticated
@UnauthenticatedWithCertificate
private val okHttpClient: OkHttpClient,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val taskExecutor: TaskExecutor

View file

@ -48,6 +48,7 @@ import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.SessionFilesDirectory
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.di.UnauthenticatedWithCertificate
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.di.UserMd5
import im.vector.matrix.android.internal.eventbus.EventBusTimberLogger
@ -183,18 +184,29 @@ internal abstract class SessionModule {
.build()
}
@JvmStatic
@Provides
@SessionScope
@UnauthenticatedWithCertificate
fun providesOkHttpClientWithCertificate(@Unauthenticated okHttpClient: OkHttpClient,
homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient {
return okHttpClient
.newBuilder()
.addSocketFactory(homeServerConnectionConfig)
.build()
}
@JvmStatic
@Provides
@SessionScope
@Authenticated
fun providesOkHttpClient(@Unauthenticated okHttpClient: OkHttpClient,
fun providesOkHttpClient(@UnauthenticatedWithCertificate okHttpClient: OkHttpClient,
@Authenticated accessTokenProvider: AccessTokenProvider,
homeServerConnectionConfig: HomeServerConnectionConfig,
@SessionId sessionId: String,
@MockHttpInterceptor testInterceptor: TestInterceptor?): OkHttpClient {
return okHttpClient.newBuilder()
return okHttpClient
.newBuilder()
.addAccessTokenInterceptor(accessTokenProvider)
.addSocketFactory(homeServerConnectionConfig)
.apply {
if (testInterceptor != null) {
testInterceptor.sessionId = sessionId

View file

@ -17,6 +17,7 @@
package im.vector.matrix.android.internal.session.homeserver
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.auth.wellknown.WellknownResult
import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilities
import im.vector.matrix.android.internal.auth.version.Versions
@ -43,6 +44,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
private val eventBus: EventBus,
private val getWellknownTask: GetWellknownTask,
private val configExtractor: IntegrationManagerConfigExtractor,
private val homeServerConnectionConfig: HomeServerConnectionConfig,
@UserId
private val userId: String
) : GetHomeServerCapabilitiesTask {
@ -78,7 +80,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
}.getOrNull()
val wellknownResult = runCatching {
getWellknownTask.execute(GetWellknownTask.Params(userId))
getWellknownTask.execute(GetWellknownTask.Params(userId, homeServerConnectionConfig))
}.getOrNull()
insertInDb(capabilities, uploadCapabilities, versions, wellknownResult)

View file

@ -36,7 +36,7 @@ import im.vector.matrix.android.api.session.identity.ThreePid
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.NoOpCancellable
import im.vector.matrix.android.internal.di.AuthenticatedIdentity
import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.di.UnauthenticatedWithCertificate
import im.vector.matrix.android.internal.extensions.observeNotNull
import im.vector.matrix.android.internal.network.RetrofitFactory
import im.vector.matrix.android.internal.session.SessionLifecycleObserver
@ -68,7 +68,7 @@ internal class DefaultIdentityService @Inject constructor(
private val identityPingTask: IdentityPingTask,
private val identityDisconnectTask: IdentityDisconnectTask,
private val identityRequestTokenForBindingTask: IdentityRequestTokenForBindingTask,
@Unauthenticated
@UnauthenticatedWithCertificate
private val unauthenticatedOkHttpClient: Lazy<OkHttpClient>,
@AuthenticatedIdentity
private val okHttpClient: Lazy<OkHttpClient>,

View file

@ -19,15 +19,13 @@ package im.vector.matrix.android.internal.session.identity
import dagger.Binds
import dagger.Module
import dagger.Provides
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.internal.database.RealmKeysUtils
import im.vector.matrix.android.internal.di.AuthenticatedIdentity
import im.vector.matrix.android.internal.di.IdentityDatabase
import im.vector.matrix.android.internal.di.SessionFilesDirectory
import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.di.UnauthenticatedWithCertificate
import im.vector.matrix.android.internal.di.UserMd5
import im.vector.matrix.android.internal.network.httpclient.addAccessTokenInterceptor
import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
import im.vector.matrix.android.internal.network.token.AccessTokenProvider
import im.vector.matrix.android.internal.session.SessionModule
import im.vector.matrix.android.internal.session.SessionScope
@ -47,13 +45,11 @@ internal abstract class IdentityModule {
@Provides
@SessionScope
@AuthenticatedIdentity
fun providesOkHttpClient(@Unauthenticated okHttpClient: OkHttpClient,
@AuthenticatedIdentity accessTokenProvider: AccessTokenProvider,
homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient {
fun providesOkHttpClient(@UnauthenticatedWithCertificate okHttpClient: OkHttpClient,
@AuthenticatedIdentity accessTokenProvider: AccessTokenProvider): OkHttpClient {
return okHttpClient
.newBuilder()
.addAccessTokenInterceptor(accessTokenProvider)
.addSocketFactory(homeServerConnectionConfig)
.build()
}

View file

@ -22,7 +22,7 @@ import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.terms.GetTermsResponse
import im.vector.matrix.android.api.session.terms.TermsService
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.di.UnauthenticatedWithCertificate
import im.vector.matrix.android.internal.network.NetworkConstants
import im.vector.matrix.android.internal.network.RetrofitFactory
import im.vector.matrix.android.internal.network.executeRequest
@ -41,7 +41,7 @@ import okhttp3.OkHttpClient
import javax.inject.Inject
internal class DefaultTermsService @Inject constructor(
@Unauthenticated
@UnauthenticatedWithCertificate
private val unauthenticatedOkHttpClient: Lazy<OkHttpClient>,
private val accountDataDataSource: AccountDataDataSource,
private val termsAPI: TermsAPI,

View file

@ -21,7 +21,7 @@ import dagger.Lazy
import dagger.Module
import dagger.Provides
import im.vector.matrix.android.api.session.terms.TermsService
import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.di.UnauthenticatedWithCertificate
import im.vector.matrix.android.internal.network.RetrofitFactory
import im.vector.matrix.android.internal.session.SessionScope
import okhttp3.OkHttpClient
@ -34,7 +34,7 @@ internal abstract class TermsModule {
@Provides
@JvmStatic
@SessionScope
fun providesTermsAPI(@Unauthenticated unauthenticatedOkHttpClient: Lazy<OkHttpClient>,
fun providesTermsAPI(@UnauthenticatedWithCertificate unauthenticatedOkHttpClient: Lazy<OkHttpClient>,
retrofitFactory: RetrofitFactory): TermsAPI {
val retrofit = retrofitFactory.create(unauthenticatedOkHttpClient, "https://foo.bar")
return retrofit.create(TermsAPI::class.java)

View file

@ -19,12 +19,14 @@ package im.vector.matrix.android.internal.wellknown
import android.util.MalformedJsonException
import dagger.Lazy
import im.vector.matrix.android.api.MatrixPatterns
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.auth.data.WellKnown
import im.vector.matrix.android.api.auth.wellknown.WellknownResult
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.network.RetrofitFactory
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
import im.vector.matrix.android.internal.session.homeserver.CapabilitiesAPI
import im.vector.matrix.android.internal.session.identity.IdentityAuthAPI
import im.vector.matrix.android.internal.task.Task
@ -36,7 +38,8 @@ import javax.net.ssl.HttpsURLConnection
internal interface GetWellknownTask : Task<GetWellknownTask.Params, WellknownResult> {
data class Params(
val matrixId: String
val matrixId: String,
val homeServerConnectionConfig: HomeServerConnectionConfig?
)
}
@ -56,7 +59,19 @@ internal class DefaultGetWellknownTask @Inject constructor(
val homeServerDomain = params.matrixId.substringAfter(":")
return findClientConfig(homeServerDomain)
val client = buildClient(params.homeServerConnectionConfig)
return findClientConfig(homeServerDomain, client)
}
private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig?): OkHttpClient {
return if (homeServerConnectionConfig != null) {
okHttpClient.get()
.newBuilder()
.addSocketFactory(homeServerConnectionConfig)
.build()
} else {
okHttpClient.get()
}
}
/**
@ -68,8 +83,8 @@ internal class DefaultGetWellknownTask @Inject constructor(
*
* @param domain: homeserver domain, deduced from mx userId (ex: "matrix.org" from userId "@user:matrix.org")
*/
private suspend fun findClientConfig(domain: String): WellknownResult {
val wellKnownAPI = retrofitFactory.create(okHttpClient, "https://dummy.org")
private suspend fun findClientConfig(domain: String, client: OkHttpClient): WellknownResult {
val wellKnownAPI = retrofitFactory.create(client, "https://dummy.org")
.create(WellKnownAPI::class.java)
return try {
@ -84,7 +99,7 @@ internal class DefaultGetWellknownTask @Inject constructor(
} else {
if (homeServerBaseUrl.isValidUrl()) {
// Check that HS is a real one
validateHomeServer(homeServerBaseUrl, wellKnown)
validateHomeServer(homeServerBaseUrl, wellKnown, client)
} else {
WellknownResult.FailError
}
@ -113,8 +128,8 @@ internal class DefaultGetWellknownTask @Inject constructor(
/**
* Return true if home server is valid, and (if applicable) if identity server is pingable
*/
private suspend fun validateHomeServer(homeServerBaseUrl: String, wellKnown: WellKnown): WellknownResult {
val capabilitiesAPI = retrofitFactory.create(okHttpClient, homeServerBaseUrl)
private suspend fun validateHomeServer(homeServerBaseUrl: String, wellKnown: WellKnown, client: OkHttpClient): WellknownResult {
val capabilitiesAPI = retrofitFactory.create(client, homeServerBaseUrl)
.create(CapabilitiesAPI::class.java)
try {
@ -135,7 +150,7 @@ internal class DefaultGetWellknownTask @Inject constructor(
WellknownResult.FailError
} else {
if (identityServerBaseUrl.isValidUrl()) {
if (validateIdentityServer(identityServerBaseUrl)) {
if (validateIdentityServer(identityServerBaseUrl, client)) {
// All is ok
WellknownResult.Prompt(homeServerBaseUrl, identityServerBaseUrl, wellKnown)
} else {
@ -151,8 +166,8 @@ internal class DefaultGetWellknownTask @Inject constructor(
/**
* Return true if identity server is pingable
*/
private suspend fun validateIdentityServer(identityServerBaseUrl: String): Boolean {
val identityPingApi = retrofitFactory.create(okHttpClient, identityServerBaseUrl)
private suspend fun validateIdentityServer(identityServerBaseUrl: String, client: OkHttpClient): Boolean {
val identityPingApi = retrofitFactory.create(client, identityServerBaseUrl)
.create(IdentityAuthAPI::class.java)
return try {

View file

@ -496,7 +496,8 @@ class LoginViewModel @AssistedInject constructor(
)
}
authenticationService.getWellKnownData(action.username, object : MatrixCallback<WellknownResult> {
// TODO Handle certificate error in this case. Direct login is deactivated now, so we will handle that later
authenticationService.getWellKnownData(action.username, null, object : MatrixCallback<WellknownResult> {
override fun onSuccess(data: WellknownResult) {
when (data) {
is WellknownResult.Prompt ->