CyberLibrarian

【注意】 このドキュメントは、IIIFのIIIF Authentication: Version 1.0の和訳です。
このドキュメントの正式版はIIIFのサイト上にある英語版であり、このドキュメントには翻訳に起因する誤りがありえます。誤訳、誤植などのご指摘は、訳者までお願い致します。

First Update: 2017年1月26日

IIIF認証API 1.0

このドキュメントのステータス

本バージョン: 1.0.0

最新安定版: 1.0.0

旧バージョン: 0.9.4

編集者:

Copyright © 2012-2017 Editors and contributors. Published by the IIIF Consortium under the CC-BY license, see disclaimer.


目次

1. はじめに

IIIF(「トリプル・アイ・エフ」と発音)仕様は、世界中で提供されている資源に対する統一的で豊かなアクセスをサポートするように設計されています。コンテンツへのオープン・アクセスが望ましいですが、内部の方針、法的規制、ビジネス・モデル、その他の制約により、一部の資源とインタラクションを行うために、認証を行って権限を得ることをユーザに要求することができます。認証プロセスは、IPアドレスやクリック・スルー合意によるシンプルな制限から、安全なIDプロバイダーを用いた多要素スキームにまで及ぶ可能性があります。

自身の資源に対するアクセスを制限する必要があるコンテンツ・プロバイダーは、単純な全か無か(all-or-nothing)の区別にとどまらず、代替バージョンへの多層型アクセスを提供できます。これらの代替バージョンは、解像度、透かし、圧縮などに基づいて品質が落とされている可能性がありますが、全くアクセスできないよりもましなことが多いです。

ウェブ・ブラウザで動作するクライアント・アプリケーションによる制限されたコンテンツへの相互運用可能なアクセスの提供には、より多くの課題があります。

  • 1つのIIIFプレゼンテーションAPIマニフェストは、複数の組織、したがって、複数ドメインのコンテンツ資源を参照できます。
  • ウェブ・キャッシュにより誤ったバージョンが提供されることを防止するために、資源の個々のバージョンには別個のURIがなければなりません。
  • 組織は様々な既存のアクセス制御システムを持っています。
  • ほとんどのIIIFビューアはクライアント・サイドJavaScriptアプリケーションであり、読み込む必要がある画像サービスとは異なるドメインから提供され、したがって信頼できない可能性があります。
  • 同様に、認証サービスのドメインは、ビューアやIIIFベースのコンテンツのドメインとは異なる可能性もあります。したがって、承認サーバーは、ビューアを提供しているドメインに関する予備知識を要求してはなりません。

さらに、IIIFコミュニティーは、この仕様に関し、下記の目標を持っています。

  • IIIFクライアントはユーザ自身を認証すべきではありません。コンテンツを提供するサーバーは、ユーザからの証明情報の取得に責任を持たなければならず、IIIFビューアにはそのやり取りに関する知識やそれに対するアクセスは必要ではありません。
  • ブラウザ・ベースのIIIFクライアントは、認証フロー中に自身の内部状態を維持できなければなりません。
  • 信頼できるドメインの登録を必須とすべきではありません。誰でもがあらゆる種類のビューアを作成でき、どこからでもそれを実行可能であるべきです。
  • 組織は既存の認証システムを変更なく使用できるべきです。

これらの課題と目標を満たすために、IIIF認証仕様は、ユーザに既存のアクセス制御システムを案内するためのワークフローを記述しています。ユーザ認証のプロセスはほとんどこの仕様の範囲外であり、それにはCASサーバー、またはOAuth2プロバイダー、または特注のログイン・システムとの往復が伴う可能性があります。その意味で、IIIF認証はCASのようなプロトコルとは同じではありません。これは、任意のサード・パーティーのプロトコルとインタラクションを行うためのパターンの1つです。

IIIF認証は、OAuth2ワークフローの要素に倣って作られており、ログイン用のユーザ・インタフェースへのリンク、および、証明情報を提供するサービスを提供します。これらは共に、サーバーで使用中のアクセス制御システムとの橋渡しの役割を努め、クライアントがそのシステムの知識を必要とすることはありません。

要約すると、この仕様では、下記を行う方法を記述しています。

  • ユーザが制限されたコンテンツを閲覧するために必要な証明情報を取得できるように、ビューア内からアクセス制御システムとのインタラクションを開始する。
  • 優れたユーザ体験を確保するために、クライアントにコンテンツ・プロバイダーに関するユーザの状態に関する最低限の知識を与える。

iiif-discuss@googlegroups.comにフィードバックを送信してください。

1.1. 用語

