From 0c405f20e7147e7cd7b29d16f1fc43b012863577 Mon Sep 17 00:00:00 2001 From: Ruan Leite <49437895+Ruanrls@users.noreply.github.com> Date: Tue, 31 Mar 2026 18:20:21 -0300 Subject: [PATCH] feat(cognito): add comprehensive group management tests for Cognito --- sdk-test-awscli/test_all.sh | 124 +++++++++++++++++- .../com/floci/test/tests/CognitoTests.java | 121 +++++++++++++++++ sdk-test-node/test-all.mjs | 76 ++++++++++- 3 files changed, 319 insertions(+), 2 deletions(-) diff --git a/sdk-test-awscli/test_all.sh b/sdk-test-awscli/test_all.sh index d1e6067..24ea11f 100755 --- a/sdk-test-awscli/test_all.sh +++ b/sdk-test-awscli/test_all.sh @@ -748,11 +748,133 @@ run_kms() { aws_cmd kms schedule-key-deletion --key-id "$key_id" --pending-window-in-days 7 >/dev/null 2>&1 || true } +# --------------------------------------------------------------------------- +# Cognito +# --------------------------------------------------------------------------- + +run_cognito() { + echo "--- Cognito Tests ---" + + local out rc pool_id client_id + + # CreateUserPool + out=$(aws_cmd cognito-idp create-user-pool --pool-name "cli-test-pool" 2>&1) && rc=0 || rc=1 + pool_id=$(echo "$out" | python -c "import sys,json; print(json.load(sys.stdin)['UserPool']['Id'])" 2>/dev/null || echo "") + check "Cognito CreateUserPool" "$( [ -n "$pool_id" ] && echo true || echo false )" "$out" + + # CreateUserPoolClient + out=$(aws_cmd cognito-idp create-user-pool-client --user-pool-id "$pool_id" --client-name "cli-client" 2>&1) && rc=0 || rc=1 + client_id=$(echo "$out" | python -c "import sys,json; print(json.load(sys.stdin)['UserPoolClient']['ClientId'])" 2>/dev/null || echo "") + check "Cognito CreateUserPoolClient" "$( [ -n "$client_id" ] && echo true || echo false )" "$out" + + # AdminCreateUser + out=$(aws_cmd cognito-idp admin-create-user \ + --user-pool-id "$pool_id" \ + --username "cliuser" \ + --temporary-password "Temp123!" \ + --user-attributes Name=email,Value=cliuser@example.com 2>&1) && rc=0 || rc=1 + local created_user + created_user=$(echo "$out" | python -c "import sys,json; print(json.load(sys.stdin)['User']['Username'])" 2>/dev/null || echo "") + check "Cognito AdminCreateUser" "$( [ "$created_user" = "cliuser" ] && echo true || echo false )" "$out" + + # AdminSetUserPassword + out=$(aws_cmd cognito-idp admin-set-user-password \ + --user-pool-id "$pool_id" --username "cliuser" \ + --password "Perm456!" --permanent 2>&1) && rc=0 || rc=1 + check "Cognito AdminSetUserPassword" "$( [ $rc -eq 0 ] && echo true || echo false )" "$out" + + # CreateGroup + out=$(aws_cmd cognito-idp create-group \ + --user-pool-id "$pool_id" \ + --group-name "test-group" \ + --description "Test group" \ + --precedence 1 2>&1) && rc=0 || rc=1 + local group_name + group_name=$(echo "$out" | python -c "import sys,json; print(json.load(sys.stdin)['Group']['GroupName'])" 2>/dev/null || echo "") + check "Cognito CreateGroup" "$( [ "$group_name" = "test-group" ] && echo true || echo false )" "$out" + + # GetGroup + out=$(aws_cmd cognito-idp get-group \ + --user-pool-id "$pool_id" --group-name "test-group" 2>&1) && rc=0 || rc=1 + local got_name got_desc got_prec + got_name=$(echo "$out" | python -c "import sys,json; print(json.load(sys.stdin)['Group']['GroupName'])" 2>/dev/null || echo "") + got_desc=$(echo "$out" | python -c "import sys,json; print(json.load(sys.stdin)['Group']['Description'])" 2>/dev/null || echo "") + got_prec=$(echo "$out" | python -c "import sys,json; print(json.load(sys.stdin)['Group']['Precedence'])" 2>/dev/null || echo "") + check "Cognito GetGroup" "$( [ "$got_name" = "test-group" ] && [ "$got_desc" = "Test group" ] && [ "$got_prec" = "1" ] && echo true || echo false )" "$out" + + # CreateGroup duplicate + out=$(aws_cmd cognito-idp create-group \ + --user-pool-id "$pool_id" --group-name "test-group" 2>&1) && rc=0 || rc=1 + check "Cognito CreateGroup duplicate rejected" "$( [ $rc -ne 0 ] && echo true || echo false )" "$out" + + # ListGroups + out=$(aws_cmd cognito-idp list-groups --user-pool-id "$pool_id" 2>&1) && rc=0 || rc=1 + local found_group + found_group=$(echo "$out" | python -c "import sys,json; d=json.load(sys.stdin); print('true' if any(g['GroupName']=='test-group' for g in d.get('Groups',[])) else 'false')" 2>/dev/null || echo false) + check "Cognito ListGroups" "$found_group" "$out" + + # AdminAddUserToGroup + out=$(aws_cmd cognito-idp admin-add-user-to-group \ + --user-pool-id "$pool_id" --group-name "test-group" --username "cliuser" 2>&1) && rc=0 || rc=1 + check "Cognito AdminAddUserToGroup" "$( [ $rc -eq 0 ] && echo true || echo false )" "$out" + + # AdminListGroupsForUser + out=$(aws_cmd cognito-idp admin-list-groups-for-user \ + --user-pool-id "$pool_id" --username "cliuser" 2>&1) && rc=0 || rc=1 + local user_has_group + user_has_group=$(echo "$out" | python -c "import sys,json; d=json.load(sys.stdin); print('true' if any(g['GroupName']=='test-group' for g in d.get('Groups',[])) else 'false')" 2>/dev/null || echo false) + check "Cognito AdminListGroupsForUser" "$user_has_group" "$out" + + # InitiateAuth and verify cognito:groups in JWT + out=$(aws_cmd cognito-idp initiate-auth \ + --auth-flow USER_PASSWORD_AUTH \ + --client-id "$client_id" \ + --auth-parameters USERNAME=cliuser,PASSWORD=Perm456! 2>&1) && rc=0 || rc=1 + local jwt_groups + jwt_groups=$(echo "$out" | python -c " +import sys,json,base64 +d=json.load(sys.stdin) +token=d['AuthenticationResult']['AccessToken'] +payload=base64.urlsafe_b64decode(token.split('.')[1]+'==') +claims=json.loads(payload) +groups=claims.get('cognito:groups',[]) +print('true' if 'test-group' in groups else 'false') +" 2>/dev/null || echo false) + check "Cognito JWT cognito:groups claim" "$jwt_groups" "$out" + + # AdminRemoveUserFromGroup + out=$(aws_cmd cognito-idp admin-remove-user-from-group \ + --user-pool-id "$pool_id" --group-name "test-group" --username "cliuser" 2>&1) && rc=0 || rc=1 + check "Cognito AdminRemoveUserFromGroup" "$( [ $rc -eq 0 ] && echo true || echo false )" "$out" + + # AdminListGroupsForUser — empty + out=$(aws_cmd cognito-idp admin-list-groups-for-user \ + --user-pool-id "$pool_id" --username "cliuser" 2>&1) && rc=0 || rc=1 + local groups_empty + groups_empty=$(echo "$out" | python -c "import sys,json; d=json.load(sys.stdin); print('true' if len(d.get('Groups',[]))==0 else 'false')" 2>/dev/null || echo false) + check "Cognito AdminListGroupsForUser empty" "$groups_empty" "$out" + + # DeleteGroup + out=$(aws_cmd cognito-idp delete-group \ + --user-pool-id "$pool_id" --group-name "test-group" 2>&1) && rc=0 || rc=1 + check "Cognito DeleteGroup" "$( [ $rc -eq 0 ] && echo true || echo false )" "$out" + + # GetGroup after delete — expect not found + out=$(aws_cmd cognito-idp get-group \ + --user-pool-id "$pool_id" --group-name "test-group" 2>&1) && rc=0 || rc=1 + check "Cognito GetGroup not found" "$( [ $rc -ne 0 ] && echo true || echo false )" "$out" + + # Cleanup + aws_cmd cognito-idp admin-delete-user --user-pool-id "$pool_id" --username "cliuser" >/dev/null 2>&1 || true + aws_cmd cognito-idp delete-user-pool-client --user-pool-id "$pool_id" --client-id "$client_id" >/dev/null 2>&1 || true + aws_cmd cognito-idp delete-user-pool --user-pool-id "$pool_id" >/dev/null 2>&1 || true +} + # --------------------------------------------------------------------------- # Group registry and entry point # --------------------------------------------------------------------------- -ALL_GROUPS=(ssm sqs sns s3 dynamodb dynamodb-gsi dynamodb-scan-filter iam sts secretsmanager kms) +ALL_GROUPS=(ssm sqs sns s3 dynamodb dynamodb-gsi dynamodb-scan-filter iam sts secretsmanager kms cognito) resolve_enabled() { local names=() diff --git a/sdk-test-java/src/main/java/com/floci/test/tests/CognitoTests.java b/sdk-test-java/src/main/java/com/floci/test/tests/CognitoTests.java index fdfe852..291ed29 100644 --- a/sdk-test-java/src/main/java/com/floci/test/tests/CognitoTests.java +++ b/sdk-test-java/src/main/java/com/floci/test/tests/CognitoTests.java @@ -6,6 +6,8 @@ import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient; import software.amazon.awssdk.services.cognitoidentityprovider.model.*; +import java.nio.charset.StandardCharsets; +import java.util.Base64; import java.util.Map; @FlociTestGroup @@ -90,6 +92,125 @@ public void run(TestContext ctx) { } } + // ── Groups ──────────────────────────────────────────────────── + + // CreateGroup + try { + CreateGroupResponse groupResp = cognito.createGroup(b -> b + .userPoolId(fPoolId) + .groupName("test-group") + .description("Test group") + .precedence(1)); + ctx.check("Cognito CreateGroup", + "test-group".equals(groupResp.group().groupName())); + } catch (Exception e) { + ctx.check("Cognito CreateGroup", false, e); + } + + // GetGroup + try { + GetGroupResponse ggResp = cognito.getGroup(b -> b + .userPoolId(fPoolId).groupName("test-group")); + ctx.check("Cognito GetGroup", + "test-group".equals(ggResp.group().groupName()) + && "Test group".equals(ggResp.group().description()) + && ggResp.group().precedence() == 1); + } catch (Exception e) { + ctx.check("Cognito GetGroup", false, e); + } + + // CreateGroup duplicate + try { + cognito.createGroup(b -> b.userPoolId(fPoolId).groupName("test-group")); + ctx.check("Cognito CreateGroup duplicate rejected", false); + } catch (GroupExistsException e) { + ctx.check("Cognito CreateGroup duplicate rejected", true); + } catch (Exception e) { + ctx.check("Cognito CreateGroup duplicate rejected", false, e); + } + + // ListGroups + try { + ListGroupsResponse lgResp = cognito.listGroups(b -> b.userPoolId(fPoolId)); + ctx.check("Cognito ListGroups", + lgResp.groups().stream().anyMatch(g -> "test-group".equals(g.groupName()))); + } catch (Exception e) { + ctx.check("Cognito ListGroups", false, e); + } + + // AdminAddUserToGroup + try { + cognito.adminAddUserToGroup(b -> b + .userPoolId(fPoolId).groupName("test-group").username(fUsername)); + ctx.check("Cognito AdminAddUserToGroup", true); + } catch (Exception e) { + ctx.check("Cognito AdminAddUserToGroup", false, e); + } + + // AdminListGroupsForUser + try { + AdminListGroupsForUserResponse algResp = cognito.adminListGroupsForUser(b -> b + .userPoolId(fPoolId).username(fUsername)); + ctx.check("Cognito AdminListGroupsForUser", + algResp.groups().stream().anyMatch(g -> "test-group".equals(g.groupName()))); + } catch (Exception e) { + ctx.check("Cognito AdminListGroupsForUser", false, e); + } + + // Authenticate and verify cognito:groups in JWT + if (clientId != null) { + final String fClientId = clientId; + try { + AdminInitiateAuthResponse authResp = cognito.adminInitiateAuth(b -> b + .userPoolId(fPoolId).clientId(fClientId) + .authFlow(AuthFlowType.ADMIN_NO_SRP_AUTH) + .authParameters(Map.of("USERNAME", fUsername, "PASSWORD", "any"))); + String token = authResp.authenticationResult().accessToken(); + String[] parts = token.split("\\."); + String payload = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); + ctx.check("Cognito JWT cognito:groups claim", + payload.contains("\"cognito:groups\"") && payload.contains("\"test-group\"")); + } catch (Exception e) { + ctx.check("Cognito JWT cognito:groups claim", false, e); + } + } + + // AdminRemoveUserFromGroup + try { + cognito.adminRemoveUserFromGroup(b -> b + .userPoolId(fPoolId).groupName("test-group").username(fUsername)); + ctx.check("Cognito AdminRemoveUserFromGroup", true); + } catch (Exception e) { + ctx.check("Cognito AdminRemoveUserFromGroup", false, e); + } + + // AdminListGroupsForUser — empty after removal + try { + AdminListGroupsForUserResponse algResp2 = cognito.adminListGroupsForUser(b -> b + .userPoolId(fPoolId).username(fUsername)); + ctx.check("Cognito AdminListGroupsForUser empty", algResp2.groups().isEmpty()); + } catch (Exception e) { + ctx.check("Cognito AdminListGroupsForUser empty", false, e); + } + + // DeleteGroup + try { + cognito.deleteGroup(b -> b.userPoolId(fPoolId).groupName("test-group")); + ctx.check("Cognito DeleteGroup", true); + } catch (Exception e) { + ctx.check("Cognito DeleteGroup", false, e); + } + + // GetGroup after delete — expect not found + try { + cognito.getGroup(b -> b.userPoolId(fPoolId).groupName("test-group")); + ctx.check("Cognito GetGroup not found", false); + } catch (ResourceNotFoundException e) { + ctx.check("Cognito GetGroup not found", true); + } catch (Exception e) { + ctx.check("Cognito GetGroup not found", false, e); + } + // ── Cleanup ─────────────────────────────────────────────────── try { diff --git a/sdk-test-node/test-all.mjs b/sdk-test-node/test-all.mjs index bbabb76..e4688b6 100644 --- a/sdk-test-node/test-all.mjs +++ b/sdk-test-node/test-all.mjs @@ -21,7 +21,7 @@ import { KMSClient, CreateKeyCommand, ListKeysCommand, DescribeKeyCommand, Encry import { KinesisClient, CreateStreamCommand, DescribeStreamCommand, PutRecordCommand, GetShardIteratorCommand, GetRecordsCommand, DeleteStreamCommand, ListStreamsCommand } from "@aws-sdk/client-kinesis"; import { CloudWatchClient, PutMetricDataCommand, GetMetricStatisticsCommand, ListMetricsCommand, PutMetricAlarmCommand, DescribeAlarmsCommand, DeleteAlarmsCommand } from "@aws-sdk/client-cloudwatch"; import { createPublicKey, createVerify } from "node:crypto"; -import { CognitoIdentityProviderClient, CreateUserPoolCommand, CreateUserPoolClientCommand, CreateResourceServerCommand, DescribeResourceServerCommand, ListResourceServersCommand, UpdateResourceServerCommand, DeleteResourceServerCommand, DeleteUserPoolClientCommand, AdminCreateUserCommand, AdminSetUserPasswordCommand, InitiateAuthCommand, RespondToAuthChallengeCommand, SignUpCommand, ConfirmSignUpCommand, AdminGetUserCommand, ListUsersCommand, DeleteUserPoolCommand } from "@aws-sdk/client-cognito-identity-provider"; +import { CognitoIdentityProviderClient, CreateUserPoolCommand, CreateUserPoolClientCommand, CreateResourceServerCommand, DescribeResourceServerCommand, ListResourceServersCommand, UpdateResourceServerCommand, DeleteResourceServerCommand, DeleteUserPoolClientCommand, AdminCreateUserCommand, AdminSetUserPasswordCommand, InitiateAuthCommand, RespondToAuthChallengeCommand, SignUpCommand, ConfirmSignUpCommand, AdminGetUserCommand, ListUsersCommand, DeleteUserPoolCommand, CreateGroupCommand, GetGroupCommand, ListGroupsCommand, DeleteGroupCommand, AdminAddUserToGroupCommand, AdminRemoveUserFromGroupCommand, AdminListGroupsForUserCommand } from "@aws-sdk/client-cognito-identity-provider"; const ENDPOINT = process.env.FLOCI_ENDPOINT || "http://localhost:4566"; const REGION = "us-east-1"; @@ -1228,6 +1228,80 @@ async function testCognito() { check("SignUp+Confirm succeeded", true); }); + // ── Groups ────────────────────────────────────────────────────── + + await tryOk("CreateGroup", async () => { + const r = await cognito.send(new CreateGroupCommand({ + UserPoolId: poolId, GroupName: "test-group", + Description: "Test group", Precedence: 1 + })); + check("Group name returned", r.Group.GroupName === "test-group"); + }); + + await tryOk("GetGroup", async () => { + const r = await cognito.send(new GetGroupCommand({ + UserPoolId: poolId, GroupName: "test-group" + })); + check("GetGroup name", r.Group.GroupName === "test-group"); + check("GetGroup description", r.Group.Description === "Test group"); + check("GetGroup precedence", r.Group.Precedence === 1); + }); + + await tryFail("CreateGroup duplicate", () => + cognito.send(new CreateGroupCommand({ + UserPoolId: poolId, GroupName: "test-group" + }))); + + await tryOk("ListGroups", async () => { + const r = await cognito.send(new ListGroupsCommand({ UserPoolId: poolId })); + check("Group in list", r.Groups.some(g => g.GroupName === "test-group")); + }); + + await tryOk("AdminAddUserToGroup", () => + cognito.send(new AdminAddUserToGroupCommand({ + UserPoolId: poolId, GroupName: "test-group", Username: "nodeuser" + }))); + + await tryOk("AdminListGroupsForUser", async () => { + const r = await cognito.send(new AdminListGroupsForUserCommand({ + UserPoolId: poolId, Username: "nodeuser" + })); + check("User has group", r.Groups.some(g => g.GroupName === "test-group")); + }); + + await tryOk("InitiateAuth groups in JWT", async () => { + const r = await cognito.send(new InitiateAuthCommand({ + AuthFlow: "USER_PASSWORD_AUTH", + AuthParameters: { USERNAME: "nodeuser", PASSWORD: "Perm456!" }, + ClientId: clientId + })); + const payload = decodeJwtPart(r.AuthenticationResult.AccessToken, 1); + check("JWT cognito:groups present", Array.isArray(payload["cognito:groups"])); + check("JWT cognito:groups contains test-group", payload["cognito:groups"]?.includes("test-group")); + }); + + await tryOk("AdminRemoveUserFromGroup", () => + cognito.send(new AdminRemoveUserFromGroupCommand({ + UserPoolId: poolId, GroupName: "test-group", Username: "nodeuser" + }))); + + await tryOk("AdminListGroupsForUser empty", async () => { + const r = await cognito.send(new AdminListGroupsForUserCommand({ + UserPoolId: poolId, Username: "nodeuser" + })); + check("No groups after removal", r.Groups.length === 0); + }); + + await tryOk("DeleteGroup", () => + cognito.send(new DeleteGroupCommand({ + UserPoolId: poolId, GroupName: "test-group" + }))); + + await tryFail("GetGroup not found", () => + cognito.send(new GetGroupCommand({ + UserPoolId: poolId, GroupName: "test-group" + }))); + await tryOk("JWKS endpoint", async () => { const resp = await fetch(`${ENDPOINT}/${poolId}/.well-known/jwks.json`); check("JWKS status 200", resp.ok);