Obsługa zestawu SDK klienta usługi Azure IoT dla serwerów tokenów innych firm

Azure IoT
Azure IoT Hub

W artykule Kontrola dostępu do usługi IoT Hub pokazano, jak można zintegrować usługę tokenów innej firmy z usługą IoT Hub. W tym artykule opisano obsługę uwierzytelniania tokenu sygnatury dostępu współdzielonego (SAS) w każdym z zestawów SDK klienta usługi Azure IoT. Opisano w nim również elementy, które należy zaimplementować w aplikacji urządzenia przy użyciu odpowiedniego zestawu SDK dla każdego języka, oraz sposób używania tokenów o zakresie urządzenia lub w zakresie modułu dla zasad dostępu współdzielonego urządzenia Połączenie lub modułu Połączenie.

Kontekst i problem

W bieżącej dokumentacji zabezpieczeń usługi Azure IoT Hub omówiono wzorzec serwera tokenów innych firm na potrzeby uwierzytelniania sas w usłudze IoT Hub przez urządzenia IoT przy użyciu zestawów SDK klienta usługi Azure IoT. Jednak nieprawidłowe założenia dokonane przez klienta podczas ostatniego zaangażowania w przedsiębiorstwie sugerują, że bez dalszych wyjaśnień można opracować mylące wrażenie dotyczące poziomu pomocy technicznej zaimplementowanej domyślnie w zestawach SDK klienta usługi Azure IoT.

W tym artykule omówiono wiedzę z tego zaangażowania i wyjaśniono, co należy zrobić w każdym zestawie SDK, aby urządzenia uzyskiwały uwierzytelnianie serwera tokenów innych firm. Ten artykuł powinien również uniemożliwić wprowadzenie podobnych nieprawidłowych założeń dotyczących obsługi wzorca serwera tokenów innych firm w zestawie SDK klienta usługi Azure IoT.

Rozwiązanie

Zestawy SDK klienta usługi Azure IoT zapewniają różne poziomy obsługi uwierzytelniania tokenu SAS, z których każdy wymaga wykonania funkcji uwierzytelniania i zarządzania tokenami.

Częstotliwość oceny tokenu zależy od wybranego protokołu transportowego — MQTT, AMQP lub HTTPS. Odmiana zależy od możliwości protokołu do obsługi proaktywnego odnawiania tokenów i limitów czasu sesji. Tylko protokół AMQP implementuje proaktywną obsługę odnawiania. Oznacza to, że inne transporty zamkną połączenie w przypadku niepowodzenia uwierzytelniania tokenu SAS, a następnie muszą wykonać nową operację połączenia. Jest to potencjalnie kosztowna operacja łączności dla klienta.

Jeśli uwierzytelnianie sygnatury dostępu współdzielonego nie powiedzie się, implementacja transportu, która może być obsługiwana w aplikacji urządzenia przez program obsługi zdarzeń "Połączenie ion Status Changed" (Zmieniono stan Połączenie ion). Niepowodzenie implementacji takiego programu obsługi zwykle spowoduje zatrzymanie aplikacji urządzenia z powodu błędu. Dzięki poprawnej implementacji programu obsługi zdarzeń i funkcji odnawiania tokenu transporty mogą ponownie próbować nawiązać połączenie.

Na poniższej ilustracji przedstawiono wzorzec serwera token-serwera innej firmy:

Illustration of the third-party token-server pattern

Na poniższej ilustracji przedstawiono obsługę implementacji w zestawie SDK klienta usługi Azure IoT z integracją operatora sieci mobilnej:

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

Przykładowe implementacje znajdują się w repozytorium Przykładów platformy Azure w witrynie GitHub.

Problemy i kwestie do rozważenia

Podczas podejmowania decyzji, czy zaimplementować ten wzorzec, należy wziąć pod uwagę następujące kwestie:

  • Zestawy SDK klienta usługi Azure IoT Hub Device Provisioning Service (Azure DPS) nie obsługują uwierzytelniania tokenu SAS. Interfejs APIREST usługi Azure DPS obsługuje uwierzytelnianie tokenu SAS. W związku z tym, aby używać usługi Azure DPS z usługą tokenu innej firmy na potrzeby uwierzytelniania sas, aplikacja urządzenia musi zaimplementować proces dps urządzenia przy użyciu interfejsu API REST usługi Azure DPS.

  • Polega to na utworzeniu początkowej operacji żądania rejestracji, a następnie sondowaniu interfejsu API stanu operacyjnego do momentu pomyślnego lub niepowodzenia procesu usługi DPS. W przypadku powodzenia można uzyskać szczegóły aprowizacji urządzenia, żądając ich od rejestracji środowiska uruchomieniowego interfejsu API REST usługi Azure DPS.

