Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AWS MQTT3 Websockets Connection Closed Unexpectedly #586

Closed
magx2 opened this issue May 24, 2024 · 10 comments
Closed

AWS MQTT3 Websockets Connection Closed Unexpectedly #586

magx2 opened this issue May 24, 2024 · 10 comments
Labels
bug This issue is a bug. p3 This is a minor priority issue

Comments

@magx2
Copy link

magx2 commented May 24, 2024

Describe the bug

I'm trying to connect to AWS MQTT3 via websockets with authentication from Cognito, but I'm getting Caused by: software.amazon.awssdk.crt.mqtt.MqttException: The connection was closed unexpectedly.. What might be the problem?

This is my method for getting GetCredentialsForIdentityResponse

    public GetCredentialsForIdentityResponse getCredentialsForIdentity(AuthenticationResultType accessToken, String identityId) {
        try (var client = CognitoIdentityClient.builder()
                .region(Region.of(region))
                .build()) {
            return client.getCredentialsForIdentity(
                    GetCredentialsForIdentityRequest.builder()
                            .identityId(identityId)
                            .logins(
                                    Map.of(
                                            "cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XGRz3CgoY",
                                            accessToken.idToken()))
                            .build());
        }
    }

After this I'm using GetCredentialsForIdentityResponse to obtain MqttClientConnection:

public MqttClientConnection buildConnection(String prefix,
                                            String region,
                                            String clientId,
                                            GetCredentialsForIdentityResponse credentialsForIdentity)  {
    try (var builder = AwsIotMqttConnectionBuilder.newMtlsBuilderFromPath(null, null)) {
        MqttClientConnectionEvents callbacks = new MqttClientConnectionEvents() {
            @Override
            public void onConnectionInterrupted(int errorCode) {
                log.error("Connection interrupted: " + errorCode + ": " + CRT.awsErrorString(errorCode));
            }

            @Override
            public void onConnectionResumed(boolean sessionPresent) {
                log.error("Connection resumed: " + (sessionPresent ? "existing session" : "clean session"));
            }
        };
        return builder.withEndpoint("%s-ats.iot.%s.amazonaws.com".formatted(prefix, region))
                .withWebsockets(true)
                .withConnectionEventCallbacks(callbacks)
                .withWebsocketSigningRegion(region)
                .withClientId(clientId)
                .withWebsocketCredentialsProvider(
                        new StaticCredentialsProvider.StaticCredentialsProviderBuilder()
                                .withAccessKeyId(  credentialsForIdentity.credentials().accessKeyId().getBytes(UTF_8))
                                .withSecretAccessKey(credentialsForIdentity.credentials().secretKey().getBytes(UTF_8))
                                .withSessionToken( credentialsForIdentity.credentials().sessionToken().getBytes(UTF_8))
                                .build())
                .build();
    }
}

and then when I'm trying to connect I'm getting previously mentioned error:

MqttClientConnection connection) throws ExecutionException, InterruptedException {
    try (connection) {
        CompletableFuture<Boolean> connected = connection.connect();
        boolean sessionPresent = connected.get(); // <--- here!
    }
}

Expected Behavior

Connect to MQTT via websockets

Current Behavior

Caused by: software.amazon.awssdk.crt.mqtt.MqttException: The connection was closed unexpectedly

Reproduction Steps

Repo: https://github.com/magx2/salus/blob/master/app/src/main/java/pl/grzeslowski/WsMqtt.java#L21

Possible Solution

No response

Additional Information/Context

No response

SDK version used

software.amazon.awssdk.iotdevicesdk:aws-iot-device-sdk:1.20.7

Environment details (OS name and version, etc.)

Windows 11

@magx2 magx2 added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels May 24, 2024
@bretambrose
Copy link
Contributor

The most likely issue is a permission problem (missing or mismatched iot connect permission) on the cognito-sourced credentials.

Beyond that, once it's working, you don't want to stuff session credentials in a static provider. You could use https://github.com/awslabs/aws-crt-java/blob/main/src/main/java/software/amazon/awssdk/crt/auth/credentials/DelegateCredentialsProvider.java to adapt the cognito sourcing or you could use the CRT's cognito provider: https://github.com/awslabs/aws-crt-java/blob/main/src/main/java/software/amazon/awssdk/crt/auth/credentials/CognitoCredentialsProvider.java