この仕様では、画像や動画などのコンテンツ資源と、画像APIの画像情報(info.json)およびプレゼンテーションAPIのコレクションやマニフェスト資源などのIIIF仕様に準拠した記述資源とを区別します。ブラウザ・ベースのアプリケーションから見れば、コンテンツ資源はHTML要素のブラウザの解釈によって間接的に読み込まれますが、記述資源は一般的に、XMLHttpRequestインタフェースを用いてJavaScriptによって直接読み込まれます。最近のブラウザに実装されているCross Origin Resource Sharing(CORS)の仕様には、これらの2種類の資源とのインタラクションに適用する異なるセキュリティ規則が記述されています。

アクセス・クッキーおよびアクセス・トークンという2つの追加の概念については、下記で説明しています。

このドキュメントの「しなければならない(must)」、「してはならない(must not)」、「必須である/要求される(required)」、「することになる(shall)」、「することはない(shall not)」、「すべきである/する必要がある(should)」、「すべきでない/する必要がない(should not)」、「推奨される(recommended)」、「することができる/してもよい(may)」、「選択できる/任意である(optional)」というキーワードは、RFC 2119で記述されているように解釈されるべきです。

1.2. コンテンツ資源に対する認証

一般的に、画像などのコンテンツ資源はウェブ・ページやアプリケーションに埋め込まれている二次資源です。ウェブ・ページの場合、画像はHTMLimgタグで記述されており、ブラウザによる追加のHTTPリクエストで検索が行われます。ユーザが、ウェブ・ページを読み込む権限を持っていない時には、サーバーはユーザを別のページにリダイレクトし、認証の機会を提供できます。埋め込まれたコンテンツ資源の場合はこのリダイレクションを行うことはできず、壊れた画像アイコンがユーザに表示されるだけです。画像がアクセス制御されている場合は、ブラウザは、画像へのアクセスを許可する証明情報としてサーバーが受け入れることができるクッキーを送信することで、壊れた画像を避けなければなりません。この仕様では、ユーザがこのアクセス・クッキーを取得するプロセスを記述しています。

1.3. 記述資源に対する認証

プレゼンテーションAPIのマニフェストや画像APIの情報ドキュメント(info.json)などの記述資源は、ブラウザにコンテンツ資源をリクエストさせるために必要な情報をクライアント・アプリケーションに提供します。記述資源は、それが記述しているコンテンツ資源と同じドメインになければなりませんが、実行するクライアント・コードもこのドメインで提供されている必要はありません。

1つのドメインから読み出されたJavaScriptを実行するブラウザは、クライアントは信頼できない場合にも機能しなければならないという上記で紹介した要件に違反することなく、XMLHttpRequestを用いて、別のドメインから記述資源を読み込み、そのドメインのクッキーをリクエストに含めることはできません。代わりに、クライアントは、アクセス・トークン(技術的には、署名無しトークン(bearer token)の一種)をアクセス・クッキーに対するプロキシとして送信します。この仕様は、ブラウザがコンテンツ資源に対するアクセス・クッキーを取得した時に、クライアントが記述資源に直接的なリクエストを行う時に用いるアクセス・トークンを取得する方法を説明しています。

資源ドメイン上のサーバーは、アクセス・トークンを、コンテンツ資源へのアクセスを得るクッキーの表現、または、それに対するプロキシとして扱います。クライアントが記述資源にリクエストを行い、アクセス・トークンを提供すると、応答は、ブラウザが、アクセス・トークンが示すアクセス・クッキーを持つ当該コンテンツ資源をリクエストすると何が起こるかをクライアントに伝えます。この応答に基づき、クライアントは、どのユーザ・インタフェースおよび/またはコンテンツ資源をユーザに表示するのかを決定します。

1.4. セキュリティ

この仕様の目的は、IIIF資源に対するアクセス制御をサポートすることであり、そのため、セキュリティは核となる関心事です。悪用を防止するために、この仕様で説明しているクッキーと署名無しトークンは、保管および転送において漏洩から守られる必要があります。実装には、すべての通信に関して、(一般的にHTTPSとして知られている)TLSよりもHTTPを用いるべきです(should)。さらに、アクセス制御された資源とインタラクションを行うすべてのIIIFクライアントは、HTTPSで提供されるページから実行されるべきです(should)。HTTPSの使用を想定する場合は、この仕様のHTTPに関するすべての参考文献を読むべきです。

この仕様は、記述資源をリクエストする際に利用するために、アクセス・トークン値をクライアント・アプリケーションのスクリプトに利用できるようにすることにより、画像などのコンテンツ資源を保護します。アクセス・トークンに関する知識は、悪意のあるクライアントには意味がありません。なぜなら、アクセス・クッキー(クライアントは見ることができない)がコンテンツ資源に認められている唯一の証明書であり、記述資源自身には価値がないからです。しかし、この仕様で紹介しているインタラクション・パターンは、将来のバージョンでは、例えば、アノテーション・サーバーでアノテーションを作成したり、マニフェストのstructures要素を修正するなど、IIIF資源の操作を記述するように拡張されるでしょう。この種類の操作のために、アクセス・トークンは証明書であり、下記で紹介する流れには、クライアントとサーバーの間の信頼を確立するために、1つ以上の追加のステップが必要かもしれません。しかし、これらの変更にはバージョン1.0との下位互換性があることが予期されます。

