Bearbeiten

Azure IoT-Client-SDK-Unterstützung für Tokenserver von Drittanbietern

Azure IoT
Azure IoT Hub

Im Artikel Steuern des Zugriffs auf IoT Hub wird gezeigt, wie ein Tokendienst von Drittanbietern in IoT Hub integriert werden kann. In diesem Artikel wird die Unterstützung für SAS-Tokenauthentifizierung (Shared Access Signature) in den einzelnen Azure IoT-Client-SDKs beschrieben. Außerdem wird beschrieben, was in einer Geräteanwendung mithilfe des entsprechenden SDKs für die jeweilige Sprache implementiert werden muss und wie Token im Geräte- oder Modulbereich für die SAS-Richtlinien von „DeviceConnect“ oder „ModuleConnect“ verwendet werden.

Kontext und Problem

In der aktuellen Azure IoT Hub-Sicherheitsdokumentation wird das Tokenservermuster von Drittanbietern für die SAS-Authentifizierung von IoT-Geräten bei IoT Hub mithilfe der Azure IoT-Client-SDKs erläutert. Falsche Annahmen, die ein Kunde während eines kürzlichen Unternehmensengagements getroffen hat, deuten jedoch darauf hin, dass Sie – ohne weitere Erläuterungen – einen irreführenden Eindruck im Hinblick auf die standardmäßig implementierte Unterstützungsebene in den Azure IoT-Client-SDKs entwickeln können.

In diesem Artikel wird der Lernprozess aus diesem Engagement erläutert, und es wird verdeutlicht, was in jedem SDK für Geräte ausgeführt werden muss, um eine Tokenserverauthentifizierung von Drittanbietern zu erreichen. Dieser Artikel sollte auch verhindern, dass Sie ähnliche falsche Annahmen zur Unterstützung für das Tokenservermuster von Drittanbietern im Azure IoT-Client-SDK treffen.

Lösung

Die Azure IoT-Client-SDKs bieten unterschiedliche Unterstützungsebenen für die SAS-Tokenauthentifizierung, die jeweils benutzerdefinierten Code zur Vervollständigung der Authentifizierungs- und Tokenverwaltungsfunktionen erfordern.

Die Häufigkeit der Tokenauswertung ist abhängig vom ausgewählten Transportprotokoll – MQTT, AMQP oder HTTPS. Die Variation ist abhängig von der Funktion des Protokolls zur Unterstützung einer proaktiven Verlängerung von Token und Sitzungstimeouts. Nur AMQP implementiert proaktive Verlängerungsunterstützung. Dies bedeutet, dass die anderen Transporte die Verbindung bei einem SAS-Tokenauthentifizierungsfehler schließen und dann einen neuen Verbindungsvorgang durchführen müssen. Dies ist ein möglicherweise teurer Konnektivitätsvorgang für den Client.

Wenn die SAS-Authentifizierung fehlschlägt, wird von der Transportimplementierung ein Fehler ausgelöst, der innerhalb der Geräteanwendung von einem Ereignishandler des Typs „Verbindungsstatus geändert" behandelt werden kann. Wenn ein solcher Handler nicht implementiert wird, wird die Geräteanwendung normalerweise aufgrund des Fehlers anhalten. Mit der richtigen Implementierung des Ereignishandlers und der Tokenverlängerungsfunktion können die Transporte die Verbindung erneut versuchen.

Die folgende Abbildung zeigt das Tokenservermuster eines Drittanbieters:

Illustration of the third-party token-server pattern

Die folgende Abbildung zeigt die Implementierungsunterstützung im Azure IoT-Client-SDK mit Mobile Net Operator-Integration:

Flowchart of implementation support in the Azure IoT client SDK with Mobile Net Operator integration

Beispielimplementierungen sind im Repository Azure-Beispiele auf GitHub enthalten.

Probleme und Überlegungen

