繁体   English   中英

使用自签名x509证书的Azure IoT中心Python SDK的问题,其中协议!= MQTT_WS

[英]Issues with Azure IoT Hub Python SDK using self-signed x509 Certs where protocol != MQTT_WS

有一些很奇怪的问题,与我的Python脚本,但我可以用包括在他们的Python SDK微软的示例脚本复制它在这里

基本上,当我使用MQTT_WS以外的任何方式运行此代码时,它将失败并显示各种错误。 这是代码:(注意,我删除了实际的证书/密钥,因此这对您不起作用)。

# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for
# full license information.

import random
import time
import sys
import iothub_client
from iothub_client import IoTHubClient, IoTHubClientError, IoTHubTransportProvider, IoTHubClientResult
from iothub_client import IoTHubMessage, IoTHubMessageDispositionResult, IoTHubError
from iothub_client_args import get_iothub_opt, OptionError

# HTTP options
# Because it can poll "after 9 seconds" polls will happen effectively
# at ~10 seconds.
# Note that for scalabilty, the default value of minimumPollingTime
# is 25 minutes. For more information, see:
# https://azure.microsoft.com/documentation/articles/iot-hub-devguide/#messaging
TIMEOUT = 241000
MINIMUM_POLLING_TIME = 9

# messageTimeout - the maximum time in milliseconds until a message times out.
# The timeout period starts at IoTHubClient.send_event_async.
# By default, messages do not expire.
MESSAGE_TIMEOUT = 10000

RECEIVE_CONTEXT = 0
AVG_WIND_SPEED = 10.0
MIN_TEMPERATURE = 20.0
MIN_HUMIDITY = 60.0
MESSAGE_COUNT = 5
RECEIVED_COUNT = 0

# global counters
RECEIVE_CALLBACKS = 0
SEND_CALLBACKS = 0

PROTOCOL = IoTHubTransportProvider.MQTT_WS

# String containing Hostname, Device Id in the format:
# "HostName=<host_name>;DeviceId=<device_id>;x509=true"
CONNECTION_STRING = "HostName=hub.azure-devices.net;DeviceId=device;x509=true"

MSG_TXT = "{\"deviceId\": \"device\",\"windSpeed\": %.2f,\"temperature\": %.2f,\"humidity\": %.2f}"

X509_CERTIFICATE = (
    '''-----BEGIN CERTIFICATE-----
MIIFtTCCA52gAwIBAgIBAzANBgkqhkiG9w0BAQsFADA0MTIwMAYDVQQDDClBenVy
...
T4kySzeQghCYqpkF06hER0KXTP8shMZedg==
-----END CERTIFICATE-----'''

)

X509_PRIVATEKEY = (
    '''-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEAnEOzMmctBZke/1kD+5g/soUTucJ28odMTW2RIlfj4kAhT1gW
...
UOBMkQUpHEBNWtBbQIyJbgrb26P1oec7dk5f2xvg7tHjSZLDOZprdEp8gxU=
-----END RSA PRIVATE KEY-----'''
)


# some embedded platforms need certificate information


def receive_message_callback(message, counter):
    global RECEIVE_CALLBACKS
    message_buffer = message.get_bytearray()
    size = len(message_buffer)
    print("Received Message [%d]:" % counter)
    print("    Data: <<<%s>>> & Size=%d" % (message_buffer[:size].decode('utf-8'), size))
    map_properties = message.properties()
    key_value_pair = map_properties.get_internals()
    print("    Properties: %s" % key_value_pair)
    counter += 1
    RECEIVE_CALLBACKS += 1
    print("    Total calls received: %d" % RECEIVE_CALLBACKS)
    return IoTHubMessageDispositionResult.ACCEPTED


def send_confirmation_callback(message, result, user_context):
    global SEND_CALLBACKS
    print("Confirmation[%d] received for message with result = %s" % (user_context, result))
    map_properties = message.properties()
    print("    message_id: %s" % message.message_id)
    print("    correlation_id: %s" % message.correlation_id)
    key_value_pair = map_properties.get_internals()
    print("    Properties: %s" % key_value_pair)
    SEND_CALLBACKS += 1
    print("    Total calls confirmed: %d" % SEND_CALLBACKS)


def iothub_client_init():
    # prepare iothub client
    client = IoTHubClient(CONNECTION_STRING, PROTOCOL)

    # HTTP specific settings
    if client.protocol == IoTHubTransportProvider.HTTP:
        client.set_option("timeout", TIMEOUT)
        client.set_option("MinimumPollingTime", MINIMUM_POLLING_TIME)

    # set the time until a message times out
    client.set_option("messageTimeout", MESSAGE_TIMEOUT)

    # this brings in x509 privateKey and certificate
    client.set_option("x509certificate", X509_CERTIFICATE)
    client.set_option("x509privatekey", X509_PRIVATEKEY)

    # to enable MQTT logging set to 1
    if client.protocol == IoTHubTransportProvider.MQTT:
        client.set_option("logtrace", 0)

    client.set_message_callback(
        receive_message_callback, RECEIVE_CONTEXT)
    return client


