こんにちは、富士榮です。
前回のポストではOpenID Connectの認可コードフローの全体像を書きましたので今回から中身について深掘りしていきたいと思います。
今回は①のディスカバリの部分です。
ディスカバリとは何をするフェーズなのか?ですが、簡単にいうとOpenID Provider自身に関する情報をRelying Partyに伝えることが目標となります。
もちろんRelying Partyに対してOpenID Providerの構成情報を都度細かく伝えても良いのですが、Relying Partyの数が増えてくるとチリも積もるので設定作業が面倒になってきますし、何よりも何らかの構成変更がOpenID Provider側に発生した場合に変更情報を全Relying Partyに伝え直すのは至難の技です。
この課題を解決するためにOpenID ConnectにはOpenID Connect Discoveryという仕様が定められています。
Discoveryの流れ
大まかな流れとしては、以下の2つのフェーズに分かれます。
- ユーザの識別子からOpenID ProviderのURLを取得する
- OpenID Providerの構成情報を取得する
まず最初のフェーズですが、元々はDiscoveryの仕様はWebfingerの仕様に則ってOpenID ProviderのURLを取得することを想定して策定されていました。
こんな流れです。
- Relying Partyにユーザが自身の識別子(例:test@example.jp)を提供する
- Relying Partyのユーザの識別子のドメインパート(example.jp)に対応するOpenID Providerを検索する(この部分がWebfinger)
- 具体的には以下のGETリクエストを投げる
- https://example.jp/.well-known/webfinger?
- resource=test@example.jp&
- rel=http://openid.net/specs/connect/1.0/issuer
- 結果として返却されるOpenID ProviderのURLをRelying Partyは取得する
しかしながら、現実問題としてほとんどのRelying Partyではユーザ自身が利用するOpenID Providerを選択するUXとなっているため、このフェーズが利用されることはほとんどありません。(OpenID Providerが利用者の識別子がOpenID Providerのドメイン名と一致していないケースも多くなってきていることもあるんだと思います)
そのため、本命は2番目のフェーズとなる、Relying PartyがあらかじめOpenID ProviderのURLまでは知っているところからスタートする構成情報の取得となっています。
こちらは{OpenID ProviderのURL}/.well-known/openid-configurationというURLへのGETリクエストを投げ込むことでOpenID Providerの構成情報(エンドポイントやサポートする署名アルゴリズムなど)を取得するという仕組みとなっています。
例えば、LINE Loginであれば「https://access.line.me/.well-known/openid-configuration」をGETすると以下のメタデータが返ってきます。
{
"issuer": "https://access.line.me",
"authorization_endpoint": "https://access.line.me/oauth2/v2.1/authorize",
"token_endpoint": "https://api.line.me/oauth2/v2.1/token",
"revocation_endpoint": "https://api.line.me/oauth2/v2.1/revoke",
"userinfo_endpoint": "https://api.line.me/oauth2/v2.1/userinfo",
"scopes_supported": ["openid", "profile", "email"],
"jwks_uri": "https://api.line.me/oauth2/v2.1/certs",
"response_types_supported": ["code"],
"subject_types_supported": ["pairwise"],
"id_token_signing_alg_values_supported": ["ES256"],
"code_challenge_methods_supported": ["S256"]
}
実態として.well-known/openid-configurationも提供していないOpenID Providerも存在しますし、返ってくる情報が当てにならないところもあるのでちゃんとドキュメントは読みましょう、という話にしかならないわけですが・・・(ちなみにLINE LoginもIDトークンの署名アルゴリズム/id_token_signing_alg_values_supportedがES256とありますが、実際の署名としてはRS256となっていたりします)
OpenID Providerの構成情報にはどの様なものがあるのか
仕様の「3. OpenID Provider Metadata」にOpenID Providerが提供するメタデータに記載されている構成情報について解説されています。
ざっくりこんな感じです。
Discoveryエンドポイントを実装してみる
では実装してみます。非常に単純なエンドポイントなので/.well-known/openid-configurationに対するGETリクエストがあったら必要な情報をJSONで返却するだけです。
githubに公開しているソースのうち、この部分が該当します。
https://github.com/fujie/oidc-study-op/blob/main/endpoints/discovery.js
const router = require("express").Router();
// Discoveryエンドポイント
router.get("/openid-configuration", (req, res) => {
const baseUrl = 'https://' + req.headers.host;
const response_types = ["code"];
const subject_types = ["public"];
const alg_values = ["RS256"];
const scopes = ["openid"];
const auth_methods = ["client_secret_post", "client_secret_basic"];
const claims =["sub", "name", "given_name", "family_name", "email", "email_verified", "iss", "aud", "exp", "exp", "iat"];
res.json({
issuer: baseUrl,
authorization_endpoint: baseUrl + "/oauth2/authorize",
token_endpoint: baseUrl + "/oauth2/token",
userinfo_endpoint: baseUrl + "/userinfo",
jwks_uri: baseUrl + "/jwks_uri",
response_types_supported: response_types,
subject_types_supported: subject_types,
id_token_signing_alg_values_supported: alg_values,
scopes_supported: scopes,
token_endpoint_auth_methods_supported: auth_methods,
claims_supported: claims
});
});
module.exports = router;
node.js.+ express routerで実装しているので/.well-knownへのアクセスはこのJSへルーティングされる様にしています。
やっていることは単純で必要な情報をres.jsonで返却しているだけですね。
Relying PartyはOpenID Providerへリクエストをする際にこのエンドポイントにアクセスして最新の構成情報を取得して各種エンドポイントを利用する、という動きをする、ということですね。(パフォーマンスの観点でRelying Party側でメタデータをキャッシュをすることも多いと思います)
0 件のコメント:
コメントを投稿