-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Auth): Add OTP API's and Tasks (#3381)
* feat(Auth): Add OTP API's and Tasks * worked on review comments
- Loading branch information
Showing
12 changed files
with
518 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
Amplify/Categories/Auth/Request/AuthSignInWithOTPRequest.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import Foundation | ||
|
||
/// Request to sign in a user with Passwordless OTP flow | ||
public struct AuthSignInWithOTPRequest: AmplifyOperationRequest { | ||
|
||
/// User name for which the passwordless OTP was initiated | ||
public let username: String | ||
|
||
/// The flow that the request should begin with. | ||
public let flow: AuthPasswordlessFlow | ||
|
||
/// The destination where the OTP will be sent | ||
public let destination: AuthPasswordlessDeliveryDestination | ||
|
||
/// Extra request options defined in `AuthSignInWithOTPRequest.Options` | ||
public var options: Options | ||
|
||
public init(username: String, | ||
flow: AuthPasswordlessFlow, | ||
destination: AuthPasswordlessDeliveryDestination, | ||
options: Options) { | ||
self.username = username | ||
self.flow = flow | ||
self.destination = destination | ||
self.options = options | ||
} | ||
} | ||
|
||
public extension AuthSignInWithOTPRequest { | ||
|
||
struct Options { | ||
|
||
/// Extra plugin specific options, only used in special circumstances when the existing options do not provide | ||
/// a way to utilize the underlying auth plugin functionality. See plugin documentation for expected | ||
/// key/values | ||
public let pluginOptions: Any? | ||
|
||
public init(pluginOptions: Any? = nil) { | ||
self.pluginOptions = pluginOptions | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
.../Sources/AWSCognitoAuthPlugin/Support/Request/AuthPasswordlessOTPRequest+Validation.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
import Amplify | ||
|
||
extension AuthConfirmSignInWithOTPRequest { | ||
|
||
func hasError() -> AuthError? { | ||
guard !challengeResponse.isEmpty else { | ||
return AuthError.validation( | ||
AuthPluginErrorConstants.confirmSignInChallengeResponseError.field, | ||
AuthPluginErrorConstants.confirmSignInChallengeResponseError.errorDescription, | ||
AuthPluginErrorConstants.confirmSignInChallengeResponseError.recoverySuggestion) | ||
} | ||
return nil | ||
} | ||
} |
123 changes: 123 additions & 0 deletions
123
AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthConfirmSignInWithOTPTask.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
import Foundation | ||
import Amplify | ||
import AWSPluginsCore | ||
|
||
class AWSAuthConfirmSignInWithOTPTask: AuthConfirmSignInWithOTPTask, DefaultLogger { | ||
|
||
private let request: AuthConfirmSignInWithOTPRequest | ||
private let authStateMachine: AuthStateMachine | ||
private let taskHelper: AWSAuthTaskHelper | ||
private let authConfiguration: AuthConfiguration | ||
|
||
var eventName: HubPayloadEventName { | ||
HubPayload.EventName.Auth.confirmSignInWithOTPAPI | ||
} | ||
|
||
init(_ request: AuthConfirmSignInWithOTPRequest, | ||
stateMachine: AuthStateMachine, | ||
configuration: AuthConfiguration) { | ||
self.request = request | ||
self.authStateMachine = stateMachine | ||
self.taskHelper = AWSAuthTaskHelper(authStateMachine: authStateMachine) | ||
self.authConfiguration = configuration | ||
} | ||
|
||
func execute() async throws -> AuthSignInResult { | ||
log.verbose("Starting execution") | ||
await taskHelper.didStateMachineConfigured() | ||
|
||
//Check if we have a user pool configuration | ||
guard authConfiguration.getUserPoolConfiguration() != nil else { | ||
let message = AuthPluginErrorConstants.configurationError | ||
let authError = AuthError.configuration( | ||
"Could not find user pool configuration", | ||
message) | ||
throw authError | ||
} | ||
|
||
if let validationError = request.hasError() { | ||
throw validationError | ||
} | ||
let invalidStateError = AuthError.invalidState( | ||
"User is not attempting signIn operation", | ||
AuthPluginErrorConstants.invalidStateError, nil) | ||
|
||
guard case .configured(let authNState, _) = await authStateMachine.currentState, | ||
case .signingIn(let signInState) = authNState else { | ||
throw invalidStateError | ||
} | ||
|
||
// [HS] TODO: Following implementations need to be complete | ||
// 1. Validate it is the correct state to confirm Sign In With OTP | ||
// 2. Send event | ||
// 3. Listent to events | ||
// 4. Complete the task | ||
guard case .resolvingChallenge(let challengeState, _, _) = signInState else { | ||
throw invalidStateError | ||
} | ||
|
||
switch challengeState { | ||
case .waitingForAnswer, .error: | ||
log.verbose("Sending confirm signIn event: \(challengeState)") | ||
await sendConfirmSignInEvent() | ||
default: | ||
throw invalidStateError | ||
} | ||
|
||
|
||
let stateSequences = await authStateMachine.listen() | ||
log.verbose("Waiting for response") | ||
for await state in stateSequences { | ||
guard case .configured(let authNState, let authZState) = state else { | ||
continue | ||
} | ||
switch authNState { | ||
case .signedIn: | ||
if case .sessionEstablished = authZState { | ||
return AuthSignInResult(nextStep: .done) | ||
} else { | ||
log.verbose("Signed In, waiting for authorization to complete") | ||
} | ||
case .error(let error): | ||
throw AuthError.unknown("Sign in reached an error state", error) | ||
|
||
case .signingIn(let signInState): | ||
guard let result = try UserPoolSignInHelper.checkNextStep(signInState) else { | ||
continue | ||
} | ||
return result | ||
case .notConfigured: | ||
throw AuthError.configuration( | ||
"UserPool configuration is missing", | ||
AuthPluginErrorConstants.configurationError) | ||
default: | ||
throw invalidStateError | ||
} | ||
} | ||
throw invalidStateError | ||
} | ||
|
||
func sendConfirmSignInEvent() async { | ||
let event = SignInChallengeEvent( | ||
eventType: .verifyChallengeAnswer(createConfirmSignInEventData())) | ||
await authStateMachine.send(event) | ||
} | ||
|
||
private func createConfirmSignInEventData() -> ConfirmSignInEventData { | ||
|
||
// [HS] TODO: Confirm if any metadata needs to be passed during confirm sign in | ||
/* | ||
* Attributes | ||
* Metadata | ||
* Device Name | ||
*/ | ||
return ConfirmSignInEventData( | ||
answer: self.request.challengeResponse) | ||
} | ||
} |
Oops, something went wrong.