def print_last_message_time(client):
    try:
        last_message = client.get_last_message_receive_time()
        print("Last Message: %s" % time.asctime(time.localtime(last_message)))
        print("Actual time : %s" % time.asctime())
    except IoTHubClientError as iothub_client_error:
        if iothub_client_error.args[0].result == IoTHubClientResult.INDEFINITE_TIME:
            print("No message received")
        else:
            print(iothub_client_error)


def iothub_client_sample_x509_run():
    try:

        client = iothub_client_init()

        while True:
            # send a few messages every minute
            print("IoTHubClient sending %d messages" % MESSAGE_COUNT)

            for message_counter in range(0, MESSAGE_COUNT):
                temperature = MIN_TEMPERATURE + (random.random() * 10)
                humidity = MIN_HUMIDITY + (random.random() * 20)
                msg_txt_formatted = MSG_TXT % (
                    AVG_WIND_SPEED + (random.random() * 4 + 2),
                    temperature,
                    humidity)
                # messages can be encoded as string or bytearray
                if (message_counter & 1) == 1:
                    message = IoTHubMessage(bytearray(msg_txt_formatted, 'utf8'))
                else:
                    message = IoTHubMessage(msg_txt_formatted)
                # optional: assign ids
                message.message_id = "message_%d" % message_counter
                message.correlation_id = "correlation_%d" % message_counter
                # optional: assign properties
                prop_map = message.properties()
                prop_map.add("temperatureAlert", 'true' if temperature > 28 else 'false')

                client.send_event_async(message, send_confirmation_callback, message_counter)
                print(
                    "IoTHubClient.send_event_async accepted message [%d] for transmission to IoT Hub." % message_counter)

            # Wait for Commands or exit
            print("IoTHubClient waiting for commands, press Ctrl-C to exit")

            status_counter = 0
            while status_counter <= MESSAGE_COUNT:
                status = client.get_send_status()
                print("Send status: %s" % status)
                time.sleep(10)
                status_counter += 1

    except IoTHubError as iothub_error:
        print("Unexpected error %s from IoTHub" % iothub_error)
        return
    except KeyboardInterrupt:
        print("IoTHubClient sample stopped")

    print_last_message_time(client)


def usage():
    print("Usage: iothub_client_sample.py -p <protocol> -c <connectionstring>")
    print("    protocol        : <amqp, http, mqtt>")
    print("    connectionstring: <HostName=<host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>>")


if __name__ == '__main__':
    print("\nPython %s" % sys.version)
    # print ( "IoT Hub for Python SDK Version: %s" % iothub_client.__version__ )

    try:
        (CONNECTION_STRING, PROTOCOL) = get_iothub_opt(sys.argv[1:], CONNECTION_STRING, PROTOCOL)
    except OptionError as option_error:
        print(option_error)
        usage()
        sys.exit(1)

    print("Starting the IoT Hub Python sample...")
    print("    Protocol %s" % PROTOCOL)
    print("    Connection string=%s" % CONNECTION_STRING)

    iothub_client_sample_x509_run()

成功运行: MQTT_WS(端口443)

IoTHubClient.send_event_async accepted message [0] for transmission to IoT Hub.

Confirmation[0] received for message with result = OK
   message_id: message_0
   correlation_id: correlation_0
   Properties: {'temperatureAlert': 'false'}
   Total calls confirmed: 1

运行不成功: MQTT(端口8883)-检索期间消息超时

IoTHubClient.send_event_async accepted message [0] for transmission to IoT Hub.

Confirmation[0] received for message with result = MESSAGE_TIMEOUT
   message_id: message_0
   correlation_id: correlation_0
   Properties: {'temperatureAlert': 'false'}
   Total calls confirmed: 1

