Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add gen2 auth e2e infra #5179

Merged
merged 37 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f695f7a
chore(infra): Api migrate to Gen 2 E2E
Equartey Jun 20, 2024
397547b
fix: git update-index --chmod=+x
Equartey Jun 26, 2024
afbcb0e
fix: code review
Equartey Jun 27, 2024
1364ac6
chore: port auth backend
Jordan-Nelson Jun 19, 2024
5ae14fd
chore: port lambda triggers for create user and custom email sender
Jordan-Nelson Jun 24, 2024
40703cb
chore: move utils to infra-common
Jordan-Nelson Jul 10, 2024
2bcbe63
chore: compile infra common to js
Jordan-Nelson Jul 10, 2024
3477d8a
chore: update utils for js restructure, add missing deps
Jordan-Nelson Jul 11, 2024
6595f17
chore: fix confirmation code infra
Jordan-Nelson Jul 17, 2024
afb51ec
chore: update tests to run for gen2 stacks
Jordan-Nelson Jul 17, 2024
2ff335d
chore: remove alias from custom sender lambda
Jordan-Nelson Jul 18, 2024
b6630f3
chore: fix deliveryMedium in reset password test
Jordan-Nelson Jul 18, 2024
a835ee6
chore: add phone sign in infra
Jordan-Nelson Jul 18, 2024
c1779b8
chore: rename email-sign-in
Jordan-Nelson Jul 18, 2024
98faf0c
chore: add license header
Jordan-Nelson Jul 18, 2024
be39985
chore: fix formatting in GH workflow
Jordan-Nelson Jul 18, 2024
d8d2e38
chore: update package-lock
Jordan-Nelson Jul 18, 2024
b974613
chore: remove deleted file
Jordan-Nelson Jul 18, 2024
6b1ee7f
chore: fix formatting
Jordan-Nelson Jul 18, 2024
bd7a3ba
chore: update package lock
Jordan-Nelson Jul 18, 2024
838de00
chore: remove dup function
Jordan-Nelson Jul 18, 2024
7ee8d7b
chore: remove changes from merge conflicts
Jordan-Nelson Jul 18, 2024
7d34dc3
chore: fix build script
Jordan-Nelson Jul 18, 2024
9e07f99
chore: fetch auth amplify_outputs
Jordan-Nelson Jul 18, 2024
4777064
chore: remove libgit2dart
Jordan-Nelson Jul 18, 2024
84fccc7
chore: add custom sms sender
Jordan-Nelson Jul 19, 2024
b51a3bb
chore: add stack name to infra resources
Jordan-Nelson Jul 25, 2024
1a6a5d4
chore: pull gen2 backend for authenticator
Jordan-Nelson Jul 25, 2024
3ec29f4
chore: update package-lock
Jordan-Nelson Jul 25, 2024
9247a68
chore: move dependencies to dev_dependencies
Jordan-Nelson Jul 25, 2024
4365b10
chore: update fetch auth session tests
Jordan-Nelson Jul 29, 2024
cbb5d80
chore: separate reset pw and confirmation delivery medium
Jordan-Nelson Jul 29, 2024
02c6590
chore: fix hanging test
Jordan-Nelson Jul 29, 2024
54f6d80
chore: rename test group
Jordan-Nelson Jul 30, 2024
bd5f695
chore: update comments, remove unused type
Jordan-Nelson Jul 30, 2024
0c551cd
chore: update package lock
Jordan-Nelson Jul 30, 2024
fb4552a
Merge branch 'main' into chore/gen2-auth-e2e
Jordan-Nelson Jul 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions infra-gen2/backends/auth/email-sign-in/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# amplify
node_modules
.amplify
amplify_outputs*
amplifyconfiguration*
14 changes: 14 additions & 0 deletions infra-gen2/backends/auth/email-sign-in/amplify/auth/resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { defineAuth } from "@aws-amplify/backend";

/**
* Define and configure your auth resource
* @see https://docs.amplify.aws/gen2/build-a-backend/auth
*/
export const auth = defineAuth({
loginWith: {
email: true,
},
});
25 changes: 25 additions & 0 deletions infra-gen2/backends/auth/email-sign-in/amplify/backend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { defineBackend } from "@aws-amplify/backend";
import { addAuthUserExtensions } from "infra-common";
import { auth } from "./auth/resource";

const backend = defineBackend({
auth,
});

const resources = backend.auth.resources;
const { userPool, cfnResources } = resources;
const { stack } = userPool;
const { cfnUserPool } = cfnResources;

