From 293b87b6ac98ff082b9df48c541b95d3172b1072 Mon Sep 17 00:00:00 2001 From: tjroach Date: Wed, 11 Dec 2024 16:49:18 -0500 Subject: [PATCH 1/4] Fix Device Metadata migration used for Device Tracking if an aliased userId was used. --- .../actions/CredentialStoreCognitoActions.kt | 25 ++++++++++++++----- .../data/AWSCognitoLegacyCredentialStore.kt | 18 +++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt index 5a634c4914..68a37fc459 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt @@ -36,13 +36,26 @@ internal object CredentialStoreCognitoActions : CredentialStoreActions { legacyCredentialStore.deleteCredential() } - // migrate device data - val lastAuthUserId = legacyCredentialStore.retrieveLastAuthUserId() - lastAuthUserId?.let { - val deviceMetaData = legacyCredentialStore.retrieveDeviceMetadata(lastAuthUserId) + /* + Migrate Device Metadata + 1. We first need to get the list of userIds that contain device metadata on the device. + 2. For each userId, we check to see if the current credential store has device metadata for that user. + 3. If the current user does not have device metadata in the current store, migrate from legacy. + This is a possibility because of a bug where we were previously attempting to migrate using an aliased + userId lookup. This situation would happen if a user migrated, signed out, then signed back in. Upon + signing back in, they would be granted new device metadata. Since that new metadata is what is + associated with the refresh token, we do not want to overwrite it. + 4. If the current user has device metadata in the current credential store, do not migrate from legacy. + 5. Upon migration completion, we delete the legacy device metadata. + */ + legacyCredentialStore.retrieveDeviceMetadataUserIdList().forEach { userId -> + val deviceMetaData = legacyCredentialStore.retrieveDeviceMetadata(userId) if (deviceMetaData != DeviceMetadata.Empty) { - credentialStore.saveDeviceMetadata(lastAuthUserId, deviceMetaData) - legacyCredentialStore.deleteDeviceKeyCredential(lastAuthUserId) + credentialStore.retrieveDeviceMetadata(userId) + if (credentialStore.retrieveDeviceMetadata(userId) == DeviceMetadata.Empty) { + credentialStore.saveDeviceMetadata(userId, deviceMetaData) + } + legacyCredentialStore.deleteDeviceKeyCredential(userId) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt index 060b859be6..18b19749d1 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt @@ -29,6 +29,7 @@ import com.amplifyframework.statemachine.codegen.data.DeviceMetadata import com.amplifyframework.statemachine.codegen.data.FederatedToken import com.amplifyframework.statemachine.codegen.data.SignInMethod import com.amplifyframework.statemachine.codegen.data.SignedInData +import java.io.File import java.time.Instant import java.time.temporal.ChronoUnit import java.util.Date @@ -74,6 +75,7 @@ internal class AWSCognitoLegacyCredentialStore( const val TOKEN_KEY = "token" } + private val userDeviceDetailsCacheKeyPrefix = "$APP_DEVICE_INFO_CACHE.${authConfiguration.userPool?.poolId}." private val userDeviceDetailsCacheKey = "$APP_DEVICE_INFO_CACHE.${authConfiguration.userPool?.poolId}.%s" private val idAndCredentialsKeyValue: KeyValueRepository by lazy { @@ -229,6 +231,22 @@ internal class AWSCognitoLegacyCredentialStore( ) } + /* + During migration away from the legacy credential store, we need to find all shared preference files that store + device metadata. These filenames contain the real userId (not aliased) for the tracked device metadata. + */ + fun retrieveDeviceMetadataUserIdList(): List { + return try { + val sharedPrefsSuffix = ".xml" + File(context.dataDir, "shared_prefs").listFiles { _, filename -> + filename.startsWith(userDeviceDetailsCacheKeyPrefix) && filename.endsWith(sharedPrefsSuffix) + }?.map { it.name.substringAfter(userDeviceDetailsCacheKeyPrefix).substringBefore(sharedPrefsSuffix) } + ?.filter { it.isNotBlank() } ?: emptyList() + } catch (e: Exception) { + return emptyList() + } + } + @Synchronized override fun retrieveDeviceMetadata(username: String): DeviceMetadata { val deviceDetailsCacheKey = String.format(userDeviceDetailsCacheKey, username) From d041ef469939fc2702a83cbf863aa0c022c23fbb Mon Sep 17 00:00:00 2001 From: tjroach Date: Thu, 12 Dec 2024 10:56:22 -0500 Subject: [PATCH 2/4] add tests --- ...egacyCredentialStoreInstrumentationTest.kt | 33 +++++-- ...ialStoreStateMachineInstrumentationTest.kt | 90 +++++++++++++++++-- .../cognito/testutils/CredentialStoreUtil.kt | 81 +++++++++++++++-- 3 files changed, 187 insertions(+), 17 deletions(-) diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AWSCognitoLegacyCredentialStoreInstrumentationTest.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AWSCognitoLegacyCredentialStoreInstrumentationTest.kt index 7745f49a68..10d8a6ff5c 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AWSCognitoLegacyCredentialStoreInstrumentationTest.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AWSCognitoLegacyCredentialStoreInstrumentationTest.kt @@ -20,7 +20,8 @@ import androidx.test.platform.app.InstrumentationRegistry import com.amplifyframework.auth.cognito.data.AWSCognitoLegacyCredentialStore import com.amplifyframework.auth.cognito.testutils.AuthConfigurationProvider import com.amplifyframework.auth.cognito.testutils.CredentialStoreUtil -import org.junit.Assert.assertTrue +import kotlin.test.assertEquals +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -31,7 +32,8 @@ class AWSCognitoLegacyCredentialStoreInstrumentationTest { private val configuration: AuthConfiguration = AuthConfigurationProvider.getAuthConfiguration() - private val credential = CredentialStoreUtil.getDefaultCredential() + private val credentialStoreUtil = CredentialStoreUtil() + private val credential = credentialStoreUtil.getDefaultCredential() private lateinit var store: AWSCognitoLegacyCredentialStore @@ -39,12 +41,33 @@ class AWSCognitoLegacyCredentialStoreInstrumentationTest { fun setup() { store = AWSCognitoLegacyCredentialStore(context, configuration) // TODO: Pull the appClientID from the configuration instead of hardcoding - CredentialStoreUtil.setupLegacyStore(context, "userPoolAppClientId", "userPoolId", "identityPoolId") + credentialStoreUtil.setupLegacyStore(context, "userPoolAppClientId", "userPoolId", "identityPoolId") + } + + @After + fun tearDown() { + credentialStoreUtil.clearSharedPreferences(context) } @Test fun test_legacy_store_implementation_can_retrieve_credentials_stored_using_aws_sdk() { - val creds = store.retrieveCredential() - assertTrue(creds == credential) + assertEquals(credential, store.retrieveCredential()) + } + + @Test + fun test_legacy_store_implementation_can_retrieve_device_metadata_using_aws_sdk() { + val user1DeviceMetadata = store.retrieveDeviceMetadata(credentialStoreUtil.user1UserId) + val user2DeviceMetadata = store.retrieveDeviceMetadata(credentialStoreUtil.user2UserId) + + assertEquals(credentialStoreUtil.getUser1DeviceMetadata(), user1DeviceMetadata) + assertEquals(credentialStoreUtil.getUser2DeviceMetadata(), user2DeviceMetadata) + } + + @Test + fun test_legacy_store_implementation_can_retrieve_userIds_for_device_metadata() { + val expectedUserIds = listOf(credentialStoreUtil.user1UserId, credentialStoreUtil.user2UserId) + val deviceMetadataUserIds = store.retrieveDeviceMetadataUserIdList() + + assertEquals(expectedUserIds, deviceMetadataUserIds) } } diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt index 2e0985320c..868cd18d2e 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt @@ -20,9 +20,11 @@ import androidx.test.platform.app.InstrumentationRegistry import com.amplifyframework.auth.cognito.data.AWSCognitoAuthCredentialStore import com.amplifyframework.auth.cognito.testutils.AuthConfigurationProvider import com.amplifyframework.auth.cognito.testutils.CredentialStoreUtil +import com.amplifyframework.statemachine.codegen.data.DeviceMetadata import com.google.gson.Gson import junit.framework.TestCase.assertEquals import org.json.JSONObject +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -30,17 +32,21 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class CredentialStoreStateMachineInstrumentationTest { private val context = InstrumentationRegistry.getInstrumentation().context + private val credentialStoreUtil = CredentialStoreUtil() private val configuration = AuthConfigurationProvider.getAuthConfigurationObject() private val userPoolId = configuration.userPool.userPool.PoolId private val identityPoolId = configuration.credentials.cognitoIdentity.identityData.PoolId private val userPoolAppClientId = configuration.userPool.userPool.AppClientId - private val credential = CredentialStoreUtil.getDefaultCredential() - @Before fun setup() { - CredentialStoreUtil.setupLegacyStore(context, userPoolAppClientId, userPoolId, identityPoolId) + credentialStoreUtil.setupLegacyStore(context, userPoolAppClientId, userPoolId, identityPoolId) + } + + @After + fun tearDown() { + credentialStoreUtil.clearSharedPreferences(context) } private val authConfigJson = JSONObject(Gson().toJson(configuration)) @@ -51,11 +57,83 @@ class CredentialStoreStateMachineInstrumentationTest { plugin.configure(authConfigJson, context) plugin.initialize(context) - val receivedCredentials = AWSCognitoAuthCredentialStore( + val credentialStore = AWSCognitoAuthCredentialStore( + context, + AuthConfiguration.fromJson(authConfigJson) + ) + + assertEquals(credentialStoreUtil.getDefaultCredential(), credentialStore.retrieveCredential()) + assertEquals( + credentialStoreUtil.getUser1DeviceMetadata(), + credentialStore.retrieveDeviceMetadata(credentialStoreUtil.user1UserId) + ) + assertEquals( + credentialStoreUtil.getUser2DeviceMetadata(), + credentialStore.retrieveDeviceMetadata(credentialStoreUtil.user2UserId) + ) + } + + @Test + fun test_CredentialStore_Missing_DeviceMetadata_Migration_Succeeds_On_Plugin_Configuration() { + // GIVEN + val userAUsername = "userA" + val expectedUserADeviceMetadata = DeviceMetadata.Metadata("A", "B", "C") + val userBUsername = "userB" + val expectedUserBDeviceMetadata = DeviceMetadata.Metadata("1", "2", "3") + + AWSCognitoAuthPlugin().apply { + configure(authConfigJson, context) + initialize(context) + } + + AWSCognitoAuthCredentialStore( + context, + AuthConfiguration.fromJson(authConfigJson) + ).apply { + saveDeviceMetadata("userA", expectedUserADeviceMetadata) + } + + // WHEN + // Simulating missed device metadata migration from issue 2929 + // We expect this to not migrate as it will conflict with existing metadata already saved + credentialStoreUtil.saveLegacyDeviceMetadata( + context, + userPoolId, + userAUsername, + DeviceMetadata.Metadata("X", "Y", "Z") + ) + + // We expect this to migrate as it does not conflict with any existing saved metadata + credentialStoreUtil.saveLegacyDeviceMetadata( + context, + userPoolId, + userBUsername, + expectedUserBDeviceMetadata + ) + + // THEN + + // Initialize plugin again to complete migration of missing device metadata + AWSCognitoAuthPlugin().apply { + configure(authConfigJson, context) + initialize(context) + } + + // WHEN + val credentialStore = AWSCognitoAuthCredentialStore( context, AuthConfiguration.fromJson(authConfigJson) - ).retrieveCredential() + ) - assertEquals(credential, receivedCredentials) + // Expect the device metadata for user A to have not changed from data that was already saved in v2 store + assertEquals( + expectedUserADeviceMetadata, + credentialStore.retrieveDeviceMetadata(userAUsername) + ) + // Expect the device metadata for user A to have not changed from data that was already saved in v2 store + assertEquals( + expectedUserBDeviceMetadata, + credentialStore.retrieveDeviceMetadata(userBUsername) + ) } } diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt index 4c07f7368a..f395603ef2 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt @@ -20,13 +20,15 @@ import com.amazonaws.internal.keyvaluestore.AWSKeyValueStore import com.amplifyframework.statemachine.codegen.data.AWSCredentials import com.amplifyframework.statemachine.codegen.data.AmplifyCredential import com.amplifyframework.statemachine.codegen.data.CognitoUserPoolTokens +import com.amplifyframework.statemachine.codegen.data.DeviceMetadata import com.amplifyframework.statemachine.codegen.data.SignInMethod import com.amplifyframework.statemachine.codegen.data.SignedInData +import java.io.File import java.util.Date -internal object CredentialStoreUtil { + internal class CredentialStoreUtil { - private const val accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwidXNlcm5hbWUiO" + + private val accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwidXNlcm5hbWUiO" + "iJhbXBsaWZ5X3VzZXIiLCJpYXQiOjE1MTYyMzkwMjJ9.zBiQ0guLRX34pUEYLPyDxQAyDDlXmL0JY7kgPWAHZos" private val credential = AmplifyCredential.UserAndIdentityPool( @@ -50,8 +52,29 @@ internal object CredentialStoreUtil { return credential } + val user1UserId = "2924030b-54c0-48bc-8bff-948418fba949" + val user2UserId = "7e001127-5f11-41fb-9d10-ab9d6cf41dba" + + fun getUser1DeviceMetadata(): DeviceMetadata.Metadata { + return DeviceMetadata.Metadata( + "DeviceKey1", + "DeviceGroupKey1", + "DeviceSecret1" + ) + } + + fun getUser2DeviceMetadata(): DeviceMetadata.Metadata { + return DeviceMetadata.Metadata( + "DeviceKey2", + "DeviceGroupKey2", + "DeviceSecret2" + ) + } + fun setupLegacyStore(context: Context, appClientId: String, userPoolId: String, identityPoolId: String) { + clearSharedPreferences(context) + AWSKeyValueStore(context, "CognitoIdentityProviderCache", true).apply { put("CognitoIdentityProvider.$appClientId.testuser.idToken", "idToken") put("CognitoIdentityProvider.$appClientId.testuser.accessToken", accessToken) @@ -60,10 +83,16 @@ internal object CredentialStoreUtil { put("CognitoIdentityProvider.$appClientId.LastAuthUser", "testuser") } - AWSKeyValueStore(context, "CognitoIdentityProviderDeviceCache.$userPoolId.testuser", true).apply { - put("DeviceKey", "someDeviceKey") - put("DeviceGroupKey", "someDeviceGroupKey") - put("DeviceSecret", "someSecret") + AWSKeyValueStore(context, "CognitoIdentityProviderDeviceCache.$userPoolId.$user1UserId", true).apply { + put("DeviceKey", "DeviceKey1") + put("DeviceGroupKey", "DeviceGroupKey1") + put("DeviceSecret", "DeviceSecret1") + } + + AWSKeyValueStore(context, "CognitoIdentityProviderDeviceCache.$userPoolId.$user2UserId", true).apply { + put("DeviceKey", "DeviceKey2") + put("DeviceGroupKey", "DeviceGroupKey2") + put("DeviceSecret", "DeviceSecret2") } AWSKeyValueStore(context, "com.amazonaws.android.auth", true).apply { @@ -73,5 +102,45 @@ internal object CredentialStoreUtil { put("$identityPoolId.expirationDate", "1212") put("$identityPoolId.identityId", "identityId") } + + // we need to wait for shared prefs to actually hit filesystem as we always use apply instead of commit + val beginWait = System.currentTimeMillis() + while(System.currentTimeMillis() - beginWait < 3000) { + if ((File(context.dataDir, "shared_prefs").listFiles()?.size ?: 0) >= 4) { + break + } else { + Thread.sleep(50) + } + } } + + fun saveLegacyDeviceMetadata( + context: Context, + userPoolId: String, + userId: String, + deviceMetadata: DeviceMetadata.Metadata + ) { + val prefsName = "CognitoIdentityProviderDeviceCache.$userPoolId.$userId" + AWSKeyValueStore( + context, + "CognitoIdentityProviderDeviceCache.$userPoolId.$userId", true).apply { + put("DeviceKey", deviceMetadata.deviceKey) + put("DeviceGroupKey", deviceMetadata.deviceGroupKey) + put("DeviceSecret", deviceMetadata.deviceSecret) + } + + // we need to wait for shared prefs to actually hit filesystem as we always use apply instead of commit + val beginWait = System.currentTimeMillis() + while(System.currentTimeMillis() - beginWait < 3000) { + if (File(context.dataDir, "shared_prefs/$prefsName.xml").exists()) { + break + } else { + Thread.sleep(50) + } + } + } + + fun clearSharedPreferences(context: Context) { + File(context.dataDir, "shared_prefs").listFiles()?.forEach { it.delete() } + } } From b24d342f25c491b359de5b1b5073243e3626f227 Mon Sep 17 00:00:00 2001 From: tjroach Date: Thu, 12 Dec 2024 11:17:43 -0500 Subject: [PATCH 3/4] correct naming, changing userId reference names to username --- ...egacyCredentialStoreInstrumentationTest.kt | 12 ++++----- ...ialStoreStateMachineInstrumentationTest.kt | 4 +-- .../cognito/testutils/CredentialStoreUtil.kt | 14 +++++------ .../actions/CredentialStoreCognitoActions.kt | 25 ++++++++++--------- .../data/AWSCognitoLegacyCredentialStore.kt | 4 +-- 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AWSCognitoLegacyCredentialStoreInstrumentationTest.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AWSCognitoLegacyCredentialStoreInstrumentationTest.kt index 10d8a6ff5c..bf31c08cfb 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AWSCognitoLegacyCredentialStoreInstrumentationTest.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AWSCognitoLegacyCredentialStoreInstrumentationTest.kt @@ -56,18 +56,18 @@ class AWSCognitoLegacyCredentialStoreInstrumentationTest { @Test fun test_legacy_store_implementation_can_retrieve_device_metadata_using_aws_sdk() { - val user1DeviceMetadata = store.retrieveDeviceMetadata(credentialStoreUtil.user1UserId) - val user2DeviceMetadata = store.retrieveDeviceMetadata(credentialStoreUtil.user2UserId) + val user1DeviceMetadata = store.retrieveDeviceMetadata(credentialStoreUtil.user1Username) + val user2DeviceMetadata = store.retrieveDeviceMetadata(credentialStoreUtil.user2Username) assertEquals(credentialStoreUtil.getUser1DeviceMetadata(), user1DeviceMetadata) assertEquals(credentialStoreUtil.getUser2DeviceMetadata(), user2DeviceMetadata) } @Test - fun test_legacy_store_implementation_can_retrieve_userIds_for_device_metadata() { - val expectedUserIds = listOf(credentialStoreUtil.user1UserId, credentialStoreUtil.user2UserId) - val deviceMetadataUserIds = store.retrieveDeviceMetadataUserIdList() + fun test_legacy_store_implementation_can_retrieve_usernames_for_device_metadata() { + val expectedUsernames = listOf(credentialStoreUtil.user1Username, credentialStoreUtil.user2Username) + val deviceMetadataUsernames = store.retrieveDeviceMetadataUsernameList() - assertEquals(expectedUserIds, deviceMetadataUserIds) + assertEquals(expectedUsernames, deviceMetadataUsernames) } } diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt index 868cd18d2e..c9bbae7816 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt @@ -65,11 +65,11 @@ class CredentialStoreStateMachineInstrumentationTest { assertEquals(credentialStoreUtil.getDefaultCredential(), credentialStore.retrieveCredential()) assertEquals( credentialStoreUtil.getUser1DeviceMetadata(), - credentialStore.retrieveDeviceMetadata(credentialStoreUtil.user1UserId) + credentialStore.retrieveDeviceMetadata(credentialStoreUtil.user1Username) ) assertEquals( credentialStoreUtil.getUser2DeviceMetadata(), - credentialStore.retrieveDeviceMetadata(credentialStoreUtil.user2UserId) + credentialStore.retrieveDeviceMetadata(credentialStoreUtil.user2Username) ) } diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt index f395603ef2..b17293ce64 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt @@ -52,8 +52,8 @@ import java.util.Date return credential } - val user1UserId = "2924030b-54c0-48bc-8bff-948418fba949" - val user2UserId = "7e001127-5f11-41fb-9d10-ab9d6cf41dba" + val user1Username = "2924030b-54c0-48bc-8bff-948418fba949" + val user2Username = "7e001127-5f11-41fb-9d10-ab9d6cf41dba" fun getUser1DeviceMetadata(): DeviceMetadata.Metadata { return DeviceMetadata.Metadata( @@ -83,13 +83,13 @@ import java.util.Date put("CognitoIdentityProvider.$appClientId.LastAuthUser", "testuser") } - AWSKeyValueStore(context, "CognitoIdentityProviderDeviceCache.$userPoolId.$user1UserId", true).apply { + AWSKeyValueStore(context, "CognitoIdentityProviderDeviceCache.$userPoolId.$user1Username", true).apply { put("DeviceKey", "DeviceKey1") put("DeviceGroupKey", "DeviceGroupKey1") put("DeviceSecret", "DeviceSecret1") } - AWSKeyValueStore(context, "CognitoIdentityProviderDeviceCache.$userPoolId.$user2UserId", true).apply { + AWSKeyValueStore(context, "CognitoIdentityProviderDeviceCache.$userPoolId.$user2Username", true).apply { put("DeviceKey", "DeviceKey2") put("DeviceGroupKey", "DeviceGroupKey2") put("DeviceSecret", "DeviceSecret2") @@ -117,13 +117,13 @@ import java.util.Date fun saveLegacyDeviceMetadata( context: Context, userPoolId: String, - userId: String, + username: String, deviceMetadata: DeviceMetadata.Metadata ) { - val prefsName = "CognitoIdentityProviderDeviceCache.$userPoolId.$userId" + val prefsName = "CognitoIdentityProviderDeviceCache.$userPoolId.$username" AWSKeyValueStore( context, - "CognitoIdentityProviderDeviceCache.$userPoolId.$userId", true).apply { + "CognitoIdentityProviderDeviceCache.$userPoolId.$username", true).apply { put("DeviceKey", deviceMetadata.deviceKey) put("DeviceGroupKey", deviceMetadata.deviceGroupKey) put("DeviceSecret", deviceMetadata.deviceSecret) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt index 68a37fc459..f0f07b98e5 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt @@ -38,24 +38,25 @@ internal object CredentialStoreCognitoActions : CredentialStoreActions { /* Migrate Device Metadata - 1. We first need to get the list of userIds that contain device metadata on the device. - 2. For each userId, we check to see if the current credential store has device metadata for that user. + 1. We first need to get the list of usernames that contain device metadata on the device. + 2. For each username, we check to see if the current credential store has device metadata for that user. 3. If the current user does not have device metadata in the current store, migrate from legacy. This is a possibility because of a bug where we were previously attempting to migrate using an aliased - userId lookup. This situation would happen if a user migrated, signed out, then signed back in. Upon - signing back in, they would be granted new device metadata. Since that new metadata is what is - associated with the refresh token, we do not want to overwrite it. + username lookup. 4. If the current user has device metadata in the current credential store, do not migrate from legacy. - 5. Upon migration completion, we delete the legacy device metadata. + This situation would happen if a user updated from legacy, signed out, then signed back in. Upon + signing back in, they would be granted new device metadata. Since that new metadata is what is + associated with the refresh token, we do not want to overwrite it with legacy metadata. + 5. Upon completed migration, we delete the legacy device metadata. */ - legacyCredentialStore.retrieveDeviceMetadataUserIdList().forEach { userId -> - val deviceMetaData = legacyCredentialStore.retrieveDeviceMetadata(userId) + legacyCredentialStore.retrieveDeviceMetadataUsernameList().forEach { username -> + val deviceMetaData = legacyCredentialStore.retrieveDeviceMetadata(username) if (deviceMetaData != DeviceMetadata.Empty) { - credentialStore.retrieveDeviceMetadata(userId) - if (credentialStore.retrieveDeviceMetadata(userId) == DeviceMetadata.Empty) { - credentialStore.saveDeviceMetadata(userId, deviceMetaData) + credentialStore.retrieveDeviceMetadata(username) + if (credentialStore.retrieveDeviceMetadata(username) == DeviceMetadata.Empty) { + credentialStore.saveDeviceMetadata(username, deviceMetaData) } - legacyCredentialStore.deleteDeviceKeyCredential(userId) + legacyCredentialStore.deleteDeviceKeyCredential(username) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt index 18b19749d1..ee5fa96ca3 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt @@ -233,9 +233,9 @@ internal class AWSCognitoLegacyCredentialStore( /* During migration away from the legacy credential store, we need to find all shared preference files that store - device metadata. These filenames contain the real userId (not aliased) for the tracked device metadata. + device metadata. These filenames contain the real username (not aliased) for the tracked device metadata. */ - fun retrieveDeviceMetadataUserIdList(): List { + fun retrieveDeviceMetadataUsernameList(): List { return try { val sharedPrefsSuffix = ".xml" File(context.dataDir, "shared_prefs").listFiles { _, filename -> From 7cbde5cc9fbe23116949e7aaa2360210f51d11c7 Mon Sep 17 00:00:00 2001 From: tjroach Date: Thu, 12 Dec 2024 11:19:42 -0500 Subject: [PATCH 4/4] lint --- .../cognito/testutils/CredentialStoreUtil.kt | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt index b17293ce64..da5de979f5 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/testutils/CredentialStoreUtil.kt @@ -26,8 +26,7 @@ import com.amplifyframework.statemachine.codegen.data.SignedInData import java.io.File import java.util.Date - internal class CredentialStoreUtil { - +internal class CredentialStoreUtil { private val accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwidXNlcm5hbWUiO" + "iJhbXBsaWZ5X3VzZXIiLCJpYXQiOjE1MTYyMzkwMjJ9.zBiQ0guLRX34pUEYLPyDxQAyDDlXmL0JY7kgPWAHZos" @@ -105,7 +104,7 @@ import java.util.Date // we need to wait for shared prefs to actually hit filesystem as we always use apply instead of commit val beginWait = System.currentTimeMillis() - while(System.currentTimeMillis() - beginWait < 3000) { + while (System.currentTimeMillis() - beginWait < 3000) { if ((File(context.dataDir, "shared_prefs").listFiles()?.size ?: 0) >= 4) { break } else { @@ -114,33 +113,34 @@ import java.util.Date } } - fun saveLegacyDeviceMetadata( - context: Context, - userPoolId: String, - username: String, - deviceMetadata: DeviceMetadata.Metadata - ) { - val prefsName = "CognitoIdentityProviderDeviceCache.$userPoolId.$username" - AWSKeyValueStore( - context, - "CognitoIdentityProviderDeviceCache.$userPoolId.$username", true).apply { - put("DeviceKey", deviceMetadata.deviceKey) - put("DeviceGroupKey", deviceMetadata.deviceGroupKey) - put("DeviceSecret", deviceMetadata.deviceSecret) - } - - // we need to wait for shared prefs to actually hit filesystem as we always use apply instead of commit - val beginWait = System.currentTimeMillis() - while(System.currentTimeMillis() - beginWait < 3000) { - if (File(context.dataDir, "shared_prefs/$prefsName.xml").exists()) { - break - } else { - Thread.sleep(50) - } - } - } - - fun clearSharedPreferences(context: Context) { - File(context.dataDir, "shared_prefs").listFiles()?.forEach { it.delete() } - } + fun saveLegacyDeviceMetadata( + context: Context, + userPoolId: String, + username: String, + deviceMetadata: DeviceMetadata.Metadata + ) { + val prefsName = "CognitoIdentityProviderDeviceCache.$userPoolId.$username" + AWSKeyValueStore( + context, + "CognitoIdentityProviderDeviceCache.$userPoolId.$username", true + ).apply { + put("DeviceKey", deviceMetadata.deviceKey) + put("DeviceGroupKey", deviceMetadata.deviceGroupKey) + put("DeviceSecret", deviceMetadata.deviceSecret) + } + + // we need to wait for shared prefs to actually hit filesystem as we always use apply instead of commit + val beginWait = System.currentTimeMillis() + while (System.currentTimeMillis() - beginWait < 3000) { + if (File(context.dataDir, "shared_prefs/$prefsName.xml").exists()) { + break + } else { + Thread.sleep(50) + } + } + } + + fun clearSharedPreferences(context: Context) { + File(context.dataDir, "shared_prefs").listFiles()?.forEach { it.delete() } + } }