Add setup for WebAuthn (#1294)

This commit is contained in:
David Perez
2024-04-22 11:18:11 -05:00
committed by Álison Fernandes
parent 77a7cb0e51
commit ae38b5d7ed
10 changed files with 263 additions and 17 deletions

View File

@@ -124,6 +124,9 @@ sealed class GetTokenResponseJson {
@SerialName("TwoFactorProviders2")
val authMethodsData: Map<TwoFactorAuthMethod, JsonObject?>,
@SerialName("TwoFactorProviders")
val twoFactorProviders: List<String>?,
@SerialName("CaptchaBypassToken")
val captchaToken: String?,

View File

@@ -2,8 +2,11 @@ package com.x8bit.bitwarden.data.auth.datasource.network.util
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorAuthMethod
import com.x8bit.bitwarden.data.platform.datasource.network.util.base64UrlDecodeOrNull
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
/**
@@ -58,3 +61,53 @@ val GetTokenResponseJson.TwoFactorRequired?.twoFactorDisplayEmail: String
*/
private val Map<TwoFactorAuthMethod, JsonObject?>.duo: JsonObject?
get() = get(TwoFactorAuthMethod.DUO) ?: get(TwoFactorAuthMethod.DUO_ORGANIZATION)
/**
* If it exists, return the identifier for the relying party used with Web AuthN two-factor
* authentication.
*/
val GetTokenResponseJson.TwoFactorRequired?.webAuthRpId: String?
get() = this
?.authMethodsData
?.get(TwoFactorAuthMethod.WEB_AUTH)
?.get("rpId")
?.jsonPrimitive
?.contentOrNull
/**
* If it exists, return the type of user verification needed to complete the Web AuthN two-factor
* authentication.
*/
val GetTokenResponseJson.TwoFactorRequired?.webAuthUserVerification: String?
get() = this
?.authMethodsData
?.get(TwoFactorAuthMethod.WEB_AUTH)
?.get("userVerification")
?.jsonPrimitive
?.contentOrNull
/**
* If it exists, return the challenge that the authenticator need to solve to complete the
* Web AuthN two-factor authentication.
*/
val GetTokenResponseJson.TwoFactorRequired?.webAuthChallenge: String?
get() = this
?.authMethodsData
?.get(TwoFactorAuthMethod.WEB_AUTH)
?.get("challenge")
?.jsonPrimitive
?.contentOrNull
/**
* If it exists, return the credentials allowed to be used to solve the challenge to complete the
* Web AuthN two-factor authentication.
*/
val GetTokenResponseJson.TwoFactorRequired?.webAuthAllowCredentials: List<String>?
get() = this
?.authMethodsData
?.get(TwoFactorAuthMethod.WEB_AUTH)
?.get("allowCredentials")
?.jsonArray
?.mapNotNull {
it.jsonObject["id"]?.jsonPrimitive?.contentOrNull?.base64UrlDecodeOrNull()
}

View File

@@ -19,6 +19,7 @@ import com.x8bit.bitwarden.data.auth.repository.util.CaptchaCallbackTokenResult
import com.x8bit.bitwarden.data.auth.repository.util.DuoCallbackTokenResult
import com.x8bit.bitwarden.data.auth.repository.util.generateUriForCaptcha
import com.x8bit.bitwarden.data.auth.util.YubiKeyResult
import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.button
import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.imageRes
import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.isDuo
import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.shouldUseNfc
@@ -456,12 +457,7 @@ data class TwoFactorLoginState(
/**
* The text to display for the button given the [authMethod].
*/
val buttonText: Text
get() = if (authMethod.isDuo) {
R.string.launch_duo.asText()
} else {
R.string.continue_text.asText()
}
val buttonText: Text get() = authMethod.button
/**
* Indicates if the screen should be listening for NFC events from the operating system.

View File

@@ -20,6 +20,7 @@ val TwoFactorAuthMethod.title: Text
TwoFactorAuthMethod.EMAIL -> R.string.email.asText()
TwoFactorAuthMethod.RECOVERY_CODE -> R.string.recovery_code_title.asText()
TwoFactorAuthMethod.WEB_AUTH -> R.string.fido2_authenticate_web_authn.asText()
TwoFactorAuthMethod.YUBI_KEY -> R.string.yubi_key_title.asText()
else -> "".asText()
}
@@ -38,10 +39,31 @@ fun TwoFactorAuthMethod.description(email: String): Text = when (this) {
}
TwoFactorAuthMethod.EMAIL -> R.string.enter_verification_code_email.asText(email)
TwoFactorAuthMethod.WEB_AUTH -> R.string.continue_to_complete_web_authn_verfication.asText()
TwoFactorAuthMethod.YUBI_KEY -> R.string.yubi_key_instruction.asText()
else -> "".asText()
}
/**
* Get the button label for the given auth method.
*/
val TwoFactorAuthMethod.button: Text
get() = when (this) {
TwoFactorAuthMethod.DUO,
TwoFactorAuthMethod.DUO_ORGANIZATION,
-> R.string.launch_duo.asText()
TwoFactorAuthMethod.AUTHENTICATOR_APP,
TwoFactorAuthMethod.EMAIL,
TwoFactorAuthMethod.YUBI_KEY,
TwoFactorAuthMethod.U2F,
TwoFactorAuthMethod.REMEMBER,
TwoFactorAuthMethod.RECOVERY_CODE,
-> R.string.continue_text.asText()
TwoFactorAuthMethod.WEB_AUTH -> R.string.launch_web_authn.asText()
}
/**
* Gets a boolean indicating if the given auth method uses Duo.
*/