question

NikolaRadovanovic-0150 avatar image
1 Vote"
NikolaRadovanovic-0150 asked NikolaRadovanovic-0150 commented

IoT Hub MQTT Paho issues

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
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

AshokPeddakotla-MSFT avatar image
0 Votes"
AshokPeddakotla-MSFT answered NikolaRadovanovic-0150 commented

@NikolaRadovanovic-0150 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://docs.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
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you for the answer.

We already decided to use conventional broker since what Azure offers is not flexible enough. We have found that the fact device ID must be used as client ID when connecting (which causes connection drops) and forced format of publish/subscribe topics are rather limiting. I used MQTT brokers in the past, but but this one is by far most complicated and yet so restrictive

Best regards.

0 Votes 0 ·
NikolaRadovanovic-0150 avatar image
1 Vote"
NikolaRadovanovic-0150 answered NikolaRadovanovic-0150 edited

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.


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.