Skip to content

Commit

Permalink
feat: add support for email mfa (#94)
Browse files Browse the repository at this point in the history
* add support for email mfa code

* adding support for mfa setup selection and setting up email

* Apply suggestions from code review

Co-authored-by: Sebastian Villena <[email protected]>

* worked on review comments

* update strings and some logics

* missed update

* fix conflicts

* pushing a test.

* update sign in step to confirmSignInWithOTP

* Update Sources/Authenticator/Views/ConfirmSignInWithOTPView.swift

Co-authored-by: Sebastian Villena <[email protected]>

* Update Sources/Authenticator/Views/ConfirmSignInWithOTPView.swift

Co-authored-by: Sebastian Villena <[email protected]>

* Update Sources/Authenticator/Views/ConfirmSignInWithOTPView.swift

Co-authored-by: Sebastian Villena <[email protected]>

* worked on review comment

* updated to match Android

* fix failing tests

* add/update UI Tests and snapshot images

* trying out ui tests

* update

* missing added file

* adding ui tests for next steps

* revert the package swift for release

* Update Sources/Authenticator/Views/Internal/ConfirmSignInWithCodeView.swift

* Update Sources/Authenticator/Views/Internal/ConfirmSignInWithCodeView.swift

* Update Sources/Authenticator/Views/Internal/ConfirmSignInWithCodeView.swift

* Update Sources/Authenticator/Views/Internal/ConfirmSignInWithCodeView.swift

* update workflow to get the the latest package dependencies

* update workflow

* another update

* update

* update

* update

* update package.resolved to remove email mfa support branch reference

* update amplify version dependency

---------

Co-authored-by: Sebastian Villena <[email protected]>
  • Loading branch information
harsh62 and sebaland authored Oct 31, 2024
1 parent 1ec95fb commit 541ec6e
Show file tree
Hide file tree
Showing 55 changed files with 1,095 additions and 123 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/ui_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Run UI Tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
ui-test-ios:
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2

- name: Resolve and update Swift packages
run: xcodebuild -resolvePackageDependencies -scheme Authenticator

- name: UI test Authenticator on iOS
working-directory: Tests/AuthenticatorHostApp
run: |
xcodebuild -resolvePackageDependencies -scheme Authenticator
xcodebuild test -scheme AuthenticatorHostApp -sdk 'iphonesimulator' -destination 'platform=iOS Simulator,name=iPhone 16 Pro Max,OS=latest' -derivedDataPath Build/ -clonedSourcePackagesDirPath ~/Library/Developer/Xcode/DerivedData/Authenticator | xcpretty --simple --color --report junit && exit ${PIPESTATUS[0]}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ amplifyconfiguration.dart
amplify-build-config.json
amplify-gradle-config.json
amplifytools.xcconfig
.secret-*
.secret-*
Tests/AuthenticatorHostApp/AuthenticatorHostApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 1.2.0 (2024-10-31)

### Feature
- **Authenticator**: Adding support for Email MFA (#96)

## 1.1.8 (2024-09-20)

### Bug Fixes
Expand Down
20 changes: 10 additions & 10 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/aws-amplify/amplify-swift",
"state" : {
"revision" : "dbc4a0412f4b5cd96f3e756e78bbd1e8e0a35a2f",
"version" : "2.35.4"
"revision" : "aef29d1665f9fad1c88fa6a781b8c847913dd7c6",
"version" : "2.44.0"
}
},
{
Expand All @@ -23,26 +23,26 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/awslabs/aws-crt-swift",
"state" : {
"revision" : "0d0a0cf2e2cb780ceeceac190b4ede94f4f96902",
"version" : "0.26.0"
"revision" : "7b42e0343f28b3451aab20840dc670abd12790bd",
"version" : "0.36.0"
}
},
{
"identity" : "aws-sdk-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/awslabs/aws-sdk-swift.git",
"state" : {
"revision" : "47922c05dd66be717c7bce424651a534456717b7",
"version" : "0.36.2"
"revision" : "828358a2c39d138325b0f87a2d813f4b972e5f4f",
"version" : "1.0.0"
}
},
{
"identity" : "smithy-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/smithy-lang/smithy-swift",
"state" : {
"revision" : "8a5b0105c1b8a1d26a9435fb0af3959a7f5de578",
"version" : "0.41.1"
"revision" : "0ed3440f8c41e27a0937364d5035d2d4fefb8aa3",
"version" : "0.71.0"
}
},
{
Expand All @@ -59,8 +59,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "e97a6fcb1ab07462881ac165fdbb37f067e205d5",
"version" : "1.5.4"
"revision" : "9cb486020ebf03bfa5b5df985387a14a98744537",
"version" : "1.6.1"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ let package = Package(
targets: ["Authenticator"]),
],
dependencies: [
.package(url: "https://github.com/aws-amplify/amplify-swift", from: "2.35.0"),
.package(url: "https://github.com/aws-amplify/amplify-swift", from: "2.44.0"),
],
targets: [
.target(
Expand Down
51 changes: 45 additions & 6 deletions Sources/Authenticator/Authenticator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ public struct Authenticator<LoadingContent: View,
SignInContent: View,
ConfirmSignInWithNewPasswordContent: View,
ConfirmSignInWithMFACodeContent: View,
ConfirmSignInWithOTPContent: View,
ConfirmSignInWithTOTPCodeContent: View,
ContinueSignInWithMFASelectionContent: View,
ContinueSignInWithMFASetupSelectionContent: View,
ContinueSignInWithEmailMFASetupContent: View,
ContinueSignInWithTOTPSetupContent: View,
ConfirmSignInWithCustomChallengeContent: View,
SignUpContent: View,
Expand All @@ -37,10 +40,13 @@ public struct Authenticator<LoadingContent: View,
private var contentStates: NSHashTable<AuthenticatorBaseState> = .weakObjects()
private let loadingContent: LoadingContent
private let signInContent: SignInContent
private let confirmSignInContentWithMFACodeContent: ConfirmSignInWithMFACodeContent
private let confirmSignInWithMFACodeContent: ConfirmSignInWithMFACodeContent
private let confirmSignInWithOTPContent: (ConfirmSignInWithCodeState) -> ConfirmSignInWithOTPContent
private let confirmSignInWithTOTPCodeContent: (ConfirmSignInWithCodeState) -> ConfirmSignInWithTOTPCodeContent
private let continueSignInWithMFASelectionContent: (ContinueSignInWithMFASelectionState) -> ContinueSignInWithMFASelectionContent
private let continueSignInWithMFASetupSelectionContent: (ContinueSignInWithMFASetupSelectionState) -> ContinueSignInWithMFASetupSelectionContent
private let continueSignInWithTOTPSetupContent: (ContinueSignInWithTOTPSetupState) -> ContinueSignInWithTOTPSetupContent
private let continueSignInWithEmailMFASetupContent: (ContinueSignInWithEmailMFASetupState) -> ContinueSignInWithEmailMFASetupContent
private let confirmSignInContentWithCustomChallengeContent: ConfirmSignInWithCustomChallengeContent
private let confirmSignInContentWithNewPasswordContent: ConfirmSignInWithNewPasswordContent
private let signUpContent: SignUpContent
Expand All @@ -65,12 +71,18 @@ public struct Authenticator<LoadingContent: View,
/// Defaults to a ``SignInView``.
/// - Parameter confirmSignInWithMFACodeContent: The content associated with the ``AuthenticatorStep/confirmSignInWithMFACode`` step.
/// Defaults to a ``ConfirmSignInWithMFACodeView``.
/// - Parameter confirmSignInWithOTPContent: The content associated with the ``AuthenticatorStep/confirmSignInWithOTP`` step.
/// Defaults to a ``ConfirmSignInWithOTPView``.
///- Parameter confirmSignInWithTOTPCodeContent: The content associated with the ``AuthenticatorStep/confirmSignInWithTOTPCode`` step.
/// Defaults to a ``ConfirmSignInWithMFACodeView``.
///- Parameter continueSignInWithMFASelectionContent: The content associated with the ``AuthenticatorStep/continueSignInWithMFASelection`` step.
/// Defaults to a ``ContinueSignInWithMFASelectionView``.
///- Parameter continueSignInWithMFASetupSelectionContent: The content associated with the ``AuthenticatorStep/continueSignInWithMFASetupSelection`` step.
/// Defaults to a ``ContinueSignInWithMFASetupSelectionView``.
///- Parameter continueSignInWithTOTPSetupContent: The content associated with the ``AuthenticatorStep/continueSignInWithTOTPSetup`` step.
/// Defaults to a ``ContinueSignInWithTOTPSetupView``.
///- Parameter continueSignInWithEmailMFASetupContent: The content associated with the ``AuthenticatorStep/continueSignInWithEmailMFASetup`` step.
/// Defaults to a ``ContinueSignInWithEmailMFASetupView``.
/// - Parameter confirmSignInWithCustomChallengeContent: The content associated with the ``AuthenticatorStep/confirmSignInWithCustomChallenge`` step.
/// Defaults to a ``ConfirmSignInWithCustomChallengeView``.
/// - Parameter confirmSignInWithNewPasswordContent: The content associated with the ``AuthenticatorStep/confirmSignInWithNewPassword`` step.
Expand Down Expand Up @@ -106,15 +118,24 @@ public struct Authenticator<LoadingContent: View,
@ViewBuilder confirmSignInWithMFACodeContent: (ConfirmSignInWithCodeState) -> ConfirmSignInWithMFACodeContent = { state in
ConfirmSignInWithMFACodeView(state: state)
},
@ViewBuilder confirmSignInWithOTPContent: @escaping (ConfirmSignInWithCodeState) -> ConfirmSignInWithOTPContent = { state in
ConfirmSignInWithOTPView(state: state)
},
@ViewBuilder confirmSignInWithTOTPCodeContent: @escaping (ConfirmSignInWithCodeState) -> ConfirmSignInWithTOTPCodeContent = { state in
ConfirmSignInWithTOTPView(state: state)
},
@ViewBuilder continueSignInWithMFASelectionContent: @escaping (ContinueSignInWithMFASelectionState) -> ContinueSignInWithMFASelectionContent = { state in
ContinueSignInWithMFASelectionView(state: state)
},
@ViewBuilder continueSignInWithMFASetupSelectionContent: @escaping (ContinueSignInWithMFASetupSelectionState) -> ContinueSignInWithMFASetupSelectionContent = { state in
ContinueSignInWithMFASetupSelectionView(state: state)
},
@ViewBuilder continueSignInWithTOTPSetupContent: @escaping (ContinueSignInWithTOTPSetupState) -> ContinueSignInWithTOTPSetupContent = { state in
ContinueSignInWithTOTPSetupView(state: state)
},
@ViewBuilder continueSignInWithEmailMFASetupContent: @escaping (ContinueSignInWithEmailMFASetupState) -> ContinueSignInWithEmailMFASetupContent = { state in
ContinueSignInWithEmailMFASetupView(state: state)
},
@ViewBuilder confirmSignInWithCustomChallengeContent: (ConfirmSignInWithCodeState) -> ConfirmSignInWithCustomChallengeContent = { state in
ConfirmSignInWithCustomChallengeView(state: state)
},
Expand Down Expand Up @@ -157,13 +178,15 @@ public struct Authenticator<LoadingContent: View,

let confirmSignInWithMFACodeState = ConfirmSignInWithCodeState(credentials: credentials)
contentStates.add(confirmSignInWithMFACodeState)
self.confirmSignInContentWithMFACodeContent = confirmSignInWithMFACodeContent(
self.confirmSignInWithMFACodeContent = confirmSignInWithMFACodeContent(
confirmSignInWithMFACodeState
)

self.confirmSignInWithOTPContent = confirmSignInWithOTPContent
self.confirmSignInWithTOTPCodeContent = confirmSignInWithTOTPCodeContent
self.continueSignInWithMFASelectionContent = continueSignInWithMFASelectionContent
self.continueSignInWithMFASetupSelectionContent = continueSignInWithMFASetupSelectionContent
self.continueSignInWithTOTPSetupContent = continueSignInWithTOTPSetupContent
self.continueSignInWithEmailMFASetupContent = continueSignInWithEmailMFASetupContent

let confirmSignInWithCustomChallengeState = ConfirmSignInWithCodeState(credentials: credentials)
contentStates.add(confirmSignInWithMFACodeState)
Expand Down Expand Up @@ -337,25 +360,41 @@ public struct Authenticator<LoadingContent: View,
case .confirmSignInWithNewPassword:
confirmSignInContentWithNewPasswordContent
case .confirmSignInWithMFACode:
confirmSignInContentWithMFACodeContent
confirmSignInWithMFACodeContent
case .confirmSignInWithOTP(let deliveryDetails):
let confirmSignInWithCodeState = ConfirmSignInWithCodeState(
authenticatorState: state
)
confirmSignInWithOTPContent(confirmSignInWithCodeState)
case .continueSignInWithMFASelection(let allowedMFATypes):
let continueSignInWithMFASelection = ContinueSignInWithMFASelectionState(
authenticatorState: state,
allowedMFATypes: allowedMFATypes
)
continueSignInWithMFASelectionContent(continueSignInWithMFASelection)
case .continueSignInWithMFASetupSelection(let allowedMFATypes):
let continueSignInWithMFASetupSelection = ContinueSignInWithMFASetupSelectionState(
authenticatorState: state,
allowedMFATypes: allowedMFATypes
)
continueSignInWithMFASetupSelectionContent(continueSignInWithMFASetupSelection)
case .confirmSignInWithTOTPCode:
let confirmSignInWithCodeState = ConfirmSignInWithCodeState(
authenticatorState: state
)
confirmSignInWithTOTPCodeContent(confirmSignInWithCodeState)
case .continueSignInWithTOTPSetup(let totpSetupDetails):
let totpStupState = ContinueSignInWithTOTPSetupState(
let totpSetupState = ContinueSignInWithTOTPSetupState(
authenticatorState: state,
issuer: totpOptions.issuer,
totpSetupDetails: totpSetupDetails
)
continueSignInWithTOTPSetupContent(totpStupState)
continueSignInWithTOTPSetupContent(totpSetupState)
case .continueSignInWithEmailMFASetup:
let emailMFASetupState = ContinueSignInWithEmailMFASetupState(
authenticatorState: state
)
continueSignInWithEmailMFASetupContent(emailMFASetupState)
case .confirmSignInWithCustomChallenge:
confirmSignInContentWithCustomChallengeContent
case .resetPassword:
Expand Down
2 changes: 1 addition & 1 deletion Sources/Authenticator/Constants/ComponentInformation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
import Foundation

public class ComponentInformation {
public static let version = "1.1.8"
public static let version = "1.2.0"
public static let name = "amplify-ui-swift-authenticator"
}
14 changes: 13 additions & 1 deletion Sources/Authenticator/Models/AuthenticatorStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,26 @@ public struct AuthenticatorStep: Equatable {
/// so they are presented with the TOTP Setup View
public static let continueSignInWithTOTPSetup = AuthenticatorStep("continueSignInWithTOTPSetup")

/// A user has successfully provided valid Sign In credentials but is required to select a MFA type to continue
/// A user has successfully provided valid Sign In credentials but is required to select a MFA type to continue signing in
/// so they are presented with the Confirm Sign In with MFA Selection View
public static let continueSignInWithMFASelection = AuthenticatorStep("continueSignInWithMFASelection")

/// A user has successfully provided valid Sign In credentials but is required to select a MFA type to setup before completing sign in
/// so they are presented with the Confirm Sign In with MFA Setup Selection View
public static let continueSignInWithMFASetupSelection = AuthenticatorStep("continueSignInWithMFASetupSelection")

/// A user has successfully provided valid Sign In credentials but is required to setup Email MFA before continuing sign in
/// so they are presented with the Email Setup View
public static let continueSignInWithEmailMFASetup = AuthenticatorStep("continueSignInWithEmailMFASetup")

/// A user has successfully provided valid Sign In credentials but is required to provide a MFA code,
/// so they are presented with the Confirm Sign In with MFA Code view
public static let confirmSignInWithMFACode = AuthenticatorStep("confirmSignInWithMFACode")

/// A user has successfully provided valid Sign In credentials but is required to provide a OTP,
/// so they are presented with the Confirm Sign In with OTP view
public static let confirmSignInWithOTP = AuthenticatorStep("confirmSignInWithOTP")

/// A user has successfully provided valid Sign In credentials but is required to change their password,
/// so they are presented with the Confirm Sign In with New Password view
public static let confirmSignInWithNewPassword = AuthenticatorStep("confirmSignInWithNewPassword")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
// SPDX-License-Identifier: Apache-2.0
//

enum AuthenticatorMFAType {
enum AuthenticatorFactorType {
case sms
case email
case totp
case none
}
9 changes: 9 additions & 0 deletions Sources/Authenticator/Models/Internal/Step.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ enum Step {
case confirmSignInWithCustomChallenge
case confirmSignInWithTOTPCode
case continueSignInWithMFASelection(allowedMFATypes: AllowedMFATypes)
case continueSignInWithMFASetupSelection(allowedMFATypes: AllowedMFATypes)
case continueSignInWithEmailMFASetup
case continueSignInWithTOTPSetup(totpSetupDetails: TOTPSetupDetails)
case confirmSignInWithMFACode(deliveryDetails: AuthCodeDeliveryDetails?)
case confirmSignInWithOTP(deliveryDetails: AuthCodeDeliveryDetails?)
case confirmSignInWithNewPassword
case signUp
case confirmSignUp(deliveryDetails: AuthCodeDeliveryDetails?)
Expand Down Expand Up @@ -55,8 +58,14 @@ enum Step {
return .continueSignInWithTOTPSetup
case .continueSignInWithMFASelection:
return .continueSignInWithMFASelection
case .continueSignInWithMFASetupSelection:
return .continueSignInWithMFASetupSelection
case .continueSignInWithEmailMFASetup:
return .continueSignInWithEmailMFASetup
case .confirmSignInWithMFACode:
return .confirmSignInWithMFACode
case .confirmSignInWithOTP:
return .confirmSignInWithOTP
case .confirmSignInWithNewPassword:
return .confirmSignInWithNewPassword
case .signUp:
Expand Down
Loading

0 comments on commit 541ec6e

Please sign in to comment.