aws-amplify / amplify-flutter

A declarative library with an easy-to-use interface for building Flutter applications on AWS.
https://docs.amplify.aws
Apache License 2.0
1.32k stars 248 forks source link

AWSSigV4Signer fails authentication with AWS IOT using MQTT over WSS #4437

Closed n8o closed 9 months ago

n8o commented 9 months ago

Description

I'm using AWSSigV4Signer to generate a pre-signed Uri to pass to mqtt_client in order to connect to IOT Core using MQTT over WebSockets.

AWSSigV4Signer.presignSync() doesn't return a sorted query string that matches the signed sorted and hashed string in the STS.

Categories

Steps to Reproduce

Using the following packages: aws_signature_v4: ^0.5.1 aws_common: ^0.6.3

Sample Code:

final creds = AWSCredentials(accessKey,secretKey,sessionToken);

  final signer = AWSSigV4Signer(
    credentialsProvider: AWSCredentialsProvider( creds ),
  );

  final scope = AWSCredentialScope(
      region: region,
      service: new AWSService('iotdevicegateway')
  );

  final request = AWSHttpRequest(
    method: AWSHttpMethod.get,
    uri: Uri.https(endpoint, urlPath),
  );

  var signed = signer.presignSync(request, credentialScope: scope, expiresIn: Duration(hours: 1));

this returns a Uri with query params out of order.

Work Around: Update presignSync to return AWSSignedRequest. Then I can manually create the correct uri.

var finalParams = signed.canonicalRequest.canonicalQueryParameters.toString();
return '$scheme$endpoint$urlPath?$finalParams&${AWSHeaders.signature}=${signed.signature}';

Screenshots

No response

Platforms

Flutter Version

3.16.9

Amplify Flutter Version

1.6.1

Deployment Method

Custom Pipeline

Schema

No response

n8o commented 9 months ago

I got something mixed up in my testing. Resolved my issue using the following:

    ServiceConfiguration serviceConfiguration = const BaseServiceConfiguration(omitSessionToken: true);
    var signed = signer.presignSync(request, credentialScope: scope, expiresIn: Duration(hours: 1), serviceConfiguration: serviceConfiguration);
    var finalParams = signed.query;
    return '$scheme$endpoint$urlPath?$finalParams';