// Adds infra for creating/deleting users via App Sync and fetching confirmation
// and MFA codes from App Sync.
const customOutputs = addAuthUserExtensions({
Jordan-Nelson marked this conversation as resolved.
Show resolved Hide resolved
name: "email-sign-in",
stack,
userPool,
cfnUserPool,
});
backend.addOutput(customOutputs);
3 changes: 3 additions & 0 deletions infra-gen2/backends/auth/email-sign-in/amplify/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
17 changes: 17 additions & 0 deletions infra-gen2/backends/auth/email-sign-in/amplify/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "es2022",
"module": "es2022",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"paths": {
"$amplify/*": [
"../.amplify/generated/*"
]
}
}
}
5 changes: 5 additions & 0 deletions infra-gen2/backends/auth/email-sign-in/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "email-sign-in",
"version": "1.0.0",
"main": "index.js"
}
5 changes: 5 additions & 0 deletions infra-gen2/backends/auth/phone-sign-in/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# amplify
node_modules
.amplify
amplify_outputs*
amplifyconfiguration*
14 changes: 14 additions & 0 deletions infra-gen2/backends/auth/phone-sign-in/amplify/auth/resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { defineAuth } from "@aws-amplify/backend";

/**
* Define and configure your auth resource
* @see https://docs.amplify.aws/gen2/build-a-backend/auth
*/
export const auth = defineAuth({
loginWith: {
phone: true,
},
});
25 changes: 25 additions & 0 deletions infra-gen2/backends/auth/phone-sign-in/amplify/backend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { defineBackend } from "@aws-amplify/backend";
import { addAuthUserExtensions } from "infra-common";
import { auth } from "./auth/resource";

const backend = defineBackend({
auth,
});

const resources = backend.auth.resources;
const { userPool, cfnResources } = resources;
const { stack } = userPool;
const { cfnUserPool } = cfnResources;

// Adds infra for creating/deleting users via App Sync and fetching confirmation
// and MFA codes from App Sync.
const customOutputs = addAuthUserExtensions({
Jordan-Nelson marked this conversation as resolved.
Show resolved Hide resolved
name: "phone-sign-in",
stack,
userPool,
cfnUserPool,
});
backend.addOutput(customOutputs);
3 changes: 3 additions & 0 deletions infra-gen2/backends/auth/phone-sign-in/amplify/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
17 changes: 17 additions & 0 deletions infra-gen2/backends/auth/phone-sign-in/amplify/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "es2022",
"module": "es2022",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"paths": {
"$amplify/*": [
"../.amplify/generated/*"
]
}
}
}
5 changes: 5 additions & 0 deletions infra-gen2/backends/auth/phone-sign-in/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "phone-sign-in",
"version": "1.0.0",
"main": "index.js"
}
3 changes: 2 additions & 1 deletion infra-gen2/infra-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
".": "./dist/index.js"
},
"scripts": {
"build": "tsc"
"build": "tsc && npm run copy-graphql",
"copy-graphql": "cp -r ./src/schemas ./dist"
}
}
6 changes: 6 additions & 0 deletions infra-gen2/infra-common/src/auth-user-extensions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# auth-user-extensions

This directory contains extensions useful for managing authorized users, including:

- creating & deleting users via App Sync
- sending confirmation codes to App Sync instead of email/SMS
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { BackendBase } from "@aws-amplify/backend";
import { Stack } from "aws-cdk-lib";
import { CfnUserPool, IUserPool } from "aws-cdk-lib/aws-cognito";
import { addCreateUserLambda } from "./create-user-lambda";
import { addCustomSenderLambda } from "./custom-sender-lambda";
import { addDeleteUserLambda } from "./delete-user-lambda";
import { addUserGraphql } from "./user-graphql";

type AmplifyOutputs = Parameters<BackendBase["addOutput"]>[0];

