Skip to content

Commit

Permalink
feat(auth): add support for Email MFA (#13945)
Browse files Browse the repository at this point in the history
* [Email MFA] Updating fetchMFAPreference and updateMFAPreference (#13720)

* add EMAIL MFA option in fetchMFAPreference

* add EMAIL MFA option in updateMFAPreference

* update fetchMFAPreference tests

* update updateMFAPreference tests

* update bundle size

* remove redundant assertions

* [Email MFA] Add support for EMAIL_OTP during sign in flows (#13745)

* Confirm Sign In With Email OTP

* Confirm Sign In Tests With Email OTP

* Update packages/auth/src/types/models.ts

Co-authored-by: israx <[email protected]>

* Fix Errant Pascal Casing

---------

Co-authored-by: israx <[email protected]>

* feat(auth): [EMAIL MFA] Sign In / Confirm Sign In With MFA_SETUP (#13760)

* Sign In / Confirm Sign In With MFA_SETUP

* Sign In State Management Tests

* Confirm Sign In Happy Path Tests

* Fix State Management Tests

* Apply Feedback

* loose email matching

* Remove Unnecessary Export

* Update SignInHelpers For Getting Allowed MFA Setup Types

* Add Error Case Unit Tests

* feat(auth): [EMAIL MFA] enable integ tests with backend configuration swapping (#13794)

* chore: enable mfa integ tests

* chore: add mfa-setup test def

* chore: temporarily enable push integ tests

* chore: disable push integ tests

* chore: address test strategy feedback

* chore: use trimmed challenge response

* chore: improved naming

* chore: update bundle size tests

* chore: remove trimmed challenge response

---------

Co-authored-by: israx <[email protected]>
  • Loading branch information
jjarvisp and israx authored Oct 31, 2024
1 parent caf00e2 commit 42db720
Show file tree
Hide file tree
Showing 17 changed files with 1,021 additions and 238 deletions.
45 changes: 45 additions & 0 deletions .github/integ-config/integ-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -870,3 +870,48 @@ tests:
spec: ssr-context-isolation
yarn_script: ci:ssr-context-isolation
browser: [chrome]
- test_name: integ_next_mfa_req_email
desc: 'mfa required with email sign in attribute'
framework: next
category: auth
sample_name: [mfa]
spec: mfa-req-email
browser: [chrome]
env:
NEXT_PUBLIC_BACKEND_CONFIG: mfa-req-email
- test_name: integ_next_mfa_req_phone
desc: 'mfa required with phone sign in attribute'
framework: next
category: auth
sample_name: [mfa]
spec: mfa-req-phone
browser: [chrome]
env:
NEXT_PUBLIC_BACKEND_CONFIG: mfa-req-phone
- test_name: integ_next_mfa_opt_email
desc: 'mfa optional with email sign in attribute'
framework: next
category: auth
sample_name: [mfa]
spec: mfa-opt-email
browser: [chrome]
env:
NEXT_PUBLIC_BACKEND_CONFIG: mfa-opt-email
- test_name: integ_next_mfa_opt_phone
desc: 'mfa optional with phone sign in attribute'
framework: next
category: auth
sample_name: [mfa]
spec: mfa-opt-phone
browser: [chrome]
env:
NEXT_PUBLIC_BACKEND_CONFIG: mfa-opt-phone
- test_name: integ_next_mfa_setup
desc: 'mfa setup sign in flow'
framework: next
category: auth
sample_name: [mfa]
spec: mfa-setup
browser: [chrome]
env:
NEXT_PUBLIC_BACKEND_CONFIG: mfa-setup
11 changes: 9 additions & 2 deletions .github/workflows/callable-e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ on:
yarn_script:
required: false
type: string
env:
required: false
type: string

env:
AMPLIFY_DIR: /home/runner/work/amplify-js/amplify-js/amplify-js
Expand Down Expand Up @@ -84,6 +87,7 @@ jobs:
E2E_RETRY_COUNT: ${{ inputs.retry_count }}
E2E_TEST_NAME: ${{ inputs.test_name }}
E2E_YARN_SCRIPT: ${{ inputs.yarn_script }}
E2E_ENV: ${{ inputs.env }}
run: |
if [ -z "$E2E_YARN_SCRIPT" ]; then
../amplify-js/scripts/retry-yarn-script.sh -s \
Expand All @@ -95,7 +99,8 @@ jobs:
$E2E_BROWSER \
dev \
$E2E_BACKEND \
$E2E_AMPLIFY_JS_DIR" \
$E2E_AMPLIFY_JS_DIR \
--env $(echo $E2E_ENV | jq -r 'tostring')" \
$E2E_YARN_SCRIPT \
-n $E2E_RETRY_COUNT
else
Expand All @@ -115,6 +120,7 @@ jobs:
E2E_RETRY_COUNT: ${{ inputs.retry_count }}
E2E_TEST_NAME: ${{ inputs.test_name }}
E2E_YARN_SCRIPT: ${{ inputs.yarn_script }}
E2E_ENV: ${{ inputs.env }}
run: |
if [ -z "$E2E_YARN_SCRIPT" ]; then
../amplify-js/scripts/retry-yarn-script.sh -s \
Expand All @@ -126,7 +132,8 @@ jobs:
$E2E_BROWSER \
prod \
$E2E_BACKEND \
$E2E_AMPLIFY_JS_DIR" \
$E2E_AMPLIFY_JS_DIR \
--env $(echo $E2E_ENV | jq -r 'tostring')" \
$E2E_YARN_SCRIPT \
-n $E2E_RETRY_COUNT
else
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/callable-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ jobs:
timeout_minutes: ${{ matrix.integ-config.timeout_minutes || 35 }}
retry_count: ${{ matrix.integ-config.retry_count || 3 }}
yarn_script: ${{ matrix.integ-config.yarn_script || '' }}
env: ${{ matrix.integ-config.env && toJSON(matrix.integ-config.env) || '{}' }}

# e2e-test-runner-headless:
# name: E2E test runnner_headless
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AuthValidationErrorCode } from '../../../src/errors/types/validation';
import { confirmSignIn } from '../../../src/providers/cognito/apis/confirmSignIn';
import { RespondToAuthChallengeException } from '../../../src/providers/cognito/types/errors';
import { signInStore } from '../../../src/providers/cognito/utils/signInStore';
import { AuthErrorCodes } from '../../../src/common/AuthErrorStrings';
import { createRespondToAuthChallengeClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider';

import { getMockError } from './testUtils/data';
Expand All @@ -26,7 +27,7 @@ describe('confirmSignIn API error path cases:', () => {
const signInSession = '1234234232';
const { username } = authAPITestParams.user1;
// assert mocks
const mockStoreGetState = signInStore.getState as jest.Mock;
const mockStoreGetState = jest.mocked(signInStore.getState);
const mockRespondToAuthChallenge = jest.fn();
const mockCreateRespondToAuthChallengeClient = jest.mocked(
createRespondToAuthChallengeClient,
Expand Down Expand Up @@ -62,7 +63,7 @@ describe('confirmSignIn API error path cases:', () => {
}
});

it('should throw an error when sign-in step is CONTINUE_SIGN_IN_WITH_MFA_SELECTION and challengeResponse is not "SMS" or "TOTP"', async () => {
it('should throw an error when sign-in step is CONTINUE_SIGN_IN_WITH_MFA_SELECTION and challengeResponse is not "SMS", "TOTP", or "EMAIL"', async () => {
expect.assertions(2);
try {
await confirmSignIn({ challengeResponse: 'NO_SMS' });
Expand All @@ -88,4 +89,23 @@ describe('confirmSignIn API error path cases:', () => {
);
}
});
it('should throw an error when sign-in step is MFA_SETUP and challengeResponse is not valid', async () => {
expect.assertions(3);

mockStoreGetState.mockReturnValue({
username,
challengeName: 'MFA_SETUP',
signInSession,
});

try {
await confirmSignIn({
challengeResponse: 'SMS',
});
} catch (err: any) {
expect(err).toBeInstanceOf(AuthError);
expect(err.name).toBe(AuthErrorCodes.SignInException);
expect(err.message).toContain('SMS');
}
});
});
Loading

0 comments on commit 42db720

Please sign in to comment.