Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: kickoff release #3932

Merged
merged 5 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ public enum AuthFlowType {
/// - `preferredFirstFactor`: the auth factor type the user should begin signing with if available. If the preferred first factor is not available, the flow would fallback to provide available first factors.
case userAuth(preferredFirstFactor: AuthFactorType?)

internal init?(rawValue: String) {
switch rawValue {
case "CUSTOM_AUTH":
self = .customWithSRP
case "USER_SRP_AUTH":
self = .userSRP
case "USER_PASSWORD_AUTH":
self = .userPassword
case "USER_AUTH":
self = .userAuth
default:
return nil
}
}

var rawValue: String {
switch self {
case .custom, .customWithSRP, .customWithoutSRP:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

public enum AWSCognitoAuthError: Error {

/// User not found in the system.
Expand All @@ -13,7 +15,7 @@ public enum AWSCognitoAuthError: Error {
/// User not confirmed in the system.
case userNotConfirmed

/// Username does not exists in the system.
/// Username already exists in the system.
case usernameExists

/// Alias already exists in the system.
Expand All @@ -40,7 +42,7 @@ public enum AWSCognitoAuthError: Error {
/// Amazon Cognito cannot find a multi-factor authentication (MFA) method.
case mfaMethodNotFound

/// Software token TOTP multi-factor authentication (MFA) is not enabled for the user pool.
/// Software token (TOTP) multi-factor authentication (MFA) is not enabled for the user pool.
case softwareTokenMFANotEnabled

/// Required to reset the password of the user.
Expand All @@ -55,7 +57,7 @@ public enum AWSCognitoAuthError: Error {
/// The user has made too many requests for a given operation.
case requestLimitExceeded

/// Amazon Cognito service encounters an invalid AWS Lambda response or encounters an
/// Amazon Cognito service encountered an invalid AWS Lambda response or encountered an
/// unexpected exception with the AWS Lambda service.
case lambda

Expand All @@ -71,7 +73,7 @@ public enum AWSCognitoAuthError: Error {
/// Requested resource is not available with the current account setup.
case invalidAccountTypeException

/// Request was not completed because of any network related issue
/// Request was not completed because of a network related issue
case network

/// SMS role related issue
Expand Down Expand Up @@ -107,6 +109,83 @@ public enum AWSCognitoAuthError: Error {
/// The relying party ID doesn't match
case webAuthnRelyingPartyMismatch

/// The WebAuthm configuration is missing or incomplete
/// The WebAuthn configuration is missing or incomplete
case webAuthnConfigurationMissing
}

extension AWSCognitoAuthError: LocalizedError {
public var errorDescription: String? {
var message: String = ""
switch self {
case .userNotFound:
message = "User not found in the system."
case .userNotConfirmed:
message = "User not confirmed in the system."
case .usernameExists:
message = "Username already exists in the system."
case .aliasExists:
message = "Alias already exists in the system."
case .codeDelivery:
message = "Error in delivering the confirmation code."
case .codeMismatch:
message = "Confirmation code entered is not correct."
case .codeExpired:
message = "Confirmation code has expired."
case .invalidParameter:
message = "One or more parameters are incorrect."
case .invalidPassword:
message = "Password given is invalid."
case .limitExceeded:
message = "Limit exceeded for the requested AWS resource."
case .mfaMethodNotFound:
message = "Amazon Cognito cannot find a multi-factor authentication (MFA) method."
case .softwareTokenMFANotEnabled:
message = "Software token (TOTP) multi-factor authentication (MFA) is not enabled for the user pool."
case .passwordResetRequired:
message = "Required to reset the password of the user."
case .resourceNotFound:
message = "Amazon Cognito service cannot find the requested resource."
case .failedAttemptsLimitExceeded:
message = "The user has made too many failed attempts for a given action."
case .requestLimitExceeded:
message = "The user has made too many requests for a given operation."
case .lambda:
message = "Amazon Cognito service encountered an invalid AWS Lambda response or encountered an unexpected exception with the AWS Lambda service."
case .deviceNotTracked:
message = "Device is not tracked."
case .errorLoadingUI:
message = "Error in loading the web UI."
case .userCancelled:
message = "User cancelled the step."
case .invalidAccountTypeException:
message = "Requested resource is not available with the current account setup."
case .network:
message = "Request was not completed because of a network related issue."
case .smsRole:
message = "SMS role related issue."
case .emailRole:
message = "Email role related issue."
case .externalServiceException:
message = "An external service like facebook/twitter threw an error."
case .limitExceededException:
message = "Limit exceeded exception. Thrown when the total number of user pools has exceeded a preset limit."
case .resourceConflictException:
message = "Thrown when a user tries to use a login which is already linked to another account."
case .webAuthnChallengeNotFound:
message = "The WebAuthn credentials don't match an existing request."
case .webAuthnClientMismatch:
message = "The client doesn't support WebAuhn authentication."
case .webAuthnNotSupported:
message = "WebAuthn is not supported on this device."
case .webAuthnNotEnabled:
message = "WebAuthn is not enabled."
case .webAuthnOriginNotAllowed:
message = "The device origin is not registered as an allowed origin."
case .webAuthnRelyingPartyMismatch:
message = "The relying party ID doesn't match."
case .webAuthnConfigurationMissing:
message = "The WebAuthn configuration is missing or incomplete."
}
return "\(String(describing: Self.self)).\(self): \(message)"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,17 @@ struct ConfigurationHelper {

// parse `authFlowType`
var authFlowType: AuthFlowType

// If Migration path is enabled, auth flow type should always be set to USER_PASSWORD_AUTH
if case .boolean(let isMigrationEnabled) = cognitoUserPoolJSON.value(at: "MigrationEnabled"),
isMigrationEnabled == true {
authFlowType = .userPassword
} else if let authJson = config.value(at: "Auth.Default"),
case .string(let authFlowTypeJSON) = authJson.value(at: "authenticationFlowType"),
authFlowTypeJSON == "CUSTOM_AUTH" {
authFlowType = .customWithSRP
case .string(let authFlowTypeConfigValue) = authJson.value(at: "authenticationFlowType"),
let authFlowTypeFromConfig = AuthFlowType(rawValue: authFlowTypeConfigValue) {
authFlowType = authFlowTypeFromConfig
} else {
// if the auth flow type is not found from config, default to SRP
authFlowType = .userSRP
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,95 @@ class PasswordlessSignInTests: AWSAuthBaseTest {
}
}

/// Test successful signIn of a valid user
///
/// - Given: A user registered in Cognito user pool
/// - When:
/// - I invoke Amplify.Auth.signIn with the username and password, using userAuth flow
/// - Retry confirm sign in after a wrong password attempt is not supposed to work in `userAuth` flow. Cognito doesn't support this flow.
/// - Re-initiation of sign in should work correctly after a incorrect attempt
/// - Then:
/// - I should get a completed signIn flow.
///
func testSignInWithPasswordSRP_givenValidUser_expectErrorOnWrongPassword() async throws {

let username = "integTest\(UUID().uuidString)"
let password = "Pp123@\(UUID().uuidString)"

try await signUp(username: username, password: password)

do {
let pluginOptions = AWSAuthSignInOptions(
authFlowType: .userAuth)
var signInResult = try await Amplify.Auth.signIn(
username: username,
password: password,
options: .init(pluginOptions: pluginOptions))
guard case .continueSignInWithFirstFactorSelection(let availableFactors) = signInResult.nextStep else {
XCTFail("SignIn should return a .continueSignInWithFirstFactorSelection")
return
}
XCTAssert(availableFactors.contains(.passwordSRP))
var confirmSignInResult = try await Amplify.Auth.confirmSignIn(
challengeResponse: AuthFactorType.passwordSRP.challengeResponse)

guard case .confirmSignInWithPassword = confirmSignInResult.nextStep else {
XCTFail("ConfirmSignIn should return a .confirmSignInWithPassword")
return
}

// Try confirming with wrong password and it should fail

do {
confirmSignInResult = try await Amplify.Auth.confirmSignIn(
challengeResponse: "wrong-password")
} catch {
guard let error = error as? AuthError else {
XCTFail("Error should be of type AuthError instead got: \(error)")
return
}
guard case .notAuthorized = error else {
XCTFail("Error should be .notAuthorized instead got: \(error)")
return
}
}

// Try confirming with password again and it should fail saying that re-initiation is needed

do {
confirmSignInResult = try await Amplify.Auth.confirmSignIn(
challengeResponse: password)
} catch {
guard let error = error as? AuthError else {
XCTFail("Error should be of type AuthError instead got: \(error)")
return
}
guard case .invalidState = error else {
XCTFail("Error should be .invalidState instead got: \(error)")
return
}
}

// After all the errors re-initiation of sign in should work

// Sign in
_ = try await Amplify.Auth.signIn(
username: username,
password: password,
options: .init(pluginOptions: pluginOptions))
// Select passwordSRP
_ = try await Amplify.Auth.confirmSignIn(
challengeResponse: AuthFactorType.passwordSRP.challengeResponse)
// Complete sign in
confirmSignInResult = try await Amplify.Auth.confirmSignIn(
challengeResponse: password)

XCTAssertTrue(confirmSignInResult.isSignedIn, "SignIn should be complete")
} catch {
XCTFail("SignIn with a valid username/password should not fail \(error)")
}
}

/// Test successful signIn of a valid user
///
/// - Given: A user registered in Cognito user pool
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading