Skip to content

Commit 2348fcb

Browse files
fix(auth): add missing state transitions during auto sign in (#4065)
* fix(auth): add missing state transitions during auto sign in * add unit test * fix swiftformat issues --------- Co-authored-by: Abhash Kumar Singh <[email protected]>
1 parent ff88fd8 commit 2348fcb

File tree

3 files changed

+96
-20
lines changed

3 files changed

+96
-20
lines changed

AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/StateMachine/Resolvers/SignIn/SignInState+Resolver.swift

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,48 @@ extension SignInState {
684684
)
685685
#endif
686686

687-
case .autoSigningIn:
687+
case .autoSigningIn(let signInEventData):
688+
689+
if let signInEvent = event as? SignInEvent,
690+
case .receivedChallenge(let challenge) = signInEvent.eventType {
691+
let action = InitializeResolveChallenge(
692+
challenge: challenge,
693+
signInMethod: signInEventData.signInMethod
694+
)
695+
let subState = SignInChallengeState.notStarted
696+
return .init(
697+
newState:
698+
.resolvingChallenge(
699+
subState,
700+
challenge.challenge.authChallengeType,
701+
signInEventData.signInMethod
702+
),
703+
actions: [action]
704+
)
705+
}
706+
707+
if let signInEvent = event as? SignInEvent,
708+
case .initiateDeviceSRP(let username, let challengeResponse) = signInEvent.eventType {
709+
let action = StartDeviceSRPFlow(
710+
username: username,
711+
authResponse: challengeResponse
712+
)
713+
return .init(
714+
newState: .resolvingDeviceSrpa(.notStarted),
715+
actions: [action]
716+
)
717+
}
718+
719+
if let signInEvent = event as? SignInEvent,
720+
case .initiateTOTPSetup(_, let challengeResponse) = signInEvent.eventType {
721+
let action = InitializeTOTPSetup(
722+
authResponse: challengeResponse)
723+
return .init(
724+
newState: .resolvingTOTPSetup(.notStarted, signInEventData),
725+
actions: [action]
726+
)
727+
}
728+
688729
if case .finalizeSignIn(let signedInData) = event.isSignInEvent {
689730
return .init(
690731
newState: .signedIn(signedInData),

AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/AWSAuthAutoSignInTests.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,41 @@ class AWSAuthAutoSignInTests: BasePluginTest {
5959
}
6060
}
6161

62+
/// Test auto sign in success
63+
///
64+
/// - Given: Given an auth plugin with mocked service set up to return `.selectChallenge` with `.password` and `.passwordSrp`
65+
/// for `InitiateAuth` and in signed up state
66+
/// - When:
67+
/// - I invoke autoSignIn
68+
/// - Then:
69+
/// - I should get a result with `.continueSignInWithFirstFactorSelection`
70+
///
71+
func testAutoSignInSuccessWithContinueFirstFactorSelection() async {
72+
mockIdentityProvider = MockIdentityProvider(
73+
mockInitiateAuthResponse: { input in
74+
return InitiateAuthOutput(
75+
availableChallenges: [.password, .passwordSrp],
76+
challengeName: .selectChallenge,
77+
session: "session"
78+
)
79+
}
80+
)
81+
82+
do {
83+
let result = try await plugin.autoSignIn()
84+
guard case .continueSignInWithFirstFactorSelection(let authFactorTypes) = result.nextStep else {
85+
XCTFail("Result should be .continueSignInWithFirstFactorSelection for next step")
86+
return
87+
}
88+
89+
XCTAssertTrue(authFactorTypes.count == 2)
90+
XCTAssertTrue(authFactorTypes.contains(.password))
91+
XCTAssertTrue(authFactorTypes.contains(.passwordSRP))
92+
} catch {
93+
XCTFail("Received failure with error \(error)")
94+
}
95+
}
96+
6297
/// Test auto sign in success
6398
///
6499
/// - Given: Given an auth plugin with mocked service and in `.signingIn` authentication state and

AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/CredentialStore/CredentialStoreConfigurationTests.swift

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -591,40 +591,40 @@ class CredentialStoreConfigurationTests: AWSAuthBaseTest {
591591
Defaults.makeDefaultUserPoolConfigData(),
592592
Defaults.makeIdentityConfigData()
593593
)
594-
594+
595595
#if os(watchOS)
596596
let accessGroup = keychainAccessGroupWatch
597597
#else
598598
let accessGroup = keychainAccessGroup
599599
#endif
600-
600+
601601
let credentialStore = AWSCognitoAuthCredentialStore(
602602
authConfiguration: authConfig,
603603
accessGroup: accessGroup
604604
)
605-
605+
606606
do {
607607
try credentialStore.saveCredential(initialCognitoCredentials)
608608
} catch {
609609
XCTFail("Unable to save credentials")
610610
}
611-
611+
612612
// Verify credentials are saved
613613
guard let savedCredentials = try? credentialStore.retrieveCredential() else {
614614
XCTFail("Unable to retrieve saved credentials")
615615
return
616616
}
617617
XCTAssertNotNil(savedCredentials)
618-
618+
619619
// When: Simulate fresh install by clearing UserDefaults flag
620620
UserDefaults.standard.removeObject(forKey: "amplify_secure_storage_scopes.awsCognitoAuthPlugin.isKeychainConfigured")
621-
621+
622622
// Initialize new credential store with same access group (simulates app extension scenario)
623623
let newCredentialStore = AWSCognitoAuthCredentialStore(
624624
authConfiguration: authConfig,
625625
accessGroup: accessGroup
626626
)
627-
627+
628628
// Then: Shared keychain credentials should NOT be cleared
629629
guard let retrievedCredentials = try? newCredentialStore.retrieveCredential(),
630630
case .userPoolAndIdentityPool(
@@ -635,7 +635,7 @@ class CredentialStoreConfigurationTests: AWSAuthBaseTest {
635635
XCTFail("Shared keychain credentials should not be cleared")
636636
return
637637
}
638-
638+
639639
XCTAssertNotNil(retrievedCredentials)
640640
XCTAssertNotNil(retrievedTokens)
641641
XCTAssertNotNil(retrievedIdentityID)
@@ -663,28 +663,28 @@ class CredentialStoreConfigurationTests: AWSAuthBaseTest {
663663
Defaults.makeDefaultUserPoolConfigData(),
664664
Defaults.makeIdentityConfigData()
665665
)
666-
666+
667667
let credentialStore = AWSCognitoAuthCredentialStore(authConfiguration: authConfig)
668-
668+
669669
do {
670670
try credentialStore.saveCredential(initialCognitoCredentials)
671671
} catch {
672672
XCTFail("Unable to save credentials")
673673
}
674-
674+
675675
// Verify credentials are saved
676676
guard let savedCredentials = try? credentialStore.retrieveCredential() else {
677677
XCTFail("Unable to retrieve saved credentials")
678678
return
679679
}
680680
XCTAssertNotNil(savedCredentials)
681-
681+
682682
// When: Simulate fresh install by clearing UserDefaults flag
683683
UserDefaults.standard.removeObject(forKey: "amplify_secure_storage_scopes.awsCognitoAuthPlugin.isKeychainConfigured")
684-
684+
685685
// Initialize new credential store without access group
686686
let newCredentialStore = AWSCognitoAuthCredentialStore(authConfiguration: authConfig)
687-
687+
688688
// Then: Non-shared keychain credentials should be cleared
689689
let retrievedCredentials = try? newCredentialStore.retrieveCredential()
690690
XCTAssertNil(retrievedCredentials, "Non-shared keychain credentials should be cleared on fresh install")
@@ -702,24 +702,24 @@ class CredentialStoreConfigurationTests: AWSAuthBaseTest {
702702
Defaults.makeIdentityConfigData()
703703
)
704704
let userDefaultsKey = "amplify_secure_storage_scopes.awsCognitoAuthPlugin.isKeychainConfigured"
705-
705+
706706
// Test without access group
707707
UserDefaults.standard.removeObject(forKey: userDefaultsKey)
708708
XCTAssertFalse(UserDefaults.standard.bool(forKey: userDefaultsKey))
709-
709+
710710
_ = AWSCognitoAuthCredentialStore(authConfiguration: authConfig)
711711
XCTAssertTrue(UserDefaults.standard.bool(forKey: userDefaultsKey))
712-
712+
713713
// Test with access group
714714
UserDefaults.standard.removeObject(forKey: userDefaultsKey)
715715
XCTAssertFalse(UserDefaults.standard.bool(forKey: userDefaultsKey))
716-
716+
717717
#if os(watchOS)
718718
let accessGroup = keychainAccessGroupWatch
719719
#else
720720
let accessGroup = keychainAccessGroup
721721
#endif
722-
722+
723723
_ = AWSCognitoAuthCredentialStore(
724724
authConfiguration: authConfig,
725725
accessGroup: accessGroup

0 commit comments

Comments
 (0)