Skip to content

Commit

Permalink
fix: Remove gds networking library
Browse files Browse the repository at this point in the history
Update libs.versions.toml to remove the GDS networking library dependency
Update build.gradle.kts to remove usage of the GDS networking dependency
Add AttestationClient to use in place of GenericHttpClient
Add JWK object to hold the relevant details for the attestation JWK
Swap from GenericHttpClient to AttestationClient
Update tests

Resolves: 10311
  • Loading branch information
ThomasIent committed Oct 29, 2024
1 parent 61409e9 commit b9f16c0
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 60 deletions.
1 change: 0 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ dependencies {
libs.appcompat,
libs.appauth,
libs.kotlinx.serialization.json,
libs.network,
libs.jose4j,
libs.gson
).forEach(::implementation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,19 @@ import uk.gov.android.authentication.integrity.appcheck.AppChecker
import uk.gov.android.authentication.integrity.model.AppIntegrityConfiguration
import uk.gov.android.authentication.integrity.model.AttestationResponse
import uk.gov.android.authentication.integrity.model.SignedResponse
import uk.gov.android.network.client.GenericHttpClient
import uk.gov.android.authentication.integrity.usecase.AttestationClient
import kotlin.test.assertEquals

class FirebaseAppIntegrityCheckerTest {
private lateinit var clientAttestationManager: ClientAttestationManager

private val mockHttpClient: GenericHttpClient = mock()
private val client: AttestationClient = mock()
private val mockAppChecker: AppChecker = mock()

@Before
fun setup() {
val config = AppIntegrityConfiguration(
mockHttpClient,
"url",
client,
mockAppChecker
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package uk.gov.android.authentication.integrity.model

import uk.gov.android.authentication.integrity.appcheck.AppChecker
import uk.gov.android.network.client.GenericHttpClient
import uk.gov.android.authentication.integrity.usecase.AttestationClient

data class AppIntegrityConfiguration(
val httpClient: GenericHttpClient,
val attestationUrl: String,
val attestationClient: AttestationClient,
val appChecker: AppChecker
)
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
package uk.gov.android.authentication.integrity.usecase

import uk.gov.android.network.api.ApiRequest
import uk.gov.android.network.api.ApiResponse
import uk.gov.android.network.client.GenericHttpClient

internal fun interface AttestationApiCaller {
suspend fun call(
firebaseToken: String,
backendUrl: String
signedProofOfPossession: String,
jwkX: String,
jwkY: String
): String
}

internal class AttestationApiCallerImpl (
private val httpClient: GenericHttpClient
private val client: AttestationClient
) : AttestationApiCaller {
override suspend fun call(firebaseToken: String, backendUrl: String): String {
val request = ApiRequest.Get(
url = backendUrl,
headers = listOf(
"X-Firebase-Token" to firebaseToken
)
)
val response = httpClient.makeRequest(request)
return if (response is ApiResponse.Success<*>) {
response.response.toString()
} else {
(response as ApiResponse.Failure).error.message ?: "Error"

override suspend fun call(
signedProofOfPossession: String,
jwkX: String,
jwkY: String
): String {
val result = client.attest(signedProofOfPossession, JWK.makeJWK(jwkX, jwkY))
return when {
result.isSuccess -> result.getOrNull()?.jwt ?: "Empty"
else -> result.exceptionOrNull()?.message ?: "Error"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package uk.gov.android.authentication.integrity.usecase

import org.jose4j.jwk.JsonWebKey

fun interface AttestationClient {
suspend fun attest(popJWT: String, request: JsonWebKey): Result<Response>

data class Response(val jwt: String, val expiresIn: Long)

companion object {
@Suppress("unused")
protected const val FIREBASE_HEADER = "X-Firebase-AppCheck"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package uk.gov.android.authentication.integrity.usecase

import org.jose4j.jwk.JsonWebKey

@Suppress("MemberVisibilityCanBePrivate")
object JWK {
const val keyType = "kty"
const val use = "use"
const val curve = "crv"
const val x = "x"
const val y = "y"
private const val keyTypeValue = "EC"
private const val useValue = "sig"
private const val curveValue = "P-256"

fun makeJWK(x: String, y: String): JsonWebKey = JsonWebKey.Factory.newJwk(
mapOf(
keyType to keyTypeValue,
use to useValue,
curve to curveValue,
JWK.x to x,
JWK.y to y
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,53 @@ package uk.gov.android.authentication.integrity.usecase
import kotlinx.coroutines.runBlocking
import java.io.IOException
import kotlin.test.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import kotlin.test.assertEquals
import kotlin.test.BeforeTest
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import uk.gov.android.network.api.ApiRequest
import uk.gov.android.network.api.ApiResponse
import uk.gov.android.network.client.GenericHttpClient
import kotlin.to

class AttestationApiCallImplTest {
private lateinit var httpClient: GenericHttpClient
private lateinit var attestationApiCaller: AttestationApiCaller
private lateinit var client: AttestationClient
private lateinit var caller: AttestationApiCallerImpl

@BeforeEach
@BeforeTest
fun setUp() {
httpClient = mock()
attestationApiCaller =
AttestationApiCallerImpl(httpClient)
client = mock()
caller = AttestationApiCallerImpl(client)
}

@Test
fun `invoke() - Success`() = runBlocking {
fun `call() - Success`() = runBlocking {
val response = AttestationClient.Response("Success", 1000L)
val firebaseToken = "testToken"
val expectedRequest = ApiRequest.Get(
url = "url",
headers = listOf(
"X-Firebase-Token" to firebaseToken
)
)
whenever(httpClient.makeRequest(expectedRequest)).thenReturn(ApiResponse.Success("Success"))
whenever(client.attest(eq(firebaseToken), any())).thenReturn(Result.success(response))

val result = attestationApiCaller.call(firebaseToken, "url")
val result = caller.call(firebaseToken, JWKTest.X, JWKTest.Y)

assertEquals("Success", result)
}

@Test
fun `invoke() - Failure with error message`() = runBlocking {
fun `call() - Failure with error message`() = runBlocking {
val firebaseToken = "testToken"
val errorMessage = "Test error message"
whenever(httpClient.makeRequest(any()))
.thenReturn(ApiResponse.Failure(500, IOException(errorMessage)))
whenever(client.attest(eq(firebaseToken), any()))
.thenReturn(Result.failure(IOException(errorMessage)))

val result = attestationApiCaller.call(firebaseToken, "url")
val result = caller.call(firebaseToken, JWKTest.X, JWKTest.Y)

assertEquals(errorMessage, result)
}

@Test
fun `invoke() - Failure without error message`() = runBlocking {
fun `call() - Failure without error message`() = runBlocking {
val firebaseToken = "testToken"
whenever(httpClient.makeRequest(any()))
.thenReturn(ApiResponse.Failure(500, IOException()))
whenever(client.attest(eq(firebaseToken), any()))
.thenReturn(Result.failure(IOException()))

val result = attestationApiCaller.call(firebaseToken, "url")
val result = caller.call(firebaseToken, JWKTest.X, JWKTest.Y)

assertEquals("Error", result)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package uk.gov.android.authentication.integrity.usecase

import kotlin.test.Test
import kotlin.test.assertEquals

class JWKTest {
@Test
fun `makeJWK sets defaults`() {
val actual = JWK.makeJWK(X, Y)
assertEquals(expected = "EC", actual = actual.keyType)
assertEquals(expected = "sig", actual = actual.use)
}

companion object {
const val X = "18wHLeIgW9wVN6VD1Txgpqy2LszYkMf6J8njVAibvhM"
const val Y = "-V4dS4UaLMgP_4fY4j8ir7cl1TXlFdAgcx55o7TkcSA"
}
}
4 changes: 0 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ mockito-kotlin = "5.4.0"
mockitoCore = "5.10.0"
mockito-android = "5.14.2"
espresso-core = "3.6.1"
gds-network = "0.2.8"
jose4j = "0.9.4"
gson = "2.10.1"

Expand All @@ -35,9 +34,6 @@ kotlin-gradle-plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-p
jose4j = { module = "org.bitbucket.b_c:jose4j", version.ref = "jose4j" }
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }

# GDS
network = { group = "uk.gov.android", name = "network", version.ref = "gds-network" }

#Code Quality
ktlint-gradle = { group = "org.jlleitschuh.gradle", name = "ktlint-gradle", version.ref = "ktlint-gradle" }
sonarqube-gradle = { module = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin", version.ref = "sonarqube-gradle" }
Expand Down

0 comments on commit b9f16c0

Please sign in to comment.