セキュリティに関する留意点の詳細な議論が実装ノートにありえます。

2. 認証サービス

認証サービスは、IIIF外部サービスへのリンクという注に記述されているパターンに従い、1つ以上のserviceブロックで、保護されている資源の記述から参照されます。ユーザ認証には主要なログイン・サービス・プロファイルが存在しており、その記述内には、関連するサービスが入れ子の形で記述されています。その関連するサービスには、必須のアクセス・トークン・サービスと、オプションのログアウト・サービスが含まれています。

クライアントは、画像などのコンテンツおよびアクセス・トークン・サービスとインタラクションを行う時に用いるクッキーを取得するために、このサービスを用います。クライアントがこのサービスを用いる時のインタラクションには、ユーザに表示しなければならないユーザ・インタフェースによって、いくつかの異なるパターンがあり、それはプロファイルURIで示されます。クライアントは、保護されている資源の記述内のサービス・ブロックからアクセス・クッキー・サービスへのリンクを取得します。

アクセス・クッキー・サービスの目的は、後でクライアントがコンテンツ・サーバーに画像をリクエストする時にそのリクエストが成功するように、ユーザがコンテンツ・サーバーとインタラクションを行っている間にクッキーを設定することです。クライアントは、ログイン・サービスで何が起こるのかの知識を持っておらず、ユーザがログイン・サービスとインタラクションを行っている間にコンテンツ・ドメインに設定されているクッキーを見ることができません。ブラウザは1回以上リダイレクトを行うことができますが、それはクライアント・アプリケーションには見えません。開いているタブの最後の応答には、ワークフロー上の次のステップのきっかけになるように、タブを閉じるためのJavaScriptが含まれているべきです(should)。

2.1.1. サービス記述

クライアントが、アクセス・クッキーを取得できるインタラクションには4つのパターンがあり、それぞれにプロファイルURIで識別されます。これらのパターンについては、以下の項でより詳細に説明しています。

パターン プロファイルURI 説明
Login http://iiif.io/api/auth/1/login ユーザは、外部認証システムが提供するUIで別ウィンドウを用いてログインすることを要求されます。
Clickthrough http://iiif.io/api/auth/1/clickthrough ユーザは、サービス記述で提供されているコンテンツを用いてクライアント内のボタンをクリックすることを要求されます。
Kiosk http://iiif.io/api/auth/1/kiosk ユーザは、認証システムとインタラクションを行うことを要求されず、クライアントはアクセス・クッキー・サービスを自動的に用いることが期待されます。
External http://iiif.io/api/auth/1/external ユーザが既に適切なクッキーを取得していることが期待され、アクセス・クッキー・サービスは全く用いられないでしょう。

サービス記述は記述資源に含まれており、以下のプロパティーを持っています。

プロパティー 必須? 説明
@context 必須 IIIF認証APIが記述されているコンテキスト・ドキュメント。値はhttp://iiif.io/api/auth/1/context.jsonでなければなりません(must)。
@id 説明を参照 これは、アクセス・クッキーを取得するためにクライアントがURIを開く、Login、Clickthrough、Kioskのパターンでは必須です(required)。ユーザが他の手段でクッキーを取得していることが期待され、提供される値が無視されるため、Externalのパターンではオプションです(optional)。
profile 必須 サービスのプロファイルは、上記の表のプロファイルURIのうちの1つでなければなりません(must)。
label 必須 必須のサービスが複数存在している場合に、認証サービスの読み込みを開始するためにユーザに示されるテキスト。値には、ユーザが認証を行っているドメインまたは組織が含まれていなければなりません(must)。
confirmLabel 推奨 アクセス・クッキー・サービスを開くきっかけとなるボタンや要素上でユーザに表示されるテキスト。存在していない場合は、必要に応じて、インタラクション・パターンに適したテキストをクライアントが提供します。
header 推奨 存在している場合は記述のヘッダーとして、記述がない場合には単体で、ユーザに表示されなければならない(must)短いテキスト。
description 推奨 存在している場合は、アクセス・クッキー・サービスを開く前にユーザに表示しなければならない(must)テキスト。
failureHeader オプション 存在している場合は、トークンの受信に失敗した後、または、トークンの使用によりエラーが生じた後に、ヘッダーとしてユーザに表示できる(may)短いテキスト。
failureDescription オプション 存在している場合は、トークンの受信に失敗した後、または、トークンの使用によりエラーが生じた後に、ユーザに表示できる(may)テキスト。
service 必須 下記で説明している、アクセス・トークンやその他の関連するサービスに対する参照。