Beachten Sie die folgenden Punkte bei Ihrer Entscheidung, ob dieses Muster implementiert werden soll:

  • Die Azure IoT Hub Device Provisioning Service (Azure DPS)-Client-SDKs unterstützen nicht die SAS-Tokenauthentifizierung. Die Azure DPS-REST-APIunterstützt die SAS-Tokenauthentifizierung. Wenn Sie Azure DPS bei einem Tokendienst von Drittanbietern für die SAS-Authentifizierung nutzen möchten, muss eine Geräteanwendung den DPS-Prozess des Geräts mithilfe der Azure DPS-REST-API implementieren.

  • Dies umfasst die Durchführung eines ersten Registrierungsanforderungsvorgangs und das anschließende Abrufen der Betriebsstatus-API, bis der DPS-Prozess erfolgreich ist oder fehlschlägt. Bei Erfolg können Sie die Details zur Gerätebereitstellung abrufen, indem Sie sie über die Azure DPS-REST-API-Runtime-Registrierung anfordern.

Referenzen:

Verwendung dieses Musters

Sie sollten dieses Muster immer dann verwenden, wenn Sie sich von IoT-Geräten aus mithilfe der verschiedenen Azure IoT-Client-SDKs bei Azure IoT Hub authentifizieren möchten. Statt die Client-SDKs zur SAS-Tokenauthentifizierung zu verwenden, verwenden Sie die Azure DPS-REST-API, um die Implementierung von proaktiver Verlängerungsunterstützung für alle Transportmechanismen sicherzustellen.

Beispiele

Die folgenden Abschnitte enthalten Beispiele, die Sie bei verschiedenen Programmiersprachen wie Embedded C, .NET, Java und Python verwenden können.

Azure IoT Hub-Geräte-SDK für C und Azure IoT Hub-Geräte-SDK für Embedded C

Der folgende Ansatz kann in Geräteanwendungen genutzt werden, die mithilfe des Azure IoT C-SDKs oder des Azure IoT Embedded C-SDKs erstellt wurden. Weil kein SDK die Verwaltung der SAS-Tokenlebensdauer bietet, müssen Sie eine Funktion für den SAS-Tokengültigkeitsdauer-Manager implementieren.

SAS-Token können über die Struktur IOTHUB_CLIENT_CONFIG genutzt werden, indem das Member deviceSasToken auf das Token und der Wert für deviceKey auf „NULL“ festgelegt wird. Andere nicht verwendete Werte, z. B. protocolGatewayHostName, müssen ebenfalls auf „NULL“ festgelegt werden.

IOTHUB_CLIENT_CONFIG* CONFIG = (IOTHUB_CLIENT_CONFIG*)malloc(sizeof(IOTHUB_CLIENT_CONFIG));

CONFIG->PROTOCOL = PROTOCOL;
CONFIG->DEVICEID = DEVICEID;
CONFIG->IOTHUBNAME = IOTHUBNAME;
CONFIG->IOTHUBSUFFIX = IOTHUBSUFFIX;
CONFIG->DEVICEKEY = 0;
CONFIG->DEVICESASTOKEN = TOKEN;
CONFIG->PROTOCOLGATEWAYHOSTNAME = 0;

// The created IOTHUB_CLIENT_CONFIG can then be provided to the IoTHubDeviceClient_Create function to establish a DeviceClient instance.
if ((IOTHUBCLIENTHANDLE = IoTHubDeviceClient_Create(CONFIG)) == NULL) {
    (void)printf("ERROR: IOTHUBCLIENTHANDLE IS NULL!\r\n");
}

// To capture SAS token authentication failures, a handler needs to be implemented for the IoTHubDeviceClient_SetConnectionStatusCallback.
(void)IoTHubDeviceClient_SetConnectionStatusCallback(IOTHUBCLIENTHANDLE, CONNECTION_STATUS_CALLBACK, NULL);

