diff --git a/packages/amplify-cli-core/API.md b/packages/amplify-cli-core/API.md index 6b5c55b663e..7152cd0528b 100644 --- a/packages/amplify-cli-core/API.md +++ b/packages/amplify-cli-core/API.md @@ -8,6 +8,7 @@ import Ajv from 'ajv'; import { ApiKeyConfig } from '@aws-amplify/graphql-transformer-interfaces'; +import { ARN } from '@aws-sdk/util-arn-parser'; import { BuildType } from '@aws-amplify/amplify-function-plugin-interface'; import * as cdk from 'aws-cdk-lib'; import { ChildProcess } from 'child_process'; @@ -1505,6 +1506,9 @@ export const packageManagers: Record; // @public (undocumented) export type PackageManagerType = 'yarn' | 'npm' | 'pnpm' | 'custom'; +// @public (undocumented) +export const parseArn: (arn: string) => ARN; + // @public (undocumented) export function parseHelpCommands(input: $TSAny, commandsInfo: Array): { command: string; diff --git a/packages/amplify-cli-core/package.json b/packages/amplify-cli-core/package.json index 34e4993a9ec..29366989824 100644 --- a/packages/amplify-cli-core/package.json +++ b/packages/amplify-cli-core/package.json @@ -32,6 +32,7 @@ "@aws-amplify/amplify-function-plugin-interface": "1.11.0", "@aws-amplify/amplify-prompts": "2.8.0", "@aws-amplify/graphql-transformer-interfaces": "^2.2.2", + "@aws-sdk/util-arn-parser": "^3.310.0", "@yarnpkg/lockfile": "^1.1.0", "ajv": "^6.12.6", "aws-cdk-lib": "~2.68.0", diff --git a/packages/amplify-cli-core/src/utils/arn-parser.ts b/packages/amplify-cli-core/src/utils/arn-parser.ts new file mode 100644 index 00000000000..3328538fe4f --- /dev/null +++ b/packages/amplify-cli-core/src/utils/arn-parser.ts @@ -0,0 +1,5 @@ +import { ARN, parse } from '@aws-sdk/util-arn-parser'; + +export const parseArn = (arn: string): ARN => { + return parse(arn); +}; diff --git a/packages/amplify-cli-core/src/utils/index.ts b/packages/amplify-cli-core/src/utils/index.ts index ab7dfaffbb2..83e0c37c5b6 100644 --- a/packages/amplify-cli-core/src/utils/index.ts +++ b/packages/amplify-cli-core/src/utils/index.ts @@ -1,3 +1,4 @@ +export * from './arn-parser'; export * from './doc-links'; export * from './fileSize'; /* eslint-disable import/no-cycle */ diff --git a/packages/amplify-provider-awscloudformation/src/__tests__/aws-utils/IdentityPoolService.test.ts b/packages/amplify-provider-awscloudformation/src/__tests__/aws-utils/IdentityPoolService.test.ts new file mode 100644 index 00000000000..80316360386 --- /dev/null +++ b/packages/amplify-provider-awscloudformation/src/__tests__/aws-utils/IdentityPoolService.test.ts @@ -0,0 +1,68 @@ +import { $TSContext } from '@aws-amplify/amplify-cli-core'; +import { createIdentityPoolService } from '../../aws-utils/IdentityPoolService'; +import { loadConfiguration } from '../../configuration-manager'; + +let mockCognitoIdentityRoles = { + authenticated: 'arn:aws:iam::123456789012:role/service-role/my-auth-role', + unauthenticated: 'arn:aws:iam::123456789012:role/service-role/my-unauth-role', +}; + +jest.mock('aws-sdk', () => { + return { + CognitoIdentity: jest.fn(() => { + return { + config: {}, + getIdentityPoolRoles: jest.fn().mockImplementation(() => ({ + promise: async () => { + return { + Roles: mockCognitoIdentityRoles, + }; + }, + })), + }; + }), + }; +}); + +jest.mock('../../configuration-manager', () => { + return { + loadConfiguration: jest.fn().mockReturnValue({}) as jest.MockedFunction, + }; +}); + +describe('IdentityPoolService', () => { + it('should correctly parse arn if it contains multiple forward slashes', async () => { + const idpService = await createIdentityPoolService({} as unknown as $TSContext, {}); + expect(await idpService.getIdentityPoolRoles('mockIdpId')).toEqual({ + authRoleArn: 'arn:aws:iam::123456789012:role/service-role/my-auth-role', + authRoleName: 'service-role/my-auth-role', + unauthRoleArn: 'arn:aws:iam::123456789012:role/service-role/my-unauth-role', + unauthRoleName: 'service-role/my-unauth-role', + }); + }); + + it('should correctly parse arn if it contains a single forward slash', async () => { + const idpService = await createIdentityPoolService({} as unknown as $TSContext, {}); + mockCognitoIdentityRoles = { + authenticated: 'arn:aws:iam::123456789012:role/my-auth-role', + unauthenticated: 'arn:aws:iam::123456789012:role/my-unauth-role', + }; + + expect(await idpService.getIdentityPoolRoles('mockIdpId')).toEqual({ + authRoleArn: 'arn:aws:iam::123456789012:role/my-auth-role', + authRoleName: 'my-auth-role', + unauthRoleArn: 'arn:aws:iam::123456789012:role/my-unauth-role', + unauthRoleName: 'my-unauth-role', + }); + }); + + it('should fail to parse arn if it contains no forward slash', async () => { + const idpService = await createIdentityPoolService({} as unknown as $TSContext, {}); + mockCognitoIdentityRoles = { + authenticated: 'arn:aws:iam::123456789012:my-auth-role', + unauthenticated: 'arn:aws:iam::123456789012:my-unauth-role', + }; + + await expect(idpService.getIdentityPoolRoles('mockIdpId')).rejects.toBeDefined(); + }); +}); diff --git a/packages/amplify-provider-awscloudformation/src/aws-utils/IdentityPoolService.ts b/packages/amplify-provider-awscloudformation/src/aws-utils/IdentityPoolService.ts index 2209419e141..5df260664cf 100644 --- a/packages/amplify-provider-awscloudformation/src/aws-utils/IdentityPoolService.ts +++ b/packages/amplify-provider-awscloudformation/src/aws-utils/IdentityPoolService.ts @@ -1,4 +1,4 @@ -import { $TSAny, $TSContext, AmplifyFault, AmplifyError } from '@aws-amplify/amplify-cli-core'; +import { $TSAny, $TSContext, AmplifyFault, AmplifyError, parseArn } from '@aws-amplify/amplify-cli-core'; import { IIdentityPoolService } from '@aws-amplify/amplify-util-import'; import { CognitoIdentity } from 'aws-sdk'; import { PaginationKey, IdentityPool, IdentityPoolShortDescription, ListIdentityPoolsResponse } from 'aws-sdk/clients/cognitoidentity'; @@ -101,10 +101,10 @@ export class IdentityPoolService implements IIdentityPoolService { let resourceName; if (arn) { - const parts = arn.split('/'); - - if (parts.length === 2) { - resourceName = parts[1]; + const fullRoleName = parseArn(arn).resource; + const parts = fullRoleName.split('/'); + if (parts.length >= 2) { + resourceName = parts.slice(1).join('/'); } } diff --git a/yarn.lock b/yarn.lock index a69348c835f..a30c2f7a941 100644 --- a/yarn.lock +++ b/yarn.lock @@ -389,6 +389,7 @@ __metadata: "@aws-amplify/amplify-function-plugin-interface": 1.10.3 "@aws-amplify/amplify-prompts": 2.8.0 "@aws-amplify/graphql-transformer-interfaces": ^2.2.2 + "@aws-sdk/util-arn-parser": ^3.310.0 "@types/ejs": ^3.1.1 "@types/fs-extra": ^8.0.1 "@types/hjson": ^2.4.2 @@ -4646,6 +4647,15 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/util-arn-parser@npm:^3.310.0": + version: 3.310.0 + resolution: "@aws-sdk/util-arn-parser@npm:3.310.0" + dependencies: + tslib: ^2.5.0 + checksum: 7214c1291748751976d2d5125d79d49dcb40a0f2276b6da41403c2fd4ecdeb611a604afe06d35c74f66231af78234367698c472b18b671f6e1685890d2508563 + languageName: node + linkType: hard + "@aws-sdk/util-base64-browser@npm:3.37.0": version: 3.37.0 resolution: "@aws-sdk/util-base64-browser@npm:3.37.0"