@bretambrose
Copy link
Contributor

Also, if you enable and attach SDK logs, we may be able to get a more detailed diagnosis.

@jmklix jmklix changed the title AWS MQTT3 Websockets Connection Closed Unexpectedly(short issue description) AWS MQTT3 Websockets Connection Closed Unexpectedly May 24, 2024
@jmklix jmklix added response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 2 days. p3 This is a minor priority issue and removed needs-triage This issue or PR still needs to be triaged. labels May 24, 2024
@magx2
Copy link
Author

magx2 commented May 25, 2024

I think it might not be connected with permissions. Look at this code - I'm taking credentials from cognito and I'm querying HTTP shadow endpoint (https://a24u3z7zzwrtdl-ats.iot.eu-central-1.amazonaws.com/things/%s/shadow) for thing and it works

BTW I'm aweare of CognitoCredentialsProvider, I even tried to use it but I'm getting 400 from cognito....

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 2 days. label May 25, 2024
@magx2
Copy link
Author

magx2 commented May 25, 2024

Also, if you enable and attach SDK logs, we may be able to get a more detailed diagnosis.

I'm attaching trace and debug log files. Those are runs of the same program, I just didn't know if you prefer trace or debug

issues-586-Trace.log
issues-586-Debug.log

@magx2
Copy link
Author

magx2 commented May 25, 2024

Another thing:

when I'm using CognitoCredentialsProvider I'm getting: Caused by: software.amazon.awssdk.crt.mqtt.MqttException: Attempt to sign an http request without credentials

Look at line 427 in logs: [DEBUG] [2024-05-25T11:15:27Z] [00006300] [http-stream] - id=000001D9DE8D1690: Client request complete, response status: 400 (Bad Request).. Is my cognito badly configured?

issues-586-cognito-Trace.log

@bretambrose
Copy link
Contributor

bretambrose commented May 25, 2024

I think it might not be connected with permissions. Look at this code - I'm taking credentials from cognito and I'm querying HTTP shadow endpoint (https://a24u3z7zzwrtdl-ats.iot.eu-central-1.amazonaws.com/things/%s/shadow) for thing and it works

BTW I'm aweare of CognitoCredentialsProvider, I even tried to use it but I'm getting 400 from cognito....

The permissions needed to perform an http request to the shadow service and the permissions needed to use IoT Core's mqtt broker are very different.

I looked at the logs. The connection is successfully established. The signed websocket handshake upgrade succeeds. The remote hosts closes the connection immediately after the CONNECT packet was sent. I know of no other possible explanation then a permissions problem.

What is the policy associated with the cognito query? Have you tried loosening it to allow everything as a sanity check?

@magx2
Copy link
Author

magx2 commented May 26, 2024

I'm not an owner of this MQTT endpoint so I cannot loosen anything :(.

I know the other team uses flutter/dart to connect to AWS IoT and they are attaching policy. Is it possible with MQTT?

  print(await Cognito.initialize());
  if (!await Cognito.isSignedIn()) {
    print(await Cognito.signIn(dotenv.env['USERNAME'], dotenv.env['PASSWORD']));
  }
  print(await Cognito.getIdentityId());

  var device = AWSIotDevice(
    endpoint: dotenv.env['ENDPOINT'],
    clientId: dotenv.env['CLIENT_ID'],
  );

  await device.attachPolicy(
    identityId: await Cognito.getIdentityId(),
    policyName: dotenv.env['POLICY_NAME'],
  );

  await device.connect();

@bretambrose
Copy link
Contributor

The permissions associated with the sourced credentials come from your cognito identity pool configuration, which is a resource under your control

@magx2
Copy link
Author

magx2 commented May 27, 2024

Thanks for the help! Now everything is clear :)!

@magx2 magx2 closed this as completed May 27, 2024
Copy link

This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug. p3 This is a minor priority issue
Projects
None yet
Development

No branches or pull requests

3 participants