簡體   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