Mit „connection_status_callback“ kann IOTHUB_CLIENT_CONNECTION_STATUS_REASON von IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN aufgerufen werden, um eine Verlängerung des SAS-Tokens über den Tokendienst eines Drittanbieters auszulösen. Dies ist für alle Transporte erforderlich, um Verbindungsprobleme zu erfassen, ist jedoch speziell für Transporte erforderlich, die die proaktive SAS-Tokenverlängerung nicht unterstützen. Die proaktive Verwaltung der SAS-Tokengültigkeitsdauer kann als Funktion implementiert werden, die während der Vorgangsschleife für Geräteanwendungen wiederholt ausgeführt wird. Stellen Sie sicher, dass die Gültigkeitsdauer des Tokens häufig ausgewertet wird und dass die Tokenverlängerung bei Bedarf proaktiv ausgeführt werden kann.

Zusammenfassung der Implementierung der SAS-Tokenauthentifizierung für C-SDKs:

  1. Implementieren Sie einen Handler des Typs „ConnectionStatusCallback“, um das IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN-Ereignis zu erfassen und die Tokenverlängerung auszulösen.

  2. Verwenden Sie eine Konfiguration des Typs IOTHUB_CLIENT_CONFIG, um das SAS-Token des Geräts für „IoTHubDeviceClient_Create“ zur Verfügung zu stellen.

  3. Implementieren Sie die proaktive Verwaltung der SAS-Tokengültigkeitsdauer als Teil der Vorgangsschleife für die Geräteanwendung.

Azure IoT Hub-Geräte-SDK für .NET

Das Azure IoT-Client-SDK für .NET implementiert Unterstützung für die Verwaltung der SAS-Tokengültigkeitsdauer über die abstrakte Klasse „DeviceAuthenticationWithTokenRefresh“. Eine konkrete Implementierung dieser Klasse, durch die Tokenverlängerungsfunktionen hinzugefügt werden, kann als Authentifizierungsmethode für eine „DeviceClient.Create“-Methode bereitgestellt werden. Die Transportimplementierungen verlängern das Token bei Bedarf automatisch über die Authentifizierungsmethode. Ein Handler des Typs „ConnectionStatusChangesHandler“ ist erforderlich, um Verbindungsänderungen zu erfassen und zu verhindern, dass Ausnahmen durch die Transporte ausgelöst werden.

Beispielimplementierung, die auf der Klasse „DeviceAuthenticationWithTokenRefresh“ basiert:

internal class StsDeviceAuthenticationWithTokenRefresh : DeviceAuthenticationWithTokenRefresh
{

    private readonly string _stsConnectUrl = "http://localhost:8080/sts/azure/token/operations?sr={0}/devices/{1}";

    private const int DEFAULTTIMETOLIVESECONDS = 1 * 60 * 60;

    private const int DEFAULTBUFFERPERCENTAGE = 15;

    public StsDeviceAuthenticationWithTokenRefresh(string deviceId, int suggestedTimeToLiveSeconds, int timeBufferPercentage) : BASE(deviceId, suggestedTimeToLiveSeconds, timeBufferPercentage)
    {
        If(String.IsNullOrWhitespace(deviceId)){
            throw new ArgumentNullException(nameof(deviceId));
        }
    }

    protected override async Task<string> SafeCreateNewToken(string iotHub, int suggestedTimeToLive)
    {
        string result;
        string url = string.Format(_stsConnectUrl, iotHub, deviceId);

        using (HttpClientHandler handler = new HttpClientHandler())
        using (HttpClient client = new HttpClient(handler))
        {
            try
            {
                HttpResponseMessage response = await client.GetAsync(url);
                if (response.IsSuccessStatusCode)
                {
                    result = await response.Content.ReadAsStringAsync();
                }
                else
                {
                    throw new HttpRequestException($"Request failed with status code {response.StatusCode}.");
                }
            }
            catch (HttpRequestException)
            {
                result = null;
            }
        }

        return result;
    }
}

