Skip to content

Commit 00eac15

Browse files
github-actions[bot]harsh62dmorrowclaude
authored
chore: kickoff release (#4264)
* chore(deps): bump aws-sdk-swift from 1.7.27 to 1.7.53 (#4262) Updates the aws-sdk-swift dependency to 1.7.53, which moves the transitive dependency: smithy-swift 0.223.0 -> 0.238.0 aws-crt-swift stays resolved at 0.64.1: smithy-swift raised its floor from `from: "0.63.0"` to `from: "0.64.0"`, which the already-pinned 0.64.1 satisfies. No other transitive pins change. The aws-sdk-swift range is almost entirely API and endpoint model regeneration. For the services Amplify depends on the changes are additive only: Cognito Identity Provider gains GetProvisionedLimit / UpdateProvisionedLimit, EumsSms in SmsConfigurationType, and AdminGetUserAuthFactors; CloudWatch Logs gains storage-tier and lookup-table APIs; TranscribeStreaming gains an optional TranscriptFormat parameter. The one breaking entry in the range (1.7.28 removes SimSpaceWeaver, Panorama, IoT Events, IoT Events Data) does not touch any Amplify dependency. smithy-swift's breaking changes in 0.224.0-0.238.0 are confined to the @_spi(SchemaBasedSerde) codegen surface that only the SDK's own generated code consumes: ShapeDeserializer.readInteger/readLong narrowing to Int32/Int64, readDocument returning `any SmithyDocument`, and ReadStructConsumer being replaced by a deserializeMember requirement. The modules Amplify imports directly - SmithyIdentity, SmithyRetries, SmithyHTTPAuth and their API variants - are unchanged. ClientRuntime's only behavioral delta is percent-encoding moving its implementation into SmithyHTTPAPI.URLEncodingUtils with the same allowed character sets. Verified that the non-sparse-map null regression which gated the previous bump (#4234) has not returned: SmithyJSON's Deserializer still compacts UnexpectedNullError out of non-sparse maps and lists, so Cognito RespondToAuthChallenge responses carrying a null ChallengeParameters value (e.g. "FRIENDLY_DEVICE_NAME": null in the SELECT_MFA_TYPE challenge) continue to deserialize. * fix(auth): key device metadata by inputUsername so alias sign-in pools remember devices (#4254) * fix(auth): read device metadata with the caller's username during sign-in `ConfirmDevice` stores device metadata under `signedInData.inputUsername` (the username the caller signed in with), but the sign-in flow read it back using `parameters["USERNAME"]` — the value Cognito echoes, which is the sub for pools configured with alias sign-in. On those pools the read never matched the write, so `DEVICE_KEY` was omitted from the password-verifier response. Cognito treated every sign-in as a new device: it returned fresh `NewDeviceMetadata`, `ConfirmDevice` stored it under the email again, and the next sign-in repeated the cycle — MFA on every sign-in and a new device record per attempt (one user had accumulated 50). Pools where the username *is* the email are unaffected, since the two values coincide there. Reads now use the same value as the write: - VerifyPasswordSRP: `inputUsername` - VerifySignInChallenge (both call sites): `challenge.inputUsername ?? username` Nothing sent to Cognito changes — `username` still supplies `USERNAME` on every request; only the keychain lookups moved. Known gap: the DeviceSRP actions (InitiateAuthDeviceSRP, VerifyDevicePasswordSRP) still look up by the echoed username. That path only executes once Cognito starts accepting the device key, so it is now reachable and tracked separately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(auth): delete device metadata with the same username used to read it Commit 122689e changed the sign-in flow to read device metadata with the caller's `inputUsername` (matching how `ConfirmDevice` writes it), but left the `deviceNotFound` recovery paths deleting under `username` — the value Cognito echoes, which is the sub for pools with alias sign-in. When a stored device key is stale, Cognito rejects the password verifier with `ResourceNotFoundException`. The recovery path then deletes the wrong keychain entry, leaving the real one in place, so the retry re-reads the same stale key, Cognito rejects it again, and sign-in loops indefinitely. Read and delete now use the same value in both actions: - VerifyPasswordSRP: `inputUsername` - VerifySignInChallenge: `challenge.inputUsername ?? username` Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(auth): use inputUsername for device metadata in the device SRP flow Once a device is remembered, Cognito answers the password verifier with DEVICE_SRP_AUTH instead of an MFA challenge, routing sign-in through InitiateAuthDeviceSRP / VerifyDevicePasswordSRP. Both looked the stored device metadata up by the Cognito-echoed username (the sub, on pools with alias sign-in) rather than the `inputUsername` it was written under, so the lookup missed and the request omitted DEVICE_KEY — Cognito then rejected sign-in with "Missing required parameter DEVICE_KEY". - UserPoolSignInHelper: carry `inputUsername ?? username` into `.initiateDeviceSRP` so InitiateAuthDeviceSRP reads (and re-sends) under the right key. - VerifyDevicePasswordSRP: read metadata with `inputUsername`; the request still sends `username` (the echoed value), which is what Cognito expects. Completes the alias-pool device-remembering fix (see prior two commits); the DEVICE_SRP_AUTH path is only reachable once DEVICE_KEY is accepted, so it could not be exercised until the earlier read/delete fixes landed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Harsh <6162866+harsh62@users.noreply.github.com> --------- Co-authored-by: Harsh <6162866+harsh62@users.noreply.github.com> Co-authored-by: Danny Morrow <danny@unitytheory.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 33cc3d3 commit 00eac15

6 files changed

Lines changed: 40 additions & 14 deletions

File tree

AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/DeviceSRPAuth/VerifyDevicePasswordSRP.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,12 @@ struct VerifyDevicePasswordSRP: Action {
4040
credentialStoreClient: environment.authEnvironment().credentialsClient
4141
)
4242

43+
// Read with the username the caller signed in with — `ConfirmDevice` writes the
44+
// metadata under `inputUsername` (here `stateData.username`). `username` is
45+
// `parameters["USERNAME"]`, the sub echoed by Cognito on alias pools, and is still the
46+
// correct value to send back in the request below.
4347
let deviceMetadata = await DeviceMetadataHelper.getDeviceMetadata(
44-
for: username,
48+
for: inputUsername,
4549
with: environment
4650
)
4751
guard

AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SRPAuth/VerifyPasswordSRP.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ struct VerifyPasswordSRP: Action {
5353
credentialStoreClient: environment.authEnvironment().credentialsClient
5454
)
5555

56+
// Device metadata is stored under the username the caller signed in with
57+
// (`ConfirmDevice` uses `signedInData.inputUsername`), so it must be read back with
58+
// the same value. `username` here is `parameters["USERNAME"]`, which for pools with
59+
// alias sign-in is the sub — looking metadata up with it never matches what was
60+
// written, so DEVICE_KEY would be omitted and every sign-in would register a new device.
5661
deviceMetadata = await DeviceMetadataHelper.getDeviceMetadata(
57-
for: username,
62+
for: inputUsername,
5863
with: environment
5964
)
6065
let signature = try signature(
@@ -100,8 +105,11 @@ struct VerifyPasswordSRP: Action {
100105
await dispatcher.send(event)
101106
} catch let error where deviceNotFound(error: error, deviceMetadata: deviceMetadata) {
102107
logVerbose("\(#fileID) Received device not found \(error)", environment: environment)
103-
// Remove the saved device details and retry password verify
104-
await DeviceMetadataHelper.removeDeviceMetaData(for: username, with: environment)
108+
// Remove the saved device details and retry password verify. This must use the same
109+
// value the metadata was read with above — deleting under `username` (the echoed sub)
110+
// leaves the real entry in place, so the retry re-reads the same stale device key,
111+
// Cognito rejects it again, and sign-in loops here indefinitely.
112+
await DeviceMetadataHelper.removeDeviceMetaData(for: inputUsername, with: environment)
105113
let event = SignInEvent(eventType: .retryRespondPasswordVerifier(stateData, authResponse, clientMetadata))
106114
logVerbose(
107115
"\(#fileID) Sending event \(event)",

AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/VerifySignInChallenge.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,11 @@ struct VerifySignInChallenge: Action {
7575
credentialStoreClient: environment.authEnvironment().credentialsClient
7676
)
7777

78+
// Read with the username the caller signed in with — `ConfirmDevice` writes the
79+
// metadata under `inputUsername`, and `challenge.username` is the value Cognito
80+
// returned (the sub, for pools using alias sign-in).
7881
deviceMetadata = await DeviceMetadataHelper.getDeviceMetadata(
79-
for: username,
82+
for: challenge.inputUsername ?? username,
8083
with: environment
8184
)
8285

@@ -107,8 +110,13 @@ struct VerifySignInChallenge: Action {
107110
await dispatcher.send(responseEvent)
108111
} catch let error where deviceNotFound(error: error, deviceMetadata: deviceMetadata) {
109112
logVerbose("\(#fileID) Received device not found \(error)", environment: environment)
110-
// Remove the saved device details and retry verify challenge
111-
await DeviceMetadataHelper.removeDeviceMetaData(for: username, with: environment)
113+
// Remove the saved device details and retry verify challenge. Must match the value the
114+
// metadata was read with above — deleting under `username` (the echoed sub) leaves the
115+
// real entry in place and the retry loops on the same stale device key.
116+
await DeviceMetadataHelper.removeDeviceMetaData(
117+
for: challenge.inputUsername ?? username,
118+
with: environment
119+
)
112120
let event = SignInChallengeEvent(
113121
eventType: .retryVerifyChallengeAnswer(confirmSignEventData, currentSignInStep)
114122
)
@@ -139,7 +147,7 @@ struct VerifySignInChallenge: Action {
139147
) async throws {
140148

141149
let newDeviceMetadata = await DeviceMetadataHelper.getDeviceMetadata(
142-
for: username,
150+
for: challenge.inputUsername ?? username,
143151
with: environment
144152
)
145153
if challenge.challenge == .password {

AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Helpers/UserPoolSignInHelper.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,13 @@ struct UserPoolSignInHelper: DefaultLogger {
146146
eventType: .respondPasswordVerifier(srpStateData, response, [:])
147147
)
148148
case .deviceSrpAuth:
149-
return SignInEvent(eventType: .initiateDeviceSRP(username, response))
149+
// Carry the caller's `inputUsername` into the device SRP flow. It has to look
150+
// the stored device metadata back up, and that's keyed on the username the
151+
// caller signed in with (see `ConfirmDevice`). `username` here is the value
152+
// Cognito echoed — the sub, on pools with alias sign-in — so using it makes the
153+
// lookup miss and the request omits DEVICE_KEY, which Cognito rejects with
154+
// "Missing required parameter DEVICE_KEY".
155+
return SignInEvent(eventType: .initiateDeviceSRP(inputUsername ?? username, response))
150156
case .webAuthn:
151157
let signInData = WebAuthnSignInData(
152158
username: username,

Package.resolved

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ let platforms: [SupportedPlatform] = [
99
.watchOS(.v9)
1010
]
1111
let dependencies: [Package.Dependency] = [
12-
.package(url: "https://github.com/awslabs/aws-sdk-swift", exact: "1.7.27"),
12+
.package(url: "https://github.com/awslabs/aws-sdk-swift", exact: "1.7.53"),
1313
.package(url: "https://github.com/stephencelis/SQLite.swift.git", exact: "0.15.4"),
1414
.package(url: "https://github.com/mattgallagher/CwlPreconditionTesting.git", from: "2.1.0"),
1515
.package(url: "https://github.com/aws-amplify/amplify-swift-utils-notifications.git", from: "1.1.0")

0 commit comments

Comments
 (0)