Azure IoT-client-SDK-ondersteuning voor tokenservers van derden

Azure IoT
Azure IoT Hub

In het artikel Toegang tot IoT Hub beheren ziet u hoe een tokenservice van derden kan worden geïntegreerd met IoT Hub. In dit artikel vindt u een overzicht van de ondersteuning voor SAS-tokenverificatie (Shared Access Signature) in elk van de Azure IoT-client-SDK's. Ook wordt beschreven wat er moet worden geïmplementeerd in een apparaattoepassing met behulp van de bijbehorende SDK voor elke taal en hoe u tokens met apparaatbereik of modulebereik gebruikt voor het beleid voor gedeelde toegang van Apparaat Verbinding maken of Module Verbinding maken.

Context en probleem

In de huidige azure IoT Hub-beveiligingsdocumentatie wordt het patroon van de tokenserver van derden voor SAS-verificatie met IoT Hub door IoT-apparaten besproken met behulp van de SDK's van de Azure IoT-client. Onjuiste veronderstellingen van een klant tijdens een recente ondernemingsbetrokkenheid suggereren echter dat u zonder verdere uitleg een misleidende indruk kunt ontwikkelen over het niveau van ondersteuning dat standaard is geïmplementeerd in de SDK's van de Azure IoT-client.

In dit artikel wordt het leren van die betrokkenheid besproken en wordt uitgelegd wat er moet worden gedaan in elke SDK voor apparaten om verificatie van tokens van derden te bereiken. Dit artikel moet ook voorkomen dat u vergelijkbare onjuiste veronderstellingen maakt over ondersteuning voor het patroon tokenserver van derden in de Azure IoT-client-SDK.

Oplossing

De SDK's van de Azure IoT-client bieden verschillende ondersteuningsniveaus voor SAS-tokenverificatie. Hiervoor is een aantal aangepaste code vereist om de verificatie- en tokenbeheerfunctionaliteit te voltooien.

De frequentie van de tokenevaluatie is afhankelijk van het gekozen transportprotocol: MQTT, AMQP of HTTPS. De variatie is afhankelijk van de mogelijkheid van het protocol ter ondersteuning van proactieve verlenging van tokens en time-outs voor sessies. Alleen AMQP implementeert proactieve verlengingsondersteuning. Dit betekent dat de andere transporten de verbinding op een SAS-tokenverificatiefout sluiten en vervolgens een nieuwe verbindingsbewerking moeten uitvoeren. Dit is een potentieel dure connectiviteitsbewerking voor de client.

Als SAS-verificatie mislukt, wordt er een fout gegenereerd door de transport-implementatie die binnen de apparaattoepassing kan worden verwerkt door een gebeurtenis-handler voor Verbinding maken ionstatus gewijzigd. Als u een dergelijke handler niet implementeert, wordt de apparaattoepassing meestal gestopt vanwege de fout. Met de juiste implementatie van de functionaliteit voor gebeurtenis-handler en tokenvernieuwing kunnen de transporten de verbinding opnieuw proberen.

In de volgende afbeelding ziet u het patroon tokenserver van derden:

Illustration of the third-party token-server pattern

In de volgende afbeelding ziet u implementatieondersteuning in de Sdk van de Azure IoT-client met integratie van Mobile Net Operator:

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

Voorbeeldimplementaties zijn opgenomen in de opslagplaats Azure Samples op GitHub.

Problemen en overwegingen

Houd rekening met de volgende punten bij het bepalen of u dit patroon wilt implementeren:

  • De Azure IoT Hub Device Provisioning Service -client-SDK's (Azure DPS) bieden geen ondersteuning voor SAS-tokenverificatie. De Azure DPS REST APIbiedt ondersteuning voor SAS-tokenverificatie. Als u azure DPS wilt gebruiken met een tokenservice van derden voor SAS-verificatie, moet een apparaattoepassing het DPS-apparaatproces implementeren met behulp van de Azure DPS REST API.

  • Dit bestaat uit het maken van een eerste registratieaanvraagbewerking en vervolgens het pollen van de operationele status-API totdat het DPS-proces is geslaagd of mislukt. Bij succes kunnen de details van het inrichten van apparaten worden verkregen door ze aan te vragen bij de Azure DPS REST API Runtime-registratie.

