From 9c48f1b5630994e9a1f94a3d8ee7c083e8300c4e Mon Sep 17 00:00:00 2001 From: Kirill Kamakin Date: Sun, 11 Dec 2022 10:17:13 +0100 Subject: [PATCH] Support invalidation in MealieAuthenticator --- .../datasource/AuthenticationProvider.kt | 1 + .../datasource/impl/MealieAuthenticator.kt | 18 ++++++++++--- .../datasource/MealieAuthenticatorTest.kt | 27 +++++++++++++++++-- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/AuthenticationProvider.kt b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/AuthenticationProvider.kt index 7df0e88..b43f93a 100644 --- a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/AuthenticationProvider.kt +++ b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/AuthenticationProvider.kt @@ -4,4 +4,5 @@ interface AuthenticationProvider { suspend fun getAuthHeader(): String? + suspend fun invalidateAuthHeader() } \ No newline at end of file diff --git a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/impl/MealieAuthenticator.kt b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/impl/MealieAuthenticator.kt index bf5df70..96ca52f 100644 --- a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/impl/MealieAuthenticator.kt +++ b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/impl/MealieAuthenticator.kt @@ -18,16 +18,26 @@ class MealieAuthenticator @Inject constructor( override fun authenticate(route: Route?, response: Response): Request? { val supportsBearer = response.challenges().any { it.scheme == BEARER_SCHEME } + if (!supportsBearer) { + return null + } + val request = response.request - return if (supportsBearer && request.header(HEADER_NAME) == null) { - getAuthHeader()?.let { request.copyWithHeader(HEADER_NAME, it) } - } else { - null // Either Bearer is not supported or we've already tried to authenticate + val previousHeader = request.header(HEADER_NAME) + ?: return getAuthHeader()?.let { request.copyWithHeader(HEADER_NAME, it) } + + invalidateAuthHeader() + return getAuthHeader()?.takeUnless { it == previousHeader }?.let { + request.copyWithHeader(HEADER_NAME, it) } } private fun getAuthHeader() = runBlocking { authenticationProvider.get().getAuthHeader() } + private fun invalidateAuthHeader() { + runBlocking { authenticationProvider.get().invalidateAuthHeader() } + } + companion object { @VisibleForTesting const val HEADER_NAME = "Authorization" diff --git a/datasource/src/test/kotlin/gq/kirmanak/mealient/datasource/MealieAuthenticatorTest.kt b/datasource/src/test/kotlin/gq/kirmanak/mealient/datasource/MealieAuthenticatorTest.kt index 41d8714..a9949c0 100644 --- a/datasource/src/test/kotlin/gq/kirmanak/mealient/datasource/MealieAuthenticatorTest.kt +++ b/datasource/src/test/kotlin/gq/kirmanak/mealient/datasource/MealieAuthenticatorTest.kt @@ -17,7 +17,7 @@ class MealieAuthenticatorTest : BaseUnitTest() { private lateinit var subject: MealieAuthenticator - @MockK + @MockK(relaxUnitFun = true) lateinit var authenticationProvider: AuthenticationProvider @Before @@ -48,11 +48,34 @@ class MealieAuthenticatorTest : BaseUnitTest() { } @Test - fun `when no auth header was set expect authenticate to return null`() { + fun `when had auth header but can't invalidate expect authenticate return null`() { + coEvery { authenticationProvider.getAuthHeader() } returns null val response = buildResponse(authHeader = "token") assertThat(subject.authenticate(null, response)).isNull() } + @Test + fun `when had auth header and invalidate doesn't change it expect authenticate return null`() { + coEvery { authenticationProvider.getAuthHeader() } returns "token" + val response = buildResponse(authHeader = "token") + assertThat(subject.authenticate(null, response)).isNull() + } + + @Test + fun `when had auth header and invalidate succeeds expect authenticate return new`() { + coEvery { authenticationProvider.getAuthHeader() } returns "newToken" + val response = buildResponse(authHeader = "token") + assertThat(subject.authenticate(null, response)?.header(HEADER_NAME)).isEqualTo("newToken") + } + + @Test + fun `when had auth header expect authenticate to invalidate it`() { + coEvery { authenticationProvider.getAuthHeader() } returns null + val response = buildResponse(authHeader = "token") + subject.authenticate(null, response) + coVerify { authenticationProvider.invalidateAuthHeader() } + } + @Test fun `when auth header exists expect authenticate to return request`() { coEvery { authenticationProvider.getAuthHeader() } returns "token"