リクエストオブジェクト処理手順

# **はじめに**

認可サーバー / OpenID プロバイダーの実装が『**リクエストオブジェクト**』を処理する手順について紹介します。


# **1. request, request_uri パラメーター**

認可エンドポイントに対するリクエストのパラメーター群は、リクエストオブジェクトを介して指定されていることがあります。そのため、リクエストに `request` リクエストパラメーターもしくは `request_uri` リクエストパラメーターが含まれていれば、リクエストオブジェクトを取り出し、解析します。仕様は [OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の「[6. Passing Request Parameters as JWTs](http://openid.net/specs/openid-connect-core-1_0.html#JWTRequests)」で定義されています。

まず、`request` パラメーターと `request_uri` パラメーターが同時に指定されている場合はエラーとします。

`request` パラメーターが指定されていた場合、そのパラメーターの値はリクエストオブジェクトそのものです。一方、`request_uri` パラメーターが指定されていた場合、そのパラメーターの値はリクエストオブジェクトが置かれている場所を指す URI となっているので、サーバーはその場所にリクエストオブジェクトを取りに行きます。毎回取りに行くのはパフォーマンス上よろしくないので、HTTP の各種ヘッダーを調べて有効期間を計算して適宜キャッシュします。

なお、キャッシュを用いずに再フェッチを要求するためリクエスト URI のフラグメント部を用いることについて、[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の「[6.2. Passing a Request Object by Reference](http://openid.net/specs/openid-connect-core-1_0.html#RequestUriParameter)」の第６段落で言及があります。


# **2. request_uri 事前登録**

`request_uri` に指定する URI の事前登録を求めるかどうかは、認可サーバーの実装に依存します。認可サーバーが [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) をサポートしているなら、事前登録を要求するかどうかは `require_request_uri_registration` の値を調べることで分かります。

なお、セキュリティー上の理由により [Authlete](https://www.authlete.com/) の実装では必ず事前登録を要求するようにしています。未登録の `request_uri` を許してしまうと、「実在しない、もしくは不正なリクエストオブジェクトを取りに行かせる」という攻撃をサーバーに対して簡単に実行できてしまうからです。

余談ですが、少し前までの [OpenID Certification](http://openid.net/certification/) テストには、`request_uri` を動的に生成してテストを実行している部分があり、`request_uri` の事前登録を要求する [Authlete](https://www.authlete.com/) では当該テストを実行できませんでした。そのため、事前登録要求をオン・オフするための設定項目を [Authlete](https://www.authlete.com/) に追加しようと思ったのですが、『[OAuth 2.0 In Action](https://www.manning.com/books/oauth-2-in-action/)』の著者でもある Justin Richer 氏がセキュリティー上の理由によりそのアイディアに反対しました。かわりに彼は、当該テストを OpenID Certification テストから取り除くよう [OpenID Foundation](http://openid.net/) に依頼しました。そのおかげで、[Authlete は OpenID Certification を取得](http://www.oixnet.org/openid-certifications/authlete/)することができました。この件については『[OAuth 2.0 / OIDC 実装の新アーキテクチャー](https://qiita.com/TakahikoKawasaki/items/b2a4fc39e0c1a1949aab)』の「[6.1.1. Request URI の事前登録](https://qiita.com/TakahikoKawasaki/items/b2a4fc39e0c1a1949aab#611-request-uri-の事前登録)」でも紹介しています。


# **3. JWK Set**

さて、リクエストオブジェクトを取得した後は、それが暗号化されていれば復号化を行います。そして、署名がされていれば、署名を検証します。署名アルゴリズムが非対称鍵系の場合、クライアントの JWK Set（[RFC 7517](https://tools.ietf.org/html/rfc7517)）を取得し、その中から署名の検証に必要な公開鍵を取り出し、それを用いて署名検証することになります。この場合、どこからクライアントの JWK Set を取得するのか、という話になりますが、JWK Set は、（１）クライアント属性の `jwks` の値として内容そのものがサーバーに登録されているか、（２）クライアント属性の `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` に相当するものが存在しないこともあると思いますが、その場合は、アルゴリズムが決め打ちになっているか、もしくはリクエストオブジェクトそのものを当該認可サーバーがサポートしていないと考えられます。

クライアントの[クライアントタイプ](https://tools.ietf.org/html/rfc6749#section-2.1)が public の場合、対称鍵系の署名アルゴリズムを使えないので、その点についてもチェックします。

このあと、当該署名アルゴリズムを用いて署名を検証します。

なお、署名されていないリクエストオブジェクトを `request_uri` で指定するときは、`request_uri` のスキーマは `https` でなければなりません。これについては、[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の「[6.2. Passing a Request Object by Reference](http://openid.net/specs/openid-connect-core-1_0.html#RequestUriParameter)」の第９段落で言及があります。



# **5. 復号化**

リクエストオブジェクトを復号化する場合は、まず、当該暗号アルゴリズムがサーバーでサポートされているかを確認します。これは、サーバー属性の `request_object_encryption_alg_values_supported` 及び `request_object_encryption_enc_values_supported` と照合することで行います。暗号アルゴリズムが二つ存在するのは、二段階の暗号処理を行なっているからです。詳細は『[[前編] IDトークンが分かれば OpenID Connect が分かる](http://qiita.com/TakahikoKawasaki/items/8f0e422c7edd2d220e06)』の「[4.1. 二段階の暗号処理](http://qiita.com/TakahikoKawasaki/items/8f0e422c7edd2d220e06#41-二段階の暗号処理)」で説明しています。

次に、クライアント属性の `request_object_encryption_alg` と `request_object_encryption_enc` との照合も行います。

なお、認可サーバーの実装によってはクライアント属性に `request_object_encryption_alg` と `request_object_encryption_enc` に相当するものが存在しないこともあると思いますが、その場合は、アルゴリズムが決め打ちになっているか、もしくはリクエストオブジェクトそのものを当該認可サーバーがサポートしていないと考えられます。

クライアントの[クライアントタイプ](https://tools.ietf.org/html/rfc6749#section-2.1)が public の場合、対称鍵系の暗号アルゴリズムを使えないので、その点についてもチェックします。

このあと、当該暗号アルゴリズムを用いて復号化を行います。


# **6. 整合性チェック**

リクエストオブジェクトの中に `client_id` パラメーターが含まれている場合、その値が `client_id` リクエストパラメーターの値と同一であることを確認します。

リクエストオブジェクトの中に `response_type` パラメーターが含まれている場合、その値が `response_type` リクエストパラメーターの値と同一であることを確認します。

リクエストオブジェクトの中に `request` パラメーターもしくは `request_uri` パラメーターが含まれている場合、エラーとします。


# **7. Financial API**

現在 OpenID Foundation の [Financial API ワーキンググループ](http://openid.net/wg/fapi/) で仕様策定中の Financial API（以降 FAPI）では、更新系 API 用のアクセストークンを要求する認可リクエストは `request` もしくは `request_uri` を使うことが必須とされています。また、署名も必須とされています。これについては、FAPI [Part 2](http://openid.net/specs/openid-financial-api-part-2.html) の「[5.2.2. Authorization Server](http://openid.net/specs/openid-financial-api-part-2.html#authorization-server)」に書かれています。

参考：『[Financial API 実装の技術課題](http://qiita.com/TakahikoKawasaki/items/48a9d22205f77db59726)』


# **さいごに**

ここまできてやっと、リクエストオブジェクトに含まれるパラメーター群を通常のリクエストパラメーターと同様に扱うことができるようになります。