mirror of
https://github.com/bitwarden/android.git
synced 2024-11-24 18:36:32 +03:00
[PM-12279] Update SDK reference and use Origin.Android on Fido2Credential (#3975)
This commit is contained in:
parent
10bbab971f
commit
b3e885bcb1
6 changed files with 128 additions and 17 deletions
|
@ -2,6 +2,8 @@ package com.x8bit.bitwarden.data.autofill.fido2.manager
|
||||||
|
|
||||||
import androidx.credentials.provider.CallingAppInfo
|
import androidx.credentials.provider.CallingAppInfo
|
||||||
import com.bitwarden.fido.ClientData
|
import com.bitwarden.fido.ClientData
|
||||||
|
import com.bitwarden.fido.Origin
|
||||||
|
import com.bitwarden.fido.UnverifiedAssetLink
|
||||||
import com.bitwarden.sdk.Fido2CredentialStore
|
import com.bitwarden.sdk.Fido2CredentialStore
|
||||||
import com.bitwarden.vault.CipherView
|
import com.bitwarden.vault.CipherView
|
||||||
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.model.DigitalAssetLinkResponseJson
|
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.model.DigitalAssetLinkResponseJson
|
||||||
|
@ -24,6 +26,7 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.model.AuthenticateFido2Cred
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.RegisterFido2CredentialRequest
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.RegisterFido2CredentialRequest
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.util.toAndroidAttestationResponse
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.util.toAndroidAttestationResponse
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.util.toAndroidFido2PublicKeyCredential
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.util.toAndroidFido2PublicKeyCredential
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.toHostOrPathOrNull
|
||||||
import kotlinx.serialization.SerializationException
|
import kotlinx.serialization.SerializationException
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
@ -65,11 +68,23 @@ class Fido2CredentialManagerImpl(
|
||||||
.packageName,
|
.packageName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val origin = fido2CredentialRequest
|
val assetLinkUrl = fido2CredentialRequest
|
||||||
.origin
|
.origin
|
||||||
?: getOriginUrlFromAttestationOptionsOrNull(fido2CredentialRequest.requestJson)
|
?: getOriginUrlFromAttestationOptionsOrNull(fido2CredentialRequest.requestJson)
|
||||||
?: return Fido2RegisterCredentialResult.Error
|
?: return Fido2RegisterCredentialResult.Error
|
||||||
|
|
||||||
|
val origin = Origin.Android(
|
||||||
|
UnverifiedAssetLink(
|
||||||
|
packageName = fido2CredentialRequest.packageName,
|
||||||
|
sha256CertFingerprint = fido2CredentialRequest
|
||||||
|
.callingAppInfo
|
||||||
|
.getSignatureFingerprintAsHexString()
|
||||||
|
?: return Fido2RegisterCredentialResult.Error,
|
||||||
|
host = assetLinkUrl.toHostOrPathOrNull()
|
||||||
|
?: return Fido2RegisterCredentialResult.Error,
|
||||||
|
assetLinkUrl = assetLinkUrl,
|
||||||
|
),
|
||||||
|
)
|
||||||
return vaultSdkSource
|
return vaultSdkSource
|
||||||
.registerFido2Credential(
|
.registerFido2Credential(
|
||||||
request = RegisterFido2CredentialRequest(
|
request = RegisterFido2CredentialRequest(
|
||||||
|
@ -157,7 +172,16 @@ class Fido2CredentialManagerImpl(
|
||||||
.authenticateFido2Credential(
|
.authenticateFido2Credential(
|
||||||
request = AuthenticateFido2CredentialRequest(
|
request = AuthenticateFido2CredentialRequest(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
origin = origin,
|
origin = Origin.Android(
|
||||||
|
UnverifiedAssetLink(
|
||||||
|
callingAppInfo.packageName,
|
||||||
|
callingAppInfo.getSignatureFingerprintAsHexString()
|
||||||
|
?: return Fido2CredentialAssertionResult.Error,
|
||||||
|
origin.toHostOrPathOrNull()
|
||||||
|
?: return Fido2CredentialAssertionResult.Error,
|
||||||
|
origin,
|
||||||
|
),
|
||||||
|
),
|
||||||
requestJson = """{"publicKey": ${request.requestJson}}""",
|
requestJson = """{"publicKey": ${request.requestJson}}""",
|
||||||
clientData = clientData,
|
clientData = clientData,
|
||||||
selectedCipherView = selectedCipherView,
|
selectedCipherView = selectedCipherView,
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
package com.x8bit.bitwarden.data.vault.datasource.sdk.model
|
package com.x8bit.bitwarden.data.vault.datasource.sdk.model
|
||||||
|
|
||||||
import com.bitwarden.fido.ClientData
|
import com.bitwarden.fido.ClientData
|
||||||
|
import com.bitwarden.fido.Origin
|
||||||
import com.bitwarden.vault.CipherView
|
import com.bitwarden.vault.CipherView
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models a FIDO 2 authentication request to the Bitwarden SDK.
|
* Models a FIDO 2 authentication request to the Bitwarden SDK.
|
||||||
*
|
*
|
||||||
* @param userId User whom the credential is being authenticated for.
|
* @param userId User whom the credential is being authenticated for.
|
||||||
* @param origin Origin of the Relying Party. This can either be a Relying Party's URL or their
|
* @param origin Origin of the Relying Party WebAuthn Request.
|
||||||
* application fingerprint.
|
|
||||||
* @param requestJson Authentication request JSON received from the OS.
|
* @param requestJson Authentication request JSON received from the OS.
|
||||||
* @param clientData Metadata containing either privileged application certificate hash or Android
|
* @param clientData Metadata containing either privileged application certificate hash or Android
|
||||||
* package name of the Relying Party.
|
* package name of the Relying Party.
|
||||||
|
@ -18,7 +18,7 @@ import com.bitwarden.vault.CipherView
|
||||||
*/
|
*/
|
||||||
data class AuthenticateFido2CredentialRequest(
|
data class AuthenticateFido2CredentialRequest(
|
||||||
val userId: String,
|
val userId: String,
|
||||||
val origin: String,
|
val origin: Origin,
|
||||||
val requestJson: String,
|
val requestJson: String,
|
||||||
val clientData: ClientData,
|
val clientData: ClientData,
|
||||||
val selectedCipherView: CipherView,
|
val selectedCipherView: CipherView,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.x8bit.bitwarden.data.vault.datasource.sdk.model
|
package com.x8bit.bitwarden.data.vault.datasource.sdk.model
|
||||||
|
|
||||||
import com.bitwarden.fido.ClientData
|
import com.bitwarden.fido.ClientData
|
||||||
|
import com.bitwarden.fido.Origin
|
||||||
import com.bitwarden.vault.CipherView
|
import com.bitwarden.vault.CipherView
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,7 +19,7 @@ import com.bitwarden.vault.CipherView
|
||||||
*/
|
*/
|
||||||
data class RegisterFido2CredentialRequest(
|
data class RegisterFido2CredentialRequest(
|
||||||
val userId: String,
|
val userId: String,
|
||||||
val origin: String,
|
val origin: Origin,
|
||||||
val requestJson: String,
|
val requestJson: String,
|
||||||
val clientData: ClientData,
|
val clientData: ClientData,
|
||||||
val selectedCipherView: CipherView,
|
val selectedCipherView: CipherView,
|
||||||
|
|
|
@ -5,7 +5,9 @@ import android.content.pm.SigningInfo
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import androidx.credentials.provider.CallingAppInfo
|
import androidx.credentials.provider.CallingAppInfo
|
||||||
import com.bitwarden.fido.ClientData
|
import com.bitwarden.fido.ClientData
|
||||||
|
import com.bitwarden.fido.Origin
|
||||||
import com.bitwarden.fido.PublicKeyCredentialAuthenticatorAssertionResponse
|
import com.bitwarden.fido.PublicKeyCredentialAuthenticatorAssertionResponse
|
||||||
|
import com.bitwarden.fido.UnverifiedAssetLink
|
||||||
import com.bitwarden.sdk.Fido2CredentialStore
|
import com.bitwarden.sdk.Fido2CredentialStore
|
||||||
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.model.DigitalAssetLinkResponseJson
|
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.model.DigitalAssetLinkResponseJson
|
||||||
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.service.DigitalAssetLinkService
|
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.service.DigitalAssetLinkService
|
||||||
|
@ -531,8 +533,58 @@ class Fido2CredentialManagerTest {
|
||||||
selectedCipherView = createMockCipherView(number = 1),
|
selectedCipherView = createMockCipherView(number = 1),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertTrue(
|
assertEquals(
|
||||||
result is Fido2RegisterCredentialResult.Error,
|
Fido2RegisterCredentialResult.Error,
|
||||||
|
result,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `registerFido2Credential should return Error when getSignatureFingerprintAsHexString is null`() =
|
||||||
|
runTest {
|
||||||
|
val mockSigningInfo = mockk<SigningInfo> {
|
||||||
|
every { hasMultipleSigners() } returns true
|
||||||
|
}
|
||||||
|
val mockFido2CredentialRequest = createMockFido2CredentialRequest(
|
||||||
|
number = 1,
|
||||||
|
signingInfo = mockSigningInfo,
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = fido2CredentialManager.registerFido2Credential(
|
||||||
|
userId = "mockUserId",
|
||||||
|
fido2CredentialRequest = mockFido2CredentialRequest,
|
||||||
|
selectedCipherView = createMockCipherView(number = 1),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
Fido2RegisterCredentialResult.Error,
|
||||||
|
result,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `registerFido2Credential should return Error when toHostOrPathOrNull is null`() =
|
||||||
|
runTest {
|
||||||
|
val mockSigningInfo = mockk<SigningInfo> {
|
||||||
|
every { apkContentsSigners } returns arrayOf(Signature(DEFAULT_APP_SIGNATURE))
|
||||||
|
every { hasMultipleSigners() } returns false
|
||||||
|
}
|
||||||
|
val mockFido2CredentialRequest = createMockFido2CredentialRequest(
|
||||||
|
number = 1,
|
||||||
|
origin = "illegal empty spaces",
|
||||||
|
signingInfo = mockSigningInfo,
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = fido2CredentialManager.registerFido2Credential(
|
||||||
|
userId = "mockUserId",
|
||||||
|
fido2CredentialRequest = mockFido2CredentialRequest,
|
||||||
|
selectedCipherView = createMockCipherView(number = 1),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
Fido2RegisterCredentialResult.Error,
|
||||||
|
result,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,8 +625,9 @@ class Fido2CredentialManagerTest {
|
||||||
selectedCipherView = createMockCipherView(number = 1),
|
selectedCipherView = createMockCipherView(number = 1),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertTrue(
|
assertEquals(
|
||||||
result is Fido2RegisterCredentialResult.Error,
|
Fido2RegisterCredentialResult.Error,
|
||||||
|
result,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,7 +762,14 @@ class Fido2CredentialManagerTest {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
AuthenticateFido2CredentialRequest(
|
AuthenticateFido2CredentialRequest(
|
||||||
userId = "activeUserId",
|
userId = "activeUserId",
|
||||||
origin = mockRequest.origin!!,
|
origin = Origin.Android(
|
||||||
|
UnverifiedAssetLink(
|
||||||
|
packageName = DEFAULT_PACKAGE_NAME,
|
||||||
|
sha256CertFingerprint = DEFAULT_CERT_FINGERPRINT,
|
||||||
|
host = DEFAULT_HOST,
|
||||||
|
assetLinkUrl = mockRequest.origin!!,
|
||||||
|
),
|
||||||
|
),
|
||||||
requestJson = """{"publicKey": ${mockRequest.requestJson}}""",
|
requestJson = """{"publicKey": ${mockRequest.requestJson}}""",
|
||||||
clientData = ClientData.DefaultWithExtraData(
|
clientData = ClientData.DefaultWithExtraData(
|
||||||
androidPackageName = "android:apk-key-hash:$DEFAULT_APP_SIGNATURE",
|
androidPackageName = "android:apk-key-hash:$DEFAULT_APP_SIGNATURE",
|
||||||
|
@ -756,7 +816,14 @@ class Fido2CredentialManagerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
Origin.Android(
|
||||||
|
UnverifiedAssetLink(
|
||||||
|
DEFAULT_PACKAGE_NAME,
|
||||||
|
DEFAULT_CERT_FINGERPRINT,
|
||||||
|
mockAssertionOptions.relyingPartyId!!,
|
||||||
"https://${mockAssertionOptions.relyingPartyId}",
|
"https://${mockAssertionOptions.relyingPartyId}",
|
||||||
|
),
|
||||||
|
),
|
||||||
requestCaptureSlot.captured.origin,
|
requestCaptureSlot.captured.origin,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -942,9 +1009,17 @@ class Fido2CredentialManagerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val DEFAULT_PACKAGE_NAME = "com.x8bit.bitwarden"
|
private const val DEFAULT_PACKAGE_NAME = "com.x8bit.bitwarden"
|
||||||
private const val DEFAULT_ORIGIN = "bitwarden.com"
|
|
||||||
private const val DEFAULT_APP_SIGNATURE = "0987654321ABCDEF"
|
private const val DEFAULT_APP_SIGNATURE = "0987654321ABCDEF"
|
||||||
private const val DEFAULT_CERT_FINGERPRINT = "30:39:38:37:36:35:34:33:32:31:41:42:43:44:45:46"
|
private const val DEFAULT_CERT_FINGERPRINT = "30:39:38:37:36:35:34:33:32:31:41:42:43:44:45:46"
|
||||||
|
private const val DEFAULT_HOST = "bitwarden.com"
|
||||||
|
private val DEFAULT_ORIGIN = Origin.Android(
|
||||||
|
UnverifiedAssetLink(
|
||||||
|
packageName = DEFAULT_PACKAGE_NAME,
|
||||||
|
sha256CertFingerprint = DEFAULT_CERT_FINGERPRINT,
|
||||||
|
host = DEFAULT_HOST,
|
||||||
|
assetLinkUrl = "bitwarden.com",
|
||||||
|
),
|
||||||
|
)
|
||||||
private val DEFAULT_STATEMENT = DigitalAssetLinkResponseJson(
|
private val DEFAULT_STATEMENT = DigitalAssetLinkResponseJson(
|
||||||
relation = listOf(
|
relation = listOf(
|
||||||
"delegate_permission/common.get_login_creds",
|
"delegate_permission/common.get_login_creds",
|
||||||
|
@ -1029,7 +1104,7 @@ private const val DEFAULT_FIDO2_AUTH_REQUEST_JSON = """
|
||||||
"""
|
"""
|
||||||
|
|
||||||
private fun createMockFido2AssertionRequest(
|
private fun createMockFido2AssertionRequest(
|
||||||
mockOrigin: String? = DEFAULT_ORIGIN,
|
mockOrigin: String? = "bitwarden.com",
|
||||||
mockClientDataHash: ByteArray? = null,
|
mockClientDataHash: ByteArray? = null,
|
||||||
mockSigningInfo: SigningInfo,
|
mockSigningInfo: SigningInfo,
|
||||||
) = mockk<Fido2CredentialAssertionRequest> {
|
) = mockk<Fido2CredentialAssertionRequest> {
|
||||||
|
|
|
@ -11,8 +11,10 @@ import com.bitwarden.crypto.TrustDeviceResponse
|
||||||
import com.bitwarden.exporters.ExportFormat
|
import com.bitwarden.exporters.ExportFormat
|
||||||
import com.bitwarden.fido.ClientData
|
import com.bitwarden.fido.ClientData
|
||||||
import com.bitwarden.fido.Fido2CredentialAutofillView
|
import com.bitwarden.fido.Fido2CredentialAutofillView
|
||||||
|
import com.bitwarden.fido.Origin
|
||||||
import com.bitwarden.fido.PublicKeyCredentialAuthenticatorAssertionResponse
|
import com.bitwarden.fido.PublicKeyCredentialAuthenticatorAssertionResponse
|
||||||
import com.bitwarden.fido.PublicKeyCredentialAuthenticatorAttestationResponse
|
import com.bitwarden.fido.PublicKeyCredentialAuthenticatorAttestationResponse
|
||||||
|
import com.bitwarden.fido.UnverifiedAssetLink
|
||||||
import com.bitwarden.sdk.BitwardenException
|
import com.bitwarden.sdk.BitwardenException
|
||||||
import com.bitwarden.sdk.Client
|
import com.bitwarden.sdk.Client
|
||||||
import com.bitwarden.sdk.ClientAuth
|
import com.bitwarden.sdk.ClientAuth
|
||||||
|
@ -1239,9 +1241,18 @@ class VaultSdkSourceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val DEFAULT_SIGNATURE = "0987654321ABCDEF"
|
private const val DEFAULT_SIGNATURE = "0987654321ABCDEF"
|
||||||
|
|
||||||
|
private val DEFAULT_ORIGIN = Origin.Android(
|
||||||
|
UnverifiedAssetLink(
|
||||||
|
packageName = "com.x8bit.bitwarden",
|
||||||
|
sha256CertFingerprint = "30:39:38:37:36:35:34:33:32:31:41:42:43:44:45:46",
|
||||||
|
host = "bitwarden.com",
|
||||||
|
assetLinkUrl = "www.bitwarden.com",
|
||||||
|
),
|
||||||
|
)
|
||||||
private val DEFAULT_FIDO_2_REGISTER_CREDENTIAL_REQUEST = RegisterFido2CredentialRequest(
|
private val DEFAULT_FIDO_2_REGISTER_CREDENTIAL_REQUEST = RegisterFido2CredentialRequest(
|
||||||
userId = "mockUserId",
|
userId = "mockUserId",
|
||||||
origin = "www.bitwarden.com",
|
origin = DEFAULT_ORIGIN,
|
||||||
requestJson = "requestJson",
|
requestJson = "requestJson",
|
||||||
clientData = ClientData.DefaultWithCustomHash(
|
clientData = ClientData.DefaultWithCustomHash(
|
||||||
DEFAULT_SIGNATURE.toByteArray(),
|
DEFAULT_SIGNATURE.toByteArray(),
|
||||||
|
@ -1251,7 +1262,7 @@ private val DEFAULT_FIDO_2_REGISTER_CREDENTIAL_REQUEST = RegisterFido2Credential
|
||||||
)
|
)
|
||||||
private val DEFAULT_FIDO_2_AUTH_REQUEST = AuthenticateFido2CredentialRequest(
|
private val DEFAULT_FIDO_2_AUTH_REQUEST = AuthenticateFido2CredentialRequest(
|
||||||
userId = "mockUserId",
|
userId = "mockUserId",
|
||||||
origin = "www.bitwarden.com",
|
origin = DEFAULT_ORIGIN,
|
||||||
requestJson = "requestJson",
|
requestJson = "requestJson",
|
||||||
clientData = ClientData.DefaultWithCustomHash(
|
clientData = ClientData.DefaultWithCustomHash(
|
||||||
DEFAULT_SIGNATURE.toByteArray(),
|
DEFAULT_SIGNATURE.toByteArray(),
|
||||||
|
|
|
@ -24,7 +24,7 @@ androidxSplash = "1.1.0-rc01"
|
||||||
androidXAppCompat = "1.7.0"
|
androidXAppCompat = "1.7.0"
|
||||||
androdixAutofill = "1.1.0"
|
androdixAutofill = "1.1.0"
|
||||||
androidxWork = "2.9.1"
|
androidxWork = "2.9.1"
|
||||||
bitwardenSdk = "0.5.0-20240819.160739-177"
|
bitwardenSdk = "1.0.0-20240924.112512-21"
|
||||||
crashlytics = "3.0.2"
|
crashlytics = "3.0.2"
|
||||||
detekt = "1.23.7"
|
detekt = "1.23.7"
|
||||||
firebaseBom = "33.3.0"
|
firebaseBom = "33.3.0"
|
||||||
|
|
Loading…
Reference in a new issue