161
133

More than 1 year has passed since last update.

図解 OpenID Connect による ID 連携

Last updated at Posted at 2022-01-31

ID 連携フローの説明

1

ウェブブラウザを使い、ウェブサービスのログインページにアクセスします。

oidc-id-federation_ja_01.png

2

ウェブサービスはログインページを生成し、ウェブブラウザに返します。ウェブサービスが外部のアイデンティティプロバイダIdP)との ID 連携をサポートしていれば、ログインページ内に ID 連携を開始するためのリンクが埋め込まれます。

oidc-id-federation_ja_02.png

3

ID 連携を開始するためのリンクをクリックします。

oidc-id-federation_ja_03.png

4

ID 連携開始の要望を受けたウェブサービスは、対象となる IdP への認証リクエストOpenID Connect Core 1.0 Section 3.1.2.1. Authentication Request)を作成します。

認証リクエストの形式は、リクエストパラメーター群を含めた、IdP の認可エンドポイントRFC 6749 Section 3.1. Authorization Endpoint)を指す URL です。ですので、認証リクエストを作成するにあたり、認可エンドポイントの URL を知る必要があります。IdP の技術文書を読めば認可エンドポイントの URL を知ることはできますが、もしも IdP が OpenID Connect Discovery 1.0 をサポートしているなら、ディスカバリーエンドポイントが返す IdP 設定情報の中から認可エンドポイントの URL を取り出すこともできます。

oidc-id-federation_ja_04.png

なお、仕様により(OpenID Connect Discovery 1.0 Section 4. Obtaining OpenID Provider Configuration Information)、ディスカバリーエンドポイントの場所は「{IdPの識別子}/.well-known/openid-configuration」と決められているので、IdP の識別子さえ知っていればディスカバリーエンドポイントの場所を特定することができます。

認証リクエストに含める state リクエストパラメーターの値はこのタイミングで生成し、HTTP セッションの中に入れて覚えておきます。また、code_challenge リクエストパラメーター(RFC 7636)を含めるなら、code verifier の生成もこのタイミングになります。

5

認証リクエスト作成後、ウェブブラウザを IdP の認可エンドポイントにリダイレクトするため、ウェブサービスは HTTP ステータスコード 302 Found(リダイレクトを促すものであれば他のステータスコードでもかまわない)を返します。このとき、Location レスポンスヘッダーに認証リクエストを表す URL をセットしておきます。

HTTP/1.1 302 Found
Location: 認可エンドポイント?パラメーター群...

oidc-id-federation_ja_05.png

6

HTTP ステータスコード 302 Found を受け取ったウェブブラウザは、Location ヘッダーに書かれている URL にアクセスします。結果として、ウェブブラウザは、IdP の認可エンドポイントに認証リクエストを投げることになります。

oidc-id-federation_ja_06.png

7

認証リクエストを受け取った認可エンドポイントは、(1)ユーザーを認証して(2)ウェブサービスへ権限を渡すことに対する同意をユーザーから得るため、認可ページを作成し、ウェブブラウザに返します。

oidc-id-federation_ja_07.png

図では、ユーザー認証と同意取得をまとめておこなうためのページが返されていますが、ページ遷移を複数回伴う実装でもかまいません。特に近年は、ユーザーを特定した後に認証手続きを開始する(identify してから authenticate する)のが好ましいとされているので、むしろ、ページ遷移もしくは JavaScript による表示切り替えにより遷移を複数回おこなう実装のほうが主流かもしれません。

8

ユーザーは、ユーザー認証に必要な情報を入力し、ウェブサービスからのリクエストを承認します。

oidc-id-federation_ja_08.png

どのようにユーザーを認証するかは IdP 次第です。図では ID とパスワードを要求していますが、近年のユーザー認証方法は多種多様です。

9

ユーザー認証と同意確認後、IdP は認可コードを生成します。

ここでは、先の認証リクエストのフローが OpenID Connect 認可コードフローresponse_typecodescopeopenid を含む)だったと想定しています。このフローの図解は『OpenID Connect 全フロー解説』の「1. response_type=code」にあります。

そして、認可コードをウェブサービスのリダイレクションエンドポイントRFC 6749 Section 3.1.2. Redirection Endpoint)に届けるため、ウェブサービスが IdP に事前に登録しておいたリダイレクション URI にパラメーターとして認可コードを付加し、URL を作成します。

IdP は、認証リクエストに含まれていたものと同じ値をもつ state パラメーターもリダイレクション URI に付加します。また、IdP が OAuth 2.0 Authorization Server Issuer Identification をサポートしているなら、iss パラメーターも付加します。

そのように作成した URL にウェブブラウザをリダイレクトするため、IdP はウェブブラウザに HTTP ステータスコード 302 Found(リダイレクトを促すものであれば他のステータスコードでもかまわない)を返します。このとき、Location レスポンスヘッダーに生成した URL をセットしておきます。

HTTP/1.1 302 Found
Location: リダイレクションエンドポイント?code=認可コード&state=...&iss=...

oidc-id-federation_ja_09.png

このフローの技術詳細については『OAuth 2.0 の認可レスポンスとリダイレクトに関する説明』を参照してください。

10

