diff --git a/.circleci/config.yml b/.circleci/config.yml index e0fe86e1d9b..10d2ce3b1f0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1251,6 +1251,14 @@ jobs: environment: TEST_SUITE: src/__tests__/configure-project.test.ts CLI_REGION: eu-central-1 + auth_6-amplify_e2e_tests: + working_directory: ~/repo + docker: *ref_1 + resource_class: large + steps: *ref_5 + environment: + TEST_SUITE: src/__tests__/auth_6.test.ts + CLI_REGION: ap-northeast-1 api_4-amplify_e2e_tests: working_directory: ~/repo docker: *ref_1 @@ -1258,7 +1266,7 @@ jobs: steps: *ref_5 environment: TEST_SUITE: src/__tests__/api_4.test.ts - CLI_REGION: ap-northeast-1 + CLI_REGION: ap-southeast-1 schema-iterative-update-4-amplify_e2e_tests_pkg_linux: working_directory: ~/repo docker: *ref_1 @@ -1999,6 +2007,16 @@ jobs: TEST_SUITE: src/__tests__/configure-project.test.ts CLI_REGION: eu-central-1 steps: *ref_6 + auth_6-amplify_e2e_tests_pkg_linux: + working_directory: ~/repo + docker: *ref_1 + resource_class: large + environment: + AMPLIFY_DIR: /home/circleci/repo/out + AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux + TEST_SUITE: src/__tests__/auth_6.test.ts + CLI_REGION: ap-northeast-1 + steps: *ref_6 api_4-amplify_e2e_tests_pkg_linux: working_directory: ~/repo docker: *ref_1 @@ -2007,7 +2025,7 @@ jobs: AMPLIFY_DIR: /home/circleci/repo/out AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux TEST_SUITE: src/__tests__/api_4.test.ts - CLI_REGION: ap-northeast-1 + CLI_REGION: ap-southeast-1 steps: *ref_6 workflows: version: 2 @@ -2130,11 +2148,11 @@ workflows: - interactions-amplify_e2e_tests - datastore-modelgen-amplify_e2e_tests - layer-2-amplify_e2e_tests - - api_4-amplify_e2e_tests - - schema-iterative-update-2-amplify_e2e_tests + - auth_6-amplify_e2e_tests - schema-data-access-patterns-amplify_e2e_tests - init-special-case-amplify_e2e_tests - iam-permissions-boundary-amplify_e2e_tests + - api_4-amplify_e2e_tests - feature-flags-amplify_e2e_tests - schema-versioned-amplify_e2e_tests - plugin-amplify_e2e_tests @@ -2160,11 +2178,11 @@ workflows: - interactions-amplify_e2e_tests_pkg_linux - datastore-modelgen-amplify_e2e_tests_pkg_linux - layer-2-amplify_e2e_tests_pkg_linux - - api_4-amplify_e2e_tests_pkg_linux - - schema-iterative-update-2-amplify_e2e_tests_pkg_linux + - auth_6-amplify_e2e_tests_pkg_linux - schema-data-access-patterns-amplify_e2e_tests_pkg_linux - init-special-case-amplify_e2e_tests_pkg_linux - iam-permissions-boundary-amplify_e2e_tests_pkg_linux + - api_4-amplify_e2e_tests_pkg_linux - feature-flags-amplify_e2e_tests_pkg_linux - schema-versioned-amplify_e2e_tests_pkg_linux - plugin-amplify_e2e_tests_pkg_linux @@ -2648,7 +2666,7 @@ workflows: filters: *ref_10 requires: - function_3-amplify_e2e_tests - - api_4-amplify_e2e_tests: + - auth_6-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 filters: *ref_10 @@ -2714,6 +2732,12 @@ workflows: filters: *ref_10 requires: - auth_5-amplify_e2e_tests + - api_4-amplify_e2e_tests: + context: *ref_8 + post-steps: *ref_9 + filters: *ref_10 + requires: + - schema-iterative-update-2-amplify_e2e_tests - schema-iterative-update-3-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 @@ -3128,7 +3152,7 @@ workflows: filters: *ref_13 requires: - function_3-amplify_e2e_tests_pkg_linux - - api_4-amplify_e2e_tests_pkg_linux: + - auth_6-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 filters: *ref_13 @@ -3198,6 +3222,12 @@ workflows: filters: *ref_13 requires: - auth_5-amplify_e2e_tests_pkg_linux + - api_4-amplify_e2e_tests_pkg_linux: + context: *ref_11 + post-steps: *ref_12 + filters: *ref_13 + requires: + - schema-iterative-update-2-amplify_e2e_tests_pkg_linux - schema-iterative-update-3-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/types.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/types.ts index a05f3ab1baa..84fea969dec 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/types.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/types.ts @@ -1,4 +1,4 @@ -import { $TSContext, $TSObject } from 'amplify-cli-core'; +import { $TSAny, $TSContext, $TSObject } from 'amplify-cli-core'; import { GetUserPoolMfaConfigResponse, IdentityProviderType, @@ -50,6 +50,19 @@ export type MetaOutput = { CreatedSNSRole?: string; }; +export type AuthParameters = { + dependsOn?: $TSAny[]; + triggers?: string; + identityPoolName?: string; + aliasAttributes?: string[]; + authProviders?: string[]; + requiredAttributes?: string[]; + passwordPolicyMinLength?: string; + passwordPolicyCharacters?: string[]; + mfaConfiguration?: string; + mfaTypes?: string[]; +}; + // Persisted into team-provider-info export type EnvSpecificResourceParameters = { userPoolId: string; diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/amplify-meta-updaters.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/amplify-meta-updaters.ts index a60adde2c5c..80fe5e03425 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/amplify-meta-updaters.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/amplify-meta-updaters.ts @@ -1,6 +1,9 @@ import * as path from 'path'; -import { JSONUtilities, $TSAny, pathManager } from 'amplify-cli-core'; +import { JSONUtilities, pathManager } from 'amplify-cli-core'; import { transformUserPoolGroupSchema } from './transform-user-pool-group'; +import { authProviders as authProviderList } from '../assets/string-maps'; +import { AuthParameters } from '../import/types'; + /** * Factory function that returns a function that updates Amplify meta files after adding auth resource assets * @@ -16,7 +19,7 @@ export const getPostAddAuthMetaUpdater = (context: any, resultMetadata: { servic providerPlugin: resultMetadata.providerName, }; const parametersJSONPath = path.join(context.amplify.pathManager.getBackendDirPath(), 'auth', resourceName, 'parameters.json'); - const authParameters = JSONUtilities.readJson<{ dependsOn: any[]; triggers: string; identityPoolName: string }>(parametersJSONPath)!; + const authParameters = JSONUtilities.readJson(parametersJSONPath)!; if (authParameters.dependsOn) { options.dependsOn = authParameters.dependsOn; @@ -36,6 +39,7 @@ export const getPostAddAuthMetaUpdater = (context: any, resultMetadata: { servic } options.customAuth = customAuthConfigured; + options.frontendAuthConfig = getFrontendConfig(authParameters); context.amplify.updateamplifyMetaAfterResourceAdd('auth', resourceName, options); @@ -62,7 +66,7 @@ export const getPostAddAuthMetaUpdater = (context: any, resultMetadata: { servic */ export const getPostUpdateAuthMetaUpdater = (context: any) => async (resourceName: string) => { const resourceDirPath = path.join(pathManager.getBackendDirPath(), 'auth', resourceName, 'parameters.json'); - const authParameters = JSONUtilities.readJson<$TSAny>(resourceDirPath); + const authParameters = JSONUtilities.readJson(resourceDirPath)!; if (authParameters.dependsOn) { context.amplify.updateamplifyMetaAfterResourceUpdate('auth', resourceName, 'dependsOn', authParameters.dependsOn); } @@ -79,6 +83,7 @@ export const getPostUpdateAuthMetaUpdater = (context: any) => async (resourceNam triggers.VerifyAuthChallengeResponse.length > 0; } context.amplify.updateamplifyMetaAfterResourceUpdate('auth', resourceName, 'customAuth', customAuthConfigured); + context.amplify.updateamplifyMetaAfterResourceUpdate('auth', resourceName, 'frontendAuthConfig', getFrontendConfig(authParameters)); // Update Identity Pool dependency attributes on userpool groups const allResources = context.amplify.getProjectMeta(); @@ -100,3 +105,44 @@ export const getPostUpdateAuthMetaUpdater = (context: any) => async (resourceNam } return resourceName; }; + +function getFrontendConfig(authParameters: AuthParameters) { + const loginMechanism: string[] = []; + loginMechanism.push(...(authParameters?.aliasAttributes || []).map((att: string) => att.toUpperCase())); + + if (authParameters.authProviders) { + authParameters.authProviders.forEach((provider: string) => { + let name = authProviderList.find(it => it.value === provider)?.name; + + if (name) { + loginMechanism.push(name.toUpperCase()); + } + }); + } + + const signupAttributes = (authParameters?.requiredAttributes || []).map((att: string) => att.toUpperCase()); + + const passwordProtectionSettings = { + passwordPolicyMinLength: authParameters?.passwordPolicyMinLength, + passwordPolicyCharacters: (authParameters?.passwordPolicyCharacters || []).map((i: string) => i.replace(/ /g, '_').toUpperCase()), + }; + + const mfaTypes: string[] = []; + if (authParameters.mfaTypes) { + if (authParameters.mfaTypes.includes('SMS Text Message')) { + mfaTypes.push('SMS'); + } + + if (authParameters.mfaTypes.includes('TOTP')) { + mfaTypes.push('TOTP'); + } + } + + return { + loginMechanism: loginMechanism, + signupAttributes: signupAttributes, + passwordProtectionSettings: passwordProtectionSettings, + mfaConfiguration: authParameters?.mfaConfiguration, + mfaTypes: mfaTypes, + }; +} diff --git a/packages/amplify-e2e-core/src/categories/auth.ts b/packages/amplify-e2e-core/src/categories/auth.ts index d35c55812e5..782153a439d 100644 --- a/packages/amplify-e2e-core/src/categories/auth.ts +++ b/packages/amplify-e2e-core/src/categories/auth.ts @@ -1290,7 +1290,7 @@ export function addAuthUserPoolOnlyWithOAuth(cwd: string, settings: AddAuthUserP .wait('Do you want to add another redirect signout URI') .sendConfirmNo() .wait('Select the OAuth flows enabled for this project') - .sendCarriageReturn() // Authorication Grant + .sendCarriageReturn() // Authorization Grant .wait('Select the OAuth scopes enabled for this project') .sendCarriageReturn() // All .wait('Select the social providers you want to configure for your user pool') @@ -1414,7 +1414,7 @@ export function addAuthIdentityPoolAndUserPoolWithOAuth( .wait('Do you want to add another redirect signout URI') .sendConfirmNo() .wait('Select the OAuth flows enabled for this project') - .sendCarriageReturn() // Authorication Grant + .sendCarriageReturn() // Authorization Grant .wait('Select the OAuth scopes enabled for this project') .sendCarriageReturn() // All .wait('Select the social providers you want to configure for your user pool') diff --git a/packages/amplify-e2e-tests/src/__tests__/auth_6.test.ts b/packages/amplify-e2e-tests/src/__tests__/auth_6.test.ts new file mode 100644 index 00000000000..ae6c727a108 --- /dev/null +++ b/packages/amplify-e2e-tests/src/__tests__/auth_6.test.ts @@ -0,0 +1,64 @@ +import { $TSAny } from 'amplify-cli-core'; +import { + addAuthWithMaxOptions, + amplifyPushAuth, + createNewProjectDir, + deleteProject, + deleteProjectDir, + getProjectMeta, + initJSProjectWithProfile, +} from 'amplify-e2e-core'; + +const PROJECT_NAME = 'authTest'; +const defaultSettings = { + name: PROJECT_NAME, +}; +describe('zero config auth ', () => { + let projRoot: string; + beforeEach(async () => { + projRoot = await createNewProjectDir('zero-config-auth'); + }); + + afterEach(async () => { + await deleteProject(projRoot); + deleteProjectDir(projRoot); + }); + + it('...should init a javascript project and add auth with all options and update front end config', async () => { + await initJSProjectWithProfile(projRoot, defaultSettings); + await addAuthWithMaxOptions(projRoot, {}); + await amplifyPushAuth(projRoot); + + const meta = getProjectMeta(projRoot); + const authMeta: $TSAny = Object.values(meta.auth)[1]; + + expect(authMeta.frontendAuthConfig).toMatchInlineSnapshot(` + Object { + "loginMechanism": Array [ + "EMAIL", + "FACEBOOK", + "GOOGLE", + "AMAZON", + "APPLE", + ], + "mfaConfiguration": "ON", + "mfaTypes": Array [ + "SMS", + "TOTP", + ], + "passwordProtectionSettings": Object { + "passwordPolicyCharacters": Array [ + "REQUIRES_LOWERCASE", + "REQUIRES_UPPERCASE", + "REQUIRES_NUMBERS", + "REQUIRES_SYMBOLS", + ], + "passwordPolicyMinLength": 8, + }, + "signupAttributes": Array [ + "EMAIL", + ], + } + `); + }); +}); diff --git a/packages/amplify-frontend-android/lib/frontend-config-creator.js b/packages/amplify-frontend-android/lib/frontend-config-creator.js index 68ebccdf515..f7103cfcb78 100644 --- a/packages/amplify-frontend-android/lib/frontend-config-creator.js +++ b/packages/amplify-frontend-android/lib/frontend-config-creator.js @@ -264,6 +264,8 @@ function getCognitoConfig(cognitoResources, projectRegion) { }; } + Object.assign(cognitoConfig.Auth.Default, cognitoResource.frontendAuthConfig); + return cognitoConfig; } diff --git a/packages/amplify-frontend-flutter/lib/frontend-config-creator.js b/packages/amplify-frontend-flutter/lib/frontend-config-creator.js index 6f2a4058c44..aea9c7eb175 100644 --- a/packages/amplify-frontend-flutter/lib/frontend-config-creator.js +++ b/packages/amplify-frontend-flutter/lib/frontend-config-creator.js @@ -241,6 +241,8 @@ function getCognitoConfig(cognitoResources, projectRegion) { }; } + Object.assign(cognitoConfig.Auth.Default, cognitoResource.frontendAuthConfig); + return cognitoConfig; } diff --git a/packages/amplify-frontend-ios/lib/frontend-config-creator.js b/packages/amplify-frontend-ios/lib/frontend-config-creator.js index 14912120709..1969134f8fa 100644 --- a/packages/amplify-frontend-ios/lib/frontend-config-creator.js +++ b/packages/amplify-frontend-ios/lib/frontend-config-creator.js @@ -246,6 +246,8 @@ function getCognitoConfig(cognitoResources, projectRegion) { }; } + Object.assign(cognitoConfig.Auth.Default, cognitoResource.frontendAuthConfig); + return cognitoConfig; } diff --git a/packages/amplify-frontend-javascript/lib/frontend-config-creator.js b/packages/amplify-frontend-javascript/lib/frontend-config-creator.js index 9522ef64fa9..6e7d2e47404 100644 --- a/packages/amplify-frontend-javascript/lib/frontend-config-creator.js +++ b/packages/amplify-frontend-javascript/lib/frontend-config-creator.js @@ -289,6 +289,15 @@ function getCognitoConfig(cognitoResources, projectRegion) { federationTarget = 'COGNITO_IDENTITY_POOLS'; } + const frontendAuthConfig = {}; + if (cognitoResource.frontendAuthConfig) { + frontendAuthConfig.aws_cognito_login_mechanism = cognitoResource.frontendAuthConfig.loginMechanism; + frontendAuthConfig.aws_cognito_signup_attributes = cognitoResource.frontendAuthConfig.signupAttributes; + frontendAuthConfig.aws_cognito_mfa_configuration = cognitoResource.frontendAuthConfig.mfaConfiguration; + frontendAuthConfig.aws_cognito_mfa_types = cognitoResource.frontendAuthConfig.mfaTypes; + frontendAuthConfig.aws_cognito_password_protection_settings = cognitoResource.frontendAuthConfig.passwordProtectionSettings; + } + return { aws_cognito_identity_pool_id: cognitoResource.output.IdentityPoolId, aws_cognito_region: projectRegion, @@ -296,6 +305,7 @@ function getCognitoConfig(cognitoResources, projectRegion) { aws_user_pools_web_client_id: cognitoResource.output.AppClientIDWeb, oauth, federationTarget, + ...frontendAuthConfig, }; }