API de Autenticación 1.0 de IIIF

Estado de este Documento

Esta Versión: 1.0.0

Última Versión Estable: 1.0.0

Versión Anterior: 0.9.4

Editores:

Copyright © 2015-2017 Editores y colaboradores. Publicado por IIIF Consortium bajo la licencia CC-BY, ver aviso legal.


Tabla de Contendidos

1. Introducción

Las especificaciones de IIIF (pronunciado “Triple-I-Efe”) son diseñadas para soportar el acceso uniforme y enriquecido a recursos alojados en todo el mundo. Es conveniente el acceso abierto al contenido, pero políticas internas, regulaciones legales, modelos empresariales, y otras limitaciones pueden requerir que los usuarios se autentiquen y sean autorizados a interactuar con algunos recursos. Los procesos de autenticación incluyen desde sencillas restricciones por dirección IP o acuerdos click-through, hasta planes de múltiples factores con proveedores de identidad segura.

Los proveedores de contenido que necesiten limitar el acceso a sus recursos pueden ofrecer acceso por niveles a versiones alternativas en lugar de una simple proposición todo-o-nada. Las versiones alternativas pueden estar degradadas en cuanto a resolución, marcas de agua, o compresión, pero son mejores que un acceso denegado.

Ofrecer acceso interoperable a contenido restringido mediante aplicaciones cliente basadas en un navegador web presenta muchos retos:

  • Un único manifest de la API de Presentación de IIIF puede referenciar recursos de contenido de múltiples instituciones y, por tanto, de múltiples dominios.
  • Cada versión de un recurso debe poseer una URI única para evitar que las cachés web retornen la versión incorrecta.
  • Los sistemas de control de acceso existentes en las instituciones son diferentes.
  • La mayoría de los visores IIIF son aplicaciones de JavaScript del lado del cliente que pueden ser servidas desde un dominio distinto de, y, por tanto, no confiable para, los servicios de imagen que se deben cargar.
  • Similarmente, el dominio de los servicios de autenticación puede ser diferente del dominio de un visor o del contenido basado en IIIF. Por tanto, el servidor de autorización no debe requerir conocimiento previo del dominio que aloja el visor.

Adicionalmente, la comunidad IIIF tiene los siguientes objetivos para esta especificación:

  • Un cliente IIIF no debiera autenticar al usuario; el servidor que aloja el contenido debe ser responsable de obtener las credenciales del usuario, y el visor IIIF no requiere conocimiento de, o acceso a, ese intercambio.
  • Un cliente IIIF basado en navegador debe ser capaz de mantener su estado interno durante un flujo de autenticación.
  • No se debiera requerir un registro de dominios confiables; cualquiera debiera poder crear cualquier tipo de visor y ejecutarlo desde cualquier parte.
  • Las instituciones debieran poder usar sus sistemas de autenticación existentes sin modificarlos.

Para vencer esos retos y objetivos, la especificación de Autenticación de IIIF describe un conjunto de flujos de trabajo para guiar al usuario a través de un sistema de control de acceso existente. El proceso de autenticación del usuario está, en su mayor parte, fuera de los objetivos de esta especificación, y puede involucrar un viaje redondo a un servidor CAS, o un proveedor OAuth2, o un sistema de inicio de sesión personalizado. En este sentido, la Autenticación de IIIF no es igual a un protocolo como CAS; es un patrón para interactuar con protocolos de terceros arbitrarios.

La Autenticación de IIIF ofrece un enlace a una interfaz de usuario para iniciar sesión, y servicios que proporcionan credenciales, modelados como los elementos del flujo de trabajo OAuth2. La combinación actúa como puente hacia el sistema de control de acceso que utiliza el servidor, sin que el cliente necesite conocer el mismo.

En resumen, la especificación describe como:

  • Desde un visor, iniciar una interacción con un sistema de control de acceso que permita al usuario adquirir las credenciales requeridas para ver contenido restringido.
  • Proporcionar al cliente suficiente conocimiento del estado del usuario respecto al proveedor de contenido para garantizar una buena experiencia de usuario.

Por favor, envíe sus comentarios a iiif-discuss@googlegroups.com.

1.1. Terminología

Esta especificación distingue Recursos de Contenido, por ejemplo, imágenes o videos, y Recursos de Descripción que cumplen las especificaciones de IIIF, por ejemplo, recursos de información de imagen de la API de Imagen (info.json) y recursos collection o manifest de la API de Presentación. Desde el punto de vista de una aplicación basada en navegador, los Recursos de Contenido son cargados indirectamente mediante la interpretación del navegador de los elementos HTML; y los Recursos de Descripción, típicamente, son cargados directamente por JavaScript usando la interfaz XMLHttpRequest. La especificación Cross Origin Resource Sharing (CORS) implementada por los navegadores modernos describe las distintas reglas de seguridad aplicables a las interacciones con esos dos tipos de recursos.

Dos conceptos adicionales, cookie de acceso y token de acceso, se describen posteriormente.

