diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/StateMachine/Resolvers/SignIn/SignInState+Resolver.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/StateMachine/Resolvers/SignIn/SignInState+Resolver.swift index d55d265d6a..f7cfbfb3e7 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/StateMachine/Resolvers/SignIn/SignInState+Resolver.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/StateMachine/Resolvers/SignIn/SignInState+Resolver.swift @@ -555,6 +555,14 @@ extension SignInState { return .init(newState: .signedIn(signedInData), actions: [SignInComplete(signedInData: signedInData)]) } + + if let signInEvent = event as? SignInEvent, + case .confirmDevice(let signedInData) = signInEvent.eventType { + let action = ConfirmDevice(signedInData: signedInData) + return .init(newState: .confirmingDevice, + actions: [action]) + } + if let signInEvent = event as? SignInEvent, case .throwAuthError(let error) = signInEvent.eventType { let action = ThrowSignInError(error: error) diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthAutoSignInTask.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthAutoSignInTask.swift index de48f86c53..a7704e4621 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthAutoSignInTask.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthAutoSignInTask.swift @@ -49,6 +49,7 @@ class AWSAuthAutoSignInTask: AuthAutoSignInTask, DefaultLogger { log.verbose("Received result") return result } catch { + await waitForSignInCancel() throw error } } @@ -76,7 +77,8 @@ class AWSAuthAutoSignInTask: AuthAutoSignInTask, DefaultLogger { AuthPluginErrorConstants.invalidStateError, nil) throw error case .signingIn: - continue + log.verbose("Cancelling existing signIn flow") + await sendCancelSignInEvent() case .configured, .signedOut: return default: continue @@ -85,10 +87,11 @@ class AWSAuthAutoSignInTask: AuthAutoSignInTask, DefaultLogger { } private func doAutoSignIn() async throws -> AuthSignInResult { - let stateSequences = await authStateMachine.listen() log.verbose("Sending autoSignIn event") try await sendAutoSignInEvent() + log.verbose("Waiting for autoSignIn to complete") + let stateSequences = await authStateMachine.listen() for await state in stateSequences { guard case .configured(let authNState, let authZState, _) = state else { continue } @@ -113,7 +116,28 @@ class AWSAuthAutoSignInTask: AuthAutoSignInTask, DefaultLogger { } throw AuthError.unknown("Sign in reached an error state") } - + + private func sendCancelSignInEvent() async { + let event = AuthenticationEvent(eventType: .cancelSignIn) + await authStateMachine.send(event) + } + + private func waitForSignInCancel() async { + await sendCancelSignInEvent() + let stateSequences = await authStateMachine.listen() + log.verbose("Wait for signIn to cancel") + for await state in stateSequences { + guard case .configured(let authenticationState, _, _) = state else { + continue + } + switch authenticationState { + case .signedOut: + return + default: continue + } + } + } + private func sendAutoSignInEvent() async throws { let currentState = await authStateMachine.currentState guard case .configured(_, _, let signUpState) = currentState else { diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/AWSAuthAutoSignInTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/AWSAuthAutoSignInTests.swift index 2452700b54..48d5cc6970 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/AWSAuthAutoSignInTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/AWSAuthAutoSignInTests.swift @@ -12,7 +12,7 @@ import AWSCognitoIdentity import AWSCognitoIdentityProvider @_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime -class AutoSignInTests: BasePluginTest { +class AWSAuthAutoSignInTests: BasePluginTest { override var initialState: AuthState { AuthState.configured( @@ -56,6 +56,79 @@ class AutoSignInTests: BasePluginTest { } } + /// Test auto sign in success + /// + /// - Given: Given an auth plugin with mocked service and in `.signingIn` authentication state and + /// `.signedUp` sign up state + /// + /// - When: + /// - I invoke autoSignIn + /// - Then: + /// - I should get a successful result with tokens + /// + func testAutoSignInSuccessFromSigningInAuthenticationState() async { + let mockIdentityProvider = MockIdentityProvider( + mockSignUpResponse: { _ in + return .init( + codeDeliveryDetails: .init( + attributeName: "some attribute", + deliveryMedium: .email, + destination: "jeffb@amazon.com" + ), + userConfirmed: false, + userSub: "userSub" + ) + }, + mockInitiateAuthResponse: { input in + return InitiateAuthOutput( + authenticationResult: .init( + accessToken: Defaults.validAccessToken, + expiresIn: 300, + idToken: "idToken", + newDeviceMetadata: nil, + refreshToken: "refreshToken", + tokenType: "")) + }, + mockConfirmSignUpResponse: { request in + XCTAssertNil(request.clientMetadata) + XCTAssertNil(request.forceAliasCreation) + return .init(session: "session") + } + ) + + let initialStateSigningIn = AuthState.configured( + .signingIn(.resolvingChallenge( + .waitingForAnswer( + .init( + challenge: .emailOtp, + availableChallenges: [.emailOtp], + username: "jeffb", + session: nil, + parameters: nil), + .apiBased(.userAuth), + .confirmSignInWithOTP(.init(destination: .email("jeffb@amazon.com")))), + .emailOTP, + .apiBased(.userAuth))), + .configured, + .signedUp( + .init(username: "jeffb", session: "session"), + .init(.completeAutoSignIn("session")))) + + let authPluginSigningIn = configureCustomPluginWith(userPool: { mockIdentityProvider }, + initialState: initialStateSigningIn) + + do { + let result = try await authPluginSigningIn.autoSignIn() + guard case .done = result.nextStep else { + XCTFail("Result should be .done for next step") + return + } + XCTAssertTrue(result.isSignedIn, "Signin result should be complete") + } catch { + XCTFail("Received failure with error \(error)") + } + } + /// Test auto sign in failure /// /// - Given: Given an auth plugin with mocked service and in `.notStarted` sign up state @@ -331,7 +404,6 @@ class AutoSignInTests: BasePluginTest { } } - // MARK: - Service error for initiateAuth /// Test a autoSignIn with an `InternalErrorException` from service diff --git a/Package.resolved b/Package.resolved index 8eb8ae7446..cd8b5fc9e1 100644 --- a/Package.resolved +++ b/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/smithy-lang/smithy-swift", "state" : { - "revision" : "0d4d3eae8cfb04f3e0cbc4e7740e7344cc9fac55", - "version" : "0.87.0" + "revision" : "697ab725e92622427f536c2f2a176f0dbecb3776", + "version" : "0.90.0" } }, {