Skip to content

Commit 04406a5

Browse files
chore: migrate sms only MFA infra to Gen 2 (#5291)
* chore: add new auth backend * chore: add auth extension * chore: add license headers * chore: add mfa to env * chore: add trigger to enable MFA * chore: add infra for sms required * chore: refactor tests for gen 2 backends * chore: add backends to deploy script * chore: package-lock for mfa-required-sms * chore: remove bundling of @aws-crypto/client-node * chore: fix formatting
1 parent c51445e commit 04406a5

28 files changed

+423
-150
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# amplify
2+
node_modules
3+
.amplify
4+
amplify_outputs*
5+
amplifyconfiguration*
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { defineAuth } from "@aws-amplify/backend";
5+
6+
export const auth = defineAuth({
7+
loginWith: {
8+
email: true,
9+
},
10+
multifactor: {
11+
mode: "OPTIONAL",
12+
sms: true,
13+
},
14+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { defineBackend } from "@aws-amplify/backend";
5+
import { addAuthUserExtensions } from "infra-common";
6+
import { auth } from "./auth/resource";
7+
8+
const backend = defineBackend({
9+
auth,
10+
});
11+
12+
const resources = backend.auth.resources;
13+
const { userPool, cfnResources } = resources;
14+
const { stack } = userPool;
15+
const { cfnUserPool } = cfnResources;
16+
17+
// Adds infra for creating/deleting users via App Sync and fetching confirmation
18+
// and MFA codes from App Sync.
19+
const customOutputs = addAuthUserExtensions({
20+
name: "mfa-optional-sms",
21+
stack,
22+
userPool,
23+
cfnUserPool,
24+
});
25+
backend.addOutput(customOutputs);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2022",
4+
"module": "es2022",
5+
"moduleResolution": "bundler",
6+
"resolveJsonModule": true,
7+
"esModuleInterop": true,
8+
"forceConsistentCasingInFileNames": true,
9+
"strict": true,
10+
"skipLibCheck": true,
11+
"paths": {
12+
"$amplify/*": [
13+
"../.amplify/generated/*"
14+
]
15+
}
16+
}
17+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "mfa-optional-sms",
3+
"version": "1.0.0",
4+
"main": "index.js"
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# amplify
2+
node_modules
3+
.amplify
4+
amplify_outputs*
5+
amplifyconfiguration*
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { defineAuth } from "@aws-amplify/backend";
5+
6+
export const auth = defineAuth({
7+
loginWith: {
8+
email: true,
9+
},
10+
multifactor: {
11+
mode: "REQUIRED",
12+
sms: true,
13+
},
14+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { defineBackend } from "@aws-amplify/backend";
5+
import { addAuthUserExtensions } from "infra-common";
6+
import { auth } from "./auth/resource";
7+
8+
const backend = defineBackend({
9+
auth,
10+
});
11+
12+
const resources = backend.auth.resources;
13+
const { userPool, cfnResources } = resources;
14+
const { stack } = userPool;
15+
const { cfnUserPool } = cfnResources;
16+
17+
// Adds infra for creating/deleting users via App Sync and fetching confirmation
18+
// and MFA codes from App Sync.
19+
const customOutputs = addAuthUserExtensions({
20+
name: "mfa-required-sms",
21+
stack,
22+
userPool,
23+
cfnUserPool,
24+
});
25+
backend.addOutput(customOutputs);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2022",
4+
"module": "es2022",
5+
"moduleResolution": "bundler",
6+
"resolveJsonModule": true,
7+
"esModuleInterop": true,
8+
"forceConsistentCasingInFileNames": true,
9+
"strict": true,
10+
"skipLibCheck": true,
11+
"paths": {
12+
"$amplify/*": [
13+
"../.amplify/generated/*"
14+
]
15+
}
16+
}
17+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "mfa-required-sms",
3+
"version": "1.0.0",
4+
"main": "index.js"
5+
}

infra-gen2/infra-common/src/auth-user-extensions/auth-user-extensions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { CfnUserPool, IUserPool } from "aws-cdk-lib/aws-cognito";
44
import { addCreateUserLambda } from "./create-user-lambda";
55
import { addCustomSenderLambda } from "./custom-sender-lambda";
66
import { addDeleteUserLambda } from "./delete-user-lambda";
7+
import { addEnableSmsMfaLambda } from "./enable-sms-mfa-lambda";
78
import { addUserGraphql } from "./user-graphql";
89

910
type AmplifyOutputs = Parameters<BackendBase["addOutput"]>[0];
@@ -23,6 +24,7 @@ export const addAuthUserExtensions = ({
2324
addCustomSenderLambda({ name, stack, cfnUserPool, graphQL });
2425
addCreateUserLambda({ name, stack, userPool, graphQL });
2526
addDeleteUserLambda({ name, stack, userPool, graphQL });
27+
addEnableSmsMfaLambda({ name, stack, userPool, graphQL });
2628
return {
2729
data: {
2830
aws_region: stack.region,

infra-gen2/infra-common/src/auth-user-extensions/custom-sender-lambda.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ export function addCustomSenderLambda({
4444
"custom-email-sender.js"
4545
),
4646
runtime: Runtime.NODEJS_18_X,
47-
bundling: {
48-
nodeModules: ["@aws-crypto/client-node"],
49-
},
5047
environment: {
5148
GRAPHQL_API_ENDPOINT: graphQL.graphqlUrl,
5249
GRAPHQL_API_KEY: graphQL.apiKey!,
@@ -68,9 +65,6 @@ export function addCustomSenderLambda({
6865
"custom-sms-sender.js"
6966
),
7067
runtime: Runtime.NODEJS_18_X,
71-
bundling: {
72-
nodeModules: ["@aws-crypto/client-node"],
73-
},
7468
environment: {
7569
GRAPHQL_API_ENDPOINT: graphQL.graphqlUrl,
7670
GRAPHQL_API_KEY: graphQL.apiKey!,
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Stack } from "aws-cdk-lib";
5+
import { GraphqlApi, MappingTemplate } from "aws-cdk-lib/aws-appsync";
6+
import { IUserPool } from "aws-cdk-lib/aws-cognito";
7+
import { Runtime } from "aws-cdk-lib/aws-lambda";
8+
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
9+
import path from "path";
10+
11+
export function addEnableSmsMfaLambda({
12+
name,
13+
stack,
14+
graphQL,
15+
userPool,
16+
}: {
17+
name: string;
18+
stack: Stack;
19+
graphQL: GraphqlApi;
20+
userPool: IUserPool;
21+
}) {
22+
const enableSmsMfaLambda = new NodejsFunction(stack, `${name}-enableSmsMfa`, {
23+
runtime: Runtime.NODEJS_18_X,
24+
entry: path.resolve(
25+
__dirname,
26+
"..",
27+
"lambda-triggers",
28+
"enable-sms-mfa.js"
29+
),
30+
environment: {
31+
USER_POOL_ID: userPool.userPoolId,
32+
},
33+
});
34+
35+
userPool.grant(enableSmsMfaLambda, "cognito-idp:AdminSetUserMFAPreference");
36+
37+
// Mutation.enableSmsMfa
38+
const enableSmsMfaSource = graphQL.addLambdaDataSource(
39+
"GraphQLApiEnableSmsMfaLambda",
40+
enableSmsMfaLambda
41+
);
42+
43+
enableSmsMfaSource.createResolver("MutationEnableSmsMfaResolver", {
44+
typeName: "Mutation",
45+
fieldName: "enableSmsMfa",
46+
requestMappingTemplate: MappingTemplate.lambdaRequest(),
47+
responseMappingTemplate: MappingTemplate.lambdaResult(),
48+
});
49+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import * as cognito from "@aws-sdk/client-cognito-identity-provider";
5+
import type * as lambda from "aws-lambda";
6+
7+
interface EnableSmsMfaRequest {
8+
username: string;
9+
}
10+
11+
interface EnableSmsMfaResponse {
12+
success: boolean;
13+
error?: string;
14+
}
15+
16+
const USER_POOL_ID = process.env.USER_POOL_ID;
17+
const CLIENT = new cognito.CognitoIdentityProviderClient({
18+
region: process.env.REGION,
19+
});
20+
21+
export const handler: lambda.AppSyncResolverHandler<
22+
EnableSmsMfaRequest,
23+
EnableSmsMfaResponse
24+
> = async (
25+
event: lambda.AppSyncResolverEvent<EnableSmsMfaRequest>
26+
): Promise<EnableSmsMfaResponse> => {
27+
console.log(`Got event: ${JSON.stringify(event, null, 2)}`);
28+
29+
const { username } = event.arguments;
30+
console.log(`Enabling SMS MFA for user ${username}...`);
31+
try {
32+
const mfaParams: cognito.AdminSetUserMFAPreferenceCommandInput = {
33+
UserPoolId: USER_POOL_ID,
34+
Username: username,
35+
SMSMfaSettings: {
36+
Enabled: true,
37+
PreferredMfa: true,
38+
},
39+
};
40+
const resp = await CLIENT.send(
41+
new cognito.AdminSetUserMFAPreferenceCommand(mfaParams),
42+
);
43+
console.log(`Successfully enabled MFA for ${username}`, resp);
44+
return {
45+
success: true,
46+
};
47+
} catch (err: any) {
48+
console.log(`Could not enable MFA for ${username}`, err);
49+
return {
50+
success: false,
51+
error: err.toString(),
52+
};
53+
}
54+
};

infra-gen2/package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

infra-gen2/tool/deploy_gen2.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ const List<AmplifyBackendGroup> infraConfig = [
5353
identifier: 'phone-sign-in',
5454
pathToSource: 'infra-gen2/backends/auth/phone-sign-in',
5555
),
56+
AmplifyBackend(
57+
name: 'mfa-optional-sms',
58+
identifier: 'mfa-opt-sms',
59+
pathToSource: 'infra-gen2/backends/auth/mfa-optional-sms',
60+
),
61+
AmplifyBackend(
62+
name: 'mfa-required-sms',
63+
identifier: 'mfa-req-sms',
64+
pathToSource: 'infra-gen2/backends/auth/mfa-required-sms',
65+
),
5666
],
5767
),
5868
AmplifyBackendGroup(

0 commit comments

Comments
 (0)