Dokumentacja:

Kiedy używać tego wzorca

Ten wzorzec należy używać zawsze, gdy chcesz uwierzytelnić się w usłudze Azure IoT Hub z urządzeń IoT przy użyciu różnych zestawów SDK klienta usługi Azure IoT. Zamiast używać zestawów SDK klienta na potrzeby uwierzytelniania tokenu SAS, użyj interfejsu API REST usługi Azure DPS, aby zapewnić implementację proaktywnego odnawiania dla wszystkich mechanizmów transportu.

Przykłady

W poniższych sekcjach przedstawiono przykłady, których można używać w różnych językach programowania, takich jak Embedded C, .NET, Java i Python.

Zestaw SDK urządzeń usługi Azure IoT Hub dla języka C i zestawu SDK urządzeń usługi Azure IoT Hub dla osadzonego języka C

Poniższe podejście można wykorzystać w aplikacjach urządzeń utworzonych przy użyciu zestawu SDK języka C usługi Azure IoT lub zestawu SDK języka C usługi Azure IoT Embedded. Żaden zestaw SDK nie zapewnia zarządzania okresem istnienia tokenu SAS, dlatego należy zaimplementować funkcję menedżera okresu istnienia tokenu SAS.

Tokeny SAS mogą być używane za pośrednictwem struktury IOTHUB_CLIENT_CONFIG , ustawiając element członkowski deviceSasToken na token i ustawiając wartość null elementu deviceKey . Inne nieużywane wartości, takie jak protocolGatewayHostName, muszą być również ustawione na wartość 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);

Connection_status_callback może przechwytywać IOTHUB_CLIENT_CONNECTION_STATUS_REASON IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN w celu wyzwolenia odnowienia tokenu SAS za pośrednictwem usługi tokenu innej firmy. Jest to wymagane dla wszystkich transportów do przechwytywania problemów z połączeniem, ale jest to szczególnie wymagane przez transporty, które nie obsługują proaktywnego odnawiania tokenu SAS. Aktywne zarządzanie okresem istnienia tokenu SAS można zaimplementować jako funkcję wielokrotnie uruchamianą podczas pętli "operacyjnej" aplikacji urządzeń. Zapewnienie, że okres istnienia tokenu jest często oceniany, a odnawianie tokenu może być proaktywnie wykonywane w razie potrzeby.

Podsumowanie implementacji uwierzytelniania tokenu SAS dla zestawów SDK języka C:

  1. Zaimplementuj program obsługi Połączenie ionStatusCallback, aby przechwycić zdarzenie IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN i wyzwolić odnawianie tokenu.

  2. Użyj IOTHUB_CLIENT_CONFIG, aby podać token SAS urządzenia do IoTHubDeviceClient_Create.

  3. Zaimplementuj aktywne zarządzanie okresem istnienia tokenu SAS w ramach pętli operacji aplikacji urządzenia.

Zestaw SDK urządzenia usługi Azure IoT Hub dla platformy .NET

Zestaw SDK klienta usługi Azure IoT dla platformy .NET implementuje obsługę zarządzania okresami istnienia tokenu SAS za pomocą abstrakcyjnej klasy DeviceAuthenticationWithTokenRefresh. Konkretną implementację tej klasy, dodając funkcję odnawiania tokenu, można podać jako metodę uwierzytelniania do metody DeviceClient.Create. Implementacje transportu automatycznie odnawiają token za pośrednictwem metody uwierzytelniania zgodnie z potrzebami. Do przechwytywania zmian połączenia jest wymagany Połączenie ionStatusChangesHandler i zapobiegać zgłaszaniu wyjątków przez transporty.

Przykładowa implementacja oparta na klasie 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;
    }
}

Podsumowanie implementacji uwierzytelniania tokenu SAS dla zestawu SDK urządzenia usługi Azure IoT Hub dla platformy .NET:

  1. Zaimplementuj konkretną klasę na podstawie klasy abstrakcyjnej DeviceAuthenticationWithTokenRefresh, która implementuje funkcję odnawiania tokenu.

  2. Zaimplementuj Połączenie ionStatusChangesHandler, aby przechwycić stan połączenia transportu i uniknąć wyjątków zgłaszanych przez implementację transportu.