HTTP ステータスコード 302 Found を受け取ったウェブブラウザは、Location ヘッダーに書かれている URL にアクセスします。結果として、認可コードがウェブサービスに渡ってきます。

oidc-id-federation_ja_10.png

認可コードに加えて state パラメーターも渡ってきます。リダイレクションエンドポイントの実装は、HTTP セッションから state の値を取り出し、その値がレスポンスに含まれる state パラメーターの値と一致することを確認します。これは CSRF 対策です。詳細は RFC 6749 Section 10.12. Cross-Site Request Forgery を参照してください。

IdP の authorization_response_iss_parameter_supported メタデータの値が true であれば、リダイレクションエンドポイントの実装は、レスポンスに iss パラメーターが含まれていること及びその値が IdP の識別子と一致することを確認します。これは Mix-up 攻撃対策です。詳細は OAuth 2.0 Authorization Server Issuer Identification を参照してください。

11

ウェブサービスは、受け取った認可コードを用いて、IdP のトークンエンドポイントRFC 6749 Section 3.2. Token Endpoint)にトークンリクエストを投げます。

oidc-id-federation_ja_11.png

12

トークンエンドポイントはアクセストークンID トークンOpenID Connect Core 1.0 Section 2. ID Token)を生成して返します。

oidc-id-federation_ja_12.png

13

ウェブサービスは受け取った ID トークンの検証をおこないます。検証項目は多岐に渡りますが(OpenID Connect Core 1.0 Section 3.1.3.7. ID Token Validation)、最も重要なのは ID トークンの署名を検証する作業です。

署名検証のためには、署名検証のための鍵を入手する必要があります。その鍵は、署名アルゴリズムが対称鍵系であればクライアントシークレット、非対称鍵系であれば公開鍵です(OpenID Connect Core 1.0 Section 10.1. Signing)。

公開鍵の場合、IdP がどこかで公開しているはずです。一般的には、JWK Set エンドポイントで公開しています。JWK Set エンドポイントの場所に関する情報は、ディスカバリーエンドポイントから返される IdP 設定情報の中に書かれています。

oidc-id-federation_ja_13.png

ID トークンの検証が済めば、「IdP によりユーザーが認証された」ことを確認できたことになります。

14

ID トークンのペイロード部に含まれる情報だけで十分なのであれば、IdP とやりとりする必要はこれ以上ありませんが、ユーザーに関する情報をもっと欲しい場合は、IdP のユーザー情報エンドポイントOpenID Connect Core 1.0 Section 5.3. UserInfo Endpoint)にアクセスします。ユーザー情報エンドポイントにアクセスする際、トークンエンドポイントから発行されたアクセストークンが必要になります。

oidc-id-federation_ja_14.png

あまり知られていませんが、アクセストークンの発行を伴うフローで ID トークンが発行された場合、特殊なスコープ(OpenID Connect Core 1.0 Section 5.4. Requesting Claims using Scope Values)で要求されたクレーム群は ID トークンには含まれません。そのため、ID トークンに含まれるユーザー属性情報は、期待されているものより少ないことがほとんどです。告白すると、この仕様に気付いたのは Authlete 実装後かなり経ってからです。Service クラスの isClaimShortcutRestrictive() の説明も参照してください。

15

ユーザー情報エンドポイントはユーザーに関する情報を返します。

oidc-id-federation_ja_15.png

ユーザー情報を受け取った後にその情報をどう扱うかはウェブサービスの実装次第です。例えば、その情報をもとにウェブサービス上にユーザーアカウントを新規作成し、そのアカウント用のデータレコードに、ユーザー情報エンドポイントから取得した情報をコピーするかもしれません。または、データコピーは最低限にとどめ、IdP のユーザー情報エンドポイントから最新のユーザー情報を好きなときに取得できるよう、かわりにアクセストークンを覚えておくという実装にするかもしれません。

16

ウェブサービスは、ユーザーをログイン状態にし、ウェブサービスのトップページ(でなくてもよいがどこかのページに)ウェブブラウザを遷移させます。

oidc-id-federation_ja_16.png

17

ウェブブラウザはトップページにアクセスします。

oidc-id-federation_ja_17.png

18

ウェブサービスはトップページを返します。このとき、ユーザーはログイン状態と認識されています。

oidc-id-federation_ja_18.png

19

以上で ID 連携完了です。

oidc-id-federation_ja.png

ID 連携のチュートリアル

Authlete 社のウェブサイト上で公開されている『外部 IdP との連携』という技術文書では、IdP として Okta、ウェブサービスとして java-oauth-server(認可サーバーのサンプル実装)を用いた ID 連携を紹介しています。ウェブサービスとして認可サーバーを用いているため、フローがかなり複雑になっていますが(認可サーバーの認可ページから ID 連携する構成)、ID 連携部分は本記事で紹介したものと同一です。

id-federation_ja.png

実際に動かすことができますので、是非チュートリアルを試してみてください。また、ID 連携の実装詳細にご興味があれば、java-oauth-server の Federation.javaFederationEndpoint.java を中心にコードを読んでみてください。

試していませんが、某有名 IDaaS のトークンエンドポイントはカスタムリクエストパラメーターを必須で要求するので、java-oauth-server に書かれている汎用コードだと ID 連携に失敗すると思われます。

161
133
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
161
133