export const addAuthUserExtensions = ({
name,
stack,
userPool,
cfnUserPool,
}: {
name: string;
stack: Stack;
userPool: IUserPool;
cfnUserPool: CfnUserPool;
}): AmplifyOutputs => {
const graphQL = addUserGraphql(stack);
addCustomSenderLambda({ name, stack, cfnUserPool, graphQL });
addCreateUserLambda({ name, stack, userPool, graphQL });
addDeleteUserLambda({ name, stack, userPool, graphQL });
return {
data: {
aws_region: stack.region,
url: graphQL.graphqlUrl,
api_key: graphQL.apiKey,
default_authorization_type: "API_KEY",
authorization_types: [],
},
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { Stack } from "aws-cdk-lib";
import { GraphqlApi, MappingTemplate } from "aws-cdk-lib/aws-appsync";
import { IUserPool } from "aws-cdk-lib/aws-cognito";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import path from "path";

export function addCreateUserLambda({
name,
stack,
graphQL,
userPool,
}: {
name: string;
stack: Stack;
graphQL: GraphqlApi;
userPool: IUserPool;
}) {
const createUserLambda = new NodejsFunction(stack, `${name}-createUser`, {
entry: path.resolve(__dirname, "..", "lambda-triggers", "create-user.js"),
runtime: Runtime.NODEJS_18_X,
environment: {
USER_POOL_ID: userPool.userPoolId,
},
});
userPool.grant(
createUserLambda,
"cognito-idp:AdminCreateUser",
"cognito-idp:AdminSetUserPassword",
"cognito-idp:AdminSetUserMFAPreference",
"cognito-idp:AdminUpdateUserAttributes"
);
const createUserSource = graphQL.addLambdaDataSource(
`${name}-GraphQLApiCreateUserLambda`,
createUserLambda
);
createUserSource.createResolver(`${name}-MutationCreateUserResolver`, {
typeName: "Mutation",
fieldName: "createUser",
requestMappingTemplate: MappingTemplate.lambdaRequest(),
responseMappingTemplate: MappingTemplate.lambdaResult(),
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { RemovalPolicy, Stack } from "aws-cdk-lib";
import {
Assign,
GraphqlApi,
MappingTemplate,
PrimaryKey,
Values,
} from "aws-cdk-lib/aws-appsync";
import { CfnUserPool } from "aws-cdk-lib/aws-cognito";
import { AttributeType, BillingMode, Table } from "aws-cdk-lib/aws-dynamodb";
import { ServicePrincipal } from "aws-cdk-lib/aws-iam";
import { Key } from "aws-cdk-lib/aws-kms";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import path from "path";

export function addCustomSenderLambda({
name,
stack,
graphQL,
cfnUserPool,
}: {
name: string;
stack: Stack;
graphQL: GraphqlApi;
cfnUserPool: CfnUserPool;
}): NodejsFunction {
const customSenderKmsKey = new Key(stack, `${name}-CustomSenderKey`, {
description: `Key for encrypting/decrypting SMS messages sent from ${stack.stackId}`,
removalPolicy: RemovalPolicy.DESTROY,
});

const customEmailSender = new NodejsFunction(
stack,
`${name}-customEmailSender`,
{
entry: path.resolve(
__dirname,
"..",
"lambda-triggers",
"custom-email-sender.js"
),
runtime: Runtime.NODEJS_18_X,
bundling: {
nodeModules: ["@aws-crypto/client-node"],
},
environment: {
GRAPHQL_API_ENDPOINT: graphQL.graphqlUrl,
GRAPHQL_API_KEY: graphQL.apiKey!,
KMS_KEY_ARN: customSenderKmsKey.keyArn,
},
}
);

customEmailSender.addPermission("PermitCognitoInvoke", {
principal: new ServicePrincipal("cognito-idp.amazonaws.com"),
sourceArn: cfnUserPool.attrArn,
});

const customSmsSender = new NodejsFunction(stack, `${name}-customSmsSender`, {
entry: path.resolve(
__dirname,
"..",
"lambda-triggers",
"custom-sms-sender.js"
),
runtime: Runtime.NODEJS_18_X,
bundling: {
nodeModules: ["@aws-crypto/client-node"],
},
environment: {
GRAPHQL_API_ENDPOINT: graphQL.graphqlUrl,
GRAPHQL_API_KEY: graphQL.apiKey!,
KMS_KEY_ARN: customSenderKmsKey.keyArn,
},
});

customSmsSender.addPermission("PermitCognitoInvoke", {
principal: new ServicePrincipal("cognito-idp.amazonaws.com"),
sourceArn: cfnUserPool.attrArn,
});

cfnUserPool.lambdaConfig = {
customEmailSender: {
lambdaArn: customEmailSender.functionArn,
lambdaVersion: "V1_0",
},
customSmsSender: {
lambdaArn: customSmsSender.functionArn,
lambdaVersion: "V1_0",
},
kmsKeyId: customSenderKmsKey.keyArn,
};

graphQL.grantMutation(customEmailSender);
customSenderKmsKey.grantDecrypt(customEmailSender);

graphQL.grantMutation(customSmsSender);
customSenderKmsKey.grantDecrypt(customSmsSender);

const mfaCodesTable = new Table(stack, `${name}-MFACodesTable`, {
removalPolicy: RemovalPolicy.DESTROY,
billingMode: BillingMode.PAY_PER_REQUEST,
partitionKey: {
type: AttributeType.STRING,
name: "username",
},
sortKey: {
type: AttributeType.STRING,
name: "code",
},
});

const mfaCodesSource = graphQL.addDynamoDbDataSource(
"GraphQLApiMFACodes",
mfaCodesTable
);

// Mutation.createMFACode
mfaCodesSource.createResolver(`${name}-MutationCreateMFACodeResolver`, {
typeName: "Mutation",
fieldName: "createMFACode",
requestMappingTemplate: MappingTemplate.dynamoDbPutItem(
new PrimaryKey(
new Assign("username", "$input.username"),
new Assign("code", "$input.code")
),
Values.projecting("input")
),
responseMappingTemplate: MappingTemplate.dynamoDbResultItem(),
});

// Query.listMFACodes
mfaCodesSource.createResolver(`${name}-QueryListMFACodesResolver`, {
typeName: "Query",
fieldName: "listMFACodes",
requestMappingTemplate: MappingTemplate.dynamoDbScanTable(),
responseMappingTemplate: MappingTemplate.dynamoDbResultItem(),
});

return customEmailSender;
}
Loading
Loading