Skip to content

Commit

Permalink
Adding ssl support (#16)
Browse files Browse the repository at this point in the history
* Making address and port configurable

* Making address and port configurable

* Adding support for SSL connections

* Small change

* Unused
  • Loading branch information
gmerinojimenez authored Apr 4, 2023
1 parent 252a572 commit a09161e
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 9 deletions.
4 changes: 2 additions & 2 deletions app/src/demo/assets/user_list_success_2.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"first": "Pablo",
"last": "Garcia"
},
"email": "Pablogarcia.sg@gmail.com",
"phone": "618 42 69 62"
"email": "Pablo.Garcia@gmail.com",
"phone": "666 66 66 66"
},
{
"name": {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/Theme.Mocks"
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="31">
<activity
android:name=".MainActivity"
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/telefonica/mocks/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class App : Application() {
if (BuildConfig.DEFAULT_ENVIRONMENT == Environment.DEMO) {
super.onCreate()
CoroutineScope(Dispatchers.IO).launch {
mockHelper.setUp()
mockHelper.setUp(enableSsl = true)
mockHelper.enqueue(getUserMocksUseCase())
initBackendUrl()
}
Expand Down
8 changes: 7 additions & 1 deletion app/src/main/java/com/telefonica/mocks/di/RemoteModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.telefonica.mocks.domain.backend.InitBackendUrl
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.telefonica.mock.MockHelper
import com.telefonica.mock.cert.AllCertsAllowedBuilderUpdater
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand All @@ -29,7 +30,12 @@ class RemoteModule {
@Provides
fun provideOkHttpClient(
interceptor: HttpLoggingInterceptor
): OkHttpClient = OkHttpClient.Builder().addInterceptor(interceptor).build()
): OkHttpClient = OkHttpClient.Builder()
.addInterceptor(interceptor)
.apply {
AllCertsAllowedBuilderUpdater.update(this)
}
.build()

@Provides
fun provideMoshi(): Moshi = Moshi
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<debug-overrides>
<trust-anchors>
<!-- Trust user added CAs while debuggable only -->
<certificates src="user" />
</trust-anchors>
</debug-overrides>
</network-security-config>
1 change: 1 addition & 0 deletions mock/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ android {
dependencies {

implementation "com.squareup.okhttp3:mockwebserver:4.9.3"
implementation "com.squareup.okhttp3:okhttp-tls:4.9.3"

implementation "com.google.dagger:dagger:2.44"
kapt "com.google.dagger:dagger-compiler:2.44"
Expand Down
22 changes: 20 additions & 2 deletions mock/src/main/java/com/telefonica/mock/MockApiClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.mockwebserver.RecordedRequest
import java.net.InetAddress
import okhttp3.tls.HandshakeCertificates
import okhttp3.tls.HeldCertificate
import java.net.InetAddress
import java.util.concurrent.TimeUnit
import javax.inject.Inject

Expand Down Expand Up @@ -35,7 +38,7 @@ open class MockApiClient @Inject constructor(
}
}

suspend fun startServer(inetAddress: InetAddress = InetAddress.getByName("localhost"), port: Int = 0) {
internal suspend fun startServer(inetAddress: InetAddress, port: Int = 0) {
withContext(coroutineDispatcher) {
runCatching {
mockWebServer.start(inetAddress = inetAddress, port = port)
Expand All @@ -59,10 +62,25 @@ open class MockApiClient @Inject constructor(
enqueuedAnswers.addAll(mocks)
}

fun setUp() {
internal fun setUp(address: InetAddress, enableSsl: Boolean) {
mockWebServer.dispatcher = dispatcher
if (enableSsl) {
enableHttpsFor(mockWebServer, address)
}
}

private fun enableHttpsFor(mockWebServer: MockWebServer, address: InetAddress) {
val serverCertificates = HandshakeCertificates.Builder()
.heldCertificate(buildCertificate(address.canonicalHostName))
.build()
mockWebServer.useHttps(serverCertificates.sslSocketFactory(), false)
}

private fun buildCertificate(altName: String): HeldCertificate = HeldCertificate.Builder()
.addSubjectAlternativeName(altName)
.build()


private fun getMockResponse(mockFiles: List<Mock>): MockResponse = when (mockFiles.isEmpty()) {
true -> MockResponse().setResponseCode(NOT_FOUND_ERROR)
false -> {
Expand Down
11 changes: 9 additions & 2 deletions mock/src/main/java/com/telefonica/mock/MockHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,15 @@ class MockHelper(context: Context) {

suspend fun getBaseUrl(): String = mockApiClient.getBaseUrl()

suspend fun setUp(inetAddress: InetAddress = InetAddress.getByName("localhost"), port: Int = 0) {
mockApiClient.setUp()
suspend fun setUp(
inetAddress: InetAddress = InetAddress.getByName("localhost"),
port: Int = 0,
enableSsl: Boolean = false,
) {
mockApiClient.setUp(
address = inetAddress,
enableSsl = enableSsl,
)
mockApiClient.startServer(inetAddress, port)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.telefonica.mock.cert

import android.annotation.SuppressLint
import okhttp3.OkHttpClient
import java.security.KeyManagementException
import java.security.NoSuchAlgorithmException
import java.security.cert.CertificateException
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager

object AllCertsAllowedBuilderUpdater {

@SuppressLint("CustomX509TrustManager")
@JvmStatic
fun update(builder: OkHttpClient.Builder) {
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
@SuppressLint("TrustAllX509TrustManager")
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
}

@SuppressLint("TrustAllX509TrustManager")
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
}

override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> {
return arrayOf()
}
})

try {
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
val sslSocketFactory = sslContext.socketFactory
builder.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
builder.hostnameVerifier(HostnameVerifier { _, _ -> true })
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException(e)
} catch (e: KeyManagementException) {
throw RuntimeException(e)
}
}

}

0 comments on commit a09161e

Please sign in to comment.