インタラクション・パターンに関わらず、クライアントは、アクセス・クッキー・サービスのURIに対するすべてのリクエストに下記のクエリ・パラメータを追加し、新しいウィンドウまたはタブでこのURIを開かなければなりません(must)。

パラメータ 説明
origin postMessage API仕様で記述されているとおり、プロトコル、ホスト名およびオプションのポート番号で構成されている、ウィンドウ内のページのオリジン(origin)が含まれている文字列。

例えば、https://authentication.example.org/loginというアクセス・クッキー・サービスのURIが与えられた場合、https://client.example.com/viewer/index.htmlというページでインスタンス化されるクライアントは、下記に対してリクエストを行うでしょう。

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

サーバーは、アクセス・トークン・サービスに対するその後のリクエストで提供されるオリジンを検証するために(例えば、返されるクッキーにおいてそれをエンコードすることにより)この情報を使用できます(may)。

2.1.3. Loginインタラクション・パターン

クライアントにユーザのログインを促させるためには、コンテンツ・プロバイダーのユーザ・インタフェースの一部を表示しなければなりません。Loginインタラクション・パターンでは、@idプロパティーという値がそのユーザ・インタフェースのURIです。

このインタラクションには、次のステップがあります。

  • headerおよび/またはdescriptionのプロパティーが存在していれば、プロバイダーの認証インタフェースを開く前に、クライアントは、プロパティーの値をユーザに表示すべきです(should)。このプロパティーは、confirmLabelを持つ要素をクリックしたらどうなるのかを表わします。
  • confirmLabel要素が有効になった時には、クライアントは、付加されたoriginクエリ・パラメータを持つ@idのURIを開かなければなりません(must)。これは、偽装攻撃の防止に役立つように、新しいウィンドウまたはタブで実行されなければなりません(must)。ブラウザのセキュリティ規定のため、クライアントは、新しいタブで何が起こっているかを知ることができず、したがって、クライアントは開いているタブが閉じられるのを待ち、それを検出するだけしかできません。
  • 下記で説明しているように、クライアントは、開いているタブが閉じられた後に、関連するアクセス・トークン・サービスを用いなければなりません(must)。

異分野の(out-of-band)知識により、権限取得済みの非ユーザ主導型クライアントは、POSTを用いて、事前認証されたユーザの情報をサービスに送信できます(may)。必須の情報は認証ロジックによって異なるため、このAPIでは詳細は規定していません。

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": "Login to Example Institution",
    "header": "Please Log In",
    "description": "Example Institution requires that you log in with your example account to view this content.",
    "confirmLabel": "Login",
    "failureHeader": "Authentication Failed",
    "failureDescription": "<a href=\"http://example.org/policy\">Access Policy</a>",
    "service": [
      // Access token and Logout services ...
    ]
  }
}

2.1.4. Clickthroughインタラクション・パターン

Clickthroughインタラクション・パターンでは、@idプロパティーの値は、アクセス・クッキーを設定した直後にユーザ・インタラクションなしにそのウィンドウやタブを閉じなければならない(must)サービスのURIです。このインタラクションには、次のステップがあります。

  • headerおよび/またはdescriptionのプロパティーが存在していれば、サービスを開く前に、クライアントは、プロパティーの値をユーザに表示しなければなりません(must)。このプロパティーは、confirmLabelを持つ要素のクリックにより暗示される承諾を記述します。
  • confirmLabel要素が有効になった時には、クライアントは、付加されたoriginクエリ・パラメータを持つ@idのURIを開かなければなりません(must)。これは新しいウィンドウまたはタブで実行されるべきです(should)。ブラウザのセキュリティ規定のため、クライアントは、新しいタブで何が起こっているかを知ることができず、したがって、クライアントは開いているウィンドウやタブやiframeが閉じられるのを待ち、それを検出するだけしかできません。
  • 下記で説明しているように、クライアントは、開いているタブが閉じられた後に、関連するアクセス・トークン・サービスを用いなければなりません(must)。

非ユーザ主導型クライアントは、Clickthroughインタラクション・パターンのアクセス・クッキー・サービスを用いてはならず、代わりに停止しなければなりません(must)。

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": "Terms of Use for Example Institution",
    "header": "Restricted Material with Terms of Use",
    "description": "<span>... terms of use ... </span>",
    "confirmLabel": "I Agree",
    "failureHeader": "Terms of Use Not Accepted",
    "failureDescription": "You must accept the terms of use to see the content.",
    "service": {
      // Access token service ...
    }
  }
}

2.1.5. Kioskインタラクション・パターン