Zusammenfassung der Implementierung der SAS-Tokenauthentifizierung für das Azure IoT Hub-Geräte-SDK für .NET:

  1. Implementieren Sie eine konkrete Klasse, die auf der abstrakten Klasse „DeviceAuthenticationWithTokenRefresh“ basiert, die die Tokenverlängerungsfunktionen implementiert.

  2. Implementieren Sie einen Handler des Typs „ConnectionStatusChangesHandler“, um den Transportverbindungsstatus zu erfassen und Ausnahmen zu vermeiden, die durch die Transportimplementierung ausgelöst werden.

Referenzen:

Azure IoT Hub-Geräte-SDK für Java

Das Azure IoT-Client-SDK für Java implementiert Unterstützung für die Verwaltung der SAS-Tokengültigkeitsdauer über die SasTokenProvider-Schnittstelle. Eine Klasse, die diese Schnittstelle mit SAS-Tokenverlängerungsfunktionen implementiert, kann als Sicherheitsanbieter„SecurityProvider“ (Sicherheitsanbieter) in einem „DeviceClient“-Konstruktor verwendet werden. Die Transportimplementierungen verlängern das Token bei Bedarf automatisch über den Sicherheitsanbieter. Ein „ConnectionStatusChangeCallback“ muss registriert werden, um Verbindungsänderungen zu erfassen und zu verhindern, dass Ausnahmen durch die Transporte ausgelöst werden.

Beispielimplementierung des Sicherheitsanbieters, der die SasTokenProvider-Schnittstelle implementiert:

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class StsSecurityProvider implements SasTokenProvider {
    private final String hostname;
    private final String deviceId;
    private int renewalBufferSeconds;
    private long expiryTimeSeconds;
    private char[] sasToken;

    public StsSecurityProvider(String hostname, String deviceId) {
        this.hostname = hostname;
        this.deviceId = deviceId;
        this.renewalBufferSeconds = 120;
        this.expiryTimeSeconds = (System.currentTimeMillis() / 1000);
    }

    @Override
    public char[] getSasToken() {
        long currentTimeSeconds = (System.currentTimeMillis() / 1000);
        try {
            if (this.sasToken == null || this.expiryTimeSeconds + this.renewalBufferSeconds >= currentTimeSeconds) {
                this.sasToken = stsGetToken();
                assert this.sasToken != null;
                String t = String.copyValueOf(this.sasToken);
                String[] bits = t.split("SE=");
                long l = Long.parseLong(bits[1]);
                this.expiryTimeSeconds = l; // the SE= number
                this.renewalBufferSeconds = (int)(l * 0.15); // renew within 15% of expiry
            }
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
        return this.sasToken;
    }

    private char[] stsGetToken() throws IOException, InterruptedException {
        String stsUrl = String.format("http://localhost:8080/sts/azure/token/operations?sr=%s/devices/%s", this.hostname, this.deviceId);
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(stsUrl))
            .timeout(Duration.ofMinutes(2))
            .header("Content-Type", "application/json")
            .build();
        HttpClient client = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .connectTimeout(Duration.ofSeconds(20))
            .build();
        HttpResponse < String > response = client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() < 200 || response.statusCode() >= 300) {
            return null;
        }
        if (response.body().isEmpty()) {
            return null;
        }
        return response.body().toCharArray();
    }
}

Zusammenfassung der SAS-Tokenauthentifizierungsimplementierung für das Azure IoT Hub-Geräte-SDK für Java:

  1. Implementieren Sie die SasTokenProvider-Schnittstelle für eine Klasse, und beziehen Sie die Funktionalität zur Tokenverlängerung mit ein.

  2. Implementieren Sie einen Handler des Typs „ConnectionStatusChangeCallback“, um Änderungen am Transportverbindungsstatus zu erfassen und Ausnahmen zu vermeiden, die durch die Transportimplementierung ausgelöst werden.