En este documento, las palabras resaltadas debe(n) y requerido(a) implican que la definición es un requisito absoluto de la especificación; la expresión no debe(n) implica que la definición es una prohibición absoluta de la especificación; las palabras debiera(n) y recomendado(a) implican que pueden existir razones válidas en circunstancias particulares para ignorar un elemento particular, pero es preciso comprender y sopesar cuidadosamente todas las consecuencias antes de seguir un curso diferente; las expresiones no debiera(n) o no recomendado(a) implican que pueden existir razones válidas en circunstancias particulares donde el comportamiento particular es aceptable o útil, pero es preciso comprender y sopesar cuidadosamente todas las consecuencias antes de implementarlo; las palabras puede(n) y opcional implican que el elemento de la especificación es verdaderamente opcional, si bien la implementación que no incluya una opción particular debe estar preparada para interoperar con otra implementación que sí la incluya (aunque quizás con funcionalidad reducida) e, inversamente, una implementación que incluya una opción particular debe estar preparada para interoperar con otra implementación que no la incluya (excepto, por supuesto, para la característica proporcionada por la opción).

El párrafo anterior es una adaptación de la parte relevante del documento referenciado (RFC 2119) por la versión original de esta sección.

1.2. Autenticación para Recursos de Contenido

En general, los Recursos de Contenido (por ejemplo, las imágenes) son recursos secundarios incrustados en una página web o aplicación. En las páginas web, las imágenes se incluyen mediante la etiqueta HTML img, y se recuperan con peticiones HTTP adicionales del navegador. Si un usuario no está autorizado a cargar una página web, el servidor puede redirigirlo a otra página y ofrecer la oportunidad de autenticar. Esa redirección no es posible para Recursos de Contenido incrustados, y en esos casos se presenta al usuario un ícono de imagen rota. Si la imagen está sujeta a control de acceso, el navegador debe evitar imágenes rotas enviando una cookie que el servidor pueda aceptar como credencial para conceder acceso a la imagen. Esta especificación describe como el usuario adquiere esa cookie de acceso.

1.3. Autenticación para Recursos de Descripción

Los Recursos de Descripción (por ejemplo, un manifest de la API de Presentación, o un documento de información de la API de Imagen (info.json)) proporcionan a la aplicación cliente la información necesaria para que el navegador solicite los Recursos de Contenido. Un Recurso de Descripción debe estar en el mismo dominio que el Recurso de Contenido que describe, pero no es requerido que el código cliente en ejecución esté alojado en ese dominio.

Un navegador que ejecute JavaScript obtenido de un dominio no puede emplear XMLHttpRequest para cargar un Recurso de Descripción de otro dominio e incluir las cookies de ese dominio en la petición, sin violar el requisito antes mencionado de que el cliente debe trabajar aunque sea no confiable. En ese caso, el cliente envía un token de acceso (técnicamente, un tipo de token al portador) como sustituto de la cookie de acceso. Esta especificación describe como, una vez que el navegador consigue la cookie de acceso para los Recursos de Contenido, el cliente adquiere el token de acceso para utilizar en las peticiones directas de Recursos de Descripción.

El servidor en el Dominio de Recurso trata al token de acceso como representación, o sustituto, de la cookie que permite acceder a los Recursos de Contenido. Cuando el cliente solicita Recursos de Descripción y presenta el token de acceso, las respuestas informan al cliente qué sucederá si el navegador solicita los recursos de contenido correspondientes usando la cookie de acceso que el token de acceso representa. Esas respuestas permiten al cliente decidir cuáles interfaz de usuario y/o Recursos de Contenido mostrar al usuario.

1.4. Seguridad

El propósito de esta especificación es soportar el control de acceso para recursos IIIF; por tanto, la seguridad es una tema fundamental. Para impedir su mala utilización, las cookies y los tokens al portador descritos en esta especificación no deben ser revelados en el almacenamiento y el transporte. Las implementaciones debieran usar HTTP sobre TLS, conocido como HTTPS, para todas las comunicaciones. Además, todo cliente IIIF que interactúe con recursos de acceso controlado debiera ser ejecutado desde páginas servidas por medio de HTTPS. Toda referencia a HTTP en esta especificación presupone el uso de HTTPS.

Esta especificación protege los Recursos de Contenido (por ejemplo, las imágenes) exponiendo el valor del token de acceso al script de la aplicación cliente, para usar en la solicitud de Recursos de Descripción. El conocimiento del token de acceso no es útil para un cliente malicioso, pues la cookie de acceso (que el cliente no puede ver) es la única credencial válida para los Recursos de Contenido, y un Recurso de Descripción carece de valor por sí solo. No obstante, en versiones futuras, los patrones de interacción introducidos en esta especificación se extenderán a operaciones de escritura sobre recursos IIIF, por ejemplo, crear anotaciones en un servidor de anotaciones, o modificar el elemento structures de un manifest. Para tales operaciones, el token de acceso es la credencial, y el flujo presentado a continuación puede requerir uno o más pasos adicionales para establecer la confianza entre cliente y servidor. Sin embargo, anticipamos que los cambios serán compatibles hacia atrás con la versión 1.0.

