mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 15:15:34 +03:00
Handle null or blank auth urls for Duo 2FA (#1044)
This commit is contained in:
parent
8eafb8e180
commit
2e2b80470c
4 changed files with 47 additions and 8 deletions
|
@ -32,14 +32,13 @@ val GetTokenResponseJson.TwoFactorRequired?.preferredAuthMethod: TwoFactorAuthMe
|
||||||
/**
|
/**
|
||||||
* If it exists, return the value of the Duo auth url.
|
* If it exists, return the value of the Duo auth url.
|
||||||
*/
|
*/
|
||||||
val GetTokenResponseJson.TwoFactorRequired?.twoFactorDuoAuthUrl: String
|
val GetTokenResponseJson.TwoFactorRequired?.twoFactorDuoAuthUrl: String?
|
||||||
get() = this
|
get() = this
|
||||||
?.authMethodsData
|
?.authMethodsData
|
||||||
?.duo
|
?.duo
|
||||||
?.get("AuthUrl")
|
?.get("AuthUrl")
|
||||||
?.jsonPrimitive
|
?.jsonPrimitive
|
||||||
?.contentOrNull
|
?.contentOrNull
|
||||||
.orEmpty()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If it exists, return the value to display for the email used with two-factor authentication.
|
* If it exists, return the value to display for the email used with two-factor authentication.
|
||||||
|
|
|
@ -160,10 +160,19 @@ class TwoFactorLoginViewModel @Inject constructor(
|
||||||
*/
|
*/
|
||||||
private fun handleContinueButtonClick() {
|
private fun handleContinueButtonClick() {
|
||||||
if (state.authMethod.isDuo) {
|
if (state.authMethod.isDuo) {
|
||||||
|
val authUrl = authRepository.twoFactorResponse.twoFactorDuoAuthUrl
|
||||||
|
// The url should not be empty unless the environment is somehow not supported.
|
||||||
sendEvent(
|
sendEvent(
|
||||||
event = TwoFactorLoginEvent.NavigateToDuo(
|
event = authUrl
|
||||||
uri = Uri.parse(authRepository.twoFactorResponse.twoFactorDuoAuthUrl),
|
?.let {
|
||||||
),
|
TwoFactorLoginEvent.NavigateToDuo(
|
||||||
|
uri = Uri.parse(it),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
?: TwoFactorLoginEvent.ShowToast(
|
||||||
|
// TODO BIT-1927 Update to use string resource
|
||||||
|
message = "Duo not yet supported".asText(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
initiateLogin()
|
initiateLogin()
|
||||||
|
|
|
@ -6,6 +6,7 @@ import kotlinx.serialization.json.JsonNull
|
||||||
import kotlinx.serialization.json.JsonObject
|
import kotlinx.serialization.json.JsonObject
|
||||||
import kotlinx.serialization.json.JsonPrimitive
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Assertions.assertNull
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
class TwoFactorRequiredExtensionTest {
|
class TwoFactorRequiredExtensionTest {
|
||||||
|
@ -62,7 +63,7 @@ class TwoFactorRequiredExtensionTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `twoFactorDuoAuthUrl returns empty string when no DUO AuthUrl is present`() {
|
fun `twoFactorDuoAuthUrl returns null when no DUO AuthUrl is present`() {
|
||||||
val subject = GetTokenResponseJson.TwoFactorRequired(
|
val subject = GetTokenResponseJson.TwoFactorRequired(
|
||||||
authMethodsData = mapOf(
|
authMethodsData = mapOf(
|
||||||
TwoFactorAuthMethod.AUTHENTICATOR_APP to JsonObject(mapOf("AuthUrl" to JsonNull)),
|
TwoFactorAuthMethod.AUTHENTICATOR_APP to JsonObject(mapOf("AuthUrl" to JsonNull)),
|
||||||
|
@ -70,7 +71,7 @@ class TwoFactorRequiredExtensionTest {
|
||||||
captchaToken = null,
|
captchaToken = null,
|
||||||
ssoToken = null,
|
ssoToken = null,
|
||||||
)
|
)
|
||||||
assertEquals("", subject.twoFactorDuoAuthUrl)
|
assertNull(subject.twoFactorDuoAuthUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -249,8 +249,9 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `ContinueButtonClick login should emit NavigateToDuo when auth method is Duo`() = runTest {
|
fun `ContinueButtonClick login should emit NavigateToDuo when auth method is Duo and authUrl is non-null`() = runTest {
|
||||||
val authMethodsData = mapOf(
|
val authMethodsData = mapOf(
|
||||||
TwoFactorAuthMethod.DUO to JsonObject(
|
TwoFactorAuthMethod.DUO to JsonObject(
|
||||||
mapOf("AuthUrl" to JsonPrimitive("bitwarden.com")),
|
mapOf("AuthUrl" to JsonPrimitive("bitwarden.com")),
|
||||||
|
@ -281,6 +282,35 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `ContinueButtonClick login should emit ShowToast when auth method is Duo and authUrl is null`() = runTest {
|
||||||
|
val authMethodsData = mapOf(
|
||||||
|
TwoFactorAuthMethod.DUO to JsonObject(
|
||||||
|
mapOf("Nothing" to JsonPrimitive("Nothing")),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val response = GetTokenResponseJson.TwoFactorRequired(
|
||||||
|
authMethodsData = authMethodsData,
|
||||||
|
captchaToken = null,
|
||||||
|
ssoToken = null,
|
||||||
|
)
|
||||||
|
every { authRepository.twoFactorResponse } returns response
|
||||||
|
val mockkUri = mockk<Uri>()
|
||||||
|
val viewModel = createViewModel(
|
||||||
|
state = DEFAULT_STATE.copy(
|
||||||
|
authMethod = TwoFactorAuthMethod.DUO,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
viewModel.eventFlow.test {
|
||||||
|
viewModel.actionChannel.trySend(TwoFactorLoginAction.ContinueButtonClick)
|
||||||
|
assertEquals(
|
||||||
|
TwoFactorLoginEvent.ShowToast("Duo not yet supported".asText()),
|
||||||
|
awaitItem(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ContinueButtonClick login returns CaptchaRequired should emit NavigateToCaptcha`() =
|
fun `ContinueButtonClick login returns CaptchaRequired should emit NavigateToCaptcha`() =
|
||||||
runTest {
|
runTest {
|
||||||
|
|
Loading…
Reference in a new issue