feat(cognito): fixed pool/client ids and seeded authenticator secrets
Merged
ZE
14d ago+1625+1625+0123456789012345678901234567890123456789-110-110-012345678901234567890123456789
Summary
Closes #2702.
CreateUserPooltakes the pool id from a_custom_id_UserPoolTagsentry andCreateUserPoolClienttakes the client id from a_custom_id_:<id>ClientName, the same convention as LocalStack. The pool id must be<region>_<alphanumeric id>in the request's region (the ARN, issuer and discovery URLs read the region back out of the id) and at most 55 characters; the client id must match theClientIdTypepattern ([\w+]+, 1-128). An id already used in any account (the JWKS, discovery and OAuth2 routes look pools and clients up across accounts) fails withInvalidParameterException. Without the tag or prefix nothing changes. The tag stays in the pool's tags and the client name is stored as sent.POST /_fakecloud/cognito/software-tokenwith{"userPoolId", "username", "secretCode"}gives the user a verified TOTP secret, the stateAssociateSoftwareToken+VerifySoftwareTokenleave behind.400for a secret that is not base32,404for an unknown pool or user. Like the other state-changing Cognito endpoints that need it (authorization-codes), it writes the snapshot through, so the secret survives a restart in persistent mode.- Rust SDK:
cognito().set_software_token(...)withSetSoftwareTokenRequest/SetSoftwareTokenResponse. I didn't add helpers to the other six SDKs; happy to add them here if you want them in this PR. - Docs:
docs/services/cognito.mdanddocs/reference/introspection.md.
Usage from an init script:
aws cognito-idp create-user-pool --pool-name local --user-pool-tags _custom_id_=us-east-1_Local
aws cognito-idp create-user-pool-client --user-pool-id us-east-1_Local --client-name _custom_id_:localclient
curl -X POST http://localhost:4566/_fakecloud/cognito/software-token \
-H 'Content-Type: application/json' \
-d '{"userPoolId":"us-east-1_Local","username":"dev","secretCode":"JBSWY3DPEHPK3PXP"}'
Test plan
- Unit (
fakecloud-cognito, 419 pass): custom pool id taken, reused and invalid ids (other region, empty, non-alphanumeric, missing region) rejected; custom client id taken, reused and invalid ids rejected;set_software_tokenstores a verified secret and rejects bad secrets and unknown pools/users. - E2E
cognito_custom_ids_and_seeded_software_token: pool and client created with the AWS CLI using the fixed ids, the duplicate pool rejected, secret seeded through the endpoint (plus 400/404 cases), thenAdminInitiateAuthon an MFAONpool getsSOFTWARE_TOKEN_MFAand a code from the seeded secret returns tokens. - E2E
persistence_custom_ids_and_seeded_software_token: the same sign-in works after a restart, with seeding as the last write before it. cognito,cognito_persistence,cognito_authorize,cognito_dispatch,cfn_cognito,cloudformation_cognitoe2e pass;fakecloud-sdktests pass;cargo fmt --all --checkandscripts/check-doc-counts.shclean.cargo clippy --workspace --all-targets -- -D warningsis clean for the changed crates. With my local clippy (1.96), three existingnonminimal_boolerrors infakecloud-ec2(image.rs:294,snapshot.rs:198,volume.rs:456) stop the workspace run; they are not touched here.
Summary by cubic
Lets local setups create Cognito pools and clients with predetermined ids and seed verified authenticator-app secrets, so sign-in flows can be scripted without inspecting generated ids.
CreateUserPooltakes the pool id from a_custom_id_tag (<region>_<alphanumeric id>in the request's region) andCreateUserPoolClientfrom a_custom_id_:<id>client name, matching LocalStack's convention; CloudFormationUserPool/UserPoolClientresources honor the same convention. Ids already in use in any account are rejected withInvalidParameterException(a duplicate pool is rejected before RSA keygen), an id is fixed at creation, and without the tag or prefix behavior is unchanged.- New
POST /_fakecloud/cognito/software-tokengives a user a verified TOTP secret (400for non-base32 secrets, including non-ASCII;404for unknown pools/users), resolving alias usernames onUsernameAttributespools; it persists through restarts in persistent mode. - Deleting a pool or client now purges all related state — tokens, sessions, authorization codes, tags, UI/risk/log config, brandings, terms, WebAuthn credentials, auth events and PreTokenGeneration invocations — so a resource recreated under the same custom id starts clean; a pool with
DeletionProtectionACTIVE cannot be deleted. - Adds
set_software_tokento all seven SDKs and documents both features.