Kioskインタラクション・パターンでは、@idプロパティーの値は、アクセス・クッキーを設定した直後にユーザ・インタラクションなしにそのウィンドウやタブを閉じなければならない(must)サービスのURIです。このインタラクションには、次のステップがあります。

  • アクセス・クッキー・サービスのURIを開く前にユーザ・インタラクションはなく、したがって、labelheaderdescription、およびconfirmLabelプロパティーが存在していれば、いずれも無視されます。
  • クライアントは、付加されたoriginクエリ・パラメータを持つ@idのURIを直ちに開かなければなりません(must)。これは新しいウィンドウまたはタブで実行されるべきです(should)。ブラウザのセキュリティ規定のため、クライアントは、新しいタブで何が起こっているかを知ることができず、したがって、クライアントは開いているウィンドウやタブやフレームが閉じられるのを待ち、それを検出するだけしかできません。
  • 下記で説明しているように、クライアントは、開いているタブが閉じられた後に、関連するアクセス・トークン・サービスを用いなければなりません(must)。

下記で説明しているように、非ユーザ主導型クライアントは、@idのURIにシンプルにアクセスしてアクセス・クッキーを取得し、その後で、関連するアクセス・トークン・サービスを用います。

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": "Internal cookie granting service",
    "failureHeader": "Ooops!",
    "failureDescription": "Call Bob at ext. 1234 to reboot the cookie server",
    "service": {
      // Access token service ...
    }
  }
}

2.1.6. Externalインタラクション・パターン

Externalインタラクション・パターンでは、ユーザは、帯域外(out of band)の方法でアクセス・クッキーを取得している必要があります。アクセス・クッキーがなければ、ユーザは失敗のメッセージを受け取るでしょう。このインタラクションには、次のステップがあります。

  • アクセス・トークン・サービスのURIを開く前にユーザ・インタラクションはなく、したがって、labelheaderdescriptionおよびconfirmLabelプロパティーが存在している場合は、いずれも無視されます。
  • アクセス・クッキー・サービスはありません。@idプロパティーで指定されているあらゆるURIは無視されなければなりません(must)。
  • 下記で説明しているように、クライアントは、直ちに関連するアクセス・トークン・サービスを用いなければなりません(must)。

下記で説明しているように、非ユーザ主導型クライアントは、シンプルに、予め取得したアクセス・クッキーで関連するアクセス・トークン・サービスを用います。

Externalインタラクション・パターンのサービス記述の例は次のとおりです。

{
  // ...
  "service" : {
    "@context": "http://iiif.io/api/auth/1/context.json",
    "profile": "http://iiif.io/api/auth/1/external",
    "label": "External Authentication Required",
    "failureHeader": "Restricted Material",
    "failureDescription": "This material is not viewable without prior agreement",
    "service": {
      // Access token service ...
    }
  }
}

2.2. アクセス・トークン・サービス

クライアントは、後で記述資源をリクエストする時に用いるアクセス・トークンを取得するために、このサービスを用います。サーバーがアクセス・トークンを発行できるように、アクセス・トークン・サービスに対するリクエストには、対応するアクセス・クッキー・サービスとのユーザのインタラクションにより取得したコンテンツ・ドメインのクッキーが含まれていなければなりません。

2.2.1. サービス記述

アクセス・クッキー・サービスの記述には、下記のテンプレートに従ったアクセス・トークン・サービスの記述が含まれていなければなりません(must)。

