diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/DeviceKeyPersistenceInstrumentationTest.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/DeviceKeyPersistenceInstrumentationTest.kt new file mode 100644 index 0000000000..8b33029788 --- /dev/null +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/DeviceKeyPersistenceInstrumentationTest.kt @@ -0,0 +1,173 @@ +/* + * Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amplifyframework.auth.cognito + +import android.content.Context +import android.util.Log +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignInOptions +import com.amplifyframework.auth.cognito.options.AuthFlowType +import com.amplifyframework.auth.cognito.testutils.Credentials +import com.amplifyframework.auth.options.AuthSignInOptions +import com.amplifyframework.core.Amplify +import com.amplifyframework.core.InitializationStatus +import com.amplifyframework.hub.HubChannel +import com.amplifyframework.testutils.DeviceFarmTestBase +import com.amplifyframework.testutils.assertAwait +import com.amplifyframework.testutils.sync.SynchronousAuth +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Integration tests for device key persistence across different auth flows. + * + * Validates that once a device is remembered, the same device key is reused + * across sign-out/sign-in cycles regardless of which auth flow is used + * (USER_PASSWORD_AUTH, USER_SRP_AUTH). The device count should always remain 1. + * + * Prerequisites: + * - Cognito User Pool with Device Tracking set to "Always Remember" + * - USER_PASSWORD_AUTH and USER_SRP_AUTH both enabled on the app client + * - Valid test credentials in credentials.json + */ +@RunWith(AndroidJUnit4::class) +class DeviceKeyPersistenceInstrumentationTest : DeviceFarmTestBase() { + + companion object { + val auth = AWSCognitoAuthPlugin() + val syncAuth = SynchronousAuth.delegatingTo(auth) + + @BeforeClass + @JvmStatic + fun setUp() { + try { + Amplify.addPlugin(auth) + Amplify.configure(ApplicationProvider.getApplicationContext()) + val latch = CountDownLatch(1) + Amplify.Hub.subscribe(HubChannel.AUTH) { event -> + when (event.name) { + InitializationStatus.SUCCEEDED.toString(), + InitializationStatus.FAILED.toString() -> + latch.countDown() + } + } + latch.assertAwait(20, TimeUnit.SECONDS) + } catch (ex: Exception) { + Log.i("DeviceKeyPersistenceTest", "Error initializing", ex) + } + } + } + + @Before + fun setup() { + signOut() + } + + /** + * Sign in with USER_PASSWORD_AUTH, remember device (1 device). + * Sign out, sign in with USER_SRP_AUTH — device count should stay 1, same device key. + * Sign out, sign in with USER_PASSWORD_AUTH again — still 1, same key. + * Sign out, sign in with USER_SRP_AUTH again — still 1, same key. + */ + @Test + fun deviceKey_stays_consistent_across_alternating_auth_flows() { + val context = ApplicationProvider.getApplicationContext() + val (username, password) = Credentials.load(context) + + // Step 1: Sign in with USER_PASSWORD_AUTH and remember device + signIn(username, password, AuthFlowType.USER_PASSWORD_AUTH) + syncAuth.rememberDevice() + + val initialDevices = syncAuth.fetchDevices() + assertEquals("Should have exactly 1 device after initial sign-in", 1, initialDevices.size) + val originalDeviceId = initialDevices[0].id + + // Step 2: Sign out, sign in with USER_SRP_AUTH — same device + signOut() + signIn(username, password, AuthFlowType.USER_SRP_AUTH) + + var devices = syncAuth.fetchDevices() + assertEquals("Should still have 1 device after SRP sign-in", 1, devices.size) + assertEquals("Device ID should match after SRP sign-in", originalDeviceId, devices[0].id) + + // Step 3: Sign out, sign in with USER_PASSWORD_AUTH — same device + signOut() + signIn(username, password, AuthFlowType.USER_PASSWORD_AUTH) + + devices = syncAuth.fetchDevices() + assertEquals("Should still have 1 device after second PASSWORD sign-in", 1, devices.size) + assertEquals("Device ID should match after second PASSWORD sign-in", originalDeviceId, devices[0].id) + + // Step 4: Sign out, sign in with USER_SRP_AUTH — same device + signOut() + signIn(username, password, AuthFlowType.USER_SRP_AUTH) + + devices = syncAuth.fetchDevices() + assertEquals("Should still have 1 device after second SRP sign-in", 1, devices.size) + assertEquals("Device ID should match after second SRP sign-in", originalDeviceId, devices[0].id) + + // Clean up + syncAuth.forgetDevice() + } + + /** + * Same-flow baseline: sign in with USER_SRP_AUTH, remember device, + * sign out, sign in with USER_SRP_AUTH — device count stays 1. + */ + @Test + fun deviceKey_persists_across_same_flow_signIn_signOut() { + val context = ApplicationProvider.getApplicationContext() + val (username, password) = Credentials.load(context) + + signIn(username, password, AuthFlowType.USER_SRP_AUTH) + syncAuth.rememberDevice() + + val initialDevices = syncAuth.fetchDevices() + assertEquals("Should have exactly 1 device", 1, initialDevices.size) + val originalDeviceId = initialDevices[0].id + + signOut() + signIn(username, password, AuthFlowType.USER_SRP_AUTH) + + val devices = syncAuth.fetchDevices() + assertEquals("Should still have 1 device after re-sign-in", 1, devices.size) + assertEquals("Device ID should be the same", originalDeviceId, devices[0].id) + + // Clean up + syncAuth.forgetDevice() + } + + private fun signIn(username: String, password: String, flowType: AuthFlowType) { + val options: AuthSignInOptions = AWSCognitoAuthSignInOptions.builder() + .authFlowType(flowType) + .build() + syncAuth.signIn(username, password, options) + } + + private fun signOut() { + try { + syncAuth.signOut() + } catch (e: Exception) { + // Ignore errors during sign-out + } + } +} diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActions.kt index f49caff08e..9156c4f052 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActions.kt @@ -35,6 +35,7 @@ internal object MigrateAuthCognitoActions : MigrateAuthActions { private const val KEY_PASSWORD = "PASSWORD" private const val KEY_SECRET_HASH = "SECRET_HASH" private const val KEY_USERID_FOR_SRP = "USER_ID_FOR_SRP" + private const val KEY_DEVICE_KEY = "DEVICE_KEY" private const val KEY_ANSWER = "ANSWER" private const val KEY_PREFERRED_CHALLENGE = "PREFERRED_CHALLENGE" @@ -54,8 +55,9 @@ internal object MigrateAuthCognitoActions : MigrateAuthActions { secretHash?.let { authParams[KEY_SECRET_HASH] = it } val encodedContextData = getUserContextData(event.username) + val deviceMetadata = getDeviceMetadata(event.username) + deviceMetadata?.let { authParams[KEY_DEVICE_KEY] = it.deviceKey } val pinpointEndpointId = getPinpointEndpointId() - if (event.respondToAuthChallenge?.session != null) { authParams[KEY_ANSWER] = ChallengeNameType.Password.value @@ -76,7 +78,8 @@ internal object MigrateAuthCognitoActions : MigrateAuthActions { session = response.session, challengeParameters = response.challengeParameters, authenticationResult = response.authenticationResult, - signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH) + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH), + inputUsername = event.username ) } else { if (event.authFlowType == AuthFlowType.USER_AUTH) { @@ -103,7 +106,8 @@ internal object MigrateAuthCognitoActions : MigrateAuthActions { session = response.session, challengeParameters = response.challengeParameters, authenticationResult = response.authenticationResult, - signInMethod = signInMethod + signInMethod = signInMethod, + inputUsername = event.username ) } } catch (e: Exception) { diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SRPCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SRPCognitoActions.kt index d2c5e208de..647262eb65 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SRPCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SRPCognitoActions.kt @@ -101,7 +101,8 @@ internal object SRPCognitoActions : SRPActions { challengeParams = response.challengeParameters, session = response.session, updatedDeviceMetadata = updatedDeviceMetadata, - metadata = event.metadata + metadata = event.metadata, + inputUsername = event.username ) } else { if (event.authFlowType == AuthFlowType.USER_AUTH) { @@ -124,7 +125,8 @@ internal object SRPCognitoActions : SRPActions { challengeParams = response.challengeParameters, session = response.session, updatedDeviceMetadata = updatedDeviceMetadata, - metadata = event.metadata + metadata = event.metadata, + inputUsername = event.username ) } } catch (e: Exception) { @@ -143,7 +145,8 @@ internal object SRPCognitoActions : SRPActions { challengeParams: Map?, session: String?, updatedDeviceMetadata: DeviceMetadata.Metadata?, - metadata: Map + metadata: Map, + inputUsername: String? = null ): SRPEvent = when (challengeNameType) { ChallengeNameType.PasswordVerifier -> { challengeParams?.let { params -> @@ -155,7 +158,8 @@ internal object SRPCognitoActions : SRPActions { SRPEvent.EventType.RespondPasswordVerifier( updatedChallengeParams, metadata, - session + session, + inputUsername = inputUsername ) ) } ?: throw ServiceException( @@ -209,7 +213,8 @@ internal object SRPCognitoActions : SRPActions { SRPEvent.EventType.RespondPasswordVerifier( challengeParams, event.metadata, - initiateAuthResponse.session + initiateAuthResponse.session, + inputUsername = event.username ) ) } ?: throw ServiceException( @@ -235,7 +240,8 @@ internal object SRPCognitoActions : SRPActions { challengeParameters: Map, metadata: Map, session: String?, - signInMethod: SignInMethod + signInMethod: SignInMethod, + inputUsername: String? ) = Action("VerifyPasswordSRP") { id, dispatcher -> logger.verbose("$id Starting execution") val evt = try { @@ -282,7 +288,8 @@ internal object SRPCognitoActions : SRPActions { session = response.session, challengeParameters = response.challengeParameters, authenticationResult = response.authenticationResult, - signInMethod = signInMethod + signInMethod = signInMethod, + inputUsername = inputUsername ) } else { throw ServiceException( @@ -306,7 +313,8 @@ internal object SRPCognitoActions : SRPActions { challengeParams, metadata, session, - signInMethod + signInMethod, + inputUsername = inputUsername ) ) } else { diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt index 4e48e2bdb6..ae46bd73e8 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt @@ -59,7 +59,8 @@ internal object SignInChallengeCognitoActions : SignInChallengeActions { session = challenge.session, challengeParameters = mapOf("MFAS_CAN_SETUP" to answer), authenticationResult = null, - signInMethod = signInMethod + signInMethod = signInMethod, + inputUsername = challenge.inputUsername ) logger.verbose("$id Sending event ${event.type}") dispatcher.send(event) @@ -111,7 +112,8 @@ internal object SignInChallengeCognitoActions : SignInChallengeActions { session = response.session, challengeParameters = response.challengeParameters, authenticationResult = response.authenticationResult, - signInMethod = signInMethod + signInMethod = signInMethod, + inputUsername = challenge.inputUsername ) } ?: CustomSignInEvent( CustomSignInEvent.EventType.ThrowAuthError( diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt index 8ec7816908..a3f1ec557b 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt @@ -137,8 +137,9 @@ internal object SignInCognitoActions : SignInActions { ) ?: throw ServiceException("Sign in failed", AmplifyException.TODO_RECOVERY_SUGGESTION) val updatedDeviceMetadata = deviceMetadata.copy(deviceSecret = deviceVerifierMap["secret"]) + val deviceMetadataUsername = event.signedInData.inputUsername ?: event.signedInData.username credentialStoreClient.storeCredentials( - CredentialType.Device(event.signedInData.username), + CredentialType.Device(deviceMetadataUsername), AmplifyCredential.DeviceData(updatedDeviceMetadata) ) @@ -230,7 +231,8 @@ internal object SignInCognitoActions : SignInActions { challengeParameters = response.challengeParameters, authenticationResult = response.authenticationResult, availableChallenges = response.availableChallenges?.map { it.value }, - signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH) + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH), + inputUsername = event.signInData.username ) } else { throw ServiceException( diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCustomCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCustomCognitoActions.kt index f210016993..bfbf658657 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCustomCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCustomCognitoActions.kt @@ -71,7 +71,8 @@ internal object SignInCustomCognitoActions : CustomSignInActions { session = initiateAuthResponse.session, challengeParameters = initiateAuthResponse.challengeParameters, authenticationResult = initiateAuthResponse.authenticationResult, - signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.CUSTOM_AUTH) + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.CUSTOM_AUTH), + inputUsername = event.username ) } else { throw ServiceException( diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/UserAuthSignInCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/UserAuthSignInCognitoActions.kt index 333f6e7d91..894b3665f2 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/UserAuthSignInCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/UserAuthSignInCognitoActions.kt @@ -83,7 +83,8 @@ internal object UserAuthSignInCognitoActions : UserAuthSignInActions { availableChallenges = listOfChallenges, authenticationResult = initiateAuthResponse.authenticationResult, callingActivity = event.callingActivity, - signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH) + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH), + inputUsername = event.username ) } else if (isSupportedChallenge(initiateAuthResponse?.challengeName) && initiateAuthResponse?.challengeParameters != null && @@ -98,7 +99,8 @@ internal object UserAuthSignInCognitoActions : UserAuthSignInActions { challengeParameters = initiateAuthResponse.challengeParameters, authenticationResult = initiateAuthResponse.authenticationResult, callingActivity = event.callingActivity, - signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH) + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH), + inputUsername = event.username ) } else { throw ServiceException("Sign in failed", AmplifyException.TODO_RECOVERY_SUGGESTION) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/WebAuthnSignInCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/WebAuthnSignInCognitoActions.kt index c6a2e8605e..06da70c2c2 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/WebAuthnSignInCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/WebAuthnSignInCognitoActions.kt @@ -63,7 +63,8 @@ internal object WebAuthnSignInCognitoActions : WebAuthnSignInActions { challengeParameters = response.challengeParameters, authenticationResult = response.authenticationResult, callingActivity = signInContext.callingActivity, - signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH) + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH), + inputUsername = signInContext.username ) } @@ -104,7 +105,8 @@ internal object WebAuthnSignInCognitoActions : WebAuthnSignInActions { challengeParameters = response.challengeParameters, authenticationResult = response.authenticationResult, callingActivity = signInContext.callingActivity, - signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH) + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH), + inputUsername = signInContext.username ) } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoAuthCredentialStore.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoAuthCredentialStore.kt index f4546a955c..a8838a6dbd 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoAuthCredentialStore.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoAuthCredentialStore.kt @@ -47,7 +47,7 @@ internal class AWSCognitoAuthCredentialStore( ) override fun saveDeviceMetadata(username: String, deviceMetadata: DeviceMetadata) = keyValue.put( - generateKey("$username.$KEY_DEVICE_METADATA"), + generateKey("${username.lowercase()}.$KEY_DEVICE_METADATA"), serializeMetaData(deviceMetadata) ) @@ -61,7 +61,7 @@ internal class AWSCognitoAuthCredentialStore( override fun retrieveCredential(): AmplifyCredential = deserializeCredential(keyValue.get(generateKey(KEY_SESSION))) override fun retrieveDeviceMetadata(username: String): DeviceMetadata = deserializeMetadata( - keyValue.get(generateKey("$username.$KEY_DEVICE_METADATA")) + keyValue.get(generateKey("${username.lowercase()}.$KEY_DEVICE_METADATA")) ) override fun retrieveASFDevice(): AmplifyCredential.ASFDevice = deserializeASFDevice( @@ -73,7 +73,7 @@ internal class AWSCognitoAuthCredentialStore( override fun deleteCredential() = keyValue.remove(generateKey(KEY_SESSION)) override fun deleteDeviceKeyCredential(username: String) = keyValue.remove( - generateKey("$username.$KEY_DEVICE_METADATA") + generateKey("${username.lowercase()}.$KEY_DEVICE_METADATA") ) override fun deleteASFDevice() = keyValue.remove(generateKey(KEY_ASF_DEVICE)) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SignInChallengeHelper.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SignInChallengeHelper.kt index 22ef18e44f..cc79b58e12 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SignInChallengeHelper.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SignInChallengeHelper.kt @@ -52,7 +52,8 @@ internal object SignInChallengeHelper { availableChallenges: List? = null, authenticationResult: AuthenticationResultType?, callingActivity: WeakReference = WeakReference(null), - signInMethod: SignInMethod + signInMethod: SignInMethod, + inputUsername: String? = null ): StateMachineEvent = when { authenticationResult != null -> { authenticationResult.let { @@ -64,7 +65,8 @@ internal object SignInChallengeHelper { username, Date(), signInMethod, - tokens + tokens, + inputUsername = inputUsername ?: username ) it.newDeviceMetadata?.let { metadata -> SignInEvent( @@ -91,13 +93,24 @@ internal object SignInChallengeHelper { challengeNameType is ChallengeNameType.SelectMfaType || challengeNameType is ChallengeNameType.SmsOtp || challengeNameType is ChallengeNameType.EmailOtp -> { - val challenge = - AuthChallenge(challengeNameType.value, username, session, challengeParameters) + val challenge = AuthChallenge( + challengeNameType.value, + username, + session, + challengeParameters, + inputUsername = inputUsername + ) SignInEvent(SignInEvent.EventType.ReceivedChallenge(challenge, signInMethod)) } challengeNameType is ChallengeNameType.MfaSetup -> { val allowedMFASetupTypes = getAllowedMFASetupTypesFromChallengeParameters(challengeParameters) - val challenge = AuthChallenge(challengeNameType.value, username, session, challengeParameters) + val challenge = AuthChallenge( + challengeNameType.value, + username, + session, + challengeParameters, + inputUsername = inputUsername + ) if (allowedMFASetupTypes.contains(MFAType.EMAIL)) { SignInEvent(SignInEvent.EventType.ReceivedChallenge(challenge, signInMethod)) @@ -123,7 +136,8 @@ internal object SignInChallengeHelper { username = username, session = session, parameters = null, - availableChallenges = availableChallenges + availableChallenges = availableChallenges, + inputUsername = inputUsername ), signInMethod ) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/actions/SRPActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/actions/SRPActions.kt index b872fda609..47179f5f5f 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/actions/SRPActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/actions/SRPActions.kt @@ -26,6 +26,7 @@ internal interface SRPActions { challengeParameters: Map, metadata: Map, session: String?, - signInMethod: SignInMethod + signInMethod: SignInMethod, + inputUsername: String? = null ): Action } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AuthChallenge.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AuthChallenge.kt index fbbcb09378..ac6100335f 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AuthChallenge.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AuthChallenge.kt @@ -25,7 +25,8 @@ internal data class AuthChallenge( val username: String? = null, val session: String?, val parameters: Map?, - val availableChallenges: List? = null + val availableChallenges: List? = null, + val inputUsername: String? = null ) { override fun toString(): String = "AuthChallenge(" + "challengeName='$challengeName', " + diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/SignedInData.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/SignedInData.kt index 955fe01320..9467f475f1 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/SignedInData.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/SignedInData.kt @@ -26,7 +26,8 @@ internal data class SignedInData( @Serializable(DateSerializer::class) val signedInDate: Date, val signInMethod: SignInMethod, - val cognitoUserPoolTokens: CognitoUserPoolTokens + val cognitoUserPoolTokens: CognitoUserPoolTokens, + val inputUsername: String? = null ) { override fun equals(other: Any?): Boolean = if (super.equals(other)) { true @@ -36,6 +37,7 @@ internal data class SignedInData( userId == other.userId && username == other.username && signInMethod == other.signInMethod && - cognitoUserPoolTokens == other.cognitoUserPoolTokens + cognitoUserPoolTokens == other.cognitoUserPoolTokens && + inputUsername == other.inputUsername } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SRPEvent.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SRPEvent.kt index e8abd4664d..0b6d14debe 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SRPEvent.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SRPEvent.kt @@ -39,14 +39,16 @@ internal class SRPEvent(val eventType: EventType, override val time: Date? = nul data class RespondPasswordVerifier( val challengeParameters: Map, val metadata: Map, - val session: String? + val session: String?, + val inputUsername: String? = null ) : EventType() data class RetryRespondPasswordVerifier( val challengeParameters: Map, val metadata: Map, val session: String?, - val signInMethod: SignInMethod + val signInMethod: SignInMethod, + val inputUsername: String? = null ) : EventType() data class ThrowAuthError(val exception: Exception) : EventType() diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/states/SRPSignInState.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/states/SRPSignInState.kt index a2c2a5b819..8e404f7760 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/states/SRPSignInState.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/states/SRPSignInState.kt @@ -61,7 +61,8 @@ internal sealed class SRPSignInState : State { srpEvent.challengeParameters, srpEvent.metadata, srpEvent.session, - oldState.signInMethod + oldState.signInMethod, + inputUsername = srpEvent.inputUsername ) StateResolution(RespondingPasswordVerifier(), listOf(action)) } @@ -75,7 +76,8 @@ internal sealed class SRPSignInState : State { srpEvent.challengeParameters, srpEvent.metadata, srpEvent.session, - srpEvent.signInMethod + srpEvent.signInMethod, + inputUsername = srpEvent.inputUsername ) StateResolution(RespondingPasswordVerifier(), listOf(action)) } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActionsTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActionsTest.kt index e793fde612..60a69bb6e1 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActionsTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActionsTest.kt @@ -34,6 +34,7 @@ import com.amplifyframework.statemachine.StateMachineEvent import com.amplifyframework.statemachine.codegen.data.AmplifyCredential import com.amplifyframework.statemachine.codegen.data.AuthChallenge import com.amplifyframework.statemachine.codegen.data.CredentialType +import com.amplifyframework.statemachine.codegen.data.DeviceMetadata import com.amplifyframework.statemachine.codegen.data.SignInMethod import com.amplifyframework.statemachine.codegen.data.UserPoolConfiguration import com.amplifyframework.statemachine.codegen.events.AuthenticationEvent @@ -65,6 +66,8 @@ class MigrateAuthCognitoActionsTest { private val cognitoAuthService = mockk() private val credentialStoreClient = mockk { coEvery { loadCredentials(CredentialType.ASF) } returns AmplifyCredential.ASFDevice("asf_id") + coEvery { loadCredentials(match { it is CredentialType.Device }) } returns + AmplifyCredential.DeviceData(DeviceMetadata.Empty) } private val logger = mockk(relaxed = true) private val cognitoIdentityProviderClientMock = mockk() diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt index ea887d8366..c9bb5779ea 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt @@ -68,7 +68,8 @@ object AuthStateJsonGenerator : SerializableProvider { accessToken = DUMMY_TOKEN, refreshToken = DUMMY_TOKEN, expiration = 300 - ) + ), + inputUsername = USERNAME ) internal val signedInAmplifyCredential = AmplifyCredential.UserAndIdentityPool( @@ -105,7 +106,8 @@ object AuthStateJsonGenerator : SerializableProvider { parameters = mapOf( "CODE_DELIVERY_DELIVERY_MEDIUM" to "SMS", "CODE_DELIVERY_DESTINATION" to "+12345678900" - ) + ), + inputUsername = USERNAME ), SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH) ) @@ -205,7 +207,8 @@ object AuthStateJsonGenerator : SerializableProvider { "SECRET_BLOCK" to "secretBlock", "SRP_B" to "def", "USERNAME" to "username" - ) + ), + inputUsername = USERNAME ), SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.CUSTOM_AUTH) ) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/helpers/InputUsernameDeviceKeyTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/helpers/InputUsernameDeviceKeyTest.kt new file mode 100644 index 0000000000..25578eb1dc --- /dev/null +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/helpers/InputUsernameDeviceKeyTest.kt @@ -0,0 +1,393 @@ +/* + * Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amplifyframework.auth.cognito.helpers + +import aws.sdk.kotlin.services.cognitoidentityprovider.model.AuthenticationResultType +import aws.sdk.kotlin.services.cognitoidentityprovider.model.ChallengeNameType +import com.amplifyframework.statemachine.codegen.data.AuthChallenge +import com.amplifyframework.statemachine.codegen.data.CognitoUserPoolTokens +import com.amplifyframework.statemachine.codegen.data.SignInMethod +import com.amplifyframework.statemachine.codegen.data.SignedInData +import com.amplifyframework.statemachine.codegen.events.AuthenticationEvent +import com.amplifyframework.statemachine.codegen.events.SRPEvent +import com.amplifyframework.statemachine.codegen.events.SignInEvent +import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeInstanceOf +import java.util.Date +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import org.junit.Test + +class InputUsernameDeviceKeyTest { + + private val json = Json { ignoreUnknownKeys = true } + + // --- SignedInData serialization tests --- + + @Test + fun `SignedInData deserialization without inputUsername field yields null`() { + // Simulates decoding persisted data from before this change + val jsonString = """ + { + "userId": "user-123", + "username": "cognito-sub-uuid", + "signedInDate": 1700000000000, + "signInMethod": { + "type": "SignInMethod.ApiBased", + "authType": "USER_SRP_AUTH" + }, + "cognitoUserPoolTokens": { + "idToken": null, + "accessToken": null, + "refreshToken": null, + "expiration": 1700003600 + } + } + """.trimIndent() + + val data = json.decodeFromString(jsonString) + data.inputUsername.shouldBeNull() + data.userId shouldBe "user-123" + data.username shouldBe "cognito-sub-uuid" + } + + @Test + fun `SignedInData round-trip serialization preserves inputUsername`() { + val original = SignedInData( + userId = "user-123", + username = "cognito-sub-uuid", + signedInDate = Date(1700000000000), + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + cognitoUserPoolTokens = CognitoUserPoolTokens( + null as String?, + null as String?, + null as String?, + 1700003600L + ), + inputUsername = "user@example.com" + ) + + val serialized = json.encodeToString(original) + val deserialized = json.decodeFromString(serialized) + + deserialized.inputUsername shouldBe "user@example.com" + deserialized.userId shouldBe original.userId + deserialized.username shouldBe original.username + } + + @Test + fun `SignedInData round-trip with null inputUsername`() { + val original = SignedInData( + userId = "user-123", + username = "cognito-sub-uuid", + signedInDate = Date(1700000000000), + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + cognitoUserPoolTokens = CognitoUserPoolTokens( + null as String?, + null as String?, + null as String?, + 1700003600L + ) + ) + + val serialized = json.encodeToString(original) + val deserialized = json.decodeFromString(serialized) + + deserialized.inputUsername.shouldBeNull() + } + + // --- AuthChallenge serialization tests --- + + @Test + fun `AuthChallenge deserialization without inputUsername field yields null`() { + val jsonString = """ + { + "challengeName": "SMS_MFA", + "username": "cognito-sub-uuid", + "session": "session-abc", + "parameters": null + } + """.trimIndent() + + val challenge = json.decodeFromString(jsonString) + challenge.inputUsername.shouldBeNull() + challenge.challengeName shouldBe "SMS_MFA" + } + + @Test + fun `AuthChallenge round-trip serialization preserves inputUsername`() { + val original = AuthChallenge( + challengeName = "SMS_MFA", + username = "cognito-sub-uuid", + session = "session-abc", + parameters = null, + inputUsername = "user@example.com" + ) + + val serialized = json.encodeToString(original) + val deserialized = json.decodeFromString(serialized) + + deserialized.inputUsername shouldBe "user@example.com" + } + + // --- SRPEvent inputUsername threading tests --- + + @Test + fun `RespondPasswordVerifier carries inputUsername`() { + val event = SRPEvent.EventType.RespondPasswordVerifier( + challengeParameters = mapOf("USERNAME" to "cognito-sub"), + metadata = emptyMap(), + session = "session-1", + inputUsername = "user@example.com" + ) + + event.inputUsername shouldBe "user@example.com" + } + + @Test + fun `RespondPasswordVerifier defaults inputUsername to null`() { + val event = SRPEvent.EventType.RespondPasswordVerifier( + challengeParameters = mapOf("USERNAME" to "cognito-sub"), + metadata = emptyMap(), + session = "session-1" + ) + + event.inputUsername.shouldBeNull() + } + + @Test + fun `RetryRespondPasswordVerifier carries inputUsername`() { + val event = SRPEvent.EventType.RetryRespondPasswordVerifier( + challengeParameters = mapOf("USERNAME" to "cognito-sub"), + metadata = emptyMap(), + session = "session-1", + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + inputUsername = "user@example.com" + ) + + event.inputUsername shouldBe "user@example.com" + } + + // --- evaluateNextStep tests --- + + @Test + fun `evaluateNextStep sets inputUsername on SignedInData for successful auth`() { + val dummyToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4g" + + "RG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o" + + val result = SignInChallengeHelper.evaluateNextStep( + username = "cognito-sub-uuid", + challengeNameType = null, + session = null, + authenticationResult = AuthenticationResultType.invoke { + accessToken = dummyToken + idToken = dummyToken + refreshToken = "refresh" + expiresIn = 3600 + }, + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + inputUsername = "user@example.com" + ) + + // Without newDeviceMetadata, this produces a SignInCompleted event + result.shouldBeInstanceOf() + val eventType = (result as AuthenticationEvent).eventType + eventType.shouldBeInstanceOf() + val signedInData = (eventType as AuthenticationEvent.EventType.SignInCompleted).signedInData + signedInData.inputUsername shouldBe "user@example.com" + signedInData.username shouldBe "cognito-sub-uuid" + } + + @Test + fun `evaluateNextStep sets inputUsername on SignedInData for ConfirmDevice event`() { + val dummyToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4g" + + "RG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o" + + val result = SignInChallengeHelper.evaluateNextStep( + username = "cognito-sub-uuid", + challengeNameType = null, + session = null, + authenticationResult = AuthenticationResultType.invoke { + accessToken = dummyToken + idToken = dummyToken + refreshToken = "refresh" + expiresIn = 3600 + newDeviceMetadata { + deviceKey = "device-key-1" + deviceGroupKey = "device-group-1" + } + }, + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + inputUsername = "user@example.com" + ) + + result.shouldBeInstanceOf() + val eventType = (result as SignInEvent).eventType + eventType.shouldBeInstanceOf() + val signedInData = (eventType as SignInEvent.EventType.ConfirmDevice).signedInData + signedInData.inputUsername shouldBe "user@example.com" + signedInData.username shouldBe "cognito-sub-uuid" + } + + @Test + fun `evaluateNextStep sets inputUsername on AuthChallenge for challenge events`() { + val result = SignInChallengeHelper.evaluateNextStep( + username = "cognito-sub-uuid", + challengeNameType = ChallengeNameType.SmsMfa, + session = "session-1", + challengeParameters = mapOf( + "CODE_DELIVERY_DELIVERY_MEDIUM" to "sms", + "CODE_DELIVERY_DESTINATION" to "+15555555555" + ), + authenticationResult = null, + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + inputUsername = "user@example.com" + ) + + result.shouldBeInstanceOf() + val eventType = (result as SignInEvent).eventType + eventType.shouldBeInstanceOf() + val challenge = (eventType as SignInEvent.EventType.ReceivedChallenge).challenge + challenge.inputUsername shouldBe "user@example.com" + challenge.username shouldBe "cognito-sub-uuid" + } + + @Test + fun `evaluateNextStep sets inputUsername on AuthChallenge for SelectChallenge`() { + val result = SignInChallengeHelper.evaluateNextStep( + username = "cognito-sub-uuid", + challengeNameType = ChallengeNameType.SelectChallenge, + session = "session-1", + availableChallenges = listOf("EMAIL_OTP", "SMS_OTP"), + authenticationResult = null, + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_AUTH), + inputUsername = "user@example.com" + ) + + result.shouldBeInstanceOf() + val eventType = (result as SignInEvent).eventType + eventType.shouldBeInstanceOf() + val challenge = (eventType as SignInEvent.EventType.ReceivedChallenge).challenge + challenge.inputUsername shouldBe "user@example.com" + } + + @Test + fun `evaluateNextStep sets inputUsername on AuthChallenge for MfaSetup`() { + val result = SignInChallengeHelper.evaluateNextStep( + username = "cognito-sub-uuid", + challengeNameType = ChallengeNameType.MfaSetup, + session = "session-1", + challengeParameters = mapOf("MFAS_CAN_SETUP" to "\"EMAIL_OTP\""), + authenticationResult = null, + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + inputUsername = "user@example.com" + ) + + result.shouldBeInstanceOf() + val eventType = (result as SignInEvent).eventType + eventType.shouldBeInstanceOf() + val challenge = (eventType as SignInEvent.EventType.ReceivedChallenge).challenge + challenge.inputUsername shouldBe "user@example.com" + } + + @Test + fun `evaluateNextStep falls back to username when inputUsername is null`() { + val dummyToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4g" + + "RG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o" + + val result = SignInChallengeHelper.evaluateNextStep( + username = "cognito-sub-uuid", + challengeNameType = null, + session = null, + authenticationResult = AuthenticationResultType.invoke { + accessToken = dummyToken + idToken = dummyToken + refreshToken = "refresh" + expiresIn = 3600 + }, + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + inputUsername = null + ) + + result.shouldBeInstanceOf() + val eventType = (result as AuthenticationEvent).eventType + eventType.shouldBeInstanceOf() + val signedInData = (eventType as AuthenticationEvent.EventType.SignInCompleted).signedInData + // When inputUsername is null, falls back to username + signedInData.inputUsername shouldBe "cognito-sub-uuid" + } + + @Test + fun `evaluateNextStep challenge events have null inputUsername when not provided`() { + val result = SignInChallengeHelper.evaluateNextStep( + username = "cognito-sub-uuid", + challengeNameType = ChallengeNameType.SmsMfa, + session = "session-1", + challengeParameters = mapOf( + "CODE_DELIVERY_DELIVERY_MEDIUM" to "sms", + "CODE_DELIVERY_DESTINATION" to "+15555555555" + ), + authenticationResult = null, + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH) + ) + + result.shouldBeInstanceOf() + val eventType = (result as SignInEvent).eventType + eventType.shouldBeInstanceOf() + val challenge = (eventType as SignInEvent.EventType.ReceivedChallenge).challenge + challenge.inputUsername.shouldBeNull() + } + + // --- SignedInData equality tests --- + + @Test + fun `SignedInData equality includes inputUsername`() { + val tokens = CognitoUserPoolTokens( + null as String?, + null as String?, + null as String?, + 1700003600L + ) + val data1 = SignedInData( + userId = "user-123", + username = "cognito-sub", + signedInDate = Date(1700000000000), + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + cognitoUserPoolTokens = tokens, + inputUsername = "user@example.com" + ) + val data2 = SignedInData( + userId = "user-123", + username = "cognito-sub", + signedInDate = Date(1700000000000), + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + cognitoUserPoolTokens = tokens, + inputUsername = "different@example.com" + ) + val data3 = SignedInData( + userId = "user-123", + username = "cognito-sub", + signedInDate = Date(1700000000000), + signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), + cognitoUserPoolTokens = tokens, + inputUsername = "user@example.com" + ) + + (data1 == data2) shouldBe false + (data1 == data3) shouldBe true + } +} diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json b/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json index 692838311a..ce7029eee3 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json @@ -15,7 +15,8 @@ "SECRET_BLOCK": "secretBlock", "SRP_B": "def", "USERNAME": "username" - } + }, + "inputUsername": "username" }, "signInMethod": { "type": "SignInMethod.ApiBased", diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn_Password_Challenge.json b/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn_Password_Challenge.json index e482106453..63cbb53949 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn_Password_Challenge.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn_Password_Challenge.json @@ -15,7 +15,8 @@ "SECRET_BLOCK": "secretBlock", "SRP_B": "def", "USERNAME": "username" - } + }, + "inputUsername": "username" }, "signInMethod": { "type": "SignInMethod.ApiBased", diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn_With_Alias.json b/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn_With_Alias.json index 379da2c839..1f0078015d 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn_With_Alias.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn_With_Alias.json @@ -15,7 +15,8 @@ "SECRET_BLOCK": "secretBlock", "SRP_B": "def", "USERNAME": "alternateUsername" - } + }, + "inputUsername": "username" }, "signInMethod": { "type": "SignInMethod.ApiBased", diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished.json index 574fb257b8..279aee5122 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished.json @@ -19,7 +19,8 @@ }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 - } + }, + "inputUsername": "username" } }, "AuthorizationState": { @@ -43,7 +44,8 @@ }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 - } + }, + "inputUsername": "username" }, "identityId": "someIdentityId", "credentials": { diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished_User_Auth.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished_User_Auth.json index 697273f882..b1c1c258ed 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished_User_Auth.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished_User_Auth.json @@ -19,7 +19,8 @@ }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 - } + }, + "inputUsername": "username" } }, "AuthorizationState": { @@ -43,7 +44,8 @@ }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 - } + }, + "inputUsername": "username" }, "identityId": "someIdentityId", "credentials": { diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json index c9fd726ecc..16eb839d55 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json @@ -19,7 +19,8 @@ }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 - } + }, + "inputUsername": "username" } }, "AuthorizationState": { @@ -43,7 +44,8 @@ }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 - } + }, + "inputUsername": "username" } } } diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json index 25d67e471e..a6c1859558 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json @@ -19,7 +19,8 @@ }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 - } + }, + "inputUsername": "username" } }, "AuthorizationState": { diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_AwaitingUserConfirmation.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_AwaitingUserConfirmation.json index 096ee1e66d..19bebc3eab 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_AwaitingUserConfirmation.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_AwaitingUserConfirmation.json @@ -27,7 +27,8 @@ }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 - } + }, + "inputUsername": "username" }, "identityId": "someIdentityId", "credentials": { diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_SignedUp.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_SignedUp.json index c286295496..61742143ba 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_SignedUp.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_SignedUp.json @@ -27,7 +27,8 @@ }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 - } + }, + "inputUsername": "username" }, "identityId": "someIdentityId", "credentials": { diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_CustomChallenge.json b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_CustomChallenge.json index 02e9ec187e..a7e31a789a 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_CustomChallenge.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_CustomChallenge.json @@ -14,7 +14,8 @@ "SALT": "abc", "SECRET_BLOCK": "secretBlock", "SRP_B": "def" - } + }, + "inputUsername": "username" }, "signInMethod": { "type": "SignInMethod.ApiBased", diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_EmailOtp.json b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_EmailOtp.json index 4f54d61522..2022331674 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_EmailOtp.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_EmailOtp.json @@ -13,7 +13,8 @@ "parameters": { "CODE_DELIVERY_DELIVERY_MEDIUM": "EMAIL", "CODE_DELIVERY_DESTINATION": "test@****.com" - } + }, + "inputUsername": "username" }, "signInMethod": { "type": "SignInMethod.ApiBased", diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SelectChallenge.json b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SelectChallenge.json index 37fa70cbec..ab51cd829c 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SelectChallenge.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SelectChallenge.json @@ -15,7 +15,8 @@ "PASSWORD", "WEB_AUTHN", "EMAIL_OTP" - ] + ], + "inputUsername": "username" }, "signInMethod": { "type": "SignInMethod.ApiBased", diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SigningIn.json b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SigningIn.json index 825c3b4119..232811e9f1 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SigningIn.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SigningIn.json @@ -13,7 +13,8 @@ "parameters": { "CODE_DELIVERY_DELIVERY_MEDIUM": "SMS", "CODE_DELIVERY_DESTINATION": "+12345678900" - } + }, + "inputUsername": "username" }, "signInMethod": { "type": "SignInMethod.ApiBased", diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SigningIn_Custom.json b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SigningIn_Custom.json index 16d9ab91e3..bccd40bca5 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SigningIn_Custom.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SigningIn_Custom.json @@ -13,7 +13,8 @@ "parameters": { "CODE_DELIVERY_DELIVERY_MEDIUM": "SMS", "CODE_DELIVERY_DESTINATION": "+12345678900" - } + }, + "inputUsername": "username" }, "signInMethod": { "type": "SignInMethod.ApiBased", diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SmsOtp.json b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SmsOtp.json index 949e1b311b..b65a4b9313 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SmsOtp.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SigningIn_SmsOtp.json @@ -13,7 +13,8 @@ "parameters": { "CODE_DELIVERY_DELIVERY_MEDIUM": "SMS", "CODE_DELIVERY_DESTINATION": "+12345678900" - } + }, + "inputUsername": "username" }, "signInMethod": { "type": "SignInMethod.ApiBased",