Referenzen:

Azure IoT Hub-Geräte-SDK für Python

Das Azure IoT Hub-Geräte-SDK für Python implementiert SAS-Tokenunterstützung über Methoden für das Objekt „IoTHubDeviceClient“. Diese Methoden ermöglichen die Erstellung eines Geräteclients mithilfe eines Tokens und bieten die Möglichkeit, ein aktualisiertes Token nach der Erstellung des Geräteclients bereitzustellen. Sie implementieren keine Verwaltung der Tokengültigkeitsdauer, aber diese kann als asynchroner Vorgang problemlos implementiert werden.

Eine Python 3.7-Beispielimplementierung, die nur den Funktionsumfang zeigt:

import asyncio
import iothub_device_client

async def main():
    # Get a SAS token you generated
    sastoken = get_new_sastoken()
    # The client object is used to interact with your Azure IoT Hub.
    device_client = iothub_device_client.create_from_sastoken(sastoken)

    # Connect the client
    await device_client.connect()

    # Define behavior for providing new SAS tokens to prevent expiry
    async def sastoken_keepalive():
        while True:
            await asyncio.sleep(new_token_interval)
            sastoken = get_new_sastoken()
            await device_client.update_sastoken(sastoken)

    # Also run the SAS token keepalive in the event loop
    keepalive_task = asyncio.create_task(sastoken_keepalive())

    # Cancel the SAS token update task
    keepalive_task.cancel()

    # Finally, shut down the client
    await device_client.shutdown()

if __name__ == "main":
    asyncio.run(main())

Zusammenfassung des Azure IoT Hub-Geräte-SDKs für die Python-SAS-Tokenauthentifizierung:

  1. Erstellen Sie eine SAS-Tokengenerierungsfunktion.

  2. Erstellen Sie mithilfe von „IoTHubDeviceClient.create_from_sastoken“ einen Geräteclient.

  3. Verwalten Sie die Tokengültigkeitsdauer als separate Aktivität, und stellen Sie dem Geräteclient ein verlängertes Token bereit, wenn dies für die SAS-Tokenmethode „IoTHubDeviceClient.update_“ erforderlich ist.

Referenzen:

Azure IoT Hub-Geräte-SDK für Node.JS/JavaScript

Das Azure IoT für Node.JS/JavaScript implementiert einen Authentifizierungsanbieter des Typs „SharedAccessSignatureAuthenticationProvider“, der dem Geräteclient und den Transporten ein SAS-Token zur Authentifizierung bei IoT Hub zur Verfügung stellt. Es implementiert keine Tokenverlängerungsfunktionen. Die Geräteanwendung muss die Tokengültigkeitsdauer verwalten und das Token bei Bedarf verlängern.

Verwenden Sie die Geräteclientmethoden „fromSharedAccessSignature“ und „updateSharedAccessSignature“, um eine Verbindung mit IoT Hub zu initiieren und dem Authentifizierungsanbieter des Typs „SharedAccessSignatuteAuthenticationProvider“ ein verlängertes Token bereitzustellen. Dies bewirkt, dass der Anbieter ein „newTokenAvailable“-Ereignis für die Transporte ausgibt.

Ein einfaches SAS-Tokenbeispiel finden Sie im Beispiel simple_sample_device_with_sas.js.

Zusammenfassung des Azure IoT Hub-Geräte-SDKs für Node.JS/JavaScript:

  1. Implementieren Sie die Verwaltung und Verlängerung der SAS-Tokengültigkeitsdauer.

  2. Verwenden Sie den Geräteclient „fromSharedAccessSignature“ zum Erstellen einer Geräteclientinstanz.

  3. Verwenden Sie den Geräteclient „updateSharedAccessSignature“ zum Bereitstellen eines verlängerten Tokens.

Referenzen:

Nächste Schritte