From 752997144479f66168023604ee326e48c3e31fb3 Mon Sep 17 00:00:00 2001 From: James Gregory Date: Thu, 25 Nov 2021 18:51:41 +1100 Subject: [PATCH] fix(api): adminCreateUser handles duplicate users --- src/targets/adminCreateUser.test.ts | 18 +++++++++++++++++- src/targets/adminCreateUser.ts | 10 ++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/targets/adminCreateUser.test.ts b/src/targets/adminCreateUser.test.ts index 971157e0..3b405dd4 100644 --- a/src/targets/adminCreateUser.test.ts +++ b/src/targets/adminCreateUser.test.ts @@ -1,8 +1,10 @@ import { ClockFake } from "../__tests__/clockFake"; import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; import { UUID } from "../__tests__/patterns"; +import { UsernameExistsError } from "../errors"; import { CognitoClient } from "../services"; import { AdminCreateUser, AdminCreateUserTarget } from "./adminCreateUser"; +import * as TDB from "../__tests__/testDataBuilder"; describe("AdminCreateUser target", () => { let adminCreateUser: AdminCreateUserTarget; @@ -52,7 +54,21 @@ describe("AdminCreateUser target", () => { it.todo("can create an alias to an existing user"); it.todo("can resend the welcome message"); it.todo("can suppress the welcome message"); - it.todo("handles creating a duplicate user"); + + it("handles creating a duplicate user", async () => { + const existingUser = TDB.user(); + MockUserPoolClient.getUserByUsername.mockResolvedValue(existingUser); + + await expect( + adminCreateUser({ + TemporaryPassword: "pwd", + UserAttributes: existingUser.Attributes, + Username: existingUser.Username, + UserPoolId: "test", + }) + ).rejects.toEqual(new UsernameExistsError()); + }); + it.todo("invokes the PreSignIn lambda"); it.todo("saves a user with a generated temporary password"); it.todo("sends a welcome message to the user"); diff --git a/src/targets/adminCreateUser.ts b/src/targets/adminCreateUser.ts index 602077db..81fef786 100644 --- a/src/targets/adminCreateUser.ts +++ b/src/targets/adminCreateUser.ts @@ -3,7 +3,7 @@ import { AdminCreateUserResponse, } from "aws-sdk/clients/cognitoidentityserviceprovider"; import uuid from "uuid"; -import { UnsupportedError } from "../errors"; +import { UnsupportedError, UsernameExistsError } from "../errors"; import { Services } from "../services"; import { attributesInclude, User } from "../services/userPoolClient"; @@ -22,6 +22,12 @@ export const AdminCreateUser = ({ } const userPool = await cognitoClient.getUserPool(req.UserPoolId); + const existingUser = await userPool.getUserByUsername(req.Username); + if (existingUser && req.MessageAction === "RESEND") { + throw new UnsupportedError("AdminCreateUser with MessageAction=RESEND"); + } else if (existingUser) { + throw new UsernameExistsError(); + } const attributes = attributesInclude("sub", req.UserAttributes) ? req.UserAttributes ?? [] @@ -41,7 +47,7 @@ export const AdminCreateUser = ({ }; await userPool.saveUser(user); - // TODO: should handle existing users + // TODO: should throw InvalidParameterException when a non-email is supplied as the Username when the pool has email as a UsernameAttribute // TODO: should send a message unless MessageAction=="SUPPRESS" // TODO: support MessageAction=="RESEND" // TODO: should generate a TemporaryPassword if one isn't set