Skip to content

Commit

Permalink
fix(auth): fix resolvers and tasks for auto sign in when state machin…
Browse files Browse the repository at this point in the history
…e is in signing in state (#172)

* fix(auth): fix resolvers and tasks for auto sign in when state machine is in signin in state

* fix indentation
  • Loading branch information
thisisabhash authored Nov 15, 2024
1 parent ed7fbf9 commit 19eeb30
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class AWSAuthAutoSignInTask: AuthAutoSignInTask, DefaultLogger {
log.verbose("Received result")
return result
} catch {
await waitForSignInCancel()
throw error
}
}
Expand Down Expand Up @@ -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
Expand All @@ -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 }

Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import AWSCognitoIdentity
import AWSCognitoIdentityProvider
@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime

class AutoSignInTests: BasePluginTest {
class AWSAuthAutoSignInTests: BasePluginTest {

override var initialState: AuthState {
AuthState.configured(
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -331,7 +404,6 @@ class AutoSignInTests: BasePluginTest {
}
}


// MARK: - Service error for initiateAuth

/// Test a autoSignIn with an `InternalErrorException` from service
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
},
{
Expand Down

0 comments on commit 19eeb30

Please sign in to comment.