Add support for different login methods (#762)

This commit is contained in:
Shannon Draeker
2024-01-24 15:54:25 -07:00
committed by Álison Fernandes
parent c977f7617a
commit 410e3072fa
8 changed files with 167 additions and 21 deletions

View File

@@ -24,12 +24,18 @@ interface IdentityApi {
@Field(value = "client_id") clientId: String,
@Field(value = "username") email: String,
@Header(value = "auth-email") authEmail: String,
@Field(value = "password") passwordHash: String,
@Field(value = "password") passwordHash: String?,
@Field(value = "deviceIdentifier") deviceIdentifier: String,
@Field(value = "deviceName") deviceName: String,
@Field(value = "deviceType") deviceType: String,
@Field(value = "grant_type") grantType: String,
@Field(value = "captchaResponse") captchaResponse: String?,
@Field(value = "code") ssoCode: String?,
@Field(value = "code_verifier") ssoCodeVerifier: String?,
@Field(value = "redirect_uri") ssoRedirectUri: String?,
@Field(value = "twoFactorToken") twoFactorCode: String?,
@Field(value = "twoFactorProvider") twoFactorMethod: String?,
@Field(value = "twoFactorRemember") twoFactorRemember: String?,
): Result<GetTokenResponseJson.Success>
@GET("/account/prevalidate")

View File

@@ -0,0 +1,62 @@
package com.x8bit.bitwarden.data.auth.datasource.network.model
/**
* Hold the authentication information for different login methods.
*/
sealed class IdentityTokenAuthModel {
/**
* The type of authentication.
*/
abstract val grantType: String
/**
* The username for login with password.
*/
abstract val username: String?
/**
* The password for login with password.
*/
abstract val password: String?
/**
* The sso code for login with single sign on.
*/
abstract val ssoCode: String?
/**
* The sso code verifier for login with single sign on.
*/
abstract val ssoCodeVerifier: String?
/**
* The sso redirect uri for login with single sign on.
*/
abstract val ssoRedirectUri: String?
/**
* The data for logging in with a username and password.
*/
data class MasterPassword(
override val username: String,
override val password: String,
) : IdentityTokenAuthModel() {
override val grantType: String get() = "password"
override val ssoCode: String? get() = null
override val ssoCodeVerifier: String? get() = null
override val ssoRedirectUri: String? get() = null
}
/**
* The data for logging in with single sign on credentials.
*/
data class SingleSignOn(
override val ssoCode: String,
override val ssoCodeVerifier: String,
override val ssoRedirectUri: String,
) : IdentityTokenAuthModel() {
override val grantType: String get() = "authorization_code"
override val username: String? get() = null
override val password: String? get() = null
}
}

View File

@@ -0,0 +1,15 @@
package com.x8bit.bitwarden.data.auth.datasource.network.model
/**
* Hold the information necessary to add two-factor authorization
* to a login request.
*
* @property code The two-factor code.
* @property method The two-factor method.
* @property remember The two-factor remember setting.
*/
data class TwoFactorDataModel(
val code: String,
val method: String,
val remember: Boolean,
)

View File

@@ -1,8 +1,10 @@
package com.x8bit.bitwarden.data.auth.datasource.network.service
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.IdentityTokenAuthModel
import com.x8bit.bitwarden.data.auth.datasource.network.model.PrevalidateSsoResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RefreshTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorDataModel
/**
* Provides an API for querying identity endpoints.
@@ -14,14 +16,18 @@ interface IdentityService {
*
* @param uniqueAppId applications unique identifier.
* @param email user's email address.
* @param passwordHash password hashed with the Bitwarden SDK.
* @param authModel information necessary to authenticate with any
* of the available login methods.
* @param captchaToken captcha token to be passed to the API (nullable).
* @param twoFactorData the two-factor data, if applicable.
*/
@Suppress("LongParameterList")
suspend fun getToken(
uniqueAppId: String,
email: String,
passwordHash: String,
authModel: IdentityTokenAuthModel,
captchaToken: String?,
twoFactorData: TwoFactorDataModel? = null,
): Result<GetTokenResponseJson>
/**

View File

@@ -2,8 +2,10 @@ package com.x8bit.bitwarden.data.auth.datasource.network.service
import com.x8bit.bitwarden.data.auth.datasource.network.api.IdentityApi
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.IdentityTokenAuthModel
import com.x8bit.bitwarden.data.auth.datasource.network.model.PrevalidateSsoResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RefreshTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorDataModel
import com.x8bit.bitwarden.data.platform.datasource.network.model.toBitwardenError
import com.x8bit.bitwarden.data.platform.datasource.network.util.base64UrlEncode
import com.x8bit.bitwarden.data.platform.datasource.network.util.executeForResult
@@ -21,8 +23,9 @@ class IdentityServiceImpl constructor(
override suspend fun getToken(
uniqueAppId: String,
email: String,
passwordHash: String,
authModel: IdentityTokenAuthModel,
captchaToken: String?,
twoFactorData: TwoFactorDataModel?,
): Result<GetTokenResponseJson> = api
.getToken(
scope = "api+offline_access",
@@ -31,9 +34,15 @@ class IdentityServiceImpl constructor(
deviceIdentifier = uniqueAppId,
deviceName = deviceModelProvider.deviceModel,
deviceType = "0",
grantType = "password",
passwordHash = passwordHash,
grantType = authModel.grantType,
passwordHash = authModel.password,
email = email,
ssoCode = authModel.ssoCode,
ssoCodeVerifier = authModel.ssoCodeVerifier,
ssoRedirectUri = authModel.ssoRedirectUri,
twoFactorCode = twoFactorData?.code,
twoFactorMethod = twoFactorData?.method,
twoFactorRemember = twoFactorData?.remember?.let { if (it) "1" else "0 " },
captchaResponse = captchaToken,
)
.recoverCatching { throwable ->

View File

@@ -7,6 +7,7 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson.CaptchaRequired
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson.Success
import com.x8bit.bitwarden.data.auth.datasource.network.model.IdentityTokenAuthModel
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RefreshTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson
@@ -194,7 +195,10 @@ class AuthRepositoryImpl(
identityService.getToken(
uniqueAppId = authDiskSource.uniqueAppId,
email = email,
passwordHash = passwordHash,
authModel = IdentityTokenAuthModel.MasterPassword(
username = email,
password = passwordHash,
),
captchaToken = captchaToken,
)
}