{
  // Access Cookie Service
  "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": "Login to Example Institution",

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

アクセス・トークン・サービスの@idプロパティーが存在していなければならず(must)、その値は、クライアントがアクセス・トークンを取得できるURIでなければなりません(must)。profileプロパティーが存在していなければならず(must)、その値は、それを他のサービスと区別するために、http://iiif.io/api/auth/1/tokenでなければなりません(must)。アクセス・クッキー・サービスの記述の囲み込みに含まれている@contextプロパティーを繰り返す要件はなく、このサービスには他のプロパティーはありません。

2.2.2. JSONアクセス・トークン応答

アクセス・クッキー・サービスによって発行されたとサーバーが認識する有効なクッキーがリクエストにあれば、アクセス・トークン・サービス応答に下記の構造を持つJSON(JSON-LDではない)オブジェクトが含まれていなければなりません(must)。

{
  "accessToken": "TOKEN_HERE",
  "expiresIn": 3600
}

accessTokenプロパティーは必須であり(required)、その値はその後のリクエストで返されるアクセス・トークンです。expiresInプロパティーはオプションであり(optional)、それが存在している場合は、その値はアクセス・トークンが有効でなくなるまでの秒数です。

アクセス・トークンは、いったん取得すれば、下記のようなBearerの後に空白とアクセス・トークンが続く値でAuthorizationリクエスト・ヘッダーを追加し、記述資源に対するその後のすべてのリクエストでサーバーに返されなければなりません(must)。

Authorization: Bearer TOKEN_HERE

この認証ヘッダーは、どのAPIとインタラクションが行われているかに関わらず、サービスへの参照を持つ同じドメインとサブドメインの資源に対するすべてのリクエストに追加されるべきです(should)。それをその他のドメインに送信してはなりません(must not)。

2.2.3. 非ブラウザ・クライアント・アプリケーションに対するインタラクション

最も簡単なアクセス・トークン・リクエストは、CORS制限があてはまらない場合に、ドメインにクッキーを送信できる非ブラウザ・クライアントによるものです。次のURLの例は、

https://authentication.example.org/token

下記のHTTPリクエストになるでしょう。

GET /token HTTP/1.1
Cookie: <cookie-acquired-during-login>

応答は、application/jsonというメディア・タイプを持つJSONアクセス・トークン・オブジェクトです。

{
  "accessToken": "TOKEN_HERE",
  "expiresIn": 3600
}

2.2.4. ブラウザベース・クライアント・アプリケーションに対するインタラクション

クライアントがウェブ・ブラウザで動作するJavaScriptアプリケーションであれば、アクセス・トークンに直接リクエストを行い、結果を蓄積する必要があります。XMLHttpRequestは、アクセス・クッキーをクロスドメイン・リクエストに含めることができないため、クライアントは使用できません。その代わりに、クライアントは、iframe要素を用いてフレーム内のアクセス・トークン・サービスを開き、postMessage APIを用いてそのフレーム内のスクリプトによってポストされたメッセージを受け取る準備ができていなければなりません(must)。この挙動を引き起こすために、クライアントは、下記のクエリ・パラメータをアクセス・トークン・サービスのURIに付け加え、フレーム内でこの新しいURIを開かなければなりません(must)。

パラメータ 説明
messageId JSONではなくウェブ・ページでの応答をサーバーに促すとともに、アクセス・トークン・サービスのリクエストと受け取ったメッセージとのマッチングをクライアントができるようにする文字列。クライアントが複数のトークン・サービスとインタラクションを行う必要がなければ、パラメータにmessageId=1などのダミーの値を使用できます。
origin postMessage API仕様で記述されているとおり、プロトコル、ホスト名およびオプションのポート番号で構成されている、ウィンドウ内のページのオリジン(origin)が含まれている文字列。

例えば、https://client.example.com/viewer/index.htmlというページでインスタンス化されるクライアントは、つぎのとおりリクエストを行うでしょう。

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

サーバーがmessageIdパラメータを持つアクセス・トークン・サービスに対するリクエストを受け取った時には、生のJSONではなく、HTMLのウェブ・ページで応答しなければなりません(must)。このウェブ・ページには、postMessage APIを用いて開くページにメッセージを送信するスクリプトが含まれていなければなりません(must)。次の項の例で示しているとおり、メッセージの本文は追加のプロパティーとして提供されたmessageIdの値を持つJSONアクセス・トークン・オブジェクトです。

既にユーザが認証されていても、サーバーはその先の認証ロジックにオリジン情報を使用できます(may)。例えば、サーバーは、単に資源を読むだけでなく、資源の作成や削除を行うような動きに関して、特定のドメインのみを信頼することができます。クライアントが間違った値を送信した場合は、postMessage APIはそのイベントを送信しないため、ポストされた応答を受け取らないでしょう。postMessage()関数呼び出しのtargetOriginパラメータは、リクエストで提供されるオリジンでなければなりません(must)。

フレームはユーザに表示されるべきではありません(should not)。これはクロスドメイン・メッセージングのためのメカニズムです。クライアントは、フレーム内のトークン・サービス・ページが送信するメッセージを受け取るために、イベント・リスナーを登録しなければなりません(must)。クライアントは、アクセス・トークン・サービスに対する複数の呼び出しのために、同じリスナーとフレームを再利用するか、呼出しごとに新たに作成することができます。

厳密な実装は多様でありえますが、下記のステップと同等の機能が含まれていなければなりません(must)。

最初に、クライアントは、クロスドメイン・メッセージを受け取るために、イベント・リスナーを登録しなければなりません。

window.addEventListener("message", receive_message);

function receive_message(event) {
    data = event.data;
    var token, error;
    if (data.hasOwnProperty('accessToken')) {
        token = data.accessToken;
    } else {
        // handle error condition
    }
    // ...
}

次に、フレーム内でアクセス・トークン・サービスを開くことができます。

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

次に、サーバー応答は、登録されたリスナーにメッセージをポストできるtext/htmlというメディア・タイプを持つウェブ・ページになるでしょう。

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

2.2.5. アクセス・トークンの使用

アクセス・トークンは、記述資源に対するその後のすべてのリクエストで送信されます。例えば、画像APIの画像情報に対するリクエストは次のようになるでしょう。

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

2.2.6. アクセス・トークン・エラー条件

アクセス・トークン・サービスからの応答はエラーでありえます。エラーは下記のテンプレートを用いたJSONとして提供されなければなりません(must)。postMessage APIを用いたブラウザ・ベースのクライアントの場合、エラー・オブジェクトは、アクセス・トークンが送信されるのと同じ方法で、JavaScriptでクライアントに送信されなければなりません。直接的なリクエストの場合、応答の本文は生のJSONです。

{
  "error": "ERROR_TYPE_HERE",
  "description": "..."
}

errorプロパティーの値は、下記表のタイプのうちの1つでなければなりません(must)。

タイプ 説明
invalidRequest サービスはリクエストの本文で送信された情報を処理できなかった。
missingCredentials リクエストは必要な証明情報を持っていなかった。
invalidCredentials リクエストはサービスに有効ではない証明情報を持っていた。
invalidOrigin リクエストは、アクセス・クッキー・サービスのリクエストで指定されているものとは異なるオリジンのものか、その他の理由でサーバーが拒絶するオリジンのものである。
unavailable 定期保守などの上記以外の理由で、リクエストを実行できなかった。

descriptionプロパティーはオプションであり(optional)、エラーに関する人間が読める補足情報を提供できます。

JSONを直接返す時には、サービスは、応答に適したHTTPステータス・コードを用いてエラーを表わさなければなりません(例えば、400、401または503)。postMessageウェブ・ページ応答は、本文がクライアントに正しく受け取られていることを保証するために、200のHTTPステータス・コードを用いなければなりません(must)。

2.3. ログアウト・サービス

Loginインタラクション・パターンの場合、クライアントは、ユーザがログアウトできるのか、また、どこでログアウトを行えるのかを知っている必要があります。例えば、ユーザは、公衆端末では自身のセッションを閉じたり、別のアカウントで再ログインすることを望むかもしれません。

2.3.1. サービス記述

認証システムが、ユーザの意思によるログアウトをサポートする場合は、下記のテンプレートに従ったアクセス・クッキー・サービスと関連付けられたログアウト・サービスが存在すべきです(should)。

{
  // ...
  "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": "Login to Example Institution",
    "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": "Logout from Example Institution"
      }
    ]
  }
}

