From 4f43a277961d6039b195a06b66a62ec38da30c05 Mon Sep 17 00:00:00 2001 From: Harshdeep Singh <6162866+harsh62@users.noreply.github.com> Date: Mon, 3 Jul 2023 12:06:17 -0400 Subject: [PATCH] feat(Auth): Adding TOTP support in Amplify Auth category (#3040) * feat(Auth): Adding TOTP support in Amplify Auth category * worked on review comments * adding more detailed comments for the new API's --- .../Auth/AuthCategory+ClientBehavior.swift | 14 +++++++ .../Auth/AuthCategoryBehavior.swift | 25 +++++++++++ .../Auth/Models/AuthSignInStep.swift | 16 +++++++ Amplify/Categories/Auth/Models/MFAType.swift | 15 +++++++ .../Auth/Models/TOTPSetupDetails.swift | 42 +++++++++++++++++++ .../Auth/Request/SetUpTOTPRequest.swift | 34 +++++++++++++++ .../Auth/Request/VerifyTOTPSetupRequest.swift | 40 ++++++++++++++++++ 7 files changed, 186 insertions(+) create mode 100644 Amplify/Categories/Auth/Models/MFAType.swift create mode 100644 Amplify/Categories/Auth/Models/TOTPSetupDetails.swift create mode 100644 Amplify/Categories/Auth/Request/SetUpTOTPRequest.swift create mode 100644 Amplify/Categories/Auth/Request/VerifyTOTPSetupRequest.swift diff --git a/Amplify/Categories/Auth/AuthCategory+ClientBehavior.swift b/Amplify/Categories/Auth/AuthCategory+ClientBehavior.swift index 73ca4510d0..ada370642f 100644 --- a/Amplify/Categories/Auth/AuthCategory+ClientBehavior.swift +++ b/Amplify/Categories/Auth/AuthCategory+ClientBehavior.swift @@ -74,4 +74,18 @@ extension AuthCategory: AuthCategoryBehavior { ) async throws { try await plugin.confirmResetPassword(for: username, with: newPassword, confirmationCode: confirmationCode, options: options) } + + public func setUpTOTP( + options: SetUpTOTPRequest.Options? = nil + ) async throws -> TOTPSetupDetails { + try await plugin.setUpTOTP(options: options) + } + + public func verifyTOTPSetup( + code: String, + options: VerifyTOTPSetupRequest.Options? = nil + ) async throws { + try await plugin.verifyTOTPSetup(code: code, options: options) + } + } diff --git a/Amplify/Categories/Auth/AuthCategoryBehavior.swift b/Amplify/Categories/Auth/AuthCategoryBehavior.swift index 4a1b4a9dcf..0bb470e5c0 100644 --- a/Amplify/Categories/Auth/AuthCategoryBehavior.swift +++ b/Amplify/Categories/Auth/AuthCategoryBehavior.swift @@ -124,4 +124,29 @@ public protocol AuthCategoryBehavior: AuthCategoryUserBehavior, AuthCategoryDevi /// - options: Parameters specific to plugin behavior func confirmResetPassword(for username: String, with newPassword: String, confirmationCode: String, options: AuthConfirmResetPasswordRequest.Options?) async throws + /// Initiates TOTP Setup + /// + /// Invoke this operation to setup TOTP for the user while signed in. + /// Calling this method will initiate TOTP setup process and returns a shared secret that can be used to generate QR code. + /// The setup details also contains a URI generator helper that can be used to retireve a TOTP Setup URI. + /// + /// - Parameters: + /// - options: Parameters specific to plugin behavior + func setUpTOTP( + options: SetUpTOTPRequest.Options? + ) async throws -> TOTPSetupDetails + + /// Verifies TOTP Setup + /// + /// Invoke this operation to verify TOTP setup for the user while signed in. + /// Calling this method with the verification code from the associated Authenticator app will complete the TOTP setup process. + /// + /// - Parameters: + /// - code: verification code from the associated Authenticator app + /// - options: Parameters specific to plugin behavior + func verifyTOTPSetup( + code: String, + options: VerifyTOTPSetupRequest.Options? + ) async throws + } diff --git a/Amplify/Categories/Auth/Models/AuthSignInStep.swift b/Amplify/Categories/Auth/Models/AuthSignInStep.swift index a7d2b2c5b7..e99fc9adf4 100644 --- a/Amplify/Categories/Auth/Models/AuthSignInStep.swift +++ b/Amplify/Categories/Auth/Models/AuthSignInStep.swift @@ -5,6 +5,9 @@ // SPDX-License-Identifier: Apache-2.0 // +/// Set of allowed MFA types that would be used for continuing sign in during MFA selection step +public typealias AllowedMFATypes = Set + /// Auth SignIn flow steps /// /// @@ -23,6 +26,19 @@ public enum AuthSignInStep { /// case confirmSignInWithNewPassword(AdditionalInfo?) + /// Auth step is TOTP multi factor authentication. + /// + /// Confirmation code for the MFA will be retrieved from the associated Authenticator app + case confirmSignInWithTOTPCode + + /// Auth step is for continuing sign in by setting up TOTP multi factor authentication. + /// + case continueSignInWithTOTPSetup(TOTPSetupDetails) + + /// Auth step is for continuing sign in by selecting multi factor authentication type + /// + case continueSignInWithMFASelection(AllowedMFATypes) + /// Auth step required the user to change their password. /// case resetPassword(AdditionalInfo?) diff --git a/Amplify/Categories/Auth/Models/MFAType.swift b/Amplify/Categories/Auth/Models/MFAType.swift new file mode 100644 index 0000000000..2726503aa1 --- /dev/null +++ b/Amplify/Categories/Auth/Models/MFAType.swift @@ -0,0 +1,15 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +public enum MFAType: String { + + /// Short Messaging Service linked with a phone number + case sms + + /// Time-based One Time Password linked with an authenticator app + case totp +} diff --git a/Amplify/Categories/Auth/Models/TOTPSetupDetails.swift b/Amplify/Categories/Auth/Models/TOTPSetupDetails.swift new file mode 100644 index 0000000000..608ddcab77 --- /dev/null +++ b/Amplify/Categories/Auth/Models/TOTPSetupDetails.swift @@ -0,0 +1,42 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation + +public struct TOTPSetupDetails { + + /// Secret code returned by the service to help setting up TOTP + public let sharedSecret: String + + /// username that will be used to construct the URI + public let username: String + + public init(sharedSecret: String, username: String) { + self.sharedSecret = sharedSecret + self.username = username + } + /// Returns a TOTP setup URI that can help the customers avoid barcode scanning and use native password manager to handle TOTP association + /// Example: On iOS and MacOS, URI will redirect to associated Password Manager for the platform + /// + /// throws AuthError.validation if a `URL` cannot be formed with the supplied parameters + /// (for example, if the parameter string contains characters that are illegal in a URL, or is an empty string). + public func getSetupURI( + appName: String, + accountName: String? = nil) throws -> URL { + guard let URL = URL( + string: "otpauth://totp/\(appName):\(accountName ?? username)?secret=\(sharedSecret)&issuer=\(appName)") else { + + throw AuthError.validation( + "appName or accountName", + "Invalid Parameters. Cannot form URL from the supplied appName or accountName", + "Please make sure that the supplied parameters don't contain any characters that are illegal in a URL or is an empty String", + nil) + } + return URL + } + +} diff --git a/Amplify/Categories/Auth/Request/SetUpTOTPRequest.swift b/Amplify/Categories/Auth/Request/SetUpTOTPRequest.swift new file mode 100644 index 0000000000..6c549cffb9 --- /dev/null +++ b/Amplify/Categories/Auth/Request/SetUpTOTPRequest.swift @@ -0,0 +1,34 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation + +/// Request to set up TOTP +public struct SetUpTOTPRequest: AmplifyOperationRequest { + + /// Extra request options defined in `SetUpTOTPRequest.Options` + public var options: Options + + public init(options: Options) { + self.options = options + } +} + +public extension SetUpTOTPRequest { + + 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 + } + } +} diff --git a/Amplify/Categories/Auth/Request/VerifyTOTPSetupRequest.swift b/Amplify/Categories/Auth/Request/VerifyTOTPSetupRequest.swift new file mode 100644 index 0000000000..4a03d3ff21 --- /dev/null +++ b/Amplify/Categories/Auth/Request/VerifyTOTPSetupRequest.swift @@ -0,0 +1,40 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation + +/// Request to verify TOTP setup +public struct VerifyTOTPSetupRequest: AmplifyOperationRequest { + + /// Code from the associated Authenticator app that will be used for verification + public var code: String + + /// Extra request options defined in `VerifyTOTPSetupRequest.Options` + public var options: Options + + public init( + code: String, + options: Options) { + self.code = code + self.options = options + } +} + +public extension VerifyTOTPSetupRequest { + + 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 + } + } +}