diff --git a/packages/amplify-e2e-core/src/categories/auth.ts b/packages/amplify-e2e-core/src/categories/auth.ts index 73e622dd8a2..3b94f5cf928 100644 --- a/packages/amplify-e2e-core/src/categories/auth.ts +++ b/packages/amplify-e2e-core/src/categories/auth.ts @@ -1648,7 +1648,18 @@ export function addAuthWithPreTokenGenerationTrigger(projectDir: string): Promis }); } -export function updateAuthAddUserGroups(projectDir: string, groupNames: string[], settings?: any): Promise { +export function updateAuthAddUserGroups( + projectDir: string, + groupNames: string[], + settings?: { + testingWithLatestCodebase?: boolean; + updateUserPoolGroupsPosition?: number; + hasExistingUserPoolGroups?: boolean; + overrides?: { + category: string; + }; + }, +): Promise { if (groupNames.length == 0) { return undefined; } @@ -1663,7 +1674,18 @@ export function updateAuthAddUserGroups(projectDir: string, groupNames: string[] for (let i = 0; i < updateUserPoolGroupsPosition; i++) { chain.send(KEY_DOWN_ARROW); } - chain.sendCarriageReturn().wait('Provide a name for your user pool group').send(groupNames[0]).sendCarriageReturn(); + chain.sendCarriageReturn(); + + if (settings?.hasExistingUserPoolGroups) { + chain + .wait('Select any user pool groups you want to delete') + .sendCarriageReturn() + .wait('Do you want to add another User Pool Group') + .sendYes() + .sendCarriageReturn(); + } + + chain.wait('Provide a name for your user pool group').send(groupNames[0]).sendCarriageReturn(); if (groupNames.length > 1) { let index = 1; diff --git a/packages/amplify-migration-tests/package.json b/packages/amplify-migration-tests/package.json index 20d757b04dd..f9a7b4b686e 100644 --- a/packages/amplify-migration-tests/package.json +++ b/packages/amplify-migration-tests/package.json @@ -29,6 +29,7 @@ "@aws-amplify/amplify-cli-core": "4.1.0", "@aws-amplify/amplify-e2e-core": "5.0.4", "@aws-cdk/cloudformation-diff": "~2.68.0", + "@aws-sdk/client-s3": "^3.303.0", "aws-cdk-lib": "~2.68.0", "constructs": "^10.0.5", "fs-extra": "^8.1.0", diff --git a/packages/amplify-migration-tests/src/__tests__/migration_tests_v12/auth-role-mapping-migration-test.ts b/packages/amplify-migration-tests/src/__tests__/migration_tests_v12/auth-role-mapping-migration-test.ts new file mode 100644 index 00000000000..65f685f1a20 --- /dev/null +++ b/packages/amplify-migration-tests/src/__tests__/migration_tests_v12/auth-role-mapping-migration-test.ts @@ -0,0 +1,185 @@ +import { allowedVersionsToMigrateFrom, versionCheck } from '../../migration-helpers'; +import { + addAuthWithDefault, + addS3WithGroupAccess, + amplifyPushAuth, + amplifyPushForce, + amplifyPushNonInteractive, + configureAmplify, + createNewProjectDir, + deleteProject, + deleteProjectDir, + getProjectMeta, + getS3StorageBucketName, + getUserPoolId, + setupUser, + signInUser, + signOutUser, + updateAuthAddUserGroups, + updateHeadlessAuth, +} from '@aws-amplify/amplify-e2e-core'; +import { initJSProjectWithProfileV12 } from '../../migration-helpers-v12/init'; +import { Auth } from 'aws-amplify'; +import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3'; +import { UpdateAuthRequest } from 'amplify-headless-interface'; + +describe('amplify auth group mapping', () => { + beforeAll(async () => { + const migrateFromVersion = { v: '12.0.3' }; + const migrateToVersion = { v: 'uninitialized' }; + + await versionCheck(process.cwd(), false, migrateFromVersion); + await versionCheck(process.cwd(), true, migrateToVersion); + + expect(allowedVersionsToMigrateFrom).toContain(migrateFromVersion.v); + }); + + let projRoot: string; + + beforeEach(async () => { + projRoot = await createNewProjectDir('groupMapping'); + }); + + afterEach(async () => { + await deleteProject(projRoot, null, true); + deleteProjectDir(projRoot); + }); + + const defaultsSettings = { + name: 'authS3Test', + }; + + const username1 = 'testUser1'; + const password1 = 'Password12#1'; + const username2 = 'testUser2'; + const password2 = 'Password12#2'; + + const setupUsers = async () => { + const meta = getProjectMeta(projRoot); + const region = meta.providers.awscloudformation.Region; + const userPoolId = getUserPoolId(projRoot); + + await configureAmplify(projRoot); + await setupUser(userPoolId, username1, password1, 'group1', region); + await setupUser(userPoolId, username2, password2, 'group2', region); + }; + + const verifyUserAccess = async () => { + const meta = getProjectMeta(projRoot); + const region = meta.providers.awscloudformation.Region; + const bucketName = getS3StorageBucketName(projRoot); + + await configureAmplify(projRoot); + + const s3key = 'foo'; + const s3val = 'bar'; + + // Check that user 1 can interact with S3 bucket + await signInUser(username1, password1); + const user1Credentials = await Auth.currentCredentials(); + + const s3Client1 = new S3Client({ + region, + credentials: Auth.essentialCredentials(user1Credentials), + }); + await s3Client1.send( + new PutObjectCommand({ + Bucket: bucketName, + Key: s3key, + Body: s3val, + }), + ); + const valRes = await ( + await s3Client1.send( + new GetObjectCommand({ + Bucket: bucketName, + Key: s3key, + }), + ) + ).Body.transformToString(); + expect(valRes).toEqual(s3val); + await signOutUser(); + + // Check that user 2 does not have permissions to interact with S3 bucket + await signInUser(username2, password2); + const user2Credentials = await Auth.currentCredentials(); + const s3Client2 = new S3Client({ + region, + credentials: Auth.essentialCredentials(user2Credentials), + }); + await expect( + s3Client2.send( + new GetObjectCommand({ + Bucket: bucketName, + Key: s3key, + }), + ), + ).rejects.toThrow('Access Denied'); + await expect( + s3Client2.send( + new PutObjectCommand({ + Bucket: bucketName, + Key: s3key, + Body: s3val, + }), + ), + ).rejects.toThrow('Access Denied'); + await signOutUser(); + }; + + describe('project with group mapping created by old version', () => { + beforeEach(async () => { + await initJSProjectWithProfileV12(projRoot, defaultsSettings); + await addAuthWithDefault(projRoot); + await updateAuthAddUserGroups(projRoot, ['group1', 'group2']); + await addS3WithGroupAccess(projRoot, ['group1', 'group2'], ['group1']); + await amplifyPushNonInteractive(projRoot); + await setupUsers(); + await verifyUserAccess(); + }); + + it('force pushes with latest and checks access', async () => { + await amplifyPushForce(projRoot, true); + await verifyUserAccess(); + }); + + it('updates auth with latest, pushes and checks access', async () => { + await updateAuthAddUserGroups(projRoot, ['group3'], { testingWithLatestCodebase: true, hasExistingUserPoolGroups: true }); + await amplifyPushAuth(projRoot, true); + await verifyUserAccess(); + }); + + it('updates auth headless with latest, pushes and checks access', async () => { + const updateAuthRequest: UpdateAuthRequest = { + version: 2, + serviceModification: { + serviceName: 'Cognito', + userPoolModification: { + autoVerifiedAttributes: [ + { + type: 'EMAIL', + }, + ], + userPoolGroups: [ + { + groupName: 'group1', + }, + { + groupName: 'group2', + }, + { + groupName: 'group3', + }, + ], + }, + includeIdentityPool: true, + identityPoolModification: {}, + }, + }; + + await updateHeadlessAuth(projRoot, updateAuthRequest, { testingWithLatestCodebase: true }); + await amplifyPushNonInteractive(projRoot, true); + await verifyUserAccess(); + }); + }); +}); diff --git a/scripts/split-e2e-test-filters.ts b/scripts/split-e2e-test-filters.ts index 393483d35dd..4ef4ea0110d 100644 --- a/scripts/split-e2e-test-filters.ts +++ b/scripts/split-e2e-test-filters.ts @@ -29,4 +29,5 @@ export const migrationFromV12Tests = [ 'src/__tests__/migration_tests_v12/auth-lambda-callout-migration.test.ts', 'src/__tests__/migration_tests_v12/auth-lambda-callout-migration-rollback.test.ts', 'src/__tests__/migration_tests_v12/auth-oauth-lambda-migration.test.ts', + 'src/__tests__/migration_tests_v12/auth-role-mapping-migration-test.ts', ]; diff --git a/yarn.lock b/yarn.lock index 4d6d001742d..c1eac90c2b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -706,6 +706,7 @@ __metadata: "@aws-amplify/amplify-cli-core": 4.1.0 "@aws-amplify/amplify-e2e-core": 5.0.4 "@aws-cdk/cloudformation-diff": ~2.68.0 + "@aws-sdk/client-s3": ^3.303.0 aws-cdk-lib: ~2.68.0 constructs: ^10.0.5 fs-extra: ^8.1.0