profileプロパティーの値はhttp://iiif.io/api/auth/1/logoutでなければなりません(must)。

2.3.2. インタラクション

クライアントは、サービスのURIにおいて、URLバーを持つ別のタブまたはウィンドウ内でHTTP GETリクエストの結果を表示すべきです(should)。同時に、クライアントは、対応するサービスから受け取ったアクセス・トークンを捨てるべきです(should)。このリクエストが行われた時に、サーバーはユーザのログイン・ステータスをリセットし、アクセス・クッキーを削除すべきです(should)。

2.4. 認証サービスを用いた記述資源の例

下の例は、すべての認証サービスを用いた画像の例に対する完全な画像情報応答です。

{
  "@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": "Login to Example Institution",
    "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": "Logout from Example Institution"
      }
    ]
  }
}

3. アクセス制御された資源とのインタラクション

この項では、クライアントが、コンテンツ資源および記述資源とインタラクションを行う際に上記サービスをどのように用いるかを説明しています。

このインタラクションは、様々な状況で200302および401HTTPステータス・コードを返す記述資源に対するリクエストに依存しています。302以外の場合には、応答の本文は有効な記述資源でなければなりません(must)。なぜなら、クライアントは、適切なワークフローに従うために、認証サービスの記述を見る必要があるからです。302というステータス・コードの応答は、XMLHttpRequest APIでインタラクションを行っているブラウザ・ベースのクライアント・スクリプトでは決して表示されません。報告される応答は、一連の中の最後のものであり、リダイレクション応答の本文が記述資源の表現である必要はありません。

3.1. 全か無かのアクセス

サーバーがコンテンツ資源に対して多層型アクセスをサポートしておらず、ユーザがそれに対するアクセス権限を持っていない場合、サーバーは、対応する記述資源に対して401(許可なし)のHTTPステータス・コードで応答を返さなければなりません(must)。

ユーザが記述資源に対して権限を持っていれば、記述されているコンテンツ資源に対するリクエストも権限取得済みであるとクライアントは推測できるでしょう。コンテンツ資源に対するリクエストは、アクセス・クッキーに頼って認証状態を伝達します。

3.2. 多層型アクセス

サーバーが多層型アクセスをサポートしている場合、記述源およびその対応するコンテンツ資源ごとに異なる識別子を用いなければなりません(must)。例えば、層ごとに異なるURIに異なる画像情報ドキュメント(/info.json)がなければなりません(must)。多層型アクセスを有する記述資源を参照する場合、システムは、適正な権限を得たユーザが閲覧すべきバージョンの識別子を用いるべきです(should)。例えば、マニフェストから画像サービスを参照する場合は、その参照は通常、低品質版ではなく最高品質版の画像に対するものでしょう。

記述資源がリクエストされ、ユーザがそれに対するアクセス権限を持っておらず、より低い層が利用できる場合、サーバーは、より低い層の記述資源にリダイレクトするために、302(発見した)のHTTPステータス応答を発行しなければなりません(must)。

