Skip to content

Commit

Permalink
feat(api): describeUserPoolClient support
Browse files Browse the repository at this point in the history
  • Loading branch information
jagregory committed Jul 23, 2021
1 parent 153b71a commit 26cf370
Show file tree
Hide file tree
Showing 17 changed files with 164 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ perfect, because it won't be.
- [ConfirmForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmForgotPassword.html)
- [ConfirmSignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmSignUp.html)
- [CreateUserPoolClient](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPoolClient.html)
- [DescribeUserPoolClient](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_DescribeUserPoolClient.html)
- [ForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ForgotPassword.html)
- [GetUser](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_GetUser.html)
- [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html)
Expand Down
7 changes: 6 additions & 1 deletion src/services/cognitoClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from "./userPoolClient";

export interface CognitoClient {
getAppClient(clientId: string): Promise<AppClient | null>;
getUserPool(userPoolId: string): Promise<UserPoolClient>;
getUserPoolForClientId(clientId: string): Promise<UserPoolClient>;
}
Expand Down Expand Up @@ -63,7 +64,7 @@ export class CognitoClientService implements CognitoClient {
public async getUserPoolForClientId(
clientId: string
): Promise<UserPoolClient> {
const appClient = await this.clients.get<AppClient>(["Clients", clientId]);
const appClient = await this.getAppClient(clientId);
if (!appClient) {
throw new ResourceNotFoundError();
}
Expand All @@ -75,4 +76,8 @@ export class CognitoClientService implements CognitoClient {
this.logger
);
}

public async getAppClient(clientId: string): Promise<AppClient | null> {
return this.clients.get(["Clients", clientId]);
}
}
1 change: 1 addition & 0 deletions src/services/triggers/customMessage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe("CustomMessage trigger", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
1 change: 1 addition & 0 deletions src/services/triggers/postConfirmation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe("PostConfirmation trigger", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
1 change: 1 addition & 0 deletions src/services/triggers/userMigration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe("UserMigration trigger", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
1 change: 1 addition & 0 deletions src/targets/confirmForgotPassword.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe("ConfirmForgotPassword target", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
1 change: 1 addition & 0 deletions src/targets/confirmSignUp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe("ConfirmSignUp target", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
1 change: 1 addition & 0 deletions src/targets/createUserPoolClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe("CreateUserPoolClient target", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
70 changes: 70 additions & 0 deletions src/targets/describeUserPoolClient.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { advanceTo } from "jest-date-mock";
import { ResourceNotFoundError } from "../errors";
import { CognitoClient, UserPoolClient } from "../services";
import { AppClient } from "../services/appClient";
import {
DescribeUserPoolClient,
DescribeUserPoolClientTarget,
} from "./describeUserPoolClient";

describe("DescribeUserPoolClient target", () => {
let describeUserPoolClient: DescribeUserPoolClientTarget;
let mockCognitoClient: jest.Mocked<CognitoClient>;
let mockUserPoolClient: jest.Mocked<UserPoolClient>;
let now: Date;

beforeEach(() => {
now = new Date(2020, 1, 2, 3, 4, 5);
advanceTo(now);

mockUserPoolClient = {
config: {
Id: "test",
},
createAppClient: jest.fn(),
getUserByUsername: jest.fn(),
listUsers: jest.fn(),
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};

describeUserPoolClient = DescribeUserPoolClient({
cognitoClient: mockCognitoClient,
});
});

it("returns an existing app client", async () => {
const existingAppClient: AppClient = {
RefreshTokenValidity: 30,
AllowedOAuthFlowsUserPoolClient: false,
LastModifiedDate: new Date().getTime(),
CreationDate: new Date().getTime(),
UserPoolId: "userPoolId",
ClientId: "abc",
ClientName: "clientName",
};
mockCognitoClient.getAppClient.mockResolvedValue(existingAppClient);

const result = await describeUserPoolClient({
ClientId: "abc",
UserPoolId: "userPoolId",
});

expect(result).toEqual({ UserPoolClient: existingAppClient });
});

it("throws resource not found for an invalid app client", async () => {
mockCognitoClient.getAppClient.mockResolvedValue(null);

await expect(
describeUserPoolClient({
ClientId: "abc",
UserPoolId: "userPoolId",
})
).rejects.toEqual(new ResourceNotFoundError());
});
});
72 changes: 72 additions & 0 deletions src/targets/describeUserPoolClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { ResourceNotFoundError } from "../errors";
import { Services } from "../services";
import { UserAttribute } from "../services/userPoolClient";

interface Input {
ClientId: string;
UserPoolId: string;
}

export interface DynamoDBUserRecord {
Username: string;
UserCreateDate: number;
UserLastModifiedDate: number;
Enabled: boolean;
UserStatus: "CONFIRMED" | "UNCONFIRMED" | "RESET_REQUIRED";
Attributes: readonly UserAttribute[];
}

interface Output {
UserPoolClient: {
AccessTokenValidity?: number;
AllowedOAuthFlows?: ("code" | "implicit" | "client_credentials")[];
AllowedOAuthFlowsUserPoolClient?: boolean;
AllowedOAuthScopes?: string[];
AnalyticsConfiguration?: {
ApplicationArn?: string;
ApplicationId?: string;
ExternalId?: string;
RoleArn?: string;
UserDataShared?: boolean;
};
CallbackURLs?: string[];
ClientId?: string;
ClientName?: string;
ClientSecret?: string;
CreationDate?: number;
DefaultRedirectURI?: string;
EnableTokenRevocation?: boolean;
ExplicitAuthFlows?: string[];
IdTokenValidity?: number;
LastModifiedDate?: number;
LogoutURLs?: string[];
PreventUserExistenceErrors?: "LEGACY" | "ENABLED";
ReadAttributes?: string[];
RefreshTokenValidity?: number;
SupportedIdentityProviders?: string[];
TokenValidityUnits?: {
AccessToken?: "seconds" | "minutes" | "hours" | "days";
IdToken?: "seconds" | "minutes" | "hours" | "days";
RefreshToken?: "seconds" | "minutes" | "hours" | "days";
};
UserPoolId?: string;
WriteAttributes?: string[];
};
}

export type DescribeUserPoolClientTarget = (body: Input) => Promise<Output>;

export const DescribeUserPoolClient = ({
cognitoClient,
}: Pick<Services, "cognitoClient">): DescribeUserPoolClientTarget => async (
body
) => {
const client = await cognitoClient.getAppClient(body.ClientId);
if (client?.UserPoolId !== body.UserPoolId) {
throw new ResourceNotFoundError();
}

return {
UserPoolClient: client,
};
};
1 change: 1 addition & 0 deletions src/targets/forgotPassword.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe("ForgotPassword target", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
1 change: 1 addition & 0 deletions src/targets/getUser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe("GetUser target", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
1 change: 1 addition & 0 deletions src/targets/initiateAuth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ describe("InitiateAuth target", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
1 change: 1 addition & 0 deletions src/targets/listUsers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe("ListUsers target", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
1 change: 1 addition & 0 deletions src/targets/respondToAuthChallenge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe("RespondToAuthChallenge target", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down
4 changes: 3 additions & 1 deletion src/targets/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { UnsupportedError } from "../errors";
import { ConfirmForgotPassword } from "./confirmForgotPassword";
import { ConfirmSignUp } from "./confirmSignUp";
import { CreateUserPoolClient } from "./createUserPoolClient";
import { DescribeUserPoolClient } from "./describeUserPoolClient";
import { ForgotPassword } from "./forgotPassword";
import { InitiateAuth } from "./initiateAuth";
import { ListUsers } from "./listUsers";
Expand All @@ -15,12 +16,13 @@ export const Targets = {
ConfirmForgotPassword,
ConfirmSignUp,
CreateUserPoolClient,
DescribeUserPoolClient,
ForgotPassword,
GetUser,
InitiateAuth,
ListUsers,
RespondToAuthChallenge,
SignUp,
GetUser,
};

type TargetName = keyof typeof Targets;
Expand Down
1 change: 1 addition & 0 deletions src/targets/signUp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe("SignUp target", () => {
saveUser: jest.fn(),
};
mockCognitoClient = {
getAppClient: jest.fn(),
getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient),
getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient),
};
Expand Down

0 comments on commit 26cf370

Please sign in to comment.