Naslaginformatie:

Wanneer dit patroon gebruiken

U moet dit patroon gebruiken wanneer u zich wilt verifiëren bij Azure IoT Hub vanaf IoT-apparaten met behulp van de verschillende Sdk's van de Azure IoT-client. Gebruik in plaats van de client-SDK's voor SAS-tokenverificatie de Azure DPS REST API te gebruiken om te zorgen voor de implementatie van proactieve verlengingsondersteuning voor alle transportmechanismen.

Voorbeelden

De volgende secties bevatten voorbeelden die u kunt gebruiken voor verschillende programmeertalen, zoals Embedded C, .NET, Java en Python.

Azure IoT Hub-apparaat-SDK voor C en Azure IoT Hub-apparaat-SDK voor Embedded C

De volgende benadering kan worden gebruikt in apparaattoepassingen die zijn gebouwd met behulp van de Azure IoT C SDK of de Azure IoT Embedded C SDK. Geen van beide SDK biedt levensduurbeheer voor SAS-tokens. Daarom moet u een mogelijkheid voor het beheer van de levensduur van een SAS-token implementeren.

SAS-tokens kunnen worden gebruikt via de IOTHUB_CLIENT_CONFIG structuur door het lid deviceSasToken in te stellen op het token en de deviceKey null te maken. Andere ongebruikte waarden, zoals protocolGatewayHostName, moeten ook worden ingesteld op null.

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);

De connection_status_callback kan de IOTHUB_CLIENT_CONNECTION_STATUS_REASON van IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN vangen om een verlenging van het SAS-token via de tokenservice van derden te activeren. Dit is vereist voor alle transporten om verbindingsproblemen vast te leggen, maar is specifiek vereist voor transporten die geen ondersteuning bieden voor proactieve vernieuwing van SAS-token. Proactief levensduurbeheer van SAS-tokens kan worden geïmplementeerd als een functie die herhaaldelijk wordt uitgevoerd tijdens de 'operationele' lus van de apparaattoepassingen. Ervoor zorgen dat de levensduur van het token regelmatig wordt geëvalueerd en dat tokenvernieuwing proactief kan worden uitgevoerd wanneer dat nodig is.

Samenvatting van implementatie van SAS-tokenverificatie voor C SDK's:

  1. Implementeer een Verbinding maken ionStatusCallback-handler om IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN gebeurtenis vast te leggen en tokenvernieuwing te activeren.

  2. Gebruik een IOTHUB_CLIENT_CONFIG om het SAS-token van het apparaat op te geven voor IoTHubDeviceClient_Create.

  3. Implementeer proactief beheer van de levensduur van SAS-tokens als onderdeel van de bewerkingslus van de apparaattoepassing.

Azure IoT Hub-apparaat-SDK voor .NET

De Azure IoT-client-SDK voor .NET implementeert ondersteuning voor levensduurbeheer van SAS-tokens via de abstracte DeviceAuthenticationWithTokenRefresh-klasse. Een concrete implementatie van deze klasse, waarbij functionaliteit voor tokenvernieuwing wordt toegevoegd, kan worden geleverd als verificatiemethode voor een DeviceClient.Create-methode. De transport-implementaties vernieuwen het token automatisch via de verificatiemethode, indien nodig. Een Verbinding maken ionStatusChangesHandler is vereist om verbindingswijzigingen vast te leggen en te voorkomen dat uitzonderingen worden gegenereerd door de transporten.

Voorbeeld van implementatie op basis van de klasse DeviceAuthenticationWithTokenRefreash:

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;
    }
}

Samenvatting van implementatie van SAS-tokenverificatie voor Azure IoT Hub-apparaat-SDK voor .NET:

  1. Implementeer een concrete klasse op basis van de abstracte klasse DeviceAuthenticationWithTokenRefresh, waarmee functionaliteit voor tokenvernieuwing wordt geïmplementeerd.

  2. Implementeer een Verbinding maken ionStatusChangesHandler om de verbindingsstatus van het transport vast te leggen en uitzonderingen te voorkomen die worden veroorzaakt door de implementatie van het transport.