Más detalles de las consideraciones de seguridad se pueden encontrar en las Notas de Implementación.

2. Servicios de Autenticación

Los servicios de autenticación siguen el patrón descrito en la nota de IIIF, Enlazando a Servicios Externos, y son referenciados en uno o más bloques service de las descripciones de los recursos que protegen. Existe un perfil de servicio primario de inicio de sesión para autenticar a los usuarios, y en su descripción se anidan servicios relacionados, que incluyen un servicio obligatorio de token de acceso, y un servicio opcional de cierre de sesión.

El cliente usa este servicio para obtener una cookie que empleará al interactuar con contenido (por ejemplo, imágenes), y con el servicio de token de acceso. Existen varios patrones de interacción en los cuales el cliente utilizará este servicio, basados en la interfaz de usuario a renderizar, indicada por una URI de perfil. El cliente obtiene el enlace hacia el servicio de cookie de acceso de un bloque service en una descripción del recurso protegido.

El objetivo del servicio de cookie de acceso es especificar una cookie durante la interacción del usuario con el servidor de contenido, de forma que las peticiones de imagen del cliente al servidor de contenido tengan éxito. El cliente no sabe qué sucede en el servicio de inicio de sesión, y no puede ver las cookies especificadas para el dominio de contenido durante la interacción del usuario con ese servicio. El navegador puede ser redirigido una o más veces, pero eso es invisible para la aplicación cliente. La respuesta final en la pestaña abierta debiera incluir JavaScript que intente cerrar la pestaña, a fin de iniciar el paso siguiente del flujo de trabajo.

2.1.1. Descripción del Servicio

Existen cuatro patrones de interacción mediante los cuales el cliente puede obtener una cookie de acceso, cada uno identificado por una URI de perfil. Esos patrones se describen en las secciones siguientes.

Patrón URI de Perfil
Descripción
Login http://iiif.io/api/auth/1/login El usuario debe iniciar sesión usando una ventana independiente con una IU provista por un sistema de autenticación externo.
Clickthrough http://iiif.io/api/auth/1/clickthrough El usuario debe hacer clic en un botón del cliente usando contenido provisto en la descripción del servicio.
Kiosk http://iiif.io/api/auth/1/kiosk El usuario no necesita interactuar con un sistema de autenticación, se espera que el cliente use el servicio de cookie de acceso automáticamente.
External http://iiif.io/api/auth/1/external Se espera que el usuario haya adquirido la cookie apropiada; el servicio de cookie de acceso no será usado.

La descripción del servicio está incluída en el Recurso de Descripción y tiene las siguientes propiedades:

Propiedad ¿Requerida? Descripción
@context requerida Documento de contexto que describe la API de Autenticación de IIIF. El valor debe ser http://iiif.io/api/auth/1/context.json.
@id ver descripción requerida para los patrones Login, Clickthrough, y Kiosk, donde el cliente abre la URI para obtener una cookie de acceso. opcional para el patrón External, pues se asume que el usuario consiguió la cookie por otros medios, y se ignora cualquier valor provisto.
profile requerida El perfil del servicio debe ser una de las URIs de perfil de la tabla anterior.
label requerida Texto a mostrar al usuario para dar inicio a la carga del servicio de autenticación cuando se requieren múltiples servicios. El valor debe incluir el dominio o institución donde el usuario se está autenticando.
confirmLabel recomendada Texto a mostrar al usuario en el botón o elemento que abre el servicio de cookie de acceso. Si no está presente, el cliente proporciona texto adecuado para el patrón de interacción, de ser necesario.
header recomendada Texto breve que, de estar presente, debe ser mostrado al usuario como un header de la descripción, o en solitario, si no hay descripción.
description recomendada Texto que, de estar presente, debe ser mostrado al usuario antes de abrir el servicio de cookie de acceso.
failureHeader opcional Texto breve que, de estar presente, puede ser mostrado al usuario como un header si no se recibe un token, o si usar el token genera un error.
failureDescription opcional Texto que, de estar presente, puede ser mostrado al usuario si no se recibe un token, o si usar el token genera un error.
service requerida Referencias a token de acceso y otros servicios relacionados, descritos más adelante.

El cliente debe adjuntar el siguiente parámetro de consulta a toda petición de una URI de servicio de cookie de acceso, con independencia del patrón de interacción, y abrir esa URI en una nueva ventana o pestaña.

Parámetro Descripción
origin String que contiene el origen de la página en la ventana, consistente de protocolo, nombre de host, y número de puerto opcional, como describe la especificación de la API postMessage.

Por ejemplo, dada la URI de servicio de cookie de acceso https://authentication.example.org/login, un cliente instanciado por la página https://client.example.com/viewer/index.html haría su petición a:

https://authentication.example.org/login?origin=https://client.example.com/

El servidor puede usar esa información para validar el origen provisto en peticiones subsiguientes al servicio de token de acceso, por ejemplo, codificándolo en la cookie retornada.

2.1.3. Patrón de Interacción Login

