IoT Hub MQTT Paho issues

Nikola Radovanovic 31 Reputation points
2021-03-25T12:59:47.557+00:00

Hi,
I am wondering how to programatically generate SAS token in Python? I tried couple of things from the web, but none worked.

Second thing is: when I try to connect multiple MQTT clients to the same device, I kept getting disconnect as soon as another client is connected. Why is this? I want to try publish/subscribe using MQTT explorer, but same thing happen when tried to use 2 python processes. I did not experience such issues with Erlang broker or Mosquitto.

Thank you in advance

Azure IoT Hub
Azure IoT Hub
An Azure service that enables bidirectional communication between internet of things (IoT) devices and applications.
1,271 questions
0 comments No comments
{count} vote

Accepted answer
  1. AshokPeddakotla-MSFT 35,971 Reputation points Moderator
    2021-03-26T11:52:06.863+00:00

    @Nikola Radovanovic Welcome to Microsoft Q&A forum! Please find the below answers.

    I am wondering how to programatically generate SAS token in Python? I tried couple of things from the web, but none worked.

    Here is the source code for generating SAS token in python: https://github.com/Azure/azure-iot-sdk-python/blob/master/azure-iot-hub/azure/iot/hub/sastoken.py

    Below is an example I have copied this code and created 2 SAS tokens. Feel free to use this code snippet.

    import base64  
    import hmac  
    import hashlib  
    import six.moves.urllib as urllib  
      
    _service_token_format = "SharedAccessSignature sr={}&sig={}&se={}&skn={}"  
    _device_token_format = "SharedAccessSignature sr={}&sig={}&se={}"  
      
    def build_token(uri, key, expiry_time, key_name=None, encoding_type="utf-8"):  
        """Buid SasToken representation  
        Returns:  
        String representation of the token  
        """  
        try:  
            message = (uri + "\n" + str(expiry_time)).encode(encoding_type)  
            signing_key = base64.b64decode(key.encode(encoding_type))  
            signed_hmac = hmac.HMAC(signing_key, message, hashlib.sha256)  
            signature = urllib.parse.quote(base64.b64encode(signed_hmac.digest()))  
        except (TypeError, base64.binascii.Error) as e:  
            raise TypeError("Unable to build SasToken from given values", e)  
        if key_name:  
            token = _service_token_format.format(  
                uri, signature, str(expiry_time), key_name  
            )  
        else:  
            token = _device_token_format.format(uri, signature, str(expiry_time))  
        return token  
      
      
    if __name__ == '__main__':  
        token_without_key_name = build_token("hogwarts.com", "OUST", 3600)  
        print(token_without_key_name)  
        token_with_key_name = build_token("hogwarts.com", "OUST", 3600, "fake_key_name")  
        print(token_with_key_name)  
    

    For more information about how to generate SAS tokens, see the device section of Using IoT Hub security tokens.

    When testing, you can also use the cross-platform Azure IoT Tools for Visual Studio Code or the CLI extension command az iot hub generate-sas-token to quickly generate a SAS token that you can copy and paste into your own code.

    Second thing is: when I try to connect multiple MQTT clients to the same device, I kept getting disconnect as soon as another client is connected. Why is this? I want to try publish/subscribe using MQTT explorer, but same thing happen when tried to use 2 python processes. I did not experience such issues with Erlang broker or Mosquitto.

    Please note that IoT Hub only supports one active MQTT connection per device. Any new MQTT connection on behalf of the same device ID causes IoT Hub to drop the existing connection and 400027 ConnectionForcefullyClosedOnNewConnection will be logged into IoT Hub Logs

    See the suggestions outlined here and let us know if it helps: https://learn.microsoft.com/en-us/answers/questions/148853/restrictions-on-deviceclient.html

    Using the same connection string is not supported and you will see unexpected errors. Only one device can use the same connection string at a time. Eg: if you have 2 devices connecting with the same ID, where would IoTHub send the C2D message or the Direct Method?

    I advise you to use Modules Instead (see here)

    -------------------------

    If an answer is helpful, please "Accept answer" or "Up-Vote" for the same which might be beneficial to other community members reading this thread.


1 additional answer

Sort by: Most helpful
  1. Nikola Radovanovic 31 Reputation points
    2021-03-26T07:07:26.967+00:00

    By examining source code of azure-iot-cli-extension I came up with this:

    def generate_sas_token(uri, key, policy=None, expiry=3600, absolute=False):
        """
        Create a shared access signature token as a string literal.
        Args:
            uri (str): Uri of target resource.
            policy (str): Name of shared access policy.
            key (str): Shared access key.
            expiry (int): Future expiry (in seconds) of the token to be generated.
            absolute (bool): In general the sas token ttl is generated relative to 'now' (UTC) + expiry.
                Set to true to generate a sas token with no relative start.
        Returns:
            result (str): SAS token as string literal.
        """
        encoded_uri = quote_plus(uri)
        ttl = int(expiry) if absolute else int(time() + expiry)
        sign_key = '%s\n%d' % (encoded_uri, ttl)
        signature = b64encode(HMAC(b64decode(key), sign_key.encode('utf-8'), sha256).digest())
    
        result = {
            'sr': uri,
            'sig': signature,
            'se': str(ttl)
        }
    
        if policy:
            result['skn'] = policy
    
        return 'SharedAccessSignature ' + urlencode(result)
    

    Still, I cant connect one publisher and one subscriber at the same time, so major question still remains.

    1 person found this answer helpful.
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.