Search code examples
javaspring-bootgoogle-cloud-platformmqttpaho

Why can't I connect to device in Google Cloud IOT Core through MQTT?


I want to connect my backend on Spring boot to one of the devices in my hardware setup in Google Cloud Iot-Core. I basically copied this github repository and adjusted the authentication and connection options. When I run my program it throws this exception:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.eclipse.paho.client.mqttv3.MqttClient]: Factory method 'connectToMqttClient' threw exception; nested exception is Incorrect username or password (4)

To create password I use this method

private static String createJwtRsa(String projectId, String privateKeyFile)
        throws NoSuchAlgorithmException, IOException, InvalidKeySpecException {
    DateTime now = new DateTime();

    JwtBuilder jwtBuilder =
            Jwts.builder()
                    .setIssuedAt(now.toDate())
                    .setExpiration(now.plusMinutes(20).toDate())
                    .setAudience(projectId);

    byte[] keyBytes = Files.readAllBytes(Paths.get(privateKeyFile));
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");

    return jwtBuilder.signWith(SignatureAlgorithm.RS256, kf.generatePrivate(spec)).compact();
}

I had an issue with privateKeyFile format. On Iot-core the device has public key of RS256_X509

enter image description here

But Spring Boot only allows RS256_PKCS8 key formats, so I had to do this:

  1. I generated key of format X509 openssl req -x509 -nodes -newkey rsa:2048 -keyout rsa_private.pem -out rsa_cert.pem -subj "/CN=unused" it also generated certificate rsa_cer.pem
  2. I converted the key to PKCS8 format openssl pkcs8 -topk8 -inform PEM -outform DER -in rsa_private.pem -out private_key.der -nocrypt
  3. The certificate I added as public key in Iot-core and rsa_private.der I used in my createJwtRsa method

Since then I get the exception: Incorrect Username and password. What can I do to fix it?

Edit:

I also tried generating normal RSA256 key and convert it to PKCS8 format, and I get the same exception. The same with ES256 key


Solution

  • I managed to fix the issue! the clientId was incorrect

    final String mqttClientId = String.format("projects/%s/locations/%s/registries/%s/devices/%s",
    options.projectId, options.cloudRegion, options.registryId, options.gatewayId);
    

    My gatewayId was an empty string because we don't have a gateway created on Iot Core, we connect directly to devices. So today I set gatewayId to deviceId and the backend connected successfully to the device. So now the line looks like this

    final String mqttClientId = String.format("projects/%s/locations/%s/registries/%s/devices/%s",options.projectId, 
     options.cloudRegion, options.registryId, options.deviceId);