Naslaginformatie:

Azure IoT Hub-apparaat-SDK voor Java

De Azure IoT Client SDK voor Java implementeert ondersteuning voor levensduurbeheer van SAS-tokens via de SasTokenProvider Interface. Een klasse die deze interface implementeert met de functionaliteit voor het vernieuwen van SAS-tokens, kan worden gebruikt als SecurityProvider in een DeviceClient-constructor. De transport-implementaties vernieuwen het token automatisch via de beveiligingsprovider, indien nodig. Een Verbinding maken ionStatusChangeCallback moet worden geregistreerd om verbindingswijzigingen vast te leggen en te voorkomen dat uitzonderingen worden gegenereerd door de transporten.

Voorbeeld van de implementatie van de beveiligingsprovider die de SasTokenProvider-interface implementeert:

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();
    }
}

Samenvatting van implementatie van SAS-tokenverificatie voor Azure IoT Hub-apparaat-SDK voor Java:

  1. Implementeer de SasTokenProvider-interface op een klasse en voeg functionaliteit toe voor het vernieuwen van tokens.

  2. Implementeer een Verbinding maken ionStatusChangeCallback-handler om wijzigingen in de transportverbindingsstatus vast te leggen en uitzonderingen te voorkomen die worden gegenereerd door de transport-implementatie.

Naslaginformatie:

Azure IoT Hub-apparaat-SDK voor Python

De Azure IoT Hub-apparaat-SDK voor Python implementeert SAS-tokenondersteuning via methoden op het IoTHubDeviceClient-object. Met deze methoden kunt u een apparaatclient maken met behulp van een token en de mogelijkheid om een bijgewerkt token op te geven zodra de apparaatclient is gemaakt. Ze implementeren geen levensduurbeheer van tokens, maar dit kan eenvoudig worden geïmplementeerd als asynchrone bewerking.

Een Python 3.7-voorbeeld van een implementatie met alleen het overzicht van de functionaliteit:

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())

Overzicht van Azure IoT Hub Device SDK voor Verificatie met SAS-tokens voor Python:

  1. Maak een sas-tokengeneratiefunctie.

  2. Maak een apparaatclient met behulp van IoTHubDeviceClient.create_from_sastoken.

  3. Beheer de levensduur van tokens als een afzonderlijke activiteit, waarbij de apparaatclient wordt voorzien van een vernieuwd token wanneer dit is vereist door de methode IoTHubDeviceClient.update_sastoken.

Naslaginformatie:

Azure IoT Hub-apparaat-SDK voor Node.JS/JavaScript

Azure IoT voor Node.JS/JavaScript implementeert een SharedAccessSignatureAuthenticationProvider die een SAS-token naar de apparaatclient levert en transporteert om te verifiëren met IoT Hub. Er wordt geen functionaliteit voor tokenvernieuwing geïmplementeerd. De apparaattoepassing moet de levensduur van tokens beheren, waarbij het token naar behoefte wordt vernieuwd.

Gebruik de apparaatclientmethoden vanSharedAccessSignature en updateSharedAccessSignature om een verbinding met IoT Hub te initiëren en een vernieuwd token op te geven aan de SharedAccessSignatuteAuthenticationProvider, waardoor de verificatieprovider een newTokenAvailable-gebeurtenis naar de transporten verzendt.

In het voorbeeld van simple_sample_device_with_sas.js wordt een eenvoudig SAS-tokenvoorbeeld gegeven.

Samenvatting van azure IoT Hub device SDK voor Node.JS/JavaScript:

  1. Sas-tokenlevensbeheer en verlenging implementeren.

  2. Gebruik de apparaatclient vanSharedAccessSignature om een apparaatclientexemplaren te maken.

  3. Gebruik device client updateSharedAccessSignature om een vernieuwd token op te geven.

Naslaginformatie:

Volgende stappen