Skip to content

Commit 544b1a2

Browse files
authored
dataconnect: auth token internal refactor to track authUid, part 2 (#7485)
1 parent d2d23d3 commit 544b1a2

File tree

4 files changed

+60
-6
lines changed

4 files changed

+60
-6
lines changed

firebase-dataconnect/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Unreleased
22

33
- [changed] Internal refactor for managing Auth and App Check tokens
4-
([#7184](https://github.com/firebase/firebase-android-sdk/pull/7184))
4+
([#7484](https://github.com/firebase/firebase-android-sdk/pull/7484),
5+
[#7485](https://github.com/firebase/firebase-android-sdk/pull/7485))
56

67
# 17.1.0
78

firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/DataConnectAuth.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,22 @@ internal class DataConnectAuth(
4949
provider.removeIdTokenListener(idTokenListener)
5050

5151
override suspend fun getToken(provider: InternalAuthProvider, forceRefresh: Boolean) =
52-
provider.getAccessToken(forceRefresh).await().let { GetAuthTokenResult(it.token) }
52+
provider.getAccessToken(forceRefresh).await().let {
53+
GetAuthTokenResult(it.token, it.getAuthUid())
54+
}
5355

54-
data class GetAuthTokenResult(override val token: String?) : GetTokenResult
56+
data class GetAuthTokenResult(override val token: String?, val authUid: String?) : GetTokenResult
5557

5658
private class IdTokenListenerImpl(private val logger: Logger) : IdTokenListener {
5759
override fun onIdTokenChanged(tokenResult: InternalTokenResult) {
5860
logger.debug { "onIdTokenChanged(token=${tokenResult.token?.toScrubbedAccessToken()})" }
5961
}
6062
}
63+
64+
private companion object {
65+
66+
// The "sub" claim is documented to be "a non-empty string and must be the uid of the user or
67+
// device". See http://goo.gle/4oGjEQt for the relevant Firebase documentation.
68+
fun com.google.firebase.auth.GetTokenResult.getAuthUid(): String? = claims["sub"] as? String
69+
}
6170
}

firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/core/DataConnectAuthUnitTest.kt

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ import io.kotest.matchers.shouldBe
5454
import io.kotest.matchers.types.shouldBeSameInstanceAs
5555
import io.kotest.property.Arb
5656
import io.kotest.property.RandomSource
57+
import io.kotest.property.arbitrary.map
5758
import io.kotest.property.arbitrary.next
59+
import io.kotest.property.arbs.products.brand
5860
import io.mockk.coEvery
5961
import io.mockk.confirmVerified
6062
import io.mockk.every
@@ -311,6 +313,46 @@ class DataConnectAuthUnitTest {
311313
mockLogger.shouldNotHaveLoggedAnyMessagesContaining(accessToken)
312314
}
313315

316+
@Test
317+
fun `getToken() should populate authUid from sub claim`() = runTest {
318+
val dataConnectAuth = newDataConnectAuth()
319+
dataConnectAuth.initialize()
320+
advanceUntilIdle()
321+
val uid = Arb.brand().map { it.value }.next(rs)
322+
coEvery { mockInternalAuthProvider.getAccessToken(any()) } returns
323+
taskForToken(accessToken, mapOf("sub" to uid))
324+
325+
val result = dataConnectAuth.getToken(requestId)
326+
327+
result.shouldNotBeNull().authUid shouldBe uid
328+
}
329+
330+
@Test
331+
fun `getToken() should populate null authUid if sub claim is missing`() = runTest {
332+
val dataConnectAuth = newDataConnectAuth()
333+
dataConnectAuth.initialize()
334+
advanceUntilIdle()
335+
coEvery { mockInternalAuthProvider.getAccessToken(any()) } returns
336+
taskForToken(accessToken, emptyMap())
337+
338+
val result = dataConnectAuth.getToken(requestId)
339+
340+
result.shouldNotBeNull().authUid.shouldBeNull()
341+
}
342+
343+
@Test
344+
fun `getToken() should populate null authUid if sub claim is not a String`() = runTest {
345+
val dataConnectAuth = newDataConnectAuth()
346+
dataConnectAuth.initialize()
347+
advanceUntilIdle()
348+
coEvery { mockInternalAuthProvider.getAccessToken(any()) } returns
349+
taskForToken(accessToken, mapOf("sub" to 42))
350+
351+
val result = dataConnectAuth.getToken(requestId)
352+
353+
result.shouldNotBeNull().authUid.shouldBeNull()
354+
}
355+
314356
@Test
315357
fun `getToken() should return re-throw the exception from the task returned from FirebaseAuth`() =
316358
runTest {
@@ -613,7 +655,7 @@ class DataConnectAuthUnitTest {
613655
interval = 100.milliseconds
614656
}
615657

616-
fun taskForToken(token: String?): Task<GetTokenResult> =
617-
Tasks.forResult(mockk(relaxed = true) { every { getToken() } returns token })
658+
fun taskForToken(token: String?, claims: Map<String, Any> = emptyMap()): Task<GetTokenResult> =
659+
Tasks.forResult(GetTokenResult(token, claims))
618660
}
619661
}

firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/testutil/property/arbitrary/arbs.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,9 @@ internal inline fun <Data, reified Variables> DataConnectArb.operationRefConstru
334334

335335
internal fun DataConnectArb.authTokenResult(
336336
accessToken: Arb<String?> = accessToken().orNull(nullProbability = 0.33),
337-
): Arb<GetAuthTokenResult> = accessToken.map { GetAuthTokenResult(it) }
337+
authUid: Arb<String?> =
338+
Arb.string(0..10, Codepoint.alphanumeric()).orNull(nullProbability = 0.33),
339+
): Arb<GetAuthTokenResult> = Arb.bind(accessToken, authUid, ::GetAuthTokenResult)
338340

339341
internal fun DataConnectArb.appCheckTokenResult(
340342
accessToken: Arb<String?> = accessToken().orNull(nullProbability = 0.33),

0 commit comments

Comments
 (0)