From f65cae2c0e288bec0d43fd1826dd224b4aa30a69 Mon Sep 17 00:00:00 2001 From: Jim Blanchard Date: Thu, 2 May 2024 15:47:20 -0500 Subject: [PATCH] fix(core): Always set login methods when parsing Gen2 config files (#13315) --- packages/aws-amplify/package.json | 2 +- packages/core/__mocks__/configMocks/README.md | 2 + .../configMocks/amplify_outputs.json | 78 ++++++++++++ .../configMocks/amplifyconfiguration.json | 69 ++++++++++ packages/core/__tests__/amplify_outputs.json | 72 ----------- .../__tests__/parseAmplifyOutputs.test.ts | 118 ++++++++++++------ .../parseAmplifyConfigCompatibility.test.ts | 12 ++ packages/core/src/parseAmplifyOutputs.ts | 14 +-- 8 files changed, 247 insertions(+), 120 deletions(-) create mode 100644 packages/core/__mocks__/configMocks/README.md create mode 100644 packages/core/__mocks__/configMocks/amplify_outputs.json create mode 100644 packages/core/__mocks__/configMocks/amplifyconfiguration.json delete mode 100644 packages/core/__tests__/amplify_outputs.json create mode 100644 packages/core/__tests__/utils/parseAmplifyConfigCompatibility.test.ts diff --git a/packages/aws-amplify/package.json b/packages/aws-amplify/package.json index a3254ed2252..6bcb6ddc582 100644 --- a/packages/aws-amplify/package.json +++ b/packages/aws-amplify/package.json @@ -293,7 +293,7 @@ "name": "[Analytics] record (Pinpoint)", "path": "./dist/esm/analytics/index.mjs", "import": "{ record }", - "limit": "17.02 kB" + "limit": "17.05 kB" }, { "name": "[Analytics] record (Kinesis)", diff --git a/packages/core/__mocks__/configMocks/README.md b/packages/core/__mocks__/configMocks/README.md new file mode 100644 index 00000000000..14e8c18908c --- /dev/null +++ b/packages/core/__mocks__/configMocks/README.md @@ -0,0 +1,2 @@ +This directory contains equivalent Gen1 & Gen2 configurations which are used to validate interoperability between +different config versions/schemas. Make sure that any updates applied to one are applied to the other. diff --git a/packages/core/__mocks__/configMocks/amplify_outputs.json b/packages/core/__mocks__/configMocks/amplify_outputs.json new file mode 100644 index 00000000000..432a6247e91 --- /dev/null +++ b/packages/core/__mocks__/configMocks/amplify_outputs.json @@ -0,0 +1,78 @@ +{ + "$schema": "adipisicing cillum", + "version": "1", + "auth": { + "aws_region": "us-west-2", + "user_pool_id": "mock-cup-id", + "user_pool_client_id": "mock-cup-client-id", + "identity_pool_id": "mock-idp-id", + "oauth": { + "identity_providers": ["FACEBOOK", "SIGN_IN_WITH_APPLE", "GOOGLE"], + "domain": "mock-oauth-domain", + "scopes": ["phone"], + "redirect_sign_in_uri": ["mock-sign-in-uri"], + "redirect_sign_out_uri": ["mock-sign-out-uri"], + "response_type": "token" + }, + "standard_required_attributes": [ + "address", + "locale", + "email" + ], + "username_attributes": ["phone_number", "email"], + "user_verification_types": ["email"], + "unauthenticated_identities_enabled": true, + "mfa_configuration": "OPTIONAL", + "mfa_methods": ["TOTP", "SMS"], + "password_policy": { + "require_lowercase": true, + "require_numbers": true, + "require_uppercase": true, + "require_symbols": true, + "min_length": 6 + } + }, + "data": { + "aws_region": "us-west-2", + "url": "mock-data-url", + "api_key": "mock-data-api-key", + "default_authorization_type": "API_KEY", + "authorization_types": [] + }, + "geo": { + "aws_region": "us-west-2", + "search_indices": { + "items": [ + "mock-geo-search-item", + "mock-geo-search-item-alt" + ], + "default": "mock-geo-search-item" + }, + "geofence_collections": { + "items": [ + "mock-geo-fence-item", + "mock-geo-fence-item-alt" + ], + "default": "mock-geo-fence-item" + } + }, + "custom": { + "custom-prop": -51806024, + "custom-prop-alt": 87599986 + }, + "notifications": { + "aws_region": "us-west-2", + "amazon_pinpoint_app_id": "mock-pinpoint-app-id", + "channels": ["IN_APP_MESSAGING", "APNS"] + }, + "analytics": { + "amazon_pinpoint": { + "app_id": "mock-pinpoint-app-id", + "aws_region": "us-west-2" + } + }, + "storage": { + "bucket_name": "mock-storage-bucket", + "aws_region": "us-west-2" + } +} diff --git a/packages/core/__mocks__/configMocks/amplifyconfiguration.json b/packages/core/__mocks__/configMocks/amplifyconfiguration.json new file mode 100644 index 00000000000..452ab0c64f0 --- /dev/null +++ b/packages/core/__mocks__/configMocks/amplifyconfiguration.json @@ -0,0 +1,69 @@ +{ + "aws_project_region": "us-west-2", + "aws_cognito_identity_pool_id": "mock-idp-id", + "aws_cognito_username_attributes": ["PHONE_NUMBER", "EMAIL"], + "aws_cognito_signup_attributes": ["EMAIL", "ADDRESS", "LOCALE"], + "aws_cognito_mfa_configuration": "OPTIONAL", + "aws_cognito_mfa_types": ["TOTP", "SMS"], + "aws_cognito_password_protection_settings": { + "passwordPolicyMinLength": 6, + "passwordPolicyCharacters": [ + "REQUIRES_SYMBOLS", + "REQUIRES_UPPERCASE", + "REQUIRES_LOWERCASE", + "REQUIRES_NUMBERS" + ] + }, + "oauth": { + "domain": "mock-oauth-domain", + "scope": ["phone"], + "redirectSignIn": "mock-sign-in-uri", + "redirectSignOut": "mock-sign-out-uri", + "responseType": "token" + }, + "aws_cognito_verification_mechanisms": ["EMAIL"], + "aws_cognito_social_providers": ["FACEBOOK", "APPLE", "GOOGLE"], + "aws_mobile_analytics_app_id": "mock-pinpoint-app-id", + "aws_mobile_analytics_app_region": "us-west-2", + "aws_user_files_s3_bucket": "mock-storage-bucket", + "aws_user_files_s3_bucket_region": "us-west-2", + "aws_user_pools_id": "mock-cup-id", + "aws_user_pools_web_client_id": "mock-cup-client-id", + "geo": { + "amazon_location_service": { + "search_indices": { + "items": [ + "mock-geo-search-item", + "mock-geo-search-item-alt" + ], + "default": "mock-geo-search-item" + }, + "geofenceCollections": { + "items": [ + "mock-geo-fence-item", + "mock-geo-fence-item-alt" + ], + "default": "mock-geo-fence-item" + }, + "region": "us-west-2" + } + }, + "aws_appsync_graphqlEndpoint": "mock-data-url", + "aws_appsync_apiKey": "mock-data-api-key", + "aws_appsync_region": "us-west-2", + "aws_appsync_authenticationType": "API_KEY", + "Notifications": { + "InAppMessaging": { + "AWSPinpoint": { + "appId": "mock-pinpoint-app-id", + "region": "us-west-2" + } + }, + "Push": { + "AWSPinpoint": { + "appId": "mock-pinpoint-app-id", + "region": "us-west-2" + } + } + } +} \ No newline at end of file diff --git a/packages/core/__tests__/amplify_outputs.json b/packages/core/__tests__/amplify_outputs.json deleted file mode 100644 index 3ab7633d1a7..00000000000 --- a/packages/core/__tests__/amplify_outputs.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "$schema": "adipisicing cillum", - "version": "1", - "auth": { - "aws_region": "non proident exercitation anim fugiat", - "user_pool_id": "sit velit dolor magna est", - "user_pool_client_id": "voluptate", - "identity_pool_id": "Lorem", - "oauth": { - "identity_providers": ["FACEBOOK", "SIGN_IN_WITH_APPLE", "GOOGLE"], - "domain": "proident dolore do mollit ad", - "scopes": ["incididunt proident"], - "redirect_sign_in_uri": ["Duis", "ipsum velit in dolore"], - "redirect_sign_out_uri": [ - "Excepteur pariatur cillum officia", - "incididunt in Ut Excepteur commodo" - ], - "response_type": "token" - }, - "standard_required_attributes": [ - "address", - "locale", - "family_name", - "sub", - "email" - ], - "username_attributes": ["phone_number", "email"], - "user_verification_types": ["email", "email"], - "unauthenticated_identities_enabled": true, - "mfa_configuration": "OPTIONAL", - "mfa_methods": ["TOTP", "TOTP", "SMS", "TOTP", "TOTP"] - }, - "data": { - "aws_region": "regasd", - "url": "dolore dolor do cillum nulla", - "api_key": "non", - "default_authorization_type": "API_KEY", - "authorization_types": [] - }, - "geo": { - "aws_region": "tempor", - "search_indices": { - "items": [ - "commodo Lorem", - "reprehenderit consequat", - "amet", - "aliquip deserunt", - "ea dolor in proident" - ], - "default": "exercitation fugiat ut dolor sed" - }, - "geofence_collections": { - "items": [ - "fugiat ea irure dolor", - "Ut", - "culpa ut enim exercitation", - "labore", - "ex pariatur est ullamco" - ], - "default": "ullamco incididunt aliquip" - } - }, - "custom": { - "occaecat_4_": -51806024, - "dolorc": 87599986 - }, - "notifications": { - "aws_region": "labore nisi ad", - "amazon_pinpoint_app_id": "in dolor veniam reprehenderit", - "channels": ["EMAIL"] - } -} diff --git a/packages/core/__tests__/parseAmplifyOutputs.test.ts b/packages/core/__tests__/parseAmplifyOutputs.test.ts index 53496954be5..7d15f7b1f52 100644 --- a/packages/core/__tests__/parseAmplifyOutputs.test.ts +++ b/packages/core/__tests__/parseAmplifyOutputs.test.ts @@ -1,7 +1,6 @@ /* eslint-disable camelcase */ import { AmplifyOutputs, parseAmplifyOutputs } from '../src/libraryUtils'; - -import mockAmplifyOutputs from './amplify_outputs.json'; +import mockAmplifyOutputs from '../__mocks__/configMocks/amplify_outputs.json'; describe('parseAmplifyOutputs tests', () => { describe('auth tests', () => { @@ -11,37 +10,42 @@ describe('parseAmplifyOutputs tests', () => { expect(result).toEqual({ API: { GraphQL: { - apiKey: 'non', + apiKey: 'mock-data-api-key', defaultAuthMode: 'apiKey', - endpoint: 'dolore dolor do cillum nulla', + endpoint: 'mock-data-url', modelIntrospection: undefined, - region: 'regasd', + region: 'us-west-2', }, }, Auth: { Cognito: { allowGuestAccess: true, - identityPoolId: 'Lorem', + identityPoolId: 'mock-idp-id', loginWith: { email: true, oauth: { - domain: 'proident dolore do mollit ad', + domain: 'mock-oauth-domain', providers: ['Facebook', 'Apple', 'Google'], - redirectSignIn: ['Duis', 'ipsum velit in dolore'], - redirectSignOut: [ - 'Excepteur pariatur cillum officia', - 'incididunt in Ut Excepteur commodo', - ], + redirectSignIn: ['mock-sign-in-uri'], + redirectSignOut: ['mock-sign-out-uri'], responseType: 'token', - scopes: ['incididunt proident'], + scopes: ['phone'], }, phone: true, + username: false, }, mfa: { smsEnabled: true, status: 'optional', totpEnabled: true, }, + passwordFormat: { + minLength: 6, + requireLowercase: true, + requireNumbers: true, + requireSpecialCharacters: true, + requireUppercase: true, + }, userAttributes: { address: { required: true, @@ -49,43 +53,51 @@ describe('parseAmplifyOutputs tests', () => { email: { required: true, }, - family_name: { - required: true, - }, locale: { required: true, }, - sub: { - required: true, - }, }, - userPoolClientId: 'voluptate', - userPoolId: 'sit velit dolor magna est', + userPoolClientId: 'mock-cup-client-id', + userPoolId: 'mock-cup-id', }, }, Geo: { LocationService: { geofenceCollections: { - default: 'ullamco incididunt aliquip', - items: [ - 'fugiat ea irure dolor', - 'Ut', - 'culpa ut enim exercitation', - 'labore', - 'ex pariatur est ullamco', - ], + default: 'mock-geo-fence-item', + items: ['mock-geo-fence-item', 'mock-geo-fence-item-alt'], }, maps: undefined, - region: 'tempor', + region: 'us-west-2', searchIndices: { - default: 'exercitation fugiat ut dolor sed', - items: [ - 'commodo Lorem', - 'reprehenderit consequat', - 'amet', - 'aliquip deserunt', - 'ea dolor in proident', - ], + default: 'mock-geo-search-item', + items: ['mock-geo-search-item', 'mock-geo-search-item-alt'], + }, + }, + }, + Storage: { + S3: { + bucket: 'mock-storage-bucket', + region: 'us-west-2', + }, + }, + Analytics: { + Pinpoint: { + appId: 'mock-pinpoint-app-id', + region: 'us-west-2', + }, + }, + Notifications: { + InAppMessaging: { + Pinpoint: { + appId: 'mock-pinpoint-app-id', + region: 'us-west-2', + }, + }, + PushNotification: { + Pinpoint: { + appId: 'mock-pinpoint-app-id', + region: 'us-west-2', }, }, }, @@ -151,6 +163,8 @@ describe('parseAmplifyOutputs tests', () => { userPoolId: 'us-east-1:', loginWith: { email: true, + phone: false, + username: false, oauth: { domain: 'https://cognito.com...', providers: ['Google'], @@ -166,6 +180,34 @@ describe('parseAmplifyOutputs tests', () => { }); }); + it('should correctly set loginWith options', () => { + const testAmplifyOutputs = JSON.parse(JSON.stringify(mockAmplifyOutputs)); + + // Phone only + testAmplifyOutputs.auth.username_attributes = ['phone_number']; + let result = parseAmplifyOutputs(testAmplifyOutputs); + + expect(result.Auth?.Cognito.loginWith?.email).toBe(false); + expect(result.Auth?.Cognito.loginWith?.phone).toBe(true); + expect(result.Auth?.Cognito.loginWith?.username).toBe(false); + + // Email only + testAmplifyOutputs.auth.username_attributes = ['email']; + result = parseAmplifyOutputs(testAmplifyOutputs); + + expect(result.Auth?.Cognito.loginWith?.email).toBe(true); + expect(result.Auth?.Cognito.loginWith?.phone).toBe(false); + expect(result.Auth?.Cognito.loginWith?.username).toBe(false); + + // Email & phone + testAmplifyOutputs.auth.username_attributes = ['email', 'phone_number']; + result = parseAmplifyOutputs(testAmplifyOutputs); + + expect(result.Auth?.Cognito.loginWith?.email).toBe(true); + expect(result.Auth?.Cognito.loginWith?.phone).toBe(true); + expect(result.Auth?.Cognito.loginWith?.username).toBe(false); + }); + describe('storage tests', () => { it('should parse storage happy path', () => { const amplifyOutputs: AmplifyOutputs = { diff --git a/packages/core/__tests__/utils/parseAmplifyConfigCompatibility.test.ts b/packages/core/__tests__/utils/parseAmplifyConfigCompatibility.test.ts new file mode 100644 index 00000000000..0642eb339ae --- /dev/null +++ b/packages/core/__tests__/utils/parseAmplifyConfigCompatibility.test.ts @@ -0,0 +1,12 @@ +import { parseAmplifyConfig } from '../../src/libraryUtils'; +import mockAmplifyOutputs from '../../__mocks__/configMocks/amplify_outputs.json'; +import mockAmplifyConfiguration from '../../__mocks__/configMocks/amplifyconfiguration.json'; + +describe('parseAmplifyConfig backwards compatibility', () => { + it('returns identical ResourcesConfig for equivalent CLI & Gen2 configuration files', () => { + const cliConfig = parseAmplifyConfig(mockAmplifyConfiguration); + const gen2Config = parseAmplifyConfig(mockAmplifyOutputs); + + expect(gen2Config).toEqual(cliConfig); + }); +}); diff --git a/packages/core/src/parseAmplifyOutputs.ts b/packages/core/src/parseAmplifyOutputs.ts index 930f36df2de..fcabd1aac06 100644 --- a/packages/core/src/parseAmplifyOutputs.ts +++ b/packages/core/src/parseAmplifyOutputs.ts @@ -135,17 +135,13 @@ function parseAuth( }; } - if (username_attributes?.includes('email')) { + if (username_attributes) { authConfig.Cognito.loginWith = { ...authConfig.Cognito.loginWith, - email: true, - }; - } - - if (username_attributes?.includes('phone_number')) { - authConfig.Cognito.loginWith = { - ...authConfig.Cognito.loginWith, - phone: true, + email: username_attributes.includes('email'), + phone: username_attributes.includes('phone_number'), + // Signing in with a username is not currently supported in Gen2, this should always evaluate to false + username: username_attributes.includes('username'), }; }