Dokumentacja:

Zestaw SDK urządzenia usługi Azure IoT Hub dla języka Java

Zestaw SDK klienta usługi Azure IoT dla języka Java implementuje obsługę zarządzania okresem istnienia tokenu SAS za pośrednictwem interfejsu SasTokenProvider. Klasa, która implementuje ten interfejs z funkcją odnawiania tokenu SAS, może służyć jako SecurityProvider w konstruktorze DeviceClient. Implementacje transportu automatycznie odnawiają token za pośrednictwem dostawcy zabezpieczeń zgodnie z potrzebami. Aby przechwycić zmiany połączenia, należy zarejestrować Połączenie ionStatusChangeCallback i zapobiec zgłaszaniu wyjątków przez transporty.

Przykładowa implementacja dostawcy zabezpieczeń implementowania interfejsu SasTokenProvider:

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

Podsumowanie implementacji uwierzytelniania tokenu SAS dla zestawu SDK urządzenia usługi Azure IoT Hub dla języka Java:

  1. Zaimplementuj interfejs SasTokenProvider w klasie i uwzględnij funkcje odnawiania tokenu.

  2. Zaimplementuj program obsługi Połączenie ionStatusChangeCallback, aby przechwycić zmiany stanu połączenia transportu i uniknąć wyjątków zgłaszanych przez implementację transportu.

Dokumentacja:

Zestaw SDK urządzenia usługi Azure IoT Hub dla języka Python

Zestaw SDK urządzenia usługi Azure IoT Hub dla języka Python implementuje obsługę tokenu SAS za pomocą metod w obiekcie IoTHubDeviceClient. Te metody umożliwiają tworzenie klienta urządzenia przy użyciu tokenu oraz możliwość podawania zaktualizowanego tokenu po utworzeniu klienta urządzenia. Nie implementują zarządzania okresem istnienia tokenu, ale można to łatwo zaimplementować jako operację asynchroniczną.

Przykładowa implementacja języka Python 3.7 przedstawiająca tylko konspekt funkcjonalności:

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

Podsumowanie zestawu SDK urządzenia usługi Azure IoT Hub na potrzeby uwierzytelniania tokenu SAS języka Python:

  1. Utwórz funkcję generowania tokenu SAS.

  2. Utwórz klienta urządzenia przy użyciu IoTHubDeviceClient.create_from_sastoken.

  3. Zarządzaj okresem istnienia tokenu jako osobnym działaniem, dostarczając klientowi urządzenia odnowiony token, jeśli jest to wymagane przez metodę IoTHubDeviceClient.update_sastoken.

Dokumentacja:

Zestaw SDK urządzenia usługi Azure IoT Hub dla środowiska Node.JS/JavaScript

Usługa Azure IoT dla środowiska Node.JS/JavaScript implementuje element SharedAccessSignatureAuthenticationProvider, który będzie obsługiwać token SAS dla klienta urządzenia i transportuje je do uwierzytelniania za pomocą usługi IoT Hub. Nie implementuje żadnych funkcji odnawiania tokenu. Aplikacja urządzenia musi zarządzać okresem istnienia tokenu, odnawiając token zgodnie z potrzebami.

Użyj metod klienta urządzenia z witrynySharedAccessSignature i updateSharedAccessSignature, aby zainicjować połączenie z usługą IoT Hub i podać odnowiony token do dostawcy SharedAccessSignatuteAuthenticationProvider, co spowoduje, że dostawca uwierzytelniania emituje noweTokenAvailable zdarzenie do transportu.

W przykładzie simple_sample_device_with_sas.js znajduje się podstawowy przykład tokenu SAS.

Podsumowanie zestawu SDK urządzenia usługi Azure IoT Hub dla środowiska Node.JS/JavaScript:

  1. Zaimplementuj zarządzanie okresem istnienia tokenu SYGNATURy dostępu współdzielonego i odnawianie.

  2. Użyj klienta urządzenia z witrynySharedAccessSignature, aby utworzyć wystąpienie klienta urządzenia.

  3. Użyj aktualizacji klienta urządzeniaSharedAccessSignature, aby podać odnowiony token.

Dokumentacja:

Następne kroki