Para inducir al usuario a iniciar sesión, el cliente debe mostrar parte de la interfaz de usuario del proveedor de contenido. Para el patrón de interacción Login, el valor de la propiedad @id es la URI de esa interfaz de usuario.

La interacción tiene los pasos siguientes:

  • Si las propiedades header y/o description están presentes, antes de abrir la interfaz de autenticación del proveedor, el cliente debiera mostrar los valores de las propiedades al usuario. Las propiedades describen qué sucederá al hacer clic en el elemento de confirmLabel.
  • Tras la activación del elemento de confirmLabel, el cliente debe abrir la URI de @id con el parámetro de consulta origin añadido. Eso se debe realizar en una nueva ventana o pestaña para contribuir a la prevención de ataques de spoofing. Las reglas de seguridad del navegador impiden que el cliente sepa lo que sucede en la nueva pestaña; por tanto, el cliente sólo puede esperar por, y detectar, el cierre de la pestaña abierta.
  • Tras el cierre de la pestaña abierta, el cliente debe usar el servicio de token de acceso relacionado, como describimos más adelante.

Con conocimiento externo, los clientes autorizados no dirigidos por el usuario pueden usar POST para enviar la información del usuario pre-autenticado al servicio. Como la información requerida depende de la lógica de autorización, esta API no especifica los detalles.

Un ejemplo de descripción de servicio para el patrón de interacción Login:

{
  // ...
  "service" : {
    "@context": "http://iiif.io/api/auth/1/context.json",
    "@id": "https://authentication.example.org/login",
    "profile": "http://iiif.io/api/auth/1/login",
    "label": "Inicio de Sesión en la Institución Ejemplo",
    "header": "Por Favor, Inicie Sesión",
    "description": "La Institución Ejemplo requiere que inicie sesión en su cuenta de Ejemplo para ver este contenido.",
    "confirmLabel": "Inicio de Sesión",
    "failureHeader": "Autenticación Fallida",
    "failureDescription": "<a href=\"http://example.org/policy\">Política de Acceso</a>",
    "service": [
      // Servicios de token de acceso y cierre de sesión ...
    ]
  }
}

2.1.4. Patrón de Interacción Clickthrough

En el patrón de interacción Clickthrough, el valor de la propiedad @id es la URI de un servicio que debe especificar una cookie de acceso y cerrar inmediatamente su ventana o pestaña sin intervención del usuario. La interacción tiene los pasos siguientes:

  • Si las propiedades header y/o description están presentes, antes de abrir el servicio, el cliente debe mostrar los valores de las propiedades al usuario. Las propiedades describen el acuerdo implícito al hacer clic en el elemento de confirmLabel.
  • Tras la activación del elemento de confirmLabel, el cliente debe abrir la URI de @id con el parámetro de consulta origin añadido. Esto se debiera realizar en una nueva ventana o pestaña. Las reglas de seguridad del navegador impiden que el cliente sepa lo que sucede en la nueva pestaña; por tanto, el cliente sólo puede esperar por, y detectar, el cierre de la ventana, pestaña, o iframe abierta.
  • Tras el cierre de la pestaña abierta, el cliente debe usar el servicio de token de acceso relacionado, como describimos más adelante.

Los clientes no dirigidos por el usuario no deben usar servicios de cookie de acceso con el patrón de interacción Clickthrough; en lugar de eso, se deben detener.

Un ejemplo de descripción de servicio para el patrón de interacción Clickthrough:

{
  // ...
  "service" : {
    "@context": "http://iiif.io/api/auth/1/context.json",
    "@id": "https://authentication.example.org/clickthrough",
    "profile": "http://iiif.io/api/auth/1/clickthrough",
    "label": "Condiciones de Uso para la Institución Ejemplo",
    "header": "Material Restringido por Condiciones de Uso",
    "description": "<span>... condiciones de uso ... </span>",
    "confirmLabel": "Acepto",
    "failureHeader": "Condiciones de Uso No Aceptadas",
    "failureDescription": "Debe aceptar las condiciones de uso para ver el contenido.",
    "service": {
      // Servicio de token de acceso ...
    }
  }
}

2.1.5. Patrón de Interacción Kiosk

En el patrón de interacción Kiosk, el valor de la propiedad @id es la URI de un servicio que debe especificar una cookie de acceso y cerrar inmediatamente su ventana o pestaña sin intervención del usuario. La interacción tiene los pasos siguientes:

  • No hay intervención del usuario antes de abrir la URI del servicio de cookie de acceso; por tanto, las propiedades label, header, description y confirmLabel se ignoran, de estar presentes.
  • El cliente debe abrir inmediatamente la URI de @id con el parámetro de consulta origin añadido. Eso se debiera realizar en una nueva ventana o pestaña. Las reglas de seguridad del navegador impiden que el cliente sepa lo que sucede en la nueva pestaña; por tanto, el cliente sólo puede esperar por, y detectar, el cierre de la ventana, pestaña, o iframe abierta.
  • Tras el cierre de la pestaña abierta, el cliente debe usar el servicio de token de acceso relacionado, como describimos más adelante.