より低い層がなく、ユーザが現在の記述資源に対するアクセス権限を持っていない場合、サーバーは401(許可なし)の応答を発行しなければなりません(must)。クライアントは、ユーザが認証を試みることができるように、記述資源に含まれているLoginおよび/またはClickthroughサービスに関する情報を表示すべきです(should)。

4. ブラウザ・クライアントから見たワークフロー

サーバー認証フロー

1クライアント認証フロー

ブラウザ・ベースのクライアントは、アクセス制御された資源にアクセスするために、下記のワークフローを実行します。

  • クライアントが記述資源をリクエストし、応答のステータス・コードをチェックします。
  • 応答が200であれば、
    • クライアントは、応答の@idプロパティーが、リクエストされたURIと同じかどうかをチェックします。
    • 同じであれば、クライアントは、コンテンツ資源のリクエストへ進むことができます。
    • URIが違っていれば、資源はリクエストされたものとは違う層のものです。200ステータスは、資源が利用可能であることを示し、したがって、クライアントは資源を表示できます。同時に、クライアントは、受け取ったJSONの認証サービスをチェックします。
  • 応答が401であれば、
    • クライアントはコンテンツ資源にアクセスできず、したがって、クライアントは、受け取ったJSONの認証サービスをチェックします。
  • 応答が200でも401でもなければ、クライアントは他のHTTPステータス・コードを処理しなければなりません。

  • クライアントが認証サービスをチェックする際には、最初に認証サービスをチェックします。
    • 最初に、ユーザ・インタラクションが必要ではないという理由で、Externalインタラクション・パターンを捜します。存在していれば、既にクッキーが取得されているかを確認するために、アクセス・トークン・サービスを開きます。
    • 存在していなければ、ユーザ・インタラクションを伴わないという理由で、Kioskインタラクション・パターンをチェックします。存在していれば、別ウィンドウでアクセス・クッキー・サービスを開きます。
    • 存在していなければ、Clickthroughインタラクション・パターンをチェックします。存在していれば、サービスの記述と確認ボタンを表示し、ユーザがクリック・スルーを行うように促します。ユーザが確認をクリックすれば、別ウィンドウでアクセス・クッキー・サービスを開きます。
    • 存在していなければ、入手可能な何らかのLoginインタラクション・パターンを示し、ユーザがそのうちの1つを用いてログインするように促します。ユーザがログインする領域を選択した時には、それはアクセス・クッキー・サービスの役割を担い、別ウィンドウでその領域のユーザ・インタフェースを開きます。
    • 自動的またはユーザによってアクセス・クッキー・サービスのウィンドウが閉じられた時に、クライアントは、アクセス・トークン・サービスを開きます。
  • アクセス・トークン・サービスがリクエストされた後に、クライアントがトークンを受け取れば、新しく取得した証明情報で記述資源を再度読もうと試みます。
    • その代わりにクライアントがエラーを受け取った場合は、戻って、インタラクションを行う別の認証サービスを捜します。
    • それ以上の認証サービスがなければ、ユーザは、どのコンテンツ資源バージョンともインタラクションを行う証明情報を持っておらず、クライアントは何も表示できません。

ユーザが資源を閲覧する権限をまだ取得していない場合は、サーバーの実装には、リクエストされた層から別の層にクライアントをリダイレクトするために302のステータス応答を提供する必要があることに注意してください。ブラウザ・ベースのクライアントがこれらの応答を見ることはないため、HTTPステータス・コードではなく、資源の識別子がリクエストされたものと同じであるかどうかをテストします。

付録

A. 実装ノート

実装者に対する案内は別の実装ノート・ドキュメントで提供しています。このノートは、ブラウザ・ベースのJavaScriptアプリケーションにおけるこの仕様の実装、および追加のセキュリティに関する留意点に関連する多くの詳細をカバーしています。

B. バージョン付け

バージョン0.9.0から、この仕様はセマンティック バージョニングに従っています。実施方法の詳細については、APIのバージョン付けのノートを参照してください。

C. 謝辞

このドキュメントの作成に、アンドリューWメロン財団の助成による寛大な支援をいただきました。

継続的な関与、革新的なアイデア、およびフィードバックに関し、IIIFコミュニティーのメンバーに感謝申し上げます。

D. 更新履歴

日付 説明
2017-01-19 バージョン1.0 (Alchemical Key)
2016-10-05 バージョン0.9.4 (Incrementing Integer) セキュリティ・ノートに追加
2016-08-22 バージョン0.9.3 (Wasabi KitKat) プロファイルを分離、クライアントIDサービスを削除、クエリ・パラメータを追加
(未発表) バージョン0.9.2 (名称なし) JSONPではなくpostMessageに
2015-10-30 バージョン0.9.1 (Table Flip) 欠けていた@contextを追加、明確化
2015-07-28 バージョン0.9.0 (名称なし) 草案