はじめに
認可サーバー / OpenID プロバイダーの実装が『リクエストオブジェクト』を処理する手順について紹介します。
1. request, request_uri パラメーター
認可エンドポイントに対するリクエストのパラメーター群は、リクエストオブジェクトを介して指定されていることがあります。そのため、リクエストに request
リクエストパラメーターもしくは request_uri
リクエストパラメーターが含まれていれば、リクエストオブジェクトを取り出し、解析します。仕様は OpenID Connect Core 1.0 の「6. Passing Request Parameters as JWTs」で定義されています。
まず、request
パラメーターと request_uri
パラメーターが同時に指定されている場合はエラーとします。
request
パラメーターが指定されていた場合、そのパラメーターの値はリクエストオブジェクトそのものです。一方、request_uri
パラメーターが指定されていた場合、そのパラメーターの値はリクエストオブジェクトが置かれている場所を指す URI となっているので、サーバーはその場所にリクエストオブジェクトを取りに行きます。毎回取りに行くのはパフォーマンス上よろしくないので、HTTP の各種ヘッダーを調べて有効期間を計算して適宜キャッシュします。
なお、キャッシュを用いずに再フェッチを要求するためリクエスト URI のフラグメント部を用いることについて、OpenID Connect Core 1.0 の「6.2. Passing a Request Object by Reference」の第6段落で言及があります。
2. request_uri 事前登録
request_uri
に指定する URI の事前登録を求めるかどうかは、認可サーバーの実装に依存します。認可サーバーが OpenID Connect Discovery 1.0 をサポートしているなら、事前登録を要求するかどうかは require_request_uri_registration
の値を調べることで分かります。
なお、セキュリティー上の理由により Authlete の実装では必ず事前登録を要求するようにしています。未登録の request_uri
を許してしまうと、「実在しない、もしくは不正なリクエストオブジェクトを取りに行かせる」という攻撃をサーバーに対して簡単に実行できてしまうからです。
余談ですが、少し前までの OpenID Certification テストには、request_uri
を動的に生成してテストを実行している部分があり、request_uri
の事前登録を要求する Authlete では当該テストを実行できませんでした。そのため、事前登録要求をオン・オフするための設定項目を Authlete に追加しようと思ったのですが、『OAuth 2.0 In Action』の著者でもある Justin Richer 氏がセキュリティー上の理由によりそのアイディアに反対しました。かわりに彼は、当該テストを OpenID Certification テストから取り除くよう OpenID Foundation に依頼しました。そのおかげで、Authlete は OpenID Certification を取得することができました。この件については『OAuth 2.0 / OIDC 実装の新アーキテクチャー』の「6.1.1. Request URI の事前登録」でも紹介しています。
3. JWK Set
さて、リクエストオブジェクトを取得した後は、それが暗号化されていれば復号化を行います。そして、署名がされていれば、署名を検証します。署名アルゴリズムが非対称鍵系の場合、クライアントの JWK Set(RFC 7517)を取得し、その中から署名の検証に必要な公開鍵を取り出し、それを用いて署名検証することになります。この場合、どこからクライアントの JWK Set を取得するのか、という話になりますが、JWK Set は、(1)クライアント属性の jwks
の値として内容そのものがサーバーに登録されているか、(2)クライアント属性の jwks_uri
の値として JWK Set の場所を示す URI が登録されているはずなので、そこから JWK Set を取得することになります。
4. 署名検証
リクエストオブジェクトの署名を検証する際に、まず、当該署名アルゴリズムがサーバーでサポートされているかどうかを確認します。これは、サーバー属性の request_object_signing_alg_values_supported
と照合することで行います。
次に、クライアント属性の request_object_signing_alg
をチェックします。request_object_signing_alg
以外の署名アルゴリズムで署名されていた場合、サーバーは認可リクエストを拒否します。
なお、認可サーバーの実装によってはクライアント属性に request_object_signing_alg
に相当するものが存在しないこともあると思いますが、その場合は、アルゴリズムが決め打ちになっているか、もしくはリクエストオブジェクトそのものを当該認可サーバーがサポートしていないと考えられます。
クライアントのクライアントタイプが public の場合、対称鍵系の署名アルゴリズムを使えないので、その点についてもチェックします。
このあと、当該署名アルゴリズムを用いて署名を検証します。
なお、署名されていないリクエストオブジェクトを request_uri
で指定するときは、request_uri
のスキーマは https
でなければなりません。これについては、OpenID Connect Core 1.0 の「6.2. Passing a Request Object by Reference」の第9段落で言及があります。
5. 復号化
リクエストオブジェクトを復号化する場合は、まず、当該暗号アルゴリズムがサーバーでサポートされているかを確認します。これは、サーバー属性の request_object_encryption_alg_values_supported
及び request_object_encryption_enc_values_supported
と照合することで行います。暗号アルゴリズムが二つ存在するのは、二段階の暗号処理を行なっているからです。詳細は『[前編] IDトークンが分かれば OpenID Connect が分かる』の「4.1. 二段階の暗号処理」で説明しています。
次に、クライアント属性の request_object_encryption_alg
と request_object_encryption_enc
との照合も行います。
なお、認可サーバーの実装によってはクライアント属性に request_object_encryption_alg
と request_object_encryption_enc
に相当するものが存在しないこともあると思いますが、その場合は、アルゴリズムが決め打ちになっているか、もしくはリクエストオブジェクトそのものを当該認可サーバーがサポートしていないと考えられます。
クライアントのクライアントタイプが public の場合、対称鍵系の暗号アルゴリズムを使えないので、その点についてもチェックします。
このあと、当該暗号アルゴリズムを用いて復号化を行います。
6. 整合性チェック
リクエストオブジェクトの中に client_id
パラメーターが含まれている場合、その値が client_id
リクエストパラメーターの値と同一であることを確認します。
リクエストオブジェクトの中に response_type
パラメーターが含まれている場合、その値が response_type
リクエストパラメーターの値と同一であることを確認します。
リクエストオブジェクトの中に request
パラメーターもしくは request_uri
パラメーターが含まれている場合、エラーとします。
7. Financial API
現在 OpenID Foundation の Financial API ワーキンググループ で仕様策定中の Financial API(以降 FAPI)では、更新系 API 用のアクセストークンを要求する認可リクエストは request
もしくは request_uri
を使うことが必須とされています。また、署名も必須とされています。これについては、FAPI Part 2 の「5.2.2. Authorization Server」に書かれています。
さいごに
ここまできてやっと、リクエストオブジェクトに含まれるパラメーター群を通常のリクエストパラメーターと同様に扱うことができるようになります。