Los clientes no dirigidos por el usuario acceden a la URI de @id para obtener la cookie de acceso, y usan el servicio de token de acceso relacionado, como describimos más adelante.

Un ejemplo de descripción de servicio para el patrón de interacción Kiosk:

{
  // ...
  "service" : {
    "@context": "http://iiif.io/api/auth/1/context.json",
    "@id": "https://authentication.example.org/cookiebaker",
    "profile": "http://iiif.io/api/auth/1/kiosk",
    "label": "Servicio interno de concesión de cookies",
    "failureHeader": "Ups!",
    "failureDescription": "Llamar a Bob a la ext. 1234 para reiniciar el servidor de cookies",
    "service": {
      // Servicio de token de acceso ...
    }
  }
}

2.1.6. Patrón de Interacción External

En el patrón de interacción External, el usuario debe haber adquirido la cookie de acceso por medios externos. Si la cookie de acceso no está presente, el usuario recibe mensajes de fallo. La interacción tiene los pasos siguientes:

  • No hay intervención del usuario antes de abrir la URI del servicio de token de acceso; por tanto, las propiedades label, header, description y confirmLabel se ignoran, de estar presentes.
  • No hay servicio de cookie de acceso. Cualquier URI especificada en la propiedad @id se debe ignorar.
  • El cliente debe usar inmediatamente el servicio de token de acceso relacionado, como describimos más adelante.

Los clientes no dirigidos por el usuario usan el servicio de token de acceso relacionado, como describimos más adelante, con una cookie de acceso adquirida previamente.

Un ejemplo de descripción de servicio para el patrón de interacción External:

{
  // ...
  "service" : {
    "@context": "http://iiif.io/api/auth/1/context.json",
    "profile": "http://iiif.io/api/auth/1/external",
    "label": "Autenticación Externa Requerida",
    "failureHeader": "Material Restringido",
    "failureDescription": "Este material no es visible sin acuerdo previo",
    "service": {
      // Servicio de token de acceso ...
    }
  }
}

2.2. Servicio de Token de Acceso

El cliente usa este servicio para obtener un token de acceso que empleará al solicitar Recursos de Descripción. Una petición al servicio de token de acceso debe incluir cualquier cookie para el dominio de contenido adquirida en la interacción del usuario con el servicio de cookie de acceso correspondiente, para que el servidor pueda generar el token de acceso.

2.2.1. Descripción del Servicio

La descripción del servicio de cookie de acceso debe incluir una descripción de servicio de token de acceso obedeciendo el patrón siguiente:

{
  // Servicio de Cookie de Acceso
  "service" : {
    "@context": "http://iiif.io/api/auth/1/context.json",
    "@id": "https://authentication.example.org/login",
    "profile": "http://iiif.io/api/auth/1/login",
    "label": "Iniciar Sesión en la Institución Ejemplo",

    // Servicio de Token de Acceso
    "service": [
      {
        "@id": "https://authentication.example.org/token",
        "profile": "http://iiif.io/api/auth/1/token"
      }
    ]
  }
}

La propiedad @id del servicio de token de acceso debe estar presente, y su valor debe ser la URI donde el cliente puede obtener el token de acceso. La propiedad profile debe estar presente, y su valor debe ser http://iiif.io/api/auth/1/token para distinguirla de otros servicios. No es necesario repetir la propiedad @context incluída en la descripción de servicio de cookie de acceso correspondiente, y no hay otras propiedades para este servicio.

2.2.2. Respuesta JSON de Token de Acceso

Si la petición incluye una cookie válida que el servidor reconoce como generada por el servicio de cookie de acceso, la respuesta del servicio de token de acceso debe incluir un objeto JSON (no JSON-LD) con la siguiente estructura:

{
  "accessToken": "TOKEN_AQUÍ",
  "expiresIn": 3600
}

La propiedad accessToken es requerida, y su valor es el token de acceso para pasar en peticiones futuras. La propiedad expiresIn es opcional y, de estar presente, su valor es la cantidad de segundos hasta que el token de acceso deje de ser válido.

Una vez obtenido, el token de acceso debe ser pasado al servidor en toda petición futura de Recurso de Descripción añadiendo un header de petición Authorization, con el valor Bearer seguido de un espacio y el token de acceso, de esta manera:

Authorization: Bearer TOKEN_AQUÍ

Ese header de autorización se debiera añadir a toda petición de recursos del mismo dominio y subdominios, que referencien al servicio, con independencia de la API con la cual se interactúe. no debe ser enviado a otros dominios.

2.2.3. Interacción para Aplicaciones Cliente No Basadas en Navegador

La petición de token de acceso más simple procede de un cliente no basado en navegador que pueda enviar cookies entre dominios, donde las restricciones CORS no son aplicables. Esta URL:

https://authentication.example.org/token

Produciría la Petición HTTP:

GET /token HTTP/1.1
Cookie: <cookie-adquirida-durante-login>

La respuesta es el objeto JSON de token de acceso con tipo de medio application/json:

{
  "accessToken": "TOKEN_AQUÍ",
  "expiresIn": 3600
}

2.2.4. Interacción para Aplicaciones Cliente Basadas en Navegador

Si el cliente es una aplicación de JavaScript que se ejecuta en un navegador web, debe solicitar directamente el token de acceso y almacenar el resultado. El cliente no puede utilizar XMLHttpRequest porque no puede incluir la cookie de acceso en una petición entre dominios. En su lugar, el cliente debe abrir el servicio de token de acceso en un frame, usando un elemento iframe, y estar listo para recibir un mensaje publicado por script en ese frame mediante la API postMessage. Para provocar ese comportamiento, el cliente debe adjuntar los siguientes parámetros de consulta a la URI del servicio de token de acceso, y abrir la nueva URI en el frame.

Parámetro Descripción
messageId String que ordena al servidor responder con una página web en lugar de JSON, y permite al cliente hacer corresponder peticiones de servicio de token de acceso y mensajes recibidos. Si el cliente no necesita interactuar con múltiples servicios de token, puede asignar un valor ficticio al parámetro, por ejemplo, messageId=1.
origin String que contiene el origen de la página en la ventana, consistente de protocolo, nombre de host, y número de puerto opcional, como describe la especificación de la API postMessage.

Por ejemplo, un cliente instanciado por la página https://client.example.com/viewer/index.html solicitaría:

https://authentication.example.org/token?messageId=1&origin=https://client.example.com/

Ante una petición de servicio de token de acceso con el parámetro messageId, el servidor debe responder con una página web HTML, no JSON puro. La página web debe contener un script que envíe un mensaje a la página que se abre, mediante la API postMessage. El cuerpo del mensaje es el objeto JSON de token de acceso, con el valor suministrado de messageId como propiedad adicional (vea los ejemplos de la sección siguiente).

El servidor puede usar la información de origen para lógica de autorización adicional, aunque el usuario ya esté autenticado. Por ejemplo, el servidor puede confiar sólo en dominios específicos para acciones distintas de la simple lectura, como crear o eliminar recursos. Si el cliente envía un valor incorrecto, no recibe respuesta, pues la API postMessage no despacha el evento. El parámetro targetOrigin de la función postMessage() debe ser el origen provisto en la petición.

El frame no debiera ser mostrado al usuario. Es un mecanismo de mensajería entre dominios. El cliente debe registrar un listener de eventos para recibir el mensaje que la página del servicio de token en el frame enviará. El cliente puede reutilizar los mismos listener y frame para múltiples llamadas al servicio de token de acceso, o puede crear nuevos en cada invocación.

La implementación precisa varía pero debe incluir características equivalentes a los pasos siguientes.

Primero, el cliente debe registrar un listener de eventos para recibir mensajes de otros dominios:

window.addEventListener("message", receive_message);

function receive_message(event) {
    data = event.data;
    var token, error;
    if (data.hasOwnProperty('accessToken')) {
        token = data.accessToken;
    } else {
        // manejar las condiciones de error
    }
    // ...
}

Después, puede abrir el servicio de token de acceso en un frame:

document.getElementById('messageFrame').src =
  'https://authentication.example.org/token?messageId=1234&origin=https://client.example.com/';

La respuesta del servidor será una página web con tipo de medio text/html que puede enviar un mensaje al listener registrado:

<html>
<body>
<script>    
    window.parent.postMessage(
      {
        "messageId": "1234",
        "accessToken": "TOKEN_AQUÍ",
        "expiresIn": 3600
      },
      'https://client.example.com/'
    );    
</script>
</body>
</html>

2.2.5. Usando el Token de Acceso

El token de acceso es enviado en toda petición subsiguiente de Recurso de Descripción. Por ejemplo, una petición de información de imagen en la API de Imagen sería:

GET /iiif/identifier/info.json HTTP/1.1
Authorization: Bearer TOKEN_AQUÍ

2.2.6. Condiciones de Error del Token de Acceso

La respuesta del servicio de token de acceso puede ser un error. El error se debe suministrar como JSON cumpliendo el patrón siguiente. Para clientes basados en navegador que utilizan la API postMessage, el objeto de error se debe enviar al cliente mediante JavaScript, del mismo modo que se envía el token de acceso. Para peticiones directas, el cuerpo de la respuesta es JSON puro.

{
  "error": "TIPO_DE_ERROR_AQUÍ",
  "description": "..."
}

El valor de la propiedad error debe ser uno de los tipos de la tabla siguiente:

Tipo Descripción
invalidRequest El servicio no puede procesar la información enviada en el cuerpo de la petición.
missingCredentials La petición no tiene las credenciales requeridas.
invalidCredentials Las credenciales de la petición no son válidas para el servicio.
invalidOrigin La petición tiene un origen distinto al especificado en la petición del servicio de cookie de acceso, o un origen que el servidor rechaza por otros motivos.
unavailable La petición no se puede satisfacer por razones distintas a las anteriores, por ejemplo, mantenimiento programado.

La propiedad description es opcional, y puede contener información adicional legible por humanos sobre el error.

Al retornar JSON directamente, el servicio debe usar el código de estado HTTP apropiado en la respuesta para describir el error (por ejemplo, 400, 401, o 503). La respuesta de página web postMessage debe usar el código de estado HTTP 200 para asegurar que el cuerpo sea recibido correctamente por el cliente.

2.3. Servicio de Cierre de Sesión

En el caso del patrón de interacción Login, el cliente debe saber si el usuario puede cerrar sesión, y donde puede hacerlo. Por ejemplo, el usuario podría querer cerrar su sesión en un terminal público, o iniciar sesión nuevamente en una cuenta distinta.

2.3.1. Descripción del Servicio

Si el sistema de autenticación soporta el cierre de sesión intencional de los usuarios, debiera existir un servicio de cierre de sesión asociado al servicio de cookie de acceso, que cumpla el patrón siguiente:

{
  // ...
  "service" : {
    "@context": "http://iiif.io/api/auth/1/context.json",
    "@id": "https://authentication.example.org/login",
    "profile": "http://iiif.io/api/auth/1/login",
    "label": "Iniciar Sesión en la Institución Ejemplo",
    "service" : [
      {
        "@id": "https://authentication.example.org/token",
        "profile": "http://iiif.io/api/auth/1/token"
      },
      {
        "@id": "https://authentication.example.org/logout",
        "profile": "http://iiif.io/api/auth/1/logout",
        "label": "Cerrar Sesión en la Institución Ejemplo"
      }
    ]
  }
}

El valor de la propiedad profile debe ser http://iiif.io/api/auth/1/logout.

2.3.2. Interacción

El cliente debiera mostrar el resultado de una petición HTTP GET de la URI del servicio en una pestaña o ventana aparte, que incluya barra de URL. Al mismo tiempo, el cliente debiera descartar cualquier token de acceso que haya recibido del servicio correspondiente. El servidor debiera anular el estado de sesión iniciada del usuario cuando reciba esta petición, y eliminar la cookie de acceso.

2.4. Ejemplo de Recurso de Descripción con Servicios de Autenticación

El ejemplo siguiente es una respuesta completa de información de imagen, para una imagen de ejemplo, con todos los servicios de autenticación.

{
  "@context" : "http://iiif.io/api/image/2/context.json",
  "@id" : "https://www.example.org/images/image1",
  "protocol" : "http://iiif.io/api/image",
  "width" : 600,
  "height" : 400,
  "sizes" : [
    {"width" : 150, "height" : 100},
    {"width" : 600, "height" : 400}
  ],
  "profile" : [
    "http://iiif.io/api/image/2/level2.json",
    {
      "formats" : [ "gif", "pdf" ],
      "qualities" : [ "color", "gray" ],
      "supports" : [
          "canonicalLinkHeader", "rotationArbitrary"
      ]
    }
  ],
  "service" : {
    "@context": "http://iiif.io/api/auth/1/context.json",
    "@id": "https://authentication.example.org/login",
    "profile": "http://iiif.io/api/auth/1/login",
    "label": "Iniciar Sesión en la Institución Ejemplo",
    "service" : [
      {
        "@id": "https://authentication.example.org/token",
        "profile": "http://iiif.io/api/auth/1/token"
      },
      {
        "@id": "https://authentication.example.org/logout",
        "profile": "http://iiif.io/api/auth/1/logout",
        "label": "Cerrar Sesión en la Institución Ejemplo"
      }
    ]
  }
}

3. Interacción con Recursos de Acceso Controlado

Esta sección describe como los clientes usan los servicios anteriores al interactuar con Recursos de Contenido y Recursos de Descripción.

Esas interacciones dependen de que las peticiones de Recursos de Descripción retornen códigos de estado HTTP 200, 302, y 401 en diferentes circunstancias. Para códigos distintos de 302, el cuerpo de la respuesta debe ser un Recurso de Descripción válido porque el cliente necesita ver las descripciones del servicio de autenticación para seguir el flujo de trabajo apropiado. Una respuesta con código de estado 302 no será visible para scripts de clientes basados en navegador que interactúen mediante la API XMLHttpRequest. La respuesta reportada será la última en la cadena y, por tanto, no es necesario que el cuerpo de las respuestas de redirección sea la representación del Recurso de Descripción.

3.1. Acceso Todo o Nada

Si el servidor no soporta múltiples niveles de acceso a un Recurso de Contenido, y el usuario no está autorizado a acceder, el servidor debe retornar una respuesta con código de estado HTTP 401 (Unauthorized) para el Recurso de Descripción correspondiente.

Si el usuario está autorizado a acceder a un Recurso de Descripción, el cliente puede asumir que acceder a los Recursos de Contenido descritos está permitido también. Las peticiones de Recursos de Contenido dependen de la cookie de acceso para transmitir el estado de autorización.

3.2. Acceso por Niveles

Un servidor que soporte varios niveles de acceso, debe usar un identificador distinto para cada Recurso de Descripción y sus Recursos de Contenido correspondientes. Por ejemplo, para cada nivel debe haber documentos de información de imagen (/info.json) diferentes en URIs distintas. Al referenciar Recursos de Descripción con varios niveles de acceso, los sistemas debieran usar el identificador de la versión que el usuario autorizado identificado debiera ver. Por ejemplo, al referenciar un servicio de imagen desde un manifest, la referencia normal sería a la versión en calidad máxima de la imagen, no a una versión degradada.

Si un usuario solicita un Recurso de Descripción que no está autorizado a acceder, y existen niveles inferiores disponibles, el servidor debe enviar una respuesta de estado HTTP 302 (Found) para redirigir hacia el Recurso de Descripción de un nivel menor.

Si el usuario no está autorizado a acceder a un Recurso de Descripción, y no existen niveles menores, el servidor debe enviar una respuesta 401 (Unauthorized). El cliente debiera presentar información sobre los servicios Login y/o Clickthrough incluídos en el Recurso de Descripción para permitir la autenticación del usuario.

4. Flujo de Trabajo desde la Perspectiva del Cliente Navegador

Server Authentication Flow

1 Flujo de Trabajo de la Autenticación del Cliente

Los clientes basados en navegador seguirán este flujo de trabajo para acceder a recursos de acceso controlado:

  • El cliente solicita el Recurso de Descripción y verifica el código de estado de la respuesta.
  • Si la respuesta es 200,
    • El cliente comprueba que la propiedad @id de la respuesta es la URI solicitada.
    • De ser así, el cliente puede solicitar el Recurso de Contenido.
    • Si las URIs son distintas, el recurso es de un nivel diferente al solicitado. El estado 200 implica que el recurso puede ser usado y, por tanto, el cliente puede renderizar el recurso. Al mismo tiempo, el cliente busca servicios de autenticación en el JSON recibido.
  • Si la respuesta es 401,
    • El cliente no tiene acceso al Recurso de Contenido, y debe buscar servicios de autenticación en el JSON recibido.
  • Si la respuesta no es 200 ni 401, el cliente debe manejar otros códigos de estado HTTP

  • Al buscar servicios de autenticación, el cliente:
    • Busca un patrón de interacción External que no requiere interacción de usuario. Si está presente, abre el servicio de token de acceso para determinar si ya se obtuvo la cookie.
    • En otro caso, busca un patrón de interacción Kiosk que no requiere interacción de usuario. Si está presente, abre el servicio de cookie de acceso en una ventana aparte.
    • En otro caso, busca un patrón de interacción Clickthrough. Si está presente, renderiza la descripción del servicio y un botón de confirmación para obtener el click-through del usuario. Tras el clic del usuario en la confirmación, abre el servicio de cookie de acceso en una ventana aparte.
    • En otro caso, presenta los patrones de interacción Login disponibles, y pide al usuario iniciar sesión con uno de ellos. Tras la selección, por parte del usuario, del ámbito para iniciar sesión, que asume el papel del servicio de cookie de acceso, abre la interfaz de usuario del ámbito en una ventana aparte.
    • Tras el cierre, automático o manual, de la ventana del servicio de cookie de acceso, el cliente abre el servicio de token de acceso.
  • Tras pedir el servicio de token de acceso, si el cliente recibe un token, intenta leer el Recurso de Descripción con las nuevas credenciales adquiridas.
    • En cambio, si recibe un error, el cliente busca otros servicios de autenticación para interactuar.
    • Si no quedan servicios de autenticación, las credenciales del usuario no permiten interactuar con ninguna versión del Recurso de Contenido, y el cliente no puede mostrar nada.

Por favor, note que la implementación de servidor incluye proporcionar respuestas de estado 302 para redirigir al cliente desde el nivel solicitado a otro nivel mientras el usuario no esté autorizado a ver el recurso. El cliente basado en navegador no ve esas respuestas y, por tanto, no revisa el código de estado HTTP retornado; sólo verifica si el identificador del recurso es igual al solicitado.

Apéndices

A. Notas de Implementación

Se ofrecen orientaciones para los implementadores en el documento Notas de Implementación. Esas notas contienen muchos detalles relacionados a la implementación de esta especificación en aplicaciones de JavaScript basadas en navegadores, y consideraciones adicionales sobre seguridad.

B. Control de Versiones

A partir de la versión 0.9.0, esta especificación sigue Semantic Versioning. Vea la nota Control de Versiones de APIs para los detalles de implementación.

C. Agradecimientos

La producción de este documento fue apoyada generosamente por una donación de la Fundación Andrew W. Mellon.

Muchas gracias a los miembros de la Comunidad IIIF por su continuo compromiso, ideas innovadoras, y retroalimentación.

D. Registro de Cambios

Fecha
Descripción
2017-01-19 Versión 1.0 (Alchemical Key)
2016-10-05 Versión 0.9.4 (Incrementing Integer) ampliar notas de seguridad
2016-08-22 Versión 0.9.3 (Wasabi KitKat) separar perfiles, eliminar servicio de identidad de cliente, añadir parámetros de consulta
(no publicada) Versión 0.9.2 (sin nombre) postMessage en lugar de JSONP
2015-10-30 Versión 0.9.1 (Table Flip) añadir @context faltante, aclaraciones
2015-07-28 Versión 0.9.0 (sin nombre) borrador