运行不成功: AMQP(端口5671)-尝试连接时出错,然后出现消息超时

    IoTHubClient.send_event_async accepted message [0] for transmission to IoT Hub.

Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransport_amqp_common.c Func:on_amqp_connection_state_changed Line:772 amqp_connection was closed unexpectedly; connection retry will be triggered.
Info: Preparing transport for re-connection
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransportamqp_methods.c Func:iothubtransportamqp_methods_unsubscribe Line:891 unsubscribe called while not subscribed
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\c-utility\adapters\tlsio_schannel.c Func:send_chunk Line:430 invalid tls_io_instance->tlsio_state: TLSIO_STATE_NOT_OPEN
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\c-utility\adapters\tlsio_schannel.c Func:internal_send Line:525 send_chunk failed
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\c-utility\adapters\tlsio_schannel.c Func:tlsio_schannel_send Line:1263 send failed
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\uamqp\src\connection.c Func:on_bytes_encoded Line:268 Cannot send encoded bytes
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\c-utility\adapters\tlsio_schannel.c Func:tlsio_schannel_close Line:1195 invalid tls_io_instance->tlsio_state = TLSIO_STATE_NOT_OPEN
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\uamqp\src\connection.c Func:on_bytes_encoded Line:272 xio_close failed
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\c-utility\adapters\tlsio_schannel.c Func:tlsio_schannel_close Line:1195 invalid tls_io_instance->tlsio_state = TLSIO_STATE_NOT_OPEN
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\uamqp\src\connection.c Func:connection_close Line:1437 xio_close failed
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransport_amqp_common.c Func:on_amqp_connection_state_changed Line:772 amqp_connection was closed unexpectedly; connection retry will be triggered.
Info: Preparing transport for re-connection
Confirmation[0] received for message with result = MESSAGE_TIMEOUT
   message_id: message_0
   correlation_id: correlation_0
   Properties: {'temperatureAlert': 'false'}
   Total calls confirmed: 1

运行不成功: AMQP_WS(端口443)-尝试连接时出错,然后出现消息超时

Same as regular AMQP

运行不成功: HTTP(端口443)-尝试连接时出错

IoTHubClient.send_event_async accepted message [0] for transmission to IoT Hub.
Error: Time:Tue Aug 21 17:20:18 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransporthttp.c Func:DoEvent Line:1700 unexpected HTTP status code (401)
Error: Time:Tue Aug 21 17:20:18 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransporthttp.c Func:DoMessages Line:2102 expected status code was 200, but actually was received 401... moving on
IoTHubClient.send_event_async accepted message [4] for transmission to IoT Hub.

Error: Time:Tue Aug 21 17:20:18 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransporthttp.c Func:DoEvent Line:1700 unexpected HTTP status code (401)

我在Windows 10计算机上安装了Python版本3.6.6。

老实说,我不确定是什么导致了此问题。 我不认为这是证书,因为当我将它们与MQTT_WS结合使用时,它们就可以工作。 在测试期间,我尝试短暂禁用Windows上的防火墙,但这也无济于事。

此外,这以前工作。 我构建了一个单独的脚本,该脚本将连接到用户传入的协议,并且我的测试脚本将循环遍历以确保所有功能正常。 我休息了一段时间,努力使这些脚本适用于Mac / Linux。 我遇到了那些平台上的障碍,当我切换回Windows时,意识到它也遇到了同样的问题。 我没有更改Azure Hub上的任何内容以阻止某种类型的连接,因此不确定是什么原因导致了此问题。

我尝试生成新证书并创建新的x509自签名设备,但是它也遇到了相同的问题:(

希望有人可以提供帮助!

编辑:我能够通过为IoTHub创建新证书来解决我的问题。 看来我那里的脚本是用测试脚本生成的,所以只用了30天就可以了。 尽管我不了解MQTT_WS协议如何仍然能够解决并通过它,但这完全是一个单独的问题。

感谢那些试图提供帮助的人!

我正在尝试重现此问题,但是失败了。 使用最新版本的Python SDK,您提到的所有协议HTTP,MQTT,MQTT_WS,AMQP,AMQP_WS对我来说都很好。

为了缩小此问题的范围,建议您创建一个新的Azure IoT中心以查看问题是否与Azure IoT中心的特定实例有关。 您可以为测试目的创建一个免费的。

如果该问题与特定的Azure IoT中心无关,则该问题也可能与网络问题有关。 请检查端口是否未阻塞,如果您在组织环境中工作,可能需要与IT部门确认。 或者,您可以在另一个网络环境中进行测试以确认此问题。

以下是测试步骤,可能也对您有所帮助:

  1. 通过PowerShell创建X.509自签名证书

    New-SelfSignedCertificate -DnsName“ www.fabrikam.com”,“ www.contoso.com” -CertStoreLocation“ cert:\\ LocalMachine \\ My”

  2. 使用下面的命令导出证书和密钥

    openssl pkcs12 -in yourpfxfile.pfx -nokeys -out publiccert.pem -nodes

    openssl pkcs12 -in x.pfx -nocerts -nodes -pass pass:123456 | openssl rsa -out privkey.pem

  3. 在Azure门户上添加X.509自签名证书设备

  4. 从GitHub 代码示例链接下载python脚本
  5. 安装最新的Azure IoT设备SDK

    python -m pip安装azure-iothub-device-client

  6. 使用证书,密钥和特定协议修改代码

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM