Skip to content

Commit

Permalink
Merge pull request #3920 from aws-amplify/passwordless
Browse files Browse the repository at this point in the history
* feat(auth): adding support for email mfa (#3892)

* feat(auth): adding support for email mfa

* fix swift lint warning

* worked on a review comment

* adding integration tests wave 1

* integration tests wave 2

* integration tests wave 3

* Add test setup instructions wave 4

* Add edge case

* update readme to include graphQL details

* chore: initial commit to add sdk with passwordless models

* chore: model update

* feat(Auth): Adding WebAuthn APIs (#153)

* feat(Auth): Adding List WebAuthn API

* feat(Auth): Adding associate and delete WebAuthn credentials APIs

* Addding missing transports array in the credentials payload

* Adding friendlyName to AuthWebAuthnCredential

* Adding excludedCredentials to avoid multiple PassKeys for the same device

* Adding pagination support in the list API

* Renaming CredentialPayload to CredentialRegistrationPayload

* Addressing PR comments

* feat(auth): add passwordless sign with otp (#151)

* feat(auth): add passwordless OTP implementation

* add fallback password and password srp flows

* add web auth n states

* modifying states

* feat(Auth): Adding WebAuthn support to signIn and confirmSignIn APIs (#155)

* feat(auth): add passwordless OTP implementation

* add fallback password and password srp flows

* add web auth n states

* modifying states

* feat(Auth): Implementing signIn with WebAuthn

* Adding support for a presentation anchor in sign in and confirm sign in options

* Fixing errors

* Addressing PR comments

* fix build error

---------

Co-authored-by: Harshdeep Singh <6162866+harsh62@users.noreply.github.com>

* fix: Fixing build issue when iOS 18/macOS 15 are not installed

* feat(WebAuthn): Adding support for retrying a confirmSignIn with WebAuthn request, if the first one fails (#158)

* feat(auth): add support for passwordless sign up and auto sign in (#160)

* add autoSignIn() category API definitions (#152)

* add autoSignIn() category API definitions

* add sign up step for auto sign in

* add state machine changes for autoSignIn() and signUp() (#154)

* add autoSignIn() category API definitions

* add sign up step for auto sign in

* add state machine changes

* add events and update resolvers

* update sign up events and resolvers

* add updates to resolver for auto sign in

* update confirm sign up flow and debug code

* Address review comments

---------

Co-authored-by: Harsh <6162866+harsh62@users.noreply.github.com>

* update auto sign state machine events and resolver (#157)

* update auto sign state machine events and resolver

* Address review comments

* update sign up and auto sign in unit tests (#159)

* update sign up and auto sign in unit tests

* add auto sign in tests and refactor existing tests

* Add more service error tests

* Address review changes

---------

Co-authored-by: Harsh <6162866+harsh62@users.noreply.github.com>

* chore: fix building of unit tests after sign up rebase

* feat(auth): adding passwordless sign in preferred flows (#162)

* feat(auth): add passwordless preferred flow

* adding confirm device and device srp flows to user auth

* update message

* worked on review comments

* update

* chore(auth): add more auto sign in and sign up state machine/e2e unit tests (#161)

* chore(auth): add more auto sign in and sign up state machine/e2e unit tests

* Address review comments

* chore: updated SDK and models

* chore: update integration test host app

* fix: Fixing build errors in watchOS/tvOS due to missing prechecks.

* feat(auth): adding an initial passwordless integration test with resources defined (#163)

* chore: update no-auth API's in the resolver

* chore: Updating to the renamed WebAuthn APIs (#164)

* chore: Updating to the renamed WebAuthn APIs

* Fixing unit tests

* chore: Adding unit tests for the WebAuthn APIs Tasks (#165)

* test: Adding AssociateWebAuthn unit tests

* test: Adding ListWebAuthnCredentials unit tests

* test: Adding DeleteWebAuthnCredential unit tests

* chore: simplifying how webauthn errors are handled

* adressing PR comments

* chore(auth): add integration tests for passwordless signup and auto sign in (#166)

* chore(auth): add integration tests for passwordless signup and auto sign in

* remove unused code

* refactor code

* chore: add integration tests for sign in flows (#168)

* chore: add integration tests for sign in flows

* Update AuthSignInWithPasswordUsingUserAuthTests.swift

* Add more integration tests

* update

* chore: update sdk to use the latest models

* test: Adding integration tests for WebAuthn APIs (#169)

* test: Adding integration tests for WebAuthn APIs

* chore: Adding webauthn integration workflow

* Refactoring the code to remove unnecesary waits and make it more easy to read

* fix: Fixing service errors being reported as .unknown when sign in fails (#170)

* fix: Fixing service errors being reported as .unknown when sign in fails. Also adding proper WebAuthn cases to the AWSCognitoAuthError enum.

* addressing PR comment

* fix(auth): fix resolvers and tasks for auto sign in when state machine 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

* feat: Adding visionOS support to the WebAuthn APIs (#171)

* chore: using the latest version aws sdk

* chore: update changes needed for the sdk updated

* chore: fix swiftlint errors (#3921)

* chore: running passwordless integration tests on GEN2 backend

* chore: update test target for watchOS

* chore: fix OTP integration tests

* chore: update more integration tests

---------

Co-authored-by: Sebastian Villena <97059974+ruisebas@users.noreply.github.com>
Co-authored-by: Abhash Kumar Singh <thisisabhash@gmail.com>
  • Loading branch information
3 people authored Nov 25, 2024
2 parents aef29d1 + c97f118 commit edd2aa7
Show file tree
Hide file tree
Showing 183 changed files with 10,617 additions and 551 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/integ_test_auth.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,9 @@ jobs:
resource_subfolder: auth
timeout-minutes: 30
secrets: inherit

# Disabling the integration test because the job is not able to connect to the local server
# auth-webauthn-integration-test-iOS:
# name: Auth WebAuthn Integration Tests (iOS)
# uses: ./.github/workflows/integ_test_auth_webauthn.yml
# secrets: inherit
101 changes: 101 additions & 0 deletions .github/workflows/integ_test_auth_webauthn.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: Integration Tests | Auth - WebAuthn
on:
workflow_dispatch:
workflow_call:

permissions:
id-token: write
contents: read

jobs:
auth-webauthn-integration-tests:
name: iOS Tests | AuthWebAuthnApp
runs-on: macos-15
timeout-minutes: 30
environment: IntegrationTest

steps:
- name: Checkout repository
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false

- name: Get build parameters for iOS
id: platform
uses: ./.github/composite_actions/get_platform_parameters
with:
platform: iOS

- name: Create the test configuration directory
run: mkdir -p ~/.aws-amplify/amplify-ios/testconfiguration/

- name: Download the Integration Test configurations
uses: ./.github/composite_actions/download_test_configuration
with:
resource_subfolder: auth
aws_role_to_assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws_region: ${{ secrets.AWS_REGION }}
aws_s3_bucket: ${{ secrets.AWS_S3_BUCKET_INTEG_V2 }}
destination: ~/.aws-amplify/amplify-ios/testconfiguration/

- name: Set up node
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version: 16.x

- name: Attempt to use the dependencies cache
id: dependencies-cache
timeout-minutes: 4
continue-on-error: true
uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
with:
path: ~/Library/Developer/Xcode/DerivedData/Amplify
key: amplify-packages-${{ hashFiles('Package.resolved') }}
restore-keys: |
amplify-packages-
- name: Attempt to restore the build cache
id: build-cache
timeout-minutes: 4
continue-on-error: true
uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
with:
path: ${{ github.workspace }}/Build
key: Amplify-iOS-build-cache

- name: Run Local Server
run: |
cd ./AmplifyPlugins/Auth/Tests/AuthWebAuthnApp/LocalServer
npm install
npm start &
shell: bash

- name: Run iOS Integration Tests
id: run-tests
continue-on-error: true
uses: ./.github/composite_actions/run_xcodebuild_test
with:
scheme: AuthWebAuthnApp
destination: ${{ steps.platform.outputs.destination }}
sdk: ${{ steps.platform.outputs.sdk }}
xcode_path: /Applications/Xcode_${{ steps.platform.outputs.xcode-version }}.app
project_path: ./AmplifyPlugins/Auth/Tests/AuthWebAuthnApp
generate_coverage: false
cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify
derived_data_path: ${{ github.workspace }}/Build
disable_package_resolution: ${{ steps.dependencies-cache.outputs.cache-hit }}

- name: Retry iOS Integration Tests
if: steps.run-tests.outcome=='failure'
id: retry-tests
uses: ./.github/composite_actions/run_xcodebuild_test
with:
scheme: AuthWebAuthnApp
destination: ${{ steps.platform.outputs.destination }}
sdk: ${{ steps.platform.outputs.sdk }}
xcode_path: /Applications/Xcode_${{ steps.platform.outputs.xcode-version }}.app
project_path: ./AmplifyPlugins/Auth/Tests/AuthWebAuthnApp
generate_coverage: false
cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify
derived_data_path: ${{ github.workspace }}/Build
disable_package_resolution: true
4 changes: 4 additions & 0 deletions Amplify/Categories/Auth/AuthCategory+ClientBehavior.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ extension AuthCategory: AuthCategoryBehavior {
return await plugin.signOut(options: options)
}

public func autoSignIn() async throws -> AuthSignInResult {
try await plugin.autoSignIn()
}

public func deleteUser() async throws {
try await plugin.deleteUser()
}
Expand Down
51 changes: 51 additions & 0 deletions Amplify/Categories/Auth/AuthCategory+WebAuthnBehaviour.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

extension AuthCategory: AuthCategoryWebAuthnBehaviour {
#if os(iOS) || os(macOS)
@available(iOS 17.4, macOS 13.5, *)
public func associateWebAuthnCredential(
presentationAnchor: AuthUIPresentationAnchor? = nil,
options: AuthAssociateWebAuthnCredentialRequest.Options? = nil
) async throws {
try await plugin.associateWebAuthnCredential(
presentationAnchor: presentationAnchor,
options: options
)
}
#elseif os(visionOS)
public func associateWebAuthnCredential(
presentationAnchor: AuthUIPresentationAnchor,
options: AuthAssociateWebAuthnCredentialRequest.Options? = nil
) async throws {
try await plugin.associateWebAuthnCredential(
presentationAnchor: presentationAnchor,
options: options
)
}
#endif

public func listWebAuthnCredentials(
options: AuthListWebAuthnCredentialsRequest.Options? = nil
) async throws -> AuthListWebAuthnCredentialsResult {
return try await plugin.listWebAuthnCredentials(
options: options
)
}

public func deleteWebAuthnCredential(
credentialId: String,
options: AuthDeleteWebAuthnCredentialRequest.Options? = nil
) async throws {
try await plugin.deleteWebAuthnCredential(
credentialId: credentialId,
options: options
)
}
}
6 changes: 5 additions & 1 deletion Amplify/Categories/Auth/AuthCategoryBehavior.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public typealias AuthUIPresentationAnchor = ASPresentationAnchor
#endif

/// Behavior of the Auth category that clients will use
public protocol AuthCategoryBehavior: AuthCategoryUserBehavior, AuthCategoryDeviceBehavior {
public protocol AuthCategoryBehavior: AuthCategoryUserBehavior, AuthCategoryDeviceBehavior, AuthCategoryWebAuthnBehaviour {

/// SignUp a user with the authentication provider.
///
Expand Down Expand Up @@ -102,6 +102,10 @@ public protocol AuthCategoryBehavior: AuthCategoryUserBehavior, AuthCategoryDevi
options: AuthConfirmSignInRequest.Options?
) async throws -> AuthSignInResult


/// Auto signs in the user for passwordless sign up
func autoSignIn() async throws -> AuthSignInResult

/// Sign out the currently logged-in user.
///
/// - Parameters:
Expand Down
35 changes: 35 additions & 0 deletions Amplify/Categories/Auth/AuthCategoryWebAuthnBehaviour.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

public protocol AuthCategoryWebAuthnBehaviour: AnyObject {
#if os(iOS) || os(macOS)
/// - Tag: AuthCategoryWebAuthnBehaviour.associate
@available(iOS 17.4, macOS 13.5, *)
func associateWebAuthnCredential(
presentationAnchor: AuthUIPresentationAnchor?,
options: AuthAssociateWebAuthnCredentialRequest.Options?
) async throws
#elseif os(visionOS)
func associateWebAuthnCredential(
presentationAnchor: AuthUIPresentationAnchor,
options: AuthAssociateWebAuthnCredentialRequest.Options?
) async throws
#endif

/// - Tag: AuthCategoryWebAuthnBehaviour.list
func listWebAuthnCredentials(
options: AuthListWebAuthnCredentialsRequest.Options?
) async throws -> AuthListWebAuthnCredentialsResult

/// - Tag: AuthCategoryWebAuthnBehaviour.delete
func deleteWebAuthnCredential(
credentialId: String,
options: AuthDeleteWebAuthnCredentialRequest.Options?
) async throws
}
27 changes: 27 additions & 0 deletions Amplify/Categories/Auth/Models/AuthFactorType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

public enum AuthFactorType: String {

/// An auth factor that uses password
case password

/// An auth factor that uses SRP protocol
case passwordSRP

/// An auth factor that uses SMS OTP
case smsOTP

/// An auth factor that uses Email OTP
case emailOTP

#if os(iOS) || os(macOS) || os(visionOS)
/// An auth factor that uses WebAuthn
@available(iOS 17.4, macOS 13.5, visionOS 1.0, *)
case webAuthn
#endif
}
11 changes: 11 additions & 0 deletions Amplify/Categories/Auth/Models/AuthSignInStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
/// Set of allowed MFA types that would be used for continuing sign in during MFA selection step
public typealias AllowedMFATypes = Set<MFAType>

/// Set of available factors that would be used for continuing/confirming sign in
public typealias AvailableAuthFactorTypes = Set<AuthFactorType>

/// Auth SignIn flow steps
///
///
Expand All @@ -26,6 +29,10 @@ public enum AuthSignInStep {
///
case confirmSignInWithNewPassword(AdditionalInfo?)

/// Auth step required the user to give a password.
///
case confirmSignInWithPassword

/// Auth step is TOTP multi factor authentication.
///
/// Confirmation code for the MFA will be retrieved from the associated Authenticator app
Expand All @@ -52,6 +59,10 @@ public enum AuthSignInStep {
/// OTP for the factor will be sent to the delivery medium.
case confirmSignInWithOTP(AuthCodeDeliveryDetails)

/// Auth step is for continuing sign in by selecting the first factor that would be used for signing in
///
case continueSignInWithFirstFactorSelection(AvailableAuthFactorTypes)

/// Auth step required the user to change their password.
///
case resetPassword(AdditionalInfo?)
Expand Down
5 changes: 5 additions & 0 deletions Amplify/Categories/Auth/Models/AuthSignUpStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

public typealias UserId = String
public typealias Session = String

/// SignUp step to be followed.
public enum AuthSignUpStep {
Expand All @@ -16,6 +17,10 @@ public enum AuthSignUpStep {
AdditionalInfo? = nil,
UserId? = nil)

/// Sign Up successfully completed
/// The customers can use this step to determine if they want to complete sign in
case completeAutoSignIn(Session)

/// Sign up is complete
case done
}
52 changes: 52 additions & 0 deletions Amplify/Categories/Auth/Models/AuthWebAuthnCredential.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

/// Represents the output of a call to
/// [`AuthCategoryWebAuthnBehaviour.listWebAuthnCredentials(options:)`](x-source-tag://AuthCategoryWebAuthnBehaviour.list)
///
/// - Tag: AuthListWebAuthnCredentialsResult
public struct AuthListWebAuthnCredentialsResult {
/// The list of WebAuthn credentials
///
/// - Tag: AuthListWebAuthnCredentialsResult.credentials
public var credentials: [AuthWebAuthnCredential]

/// String indicating the page offset at which to resume a listing.
///
/// This value is usually copied to
/// [AuthListWebAuthnCredentialsRequest.Options.nextToken](x-source-tag://AuthListWebAuthnCredentialsRequestOptions.nextToken).
///
/// - Tag: AuthListWebAuthnCredentialsResult.nextToken
public let nextToken: String?

/// - Tag: AuthListWebAuthnCredentialsResult.init
public init(
credentials: [AuthWebAuthnCredential],
nextToken: String?
) {
self.credentials = credentials
self.nextToken = nextToken
}
}

/// Defines a WebAuthn credential
/// - Tag: AuthWebAuthnCredential
public protocol AuthWebAuthnCredential {
/// The credential's ID
var credentialId: String { get }

/// The credential's creation date
var createdAt: Date { get }

/// The credential's relying party ID
var relyingPartyId: String { get }

/// The credential's friendly name
var friendlyName: String? { get }
}
Loading

0 comments on commit edd2aa7

Please sign in to comment.