Skip to content

Commit 75a4590

Browse files
@W-21933885: [MSDK Android] App Attestation Implementation (Extract Challenge API Hostname)
1 parent 39fb63d commit 75a4590

4 files changed

Lines changed: 36 additions & 23 deletions

File tree

libs/SalesforceSDK/src/com/salesforce/androidsdk/app/SalesforceSDKManager.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import androidx.compose.runtime.Composable
6464
import androidx.core.content.ContextCompat.RECEIVER_EXPORTED
6565
import androidx.core.content.ContextCompat.RECEIVER_NOT_EXPORTED
6666
import androidx.core.content.ContextCompat.registerReceiver
67+
import androidx.core.net.toUri
6768
import androidx.lifecycle.DefaultLifecycleObserver
6869
import androidx.lifecycle.LifecycleOwner
6970
import androidx.lifecycle.ProcessLifecycleOwner
@@ -241,13 +242,20 @@ open class SalesforceSDKManager protected constructor(
241242
set(value) {
242243
field = value
243244

245+
val loginHost = loginServerManager.selectedLoginServer.url.toUri().host
246+
if (loginHost == null) {
247+
w(javaClass.name, "Cannot initialize Salesforce App Attestation Client since the selected login server URL doesn't have a host. Authentication may malfunction.")
248+
return
249+
}
250+
244251
appAttestationClient = field?.let { appAttestationGoogleCloudProjectId ->
245252
AppAttestationClient(
246-
appContext,
247-
deviceId,
248-
appAttestationGoogleCloudProjectId,
249-
getBootConfig(getInstance().appContext).remoteAccessConsumerKey,
250-
clientManager.peekUnauthenticatedRestClient()
253+
context = appContext,
254+
apiHostName = loginHost,
255+
deviceId = deviceId,
256+
googleCloudProjectId = appAttestationGoogleCloudProjectId,
257+
remoteAccessConsumerKey = getBootConfig(getInstance().appContext).remoteAccessConsumerKey,
258+
restClient = clientManager.peekUnauthenticatedRestClient()
251259
)
252260
}
253261
}

libs/SalesforceSDK/src/com/salesforce/androidsdk/auth/AppAttestationClient.kt

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ package com.salesforce.androidsdk.auth
2828

2929
import android.content.Context
3030
import androidx.annotation.VisibleForTesting
31-
import com.google.android.gms.tasks.Task
3231
import com.google.android.play.core.integrity.IntegrityManagerFactory.createStandard
3332
import com.google.android.play.core.integrity.IntegrityServiceException
3433
import com.google.android.play.core.integrity.StandardIntegrityManager
@@ -51,9 +50,10 @@ import java.util.Base64
5150
* App attestation features supporting the Salesforce App Attestation External
5251
* Client App (ECA) Plugin, the Salesforce Challenge API, Google Play Integrity
5352
* API and integration of app attestation with Salesforce Authentication.
53+
* @param apiHostName The Salesforce App Attestation Challenge API host
54+
* @param deviceId The device id, usually provided by the Salesforce SDK Manager
5455
* @param googleCloudProjectId The Google Cloud Project ID used with Google Play
5556
* Integrity API
56-
* @param deviceId The device id, usually provided by the Salesforce SDK Manager
5757
* @param remoteAccessConsumerKey The Salesforce Connected App (CA) or External
5858
* Client App (ECA)remote access consumer key, usually provided by the boot
5959
* config
@@ -62,6 +62,7 @@ import java.util.Base64
6262
*/
6363
class AppAttestationClient(
6464
context: Context,
65+
val apiHostName: String,
6566
val deviceId: String,
6667
val googleCloudProjectId: Long,
6768
val remoteAccessConsumerKey: String,
@@ -87,26 +88,25 @@ class AppAttestationClient(
8788
}
8889

8990
/**
90-
* (Re-)prepares the Google Play Integrity token provider.
91+
* (Re-)prepares the Google Play Integrity token provider. Calling this
92+
* prior to requesting the Integrity Token via
93+
* [createSalesforceOAuthAuthorizationAppAttestation] reduces the latency of
94+
* the request.
9195
* @param integrityManager The Google Play Integrity API integrity manager.
9296
* This parameter is intended for testing purposes only
9397
*/
9498
@VisibleForTesting
9599
internal fun prepareIntegrityTokenProvider(
96100
integrityManager: StandardIntegrityManager = this.integrityManager
97-
): Task<StandardIntegrityTokenProvider> {
98-
99-
// Prepare the Google Play Integrity token. Calling this prior to requesting the Integrity Token reduces the latency of the request.
100-
return integrityManager.prepareIntegrityToken(
101-
PrepareIntegrityTokenRequest.builder()
102-
.setCloudProjectNumber(googleCloudProjectId)
103-
.build()
104-
).addOnSuccessListener(
105-
::onPrepareIntegrityTokenProviderSuccess
106-
).addOnFailureListener(
107-
::onPrepareIntegrityTokenProviderFailure
108-
)
109-
}
101+
) = integrityManager.prepareIntegrityToken(
102+
PrepareIntegrityTokenRequest.builder()
103+
.setCloudProjectNumber(googleCloudProjectId)
104+
.build()
105+
).addOnSuccessListener(
106+
::onPrepareIntegrityTokenProviderSuccess
107+
).addOnFailureListener(
108+
::onPrepareIntegrityTokenProviderFailure
109+
)
110110

111111
/**
112112
* A success callback used by [prepareIntegrityTokenProvider].
@@ -202,7 +202,7 @@ class AppAttestationClient(
202202
internal fun fetchSalesforceMobileAppAttestationChallenge(): String {
203203
// Create the Salesforce App Attestation Challenge API client and fetch a new challenge.
204204
val appAttestationChallengeApiClient = AppAttestationChallengeApiClient(
205-
apiHostName = "msdkappattestationtestorg.test1.my.pc-rnd.salesforce.com", // TODO: Replace with template placeholder. ECJ20260311
205+
apiHostName = apiHostName,
206206
restClient = restClient
207207
)
208208
val salesforceAppAttestationChallenge = appAttestationChallengeApiClient.fetchChallenge(

libs/SalesforceSDK/src/com/salesforce/androidsdk/rest/AppAttestationChallengeApiClient.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import com.salesforce.androidsdk.rest.RestRequest.RestMethod.GET
3535
* See https://docs.google.com/document/d/1MGw0-dO4Q-CJLNuqYBSYKAbEUy484lpLLX20ZIvwU6Y/edit?tab=t.0
3636
* TODO: Replace with final documentation when available. ECJ20260311
3737
*
38-
* @param apiHostName The Salesforce `sfap_api` hostname
38+
* @param apiHostName The Salesforce App Attestation Challenge API host
3939
* @param restClient The REST client to use
4040
*/
4141
@Suppress("unused")

libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/auth/AppAttestationClientTest.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class AppAttestationClientTest {
6666
every { integrityManager.prepareIntegrityToken(any()) } returns integrityTokenProviderTask
6767

6868
val appAttestationClient = AppAttestationClient(
69+
apiHostName = "login.example.com",
6970
context = context,
7071
deviceId = deviceId,
7172
googleCloudProjectId = googleCloudProjectId,
@@ -98,6 +99,7 @@ class AppAttestationClientTest {
9899
val integrityTokenProvider = mockk<StandardIntegrityTokenProvider>(relaxed = true)
99100

100101
val appAttestationClient = AppAttestationClient(
102+
apiHostName = "login.example.com",
101103
context = context,
102104
deviceId = deviceId,
103105
googleCloudProjectId = googleCloudProjectId,
@@ -122,6 +124,7 @@ class AppAttestationClientTest {
122124
val restClient = mockk<RestClient>(relaxed = true)
123125

124126
val appAttestationClient = AppAttestationClient(
127+
apiHostName = "login.example.com",
125128
context = context,
126129
deviceId = deviceId,
127130
googleCloudProjectId = googleCloudProjectId,
@@ -161,6 +164,7 @@ class AppAttestationClientTest {
161164
every { integrityTokenProvider.request(any()) } returns integrityTokenTask
162165

163166
val appAttestationClient = AppAttestationClient(
167+
apiHostName = "login.example.com",
164168
context = context,
165169
deviceId = deviceId,
166170
googleCloudProjectId = googleCloudProjectId,
@@ -209,6 +213,7 @@ class AppAttestationClientTest {
209213
every { integrityManager.prepareIntegrityToken(any()) } returns integrityTokenProviderTask
210214

211215
val appAttestationClient = AppAttestationClient(
216+
apiHostName = "login.example.com",
212217
context = context,
213218
deviceId = deviceId,
214219
googleCloudProjectId = googleCloudProjectId,

0 commit comments

Comments
 (0)