Compatibilidad del SDK de cliente de Azure IoT con servidores de tokens de terceros

El artículo Control del acceso a IoT Hub muestra cómo se puede integrar un servicio de token de terceros con IoT Hub. En este artículo se describe la compatibilidad con la autenticación de tokens de firma de acceso compartido (SAS) en cada uno de los SDK de cliente de Azure IoT. También se describe el contenido que debe implementarse en una aplicación de dispositivo mediante el SDK correspondiente para cada lenguaje y cómo usar tokens que cuenten con ámbito de dispositivo o de módulo en las directivas de acceso compartido de DeviceConnect o ModuleConnect.

Contexto y problema

En la documentación de seguridad de Azure IoT Hub actual se describe el patrón del servidor de tokens de terceros para que los dispositivos IoT realicen la autenticación SAS con IoT Hub mediante los SDK de cliente de Azure IoT. Sin embargo, las suposiciones incorrectas que realice un cliente durante una participación empresarial reciente sugieren que, sin tener que realizar más aclaraciones, puede llegar a tener una impresión errónea sobre el nivel de soporte implementado de forma predeterminada en los SDK de cliente de Azure IoT.

En este artículo se describe el aprendizaje de esa interacción y se aclara lo que se debe hacer en cada SDK para que los dispositivos puedan realizar la autenticación del servidor de tokens de terceros. Este artículo también debe enseñarle a evitar que haga suposiciones incorrectas similares sobre la compatibilidad con el patrón del servidor de tokens de terceros en el SDK de cliente de Azure IoT.

Solución

Los SDK de cliente de Azure IoT proporcionan distintos niveles de compatibilidad con la autenticación de tokens de SAS, ya que cada uno requiere un código personalizado para completar la funcionalidad de autenticación y administración de tokens.

La frecuencia de evaluación del token depende del protocolo de transporte elegido: MQTT, AMQP o HTTPS. Igualmente, la variación depende de la capacidad del protocolo para admitir la renovación proactiva de tokens y los tiempos de espera de la sesión. Solo AMQP implementa la compatibilidad con la renovación proactiva. Esto significa que los demás transportes cerrarán la conexión en caso de que se produzca un error de autenticación en el token de SAS, por lo que tendrán que realizar una nueva operación de conexión. Tenga en cuenta que esta es una operación de conectividad potencialmente costosa para el cliente.

Si se produce un error en la autenticación de SAS, la implementación de transporte genera un error que se puede controlar dentro de la aplicación del dispositivo mediante un controlador de eventos denominado "Estado de conexión cambiado". Si no se implementa este tipo de controlador, la aplicación de dispositivo normalmente se detendrá debido al error. Con la implementación correcta del controlador de eventos y la funcionalidad de renovación de tokens, los transportes pueden volver a intentar la conexión.

En la ilustración siguiente se muestra el patrón del servidor de tokens de terceros:

Ilustración del patrón del servidor de tokens de terceros

En la ilustración siguiente se muestra la compatibilidad con la implementación en el SDK de cliente de Azure IoT con la integración del operador de Mobile Net:

Diagrama de flujo de la compatibilidad con la implementación en el SDK de cliente de Azure IoT con la integración del operador de Mobile Net

Tiene implementaciones de ejemplo en el repositorio de ejemplos de Azure en GitHub.

Problemas y consideraciones

Tenga en cuenta los puntos siguientes al decidir cómo implementar este patrón:

  • Los SDK de cliente de Azure IoT Hub Device Provisioning Service (Azure DPS) no admiten la autenticación de tokens de SAS. La API de REST de Azure DPS es compatible con la autenticación de tokens de SAS. Por lo tanto, para usar Azure DPS con un servicio de token de terceros para realizar la autenticación SAS, una aplicación de dispositivo debe implementar el proceso de DPS del dispositivo mediante la API de REST de Azure DPS.

  • Para ello, debe realizar una operación de solicitud de registro inicial y, a continuación, sondear la API en estado operativo hasta que el proceso de DPS se realice correctamente o se produzca un error. Si se ejecuta correctamente, los detalles de aprovisionamiento de dispositivos se pueden obtener solicitándolos desde el registro en tiempo de ejecución de la API de REST de Azure DPS.

Referencias:

Cuándo usar este patrón

Debe usar este patrón siempre que quiera autenticarse en Azure IoT Hub desde dispositivos IoT mediante los distintos SDK de cliente de Azure IoT. En lugar de usar los SDK de cliente para realizar la autenticación de tokens de SAS, use la API de REST de Azure DPS para garantizar la implementación de la compatibilidad de renovación proactiva para todos los mecanismos de transporte.

Ejemplos

En las secciones siguientes se ofrecen ejemplos que puede usar en distintos lenguajes de programación, como C insertado, .NET, Java y Python.

SDK de dispositivo de Azure IoT Hub para C y el SDK de dispositivo de Azure IoT Hub para C insertado

El siguiente ejemplo se puede usar en aplicaciones de dispositivo creadas con el SDK de C de Azure IoT o el SDK de C insertado de Azure IoT. Ninguno de los SDK proporciona la opción de administrar la duración de los tokens de SAS, por lo que deberá implementar una funcionalidad de administrador para la duración de los tokens de SAS.

Los tokens de SAS se pueden usar a través de la estructura IOTHUB_CLIENT_CONFIG; para ello, debe establecer el miembro deviceSasToken en el token y estableciendo deviceKey en NULL. Otros valores que no se usan, como protocolGatewayHostName también deben establecerse en NULL.

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;

A continuación, puede proporcionar el elemento IOTHUB_CLIENT_CONFIG a la función IoTHubDeviceClient_Create para establecer una instancia DeviceClient.

IF ((IOTHUBCLIENTHANDLE = IOTHUBDEVICECLIENT\_CREATE(CONFIG)) == NULL)

{

(VOID)PRINTF("ERROR: IOTHUBCLIENTHANDLE IS NULL!\\R\\N");

}

Para capturar errores de autenticación de token de SAS, es necesario implementar un controlador para IoTHubDeviceClient_SetConnectionStatusCallback.

(VOID)IOTHUBDEVICECLIENT\_SETCONNECTIONSTATUSCALLBACK(IOTHUBCLIENTHANDLE,
CONNECTION\_STATUS\_CALLBACK, NULL);

El elemento connection_status_callback puede obtener la estructura IOTHUB_CLIENT_CONNECTION_STATUS_REASON de IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN para activar una renovación del token de SAS a través del servicio de token de terceros. Esto es necesario para que todos los transportes capturen problemas de conexión, pero lo requieren específicamente los transportes que no admiten la renovación proactiva de tokens de SAS. La administración proactiva de la duración del token de SAS se puede implementar como una función que se ejecuta repetidamente durante el bucle "operativo" de las aplicaciones de dispositivo. Debe asegurarse de que la duración del token se evalúa con frecuencia y que la renovación de tokens se puede ejecutar de forma proactiva cuando sea necesario.

Resumen de la implementación de la autenticación de tokens de SAS para los SDK de C:

  1. Implemente un controlador ConnectionStatusCallback para capturar el evento IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN y desencadenar la renovación del token.

  2. Use una estructura IOTHUB_CLIENT_CONFIG para proporcionar el token de SAS del dispositivo a IoTHubDeviceClient_Create.

  3. Implemente la administración proactiva de la duración del token de SAS como parte del bucle de operación de la aplicación de dispositivo.

Referencias:

SDK de dispositivos de Azure IoT Hub para .NET

El SDK de cliente de Azure IoT para .NET implementa la compatibilidad con la administración de la duración del token de SAS a través de la clase abstracta DeviceAuthenticationWithTokenRefresh. Se puede proporcionar una implementación concreta de esta clase, agregando la funcionalidad de renovación de tokens, como método de autenticación para un método DeviceClient.Create. Las implementaciones de transporte renovarán automáticamente el token a través del método de autenticación según sea necesario. La clase ConnectionStatusChangesHandler es necesaria para capturar los cambios de conexión e impedir que los transportes realicen excepciones.

Implementación de ejemplo basada en la clase 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 TASK\<STRING\> SAFECREATENEWTOKEN(STRING IOTHUB, INT
SUGGESTEDTIMETOLIVE)

{

STRING RESULT;

STRING URL = STRING.FORMAT(\_STSCONNECTURL, IOTHUB, DEVICEID);

HTTPCLIENTHANDLER HANDLER = NEW HTTPCLIENTHANDLER();

HTTPCLIENT = NEW HTTPCLIENT(HANDLER);

TRY

{

VAR APIRESPONSE = HTTPCLIENT.GETASYNC(URL).RESULT;

IF (APIRESPONSE.ISSUCCESSSTATUSCODE)

{

RESULT = APIRESPONSE.CONTENT.READASSTRINGASYNC().RESULT;

}

ELSE

{

THROW NEW HTTPREQUESTEXCEPTION();

}

}

CATCH (HTTPREQUESTEXCEPTION)

{

RESULT = NULL;

}

RETURN TASK.FROMRESULT(RESULT);

}

}

Resumen de la implementación de autenticación del token de SAS para el SDK de dispositivo de Azure IoT Hub para .NET:

  1. Implemente una clase concreta basada en la clase abstracta DeviceAuthenticationWithTokenRefresh, que implemente la funcionalidad de renovación de tokens.

  2. Implemente connectionStatusChangesHandler para capturar el estado de la conexión de transporte y evitar las excepciones que genera la implementación de transporte.

Referencias:

SDK de dispositivos de Azure IoT Hub para Java

El SDK de cliente de Azure IoT para Java implementa la compatibilidad con la administración de la duración del token de SAS a través de la interfaz SasTokenProvider. Una clase que implementa esta interfaz con la funcionalidad de renovación de tokens de SAS se puede usar como un elemento SecurityProvider en un constructor DeviceClient. Las implementaciones de transporte renovarán automáticamente el token a través del proveedor de seguridad según sea necesario. Debe registrar una clase ConnectionStatusChangeCallback para capturar los cambios de conexión y evitar que los transportes generen excepciones.

Implementación de ejemplo del proveedor de seguridad que implementa la interfaz 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();

}

}

Resumen de la implementación de autenticación del token de SAS para el SDK de dispositivo de Azure IoT Hub para Java:

  1. Implemente la interfaz SasTokenProvider en una clase e incluya la funcionalidad de renovación de tokens.

  2. Implemente un controlador ConnectionStatusChangeCallback para capturar los cambios de estado de la conexión de transporte y evitar las excepciones que genere la implementación del transporte.

Referencias:

SDK de dispositivos de Azure IoT Hub para Python

El SDK de dispositivos de Azure IoT Hub para Python implementa la compatibilidad con tokens de SAS a través de los métodos en el objeto IoTHubDeviceClient. Estos métodos permiten la creación de un cliente de dispositivo mediante un token, y otorgan la capacidad de proporcionar un token actualizado una vez haya creado el cliente del dispositivo. Tenga en cuenta que no implementan la administración de la duración de los tokens, pero esto se puede implementar fácilmente como una operación asincrónica.

Esta es una implementación de ejemplo de Python 3.7 que muestra solo el esquema de la funcionalidad:

ASYNC DEF MAIN():

\# GET A SASTOKEN YOU GENERATED

SASTOKEN = GET\_NEW\_SASTOKEN()

\# THE CLIENT OBJECT IS USED TO INTERACT WITH YOUR AZURE IOT HUB.

DEVICE\_CLIENT = IOTHUBDEVICECLIENT.CREATE\_FROM\_SASTOKEN(SASTOKEN)

\# CONNECT THE CLIENT.

AWAIT DEVICE\_CLIENT.CONNECT()

\# DEFINE BEHAVIOR FOR PROVIDING NEW SASTOKENS 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 SASTOKEN KEEPALIVE IN THE EVENT LOOP

KEEPALIVE\_TASK = ASYNCIO.CREATE\_TASK(SASTOKEN\_KEEPALIVE())

\# CANCEL THE SASTOKEN UPDATE TASK

KEEPALIVE\_TASK.CANCEL()

\# FINALLY, SHUT DOWN THE CLIENT

AWAIT DEVICE\_CLIENT.SHUTDOWN()

IF \_\_NAME\_\_ == "\_\_MAIN\_\_":

ASYNCIO.RUN(MAIN())

Resumen del SDK de dispositivos de Azure IoT Hub para realizar la autenticación de tokens de SAS para Python:

  1. Cree la función de generación de tokens de SAS.

  2. Cree un cliente de dispositivo mediante IoTHubDeviceClient.create_from_sastoken.

  3. Administre la duración del token como una actividad independiente y proporcione al cliente de dispositivo un token renovado cuando lo requiera el método IoTHubDeviceClient.update_sastoken.

Referencias:

SDK de dispositivos de Azure IoT Hub para Node.js y JavaScript

Azure IoT para Node.JS y JavaScript implementa una clase SharedAccessSignatureAuthenticationProvider que entregará un token de SAS al cliente del dispositivo y lo transportará para realizar la autenticación con IoT Hub. Tenga en cuenta que no implementa ninguna funcionalidad de renovación de tokens. La aplicación de dispositivo debe administrar la duración del token, renovando el token según sea necesario.

Utilice los métodos de cliente de dispositivo fromSharedAccessSignature y updateSharedAccessSignature para iniciar una conexión con IoT Hub y proporcionar un token renovado a SharedAccessSignatuteAuthenticationProvider, lo que hará que el proveedor de autenticación emita un evento newTokenAvailable a los transportes.

Puede consultar un ejemplo de token de SAS básico en simple_sample_device_with_sas.js.

Resumen del SDK de dispositivos de Azure IoT Hub para Node.js y JavaScript

  1. Implemente la administración y renovación de la duración del token de SAS.

  2. Use el cliente de dispositivo fromSharedAccessSignature para crear una instancia de cliente de dispositivo.

  3. Use el cliente de dispositivo updateSharedAccessSignature para proporcionar un token renovado.

Referencias:

Pasos siguientes