v0.14.0 影響確認
本ドキュメントは v0.14.0 に含まれる破壊的変更・挙動変更と、その利用者側(RP / テナント運用者)への影響をまとめる。
リリースに向けて対象変更が確定し次第、本ドキュメントへ追記していく。各変更は独立したセクション(## N. <変更>)として追加し、あわせて下記「影響まとめ」表に 1 行加える。
影響まとめ
| # | 変更 | 種別 | 対象 |
|---|---|---|---|
| 1 | セルフサービス連絡先(Email / 電話番号)の確認・変更を追加。DBマイグレーション 1 本(V0_14_0_1)が必要 | 🟢 追加 / ⚙️ | 全環境(マイグレーション必須) |
| 1 | 変更用スコープ email:change / phone:change を新設。テナントの scopes_supported とクライアントの scope の両方に追加しないと常に 403 | 🟢 追加 / 🔒 要点検 | セルフサービス連絡先変更を使う構成 |
| 1 | 管理権限 idp:contact-verification-challenge:read を新設 | 🟢 追加 / 🔒 要点検 | 権限を明示列挙しているロール(idp:* を持つロールは自動的に含む) |
| 1 | 管理APIが有効な verification_code を返す(監査ログには残さない) | 🔒 要点検 | 管理APIの利用者・権限設計 |
| 1 | セキュリティイベント型が 16 種増えた({email,phone}_{verify,change}_{request_,}{success,failure}) | 🟢 追加 | セキュリティイベントフック / SIEM 連携 |
| 1 | テナント取得のレスポンスに identity_policy_config.contact_change_policy が常に含まれるようになった | 🟡 挙動変更 | テナント設定を厳密なスキーマで検証している自動化・GET → 編集 → PUT を自分で書いている運用 |
| 1 | POST /v1/admin/operations/delete-expired-data のレスポンス内訳に contact_verification_challenge が増えた | 🟡 挙動変更 | 当該レスポンスを厳密に検証している自動化 |
| 2 | 組織配下の認証設定 API が要求する権限を idp:authentication-policy-config:* から idp:authentication-config:* に修正 | 🔴 破壊的 / 🔒 要点検 | 権限を明示列挙しているロール(idp:* を持つロールは影響なし) |
| 3 | 本人確認設定の GET が result / registration.response / registration.basic_auth を返すようになった | 🟡 挙動変更 | 当該レスポンスを厳密なスキーマで検証している自動化 |
| 3 | 本人確認設定の PUT で type を変更・省略すると 400(従来は 200 で無反映) | 🔴 破壊的 | PUT に毎回新しい type を入れている自動化 |
| 3 | 本人確認設定の enabled が実際に効くようになった | 🔴 破壊的 | enabled: false を書いている設定(既定は true) |
| 4 | 管理APIのユーザー検索で preferred_username が完全一致になった(従来は部分一致)。部分一致は preferred_username_like へ分離 | 🔴 破壊的 | ユーザー一覧APIを preferred_username の部分一致で呼んでいる管理画面・自動化 |
| 4 | ユーザー検索に preferred_username_like(部分一致)を追加 | 🟢 追加 | 断片で検索したい構成 |
| 5 | Spring Boot を 4.0.8 から 4.1.1 に更新(4.0 系は 2026-12-31 に OSS サポート終了) | ⚙️ | 全環境(イメージの更新のみ)。Spring に依存する自作プラグインを組み込んでいる構成は要確認 |
| 6 | FAPI 1.0 Advanced / FAPI 2.0 で openid スコープの無い認可リクエスト(JARM・PAR)にも、redirect_uri の必須・事前登録・完全一致を適用 | 🔴 破壊的 | openid なしの FAPI リクエストで redirect_uri を省略している、または登録と異なる値を送っているクライアント |
| 7 | FAPI のクライアント認証の要件(認証方式・署名アルゴリズム・鍵長・client secret の長さ・aud)を、PAR と refresh token のリクエストにも適用 | 🔴 破壊的 | FAPI のスコープで PAR / refresh token を使い、要件を満たさない認証をしているクライアント |
| 7 | FAPI のクライアント認証の要件を満たさないときのエラーを invalid_client に統一し、トークンエンドポイントでは 401 にした(従来は 400、認証方式の制限は unauthorized_client) | 🟡 挙動変更 | ステータスコードやエラーコードで分岐しているクライアント |
| 7 | client_assertion_type が urn:ietf:params:oauth:client-assertion-type:jwt-bearer 以外なら invalid_client(トークンエンドポイント・PAR とも 401。従来は値を見ていなかった) | 🔴 破壊的 | private_key_jwt / client_secret_jwt で誤った client_assertion_type を送っているクライアント |
| 7 | FAPI 1.0 Advanced で RSA1_5 を拒否(Request Object の暗号化、id_token_encrypted_response_alg / authorization_encrypted_response_alg) | 🔴 破壊的 | RSA1_5 を設定・使用しているクライアント |
| 7 | client_id_alias で認証する FAPI 1.0 Baseline(FAPI-CIBA を含む)のクライアントが、トークンリクエストで拒否されなくなった | 🟡 挙動変更 | なし(従来は常に失敗していた) |
| 7 | UserInfo が x-fapi-interaction-id を返す。アプリケーション API のログ(MDC)に fapi_interaction_id を出す | 🟢 追加 | ログの項目を厳密に扱っている収集基盤 |
| 8 | 認可拒否(POST .../deny)のエラー応答のキーを errorDescription から error_description に修正 | 🟡 挙動変更 | 認可拒否のエラー応答から errorDescription を読んでいる認可画面 |
| 9 | 認可画面を別サイトに置く構成を追加(ui_config.cross_site / クライアントの extension.cross_site_authorization_view、既定は無効)。GET /{tenant-id}/v1/authorizations/{id}/complete を追加 | 🟢 追加 | 認可画面を idp-server と別サイトに置く構成。宣言しない限り挙動は変わらない |
| 9 | 付属の認可画面(app-view)が、応答に auth_proof があれば authorize に載せ、/complete を経由するようになった | 🟢 追加 | app-view をそのまま使う構成(別サイト認可画面モードを有効にしない限り挙動は変わらない) |
| 9 | CORS の応答の Access-Control-Allow-Headers に、テナントの allow_headers の設定に関係なく x-view-binding を含めるようにした(別サイト認可画面モードで認可画面が送るヘッダー) | ⚙️ | なし(ヘッダーを許可するだけ。設定の変更は不要) |
| 10 | リクエストオブジェクトの独自クレームをカスタムパラメータとして読む。クエリと同じキーはリクエストオブジェクトの値を使う | 🟡 挙動変更 | リクエストオブジェクトに独自クレームを入れているクライアント、view-data の custom_params を読む認可画面 |
| 10 | FAPI 1.0 Advanced では、カスタムパラメータもリクエストオブジェクトの値だけを使う(クエリだけで渡した値は使われない) | 🔴 破壊的 | クエリでカスタムパラメータ(画面の振り分けの view_version など)を渡している FAPI Advanced のクライアント |
| 10 | 認可画面へのリダイレクト URL に、リクエストオブジェクトの値を載せない。リクエストオブジェクトを含む PAR では、カスタムパラメータを URL に載せない(view-data には載る) | 🟡 挙動変更 | リダイレクト URL のクエリからカスタムパラメータを読んでいる認可画面 |
| 11 | 認証ポリシーの条件式で、認可リクエストのカスタムパラメータを $.request.custom_params.* として参照できる。信頼する出どころは custom_params_trusted_sources(既定 pushed / request_object)で選ぶ。右辺を path で書く value_path(eq / ne)を追加 | 🟢 追加 | RP が渡した値(会員番号など)とログインした利用者の属性を照合したい構成 |
| 11 | 認証ポリシーの登録・更新で、value_path の誤用(value と併記、eq / ne 以外)と custom_params_trusted_sources の未知の値を 400 にする | 🟢 追加 | なし(新しい項目の検査のみ) |
| 11 | 認証トランザクションの context に custom_params を保存する。端末向けの認証トランザクション API には含めない | ⚙️ | 管理 API の認証トランザクションの応答を厳密に検証している自動化 |
| 12 | DPoP proof と Client Attestation PoP JWT の iat の許容範囲を ±5 分から ±60 秒に短縮(dpop_proof_acceptable_window_seconds / client_attestation_pop_acceptable_window_seconds で変更可。ABCA は v0.14.0 で追加) | 🟡 挙動変更 | 時計が 60 秒以上ずれる端末、iat を古いまま使い回しているクライアント |
| 12 | 受け付けた DPoP proof / PoP JWT の jti を Redis に記録し、同じ proof の 2 回目を拒否(DPoP は invalid_dpop_proof、userinfo は 401 invalid_token、ABCA は invalid_client_attestation。ABCA は v0.14.0 で追加) | 🟡 挙動変更 | 同じ proof を再送しているクライアント(リトライで proof を作り直していないもの) |
| 12 | private_key_jwt / client_secret_jwt の client assertion の jti も Redis に記録し、同じ assertion の 2 回目を 401 invalid_client で拒否(Issue #1902) | 🟡 挙動変更 | 同じ client assertion を複数のリクエストで使い回しているクライアント(リトライやトークン・PAR・introspection への流用を含む) |
| 12 | client assertion を受け入れる期間を最長 60 秒に制限(iat があれば iat から 60 秒、無ければ exp が 60 秒以内。client_assertion_max_lifetime_seconds で変更可、Issue #1902) | 🔴 破壊的 | iat から 60 秒より後に assertion を使っているクライアント、iat を付けずに exp を 60 秒より先にしているクライアント |
| 13 | 同意画面での配列の要素の選択(granted_claim_values)が、verified_claims のクレームにも効く。view-data の claim_values に verified_claims.claims の候補が増えた | 🟢 追加 | verified_claims の配列クレームを出している構成。選択を送らない限り挙動は変わらない。ローリングデプロイの途中は、古いノードでは選択が効かない |
| 13 | 付属の認可画面(app-view)の同意ステップで、verified_claims の配列クレームの要素も選べるようになった | 🟢 追加 | app-view をそのまま使う構成 |
| 13 | view-data の claim_values を、認証が成功したあとにだけ返すようにした(従来は、login_hint や多段認証の 1 段目でユーザーが決まった時点で返していた) | 🟡 挙動変更 | 認証が終わる前に claim_values を読んでいる独自の認可画面(付属の app-view は同意ステップでだけ読むので影響なし) |
| 14 | binding message の照合(authentication-device-binding-message)で、照合する値を持たないトランザクションは 400 invalid_request(従来は空の binding_message を送ると成功していた) | 🟡 挙動変更 | binding_message を付けない CIBA リクエストで、このステップを認証ポリシーに入れている構成 |
| 15 | 監査ログの管理 API(システム・組織)の応答で、request / before / after などに含まれる秘密の値(パスワード・シークレット・トークン・鍵など)を [SCRUBBED] に置き換える。記録されている内容は変わらない | 🟡 挙動変更 | 監査ログの API の応答から、これらの値を読んでいる運用ツール |
| 16 | client_attestation_trust_source: x5c で、client_attestation_trusted_root_certificates に途中の CA を置けるようにした。あわせて x5c の検証を RFC 5280 のパス検証にし、リーフが CA の証明書や、issuer と subject がつながらないチェーンを拒否する | 🟢 追加 | なし(attest_jwt_client_auth は v0.14.0 で追加。§22) |
| 17 | Introspection(introspection / introspection-extensions)で、呼び出し元のクライアント認証の失敗を 401 にし、応答から active と status_code を外した(従来は 400 + active: false) | 🔴 破壊的 | Introspection の 400 や active: false で分岐している Resource Server(資格情報が壊れているときだけ) |
| 17 | PAR のクライアント認証の失敗を 400 から 401 にした(トークンエンドポイントと同じ) | 🟡 挙動変更 | PAR のステータスコードで分岐しているクライアント |
| 17 | client_secret_basic で失敗したとき、WWW-Authenticate: Basic realm="<issuer>" を付ける(トークン・revocation・introspection・PAR・CIBA) | 🟢 追加 | なし |
| 17 | client_secret_basic 以外で登録したクライアントが Basic ヘッダーも送ると、認証に失敗する(RFC 6749 §2.3。従来は登録した方式だけで認証していた) | 🔴 破壊的 | ボディやアサーションと一緒に Basic ヘッダーも送っているクライアント(SDK の設定による) |
| 17 | 存在しない client_id を invalid_client の 401 にした(従来は revocation・CIBA が 400、introspection が 400 + active: false、PAR が 400 invalid_request) | 🟡 挙動変更 | これらのステータス・エラーコードで分岐しているクライアント |
| 18 | 身元確認の process に caller(end_user / external_service)を追加。呼べない入口からは登録されていない process と同じ 404 | 🟢 追加 | なし(書かない限り、下の行以外の挙動は変わらない) |
| 18 | caller を書いていない process でも、request.basic_auth があればコールバック(/internal/...)からだけ実行できる。エンドユーザー向けの入口(/v1/me/...)から呼ぶと 404 | 🔴 破壊的 | basic_auth を設定した process を、エンドユーザー向けの入口からも呼んでいる構成 |
| 18 | 身元確認設定の登録・更新で、caller の値が end_user / external_service 以外か、end_user に request.basic_auth(username と password の両方)を書いた設定を 400 にする | 🟢 追加 | なし(新しい項目の検査のみ) |
| 18 | 同梱のテンプレート・設定例の evaluate-result(ongoing の callback-result も)を caller: external_service にした。承認はコールバック(/internal/.../{id}/evaluate-result)から返す | 🔴 破壊的 | テンプレートから作った設定を入れ直し、エンドユーザー向けの入口から evaluate-result を呼んでいる構成 |
| 18 | 登録済みの設定は自動では変わらない。外部サービスが結果を返す process には caller: external_service を書く(同梱のテンプレートから作った設定は evaluate-result など) | 🔒 要点検 | 身元確認設定を登録している構成 |
| 18 | ongoing テンプレートの callback-result で、process の直下にあって効いていなかった required_processes を dependencies に移し、process_sequence を足した。apply より前のコールバックは 400 pre_hook_validation_failed(再送は従来どおり受け付ける) | 🟡 挙動変更 | ongoing テンプレートから作った設定を入れ直し、apply より前にコールバッ クを送る外部サービス |
| 19 | 申込みを ID で扱う API(/v1/me/... の process 実行・削除、コールバック)で、パスの verification-type が申込みの種別と違えば、申込みが見つからないときと同じ 404 にする(従来は種別を見ずに処理していた) | 🔴 破壊的 | 申込みと違う種別のパスで呼んでいるクライアント・外部サービス |
| 19 | 同梱のテンプレート・設定例から、読まれていなかったキー(トップレベルの external_service / external_application_id_param、common.external_service)を外した | ⚙️ | なし(読まれていなかったので挙動は変わらない) |
| 20 | マッピングの to: "*" で展開したキーを、パスとして読まずにそのまま使う(従来は a.b を入れ子に、0 などを配列の添字として扱っていた) | 🟡 挙動変更 | "*" で展開する元のデータに . や数字だけのキーがあり、入れ子になる動きを使っている設定 |
| 20 | マッピングの to の配列の添字を 999 までにした。超えると、そのルールが動いたときに設定の誤りとしてエラー(多くの入口で 500) | 🟡 挙動変更 | to に 1000 以上の添字を書いている設定 |
| 20 | 身元確認の process_sequence で断られた呼び出し(前提プロセスが未完了・ステータスが対象外・再実行)を、process の実行として記録しない。前提を満たしたあとに allow_retry: false の process を呼べる | 🟡 挙動変更 | 断られた呼び出しが processes の回数に入ることを 前提にしている運用 |
| 20 | 身元確認の allow_during_statuses を、申込み ID なしで呼ぶと 400(従来は 500)。値はステータスの小文字(requested など)だけを受け付け、それ以外の設定は登録・更新で 400 | 🔴 破壊的 | allow_during_statuses に大文字などの値を書いた設定(従来は一致せず、常に拒否されていた) |
| 21 | デバイスの登録・削除と、2 要素目(allow_registration: true)での連絡先の登録は、認証済みのユーザーに限る。login_hint で指定しただけのユーザーでは unauthorized | 🔴 破壊的 | login_hint だけでユーザーを決めて、デバイス登録や連絡先の登録に進ませている構成(ログイン済みのユーザーを新しい認可リクエストで登録に誘導する場合を含む) |
| 21 | FIDO2 / FIDO-UAF の登録と FIDO2 の削除の成功を、認証として数えない(amr・auth_time・amr から決まる acr・level_of_authentication_scopes) | 🔴 破壊的 | 認証のあとにデバイスを登録して認可を終える構成(CIBA では登録だけの構成も)で、amr / acr に fido2 / fido-uaf が入ることを前提にしている RP・ポリシー、成功条件(success_conditions)を書いていない /me 用の登録のポリシー(削除は完了扱いにならないだけ) |
| 21 | 外部 API 認証・パスワード・SMS・Email で $.user を外部に渡すときの「認証済み」の判定が、上の 2 行に合わせて変わる。/me の API では最初の interaction から渡る | 🟡 挙動変更 | /me の API で、外部 API などに $.user が渡らないことを前提にしている構成 |
| 21 | 外部 API 認証(external-api-authentication)とナンバーマッチングの成功は、これまでどおり認証として数える | 🔒 要点検 | これらで本人を確かめていない構成(device_registration_conditions で登録の条件を絞る) |
| 21 | FIDO2 の登録解除で、credential の持ち主をトランザクションのユーザーと照合する。リクエストの username は使わない。持ち主でなければ、存在しないときと同じ 400(本文の credential_not_found は $.error を写す設定のときだけ)。credential_id が無いときは 500 でなく 400 | 🟡 挙動変更 | 登録解除のリクエストに username を入れている構成、登録解除を http_request で外部に渡す設定($.request_body を写すと username がユーザーから決めた値になる) |
| 21 | FIDO-UAF の登録解除で、device_id がトランザクションのユーザーのデバイスか確かめる。違うとき・device_id が無いときは、FIDO サーバーに送らず 400 invalid_request | 🟡 挙動変更 | ユーザーのデバイス一覧にない device_id で登録解除している構成 |
| 21 | 認証設定の post_hook に verifications(type: match)を追加。評価するのは FIDO-UAF の認証(fido-uaf-authentication)だけで、FIDO サーバーが返す認証したデバイスとチャレンジの device_id を照合できる | 🟢 追加 / 🔒 要点検 | FIDO-UAF の認証を使う 構成(FIDO サーバーが認証したデバイスの ID を返すなら、照合の設定を推奨) |
| 22 | attest_jwt_client_auth(Attestation-Based Client Authentication)を追加。DBマイグレーション 3 本(V0_14_0_2〜V0_14_0_4)が必要 | 🟢 追加 / ⚙️ | 全環境(マイグレーション必須) |
| 22 | 管理権限 idp:client-instance:{create,read,revoke,delete} を新設 | 🟢 追加 / 🔒 要点検 | 権限を明示列挙しているロール(idp:* を持つロールは自動的に含む) |
| 22 | セキュリティイベント型が 4 種増えた(client_instance_registration_{challenge_issued,success,failure}・client_instance_revoked) | 🟢 追加 | セキュリティイベントフック / SIEM 連携 |
| 22 | POST /v1/admin/operations/delete-expired-data のレスポンス内訳に client_instance_registration_challenge が増えた | 🟡 挙動変更 | 当該レスポンスを厳密に検証している自動化 |
| 22 | payload を claims として読めない JWT への応答を、500 から入口ごとのエラーにした(DPoP は invalid_dpop_proof、JWT Bearer は invalid_grant、client_assertion はクライアント認証の失敗、それ以外は 400 invalid_request) | 🟡 挙動変更 | なし(壊れた JWT への応答コードだけ) |
| 23 | 認可エンドポイントでの認証で、同じユーザーの OP セッションがあるとき、OP セッションの auth_time / acr / amr を今回の認証の値に置き換える(acr が下がる場合も置き換える) | 🟡 挙動変更 | SSO の ID Token の auth_time / acr / amr を見ている RP、強い認証のあとに弱い認証をさせる構成 |
| 23 | TIME_ZONE が UTC 以外のとき、SSO の max_age の判定が時差の分ずれていたのを修正。更新前の OP セッションからの SSO では、ID Token の auth_time が時差の分ずれる | 🟡 挙動変更 | TIME_ZONE を UTC 以外にしている環境(UTC より東は従来より厳しく、西はゆるく判定される) |
| 24 | authentication-cancel を、AUTH_SESSION(cookie)の照合にかけない(認証端末からも認可画面からも) | 🟡 挙動変更 | なし(従来は auth_session_binding_required: true(既定)で 401 auth_session_mismatch になり、端末から取り消せなかった) |
| 25 | /v1/me/mfa/{mfa-operation-type} で oauth / ciba を指定すると 400 invalid_request | 🟡 挙動変更 | なし(従来はトランザクションを作れたが、その後の操作が 500 になり使えなかった) |
| 26 | 外部に渡す $.user に external_user_id(値があるとき)が増えた | 🟡 挙動変更 | $.user を丸ごと写して外部に送っている設定 |
| 27 | MySQL 8.0 で V0_10_0_3 / V0_10_0_4 が構文エラーで止まっていたのを、実行できる書き方に直した | ⚙️ | MySQL で、V0_10_0_3 の失敗が記録されている DB(flyway repair で失敗の記録を消してから migrate) |
種別: 🔴 破壊的 / 🟡 挙動変更 / 🟢 追加 / ⚙️ 内部・運用 / 🔒 要点検(更新では 直らず、設定の見直しが必要)
1. セルフサービス連絡先の確認・変更
認証済みエンドユーザーが自分のメールアドレスまたは電話番号を確認・変更する API を追加した(#1876 / Issue #1416)。
POST /{tenant-id}/v1/me/{email|phone}/verification スコープ openid
POST /{tenant-id}/v1/me/{email|phone}/verification/{id}/verify スコープ openid
POST /{tenant-id}/v1/me/{email|phone}/change スコープ {channel}:change
POST /{tenant-id}/v1/me/{email|phone}/change/{id}/verify スコープ {channel}:change
詳細は セルフサービス 連絡先の確認・変更。
1.1 DBマイグレーション
⚙️ 全環境で必須。
| ファイル | 内容 |
|---|---|
libs/idp-server-database/postgresql/V0_14_0_1__contact_verification_challenge.sql | contact_verification_challenge テーブル + index 2 本 + RLS |
libs/idp-server-database/mysql/V0_14_0_1__contact_verification_challenge.mysql.sql | 同(MySQL に RLS は無いため tenant_id 述語のみ) |
新規テーブルの追加のみで、既存テーブルへの変更は無い。
1.2 変更用スコープ
🔒 要点検。 確認(/verification)は openid で足りるが、変更(/change)は専用スコープを要求する。
"scopes_supported": ["openid", "profile", "email", "email:change", "phone:change"]
テナントの scopes_supported とクライアントの scope の両方に追加する必要がある。クライアント登録スコープの allow-list フィルタが効くため、片方 だけではトークンに載らず、変更エンドポイントが常に 403 insufficient_scope になる(fail closed)。
分離した理由は、確認と変更で動くものが違うため。
| 確認 | 変更 | |
|---|---|---|
| 変わるもの | *_verified のみ | 値 +*_verified(+ 対応する identity policy なら preferred_username) |
| 送信先 | 現在値に固定 | リクエストの new_value |
変更を openid で通すと、第三者クライアントに発行した通常の OIDC トークンにも識別子の移動能力を与えることになる。
1.3 管理権限
🔒 要点検。 サポート照会用の管理API に idp:contact-verification-challenge:read を新設した。
GET /v1/management/tenants/{tenant-id}/contact-verification-challenges
GET /v1/management/tenants/{tenant-id}/contact-verification-challenges/{id}
GET /v1/management/organizations/{org-id}/tenants/{tenant-id}/contact-verification-challenges
GET /v1/management/organizations/{org-id}/tenants/{tenant-id}/contact-verification-challenges/{id}
権限照合は PermissionMatcher のワイルドカード方式なので、idp:* を持つロール(既定の administrator)は自動的に含む。影響を受けるのは権限を明示列挙しているロールだけで、その場合は追加が必要。
1.4 管理APIが有効な検証コードを返す
🔒 要点検。
{ "target_value": "...", "delivery": "internal", "verification_code": "123456", "attempts": 0, "expired": false }
「コードが届かない」という問い合わせに答えるための API なので、実際の送信先と有効なコードを返す。チャレンジの消費には本人のアクセストークンが要るため、コードだけを入手したオペレーターが単独で確定させることはできない。
監査ログは永続なので、after ペイロードからは verification_code と external_reference を落としている。
委譲構成(外部サービスがコードを生成する場合)は delivery: "external" になり、verification_code の代わりに external_reference を返す。
1.5 セキュリティイベント型の追加
🟢 追加。 16 種増えた。
{email,phone}_{verify,change}_request_{success,failure}
{email,phone}_{verify,change}_{success,failure}
ログイン時の email_verification_* とは別物で、こちらは意図的なプロフィール操作を記録する。確認と変更を分けてあるのは、変更だけがログイン識別子を動かすため。
フック / SIEM 側でイベント型を allow-list している場合は追加が必要。
1.6 テナント設定に contact_change_policy が増えた
🟡 挙動変更。 identity_policy_config に contact_change_policy が加わり、テナント取得のレスポンスに常に含まれる(未設定でも既定値が出る)。
"identity_policy_config": {
"identity_unique_key_type": "EMAIL_OR_EXTERNAL_USER_ID",
"contact_change_policy": {
"identifier_move": { "allowed": true, "notify_previous_value": true },
"attribute_only": { "allowed": true, "notify_previous_value": true }
}
}
影響するのは 2 パターン。
- テナント設定のレスポンスを厳密なスキーマで検証している自動化 → 未知キーで落ちる可能性
- GET → 編集 → PUT を自分で書いている運用 → 既定値がそのまま保存されるようになる
既定で効くのは notify_previous_value: true のみで、変更の重さは既定では規定されない(スコープだけが門番)。識別子が動くテナントは authentication_conditions / max_auth_age_seconds を明示的に書くことを推奨する。
allowed が掛かるのは変更だけで、確認(/verification)には掛からない。確認は値を置き換えず *_verified を立てるだけのため。authentication_conditions / max_auth_age_seconds は確認にも掛かる。
1.7 delete-expired-data の内訳
🟡 挙動変更。 POST /v1/admin/operations/delete-expired-data のレスポンスに contact_verification_challenge が加わった。
{ "deleted": { "...": 0, "contact_verification_challenge": 47 }, "total_deleted": 47 }
期限切れチャレンジは他の有効期限付き 7 テーブルと同じ入口 で回収される。件数を固定長で扱っている自動化は影響を受ける。
1.8 既存の認証設定への影響
影響なし。 送信には既存の type: "email" / type: "sms" 認証設定をそのまま流用するが、
- 追加した
resend_cooldown_secondsを読むのはセルフサービス側だけで、ログイン OTP 側はretry_count_limitation/expire_secondsしか読まない templatesの{email,phone}_{verify,change}/*_noticeは未定義ならそれぞれの既定にフォールバックするため、既存テンプレートの変更は不要(ただし*_noticeだけはフォールバックせずスキップする。理由)detailsは生のMapのまま往復するため、保存済み設定に影響しない
認証ポリシー(flow 設定)の追加も不要。
2. 組織配下の認証設定 API の権限を修正
🔴 破壊的変更。 組織配下の認証設定 API が、認証ポリシーの権限で守られていた(Issue #1898)。
/v1/management/organizations/{organization-id}/tenants/{tenant-id}/authentication-configurations
| 修正前 | 修正後 | |
|---|---|---|
| 組織配下 | idp:authentication-policy-config:{create,read,update,delete} | idp:authentication-config:{create,read,update,delete} |
| システム管理用 | idp:authentication-config:* | (変更なし) |
同じリソースを扱う 2 本の API で要求する権限が食い違っていた。組織パスから来たというだけで、認証設定が持つもの(外部認証サービスの接続先と資格情報を含む)は変わらない。
2.1 影響を受けるロール
idp:* を持つロール(既定の administrator)は影響を受けない。権限を個別に列挙しているロールだけが対象。
| そのロールが持つ権限 | 修正前 | 修正後 |
|---|---|---|
idp:authentication-config:* のみ | 組織配下を操作できなかった(403) | 操作できる |
idp:authentication-policy-config:* のみ | 認証ポリシーに加えて認証設定も操作できた | 認証設定は 403 |
後者は権限の昇格にあたるため、修正後に 403 になるロールがあっても、それが本来の状態である。アップグレード前に、認証ポリシー権限だけで組織配下の認証設定を操作している運用がないか確認すること。必要なら idp:authentication-config:* を明示的に付与する。
2.2 ダッシュボードとの整合
idp-server-dashboard は認証設定の画面を idp:authentication-config:read で出し分けている。この修正で、画面の出し分けとサーバーの判定が一致する。
3. 本人確認設定の往復と type / enabled
本人確認設定(identity-verification-configurations)の管理 API で、GET が保存内容の一部を返さず 、GET → 編集 → PUT で設定が消えていた(Issue #1900)。あわせて PUT の type と enabled の扱いを直した。システム管理用・組織配下の両方が対象。
3.1 GET が返す項目が増えた
🟡 挙動変更。 DB には保存されていたが GET が返していなかった項目を返すようにした。
| 項目 | 修正前 | 修正後 |
|---|---|---|
result | verified_claims_mapping_rules が空だとキーごと無し | 何か設定されていれば返る |
registration.response | 常に無し | 返る |
registration.basic_auth | 常に {} | username / password を返す |
result が落ちていたのは、出力条件が verified_claims_mapping_rules の有無だけを見ていたため。user_status / user_claims_mapping_rules / custom_properties_mapping_rules / 各 *_update_policy しか持たない設定は、保存されていても一度も返らなかった。
GET のレスポンスにキーが増えるため、厳密なスキーマで検証している自動化は影響を受ける。
3.2 PUT の type が変更不可になった
🔴 破壊的変更。
PUT ... {"type": "<保存済みと違う値>"} → 400 type cannot be changed
PUT ... {} (type 省略) → 400 type is required
修正前は 200 が返るのに何も更新されなかった。UPDATE 文が WHERE id = ? AND type = ? AND tenant_id = ? でリクエスト由来の新しい type を条件に使うため 0 行更新になり、それでもレスポンスは変更後の姿を返していたので、呼び出し側から成功と区別がつかなかった。
リネームを通す方向にはしていない。type は実行時に設定を引く際のキーであり、identity_verification_application.verification_type が記録している値でもあるため、変えると旧名で積まれた申込みが宙に浮く。
PUT に毎回新しい type を入れている自動化は 400 になる。 GET の結果をそのまま PUT する使い方なら影響はない。
3.3 enabled が効くようになった
🔴 破壊的変更。 ペイロードの enabled を DB のカラムに書くようにした。
修正前は INSERT / UPDATE ともカラムに触れておらず、DDL の DEFAULT TRUE のままだった。実行時の取得は AND enabled = true でカラムを見るため、enabled: false を書いても設定は有効なままだった。
既定は true(リクエスト・ドメインオブジェクトの両方)なので、enabled を書いていない設定は影響を受けない。enabled: false を明示している設定は、アップグレード後に実際へ無効化される。
無効化されるのが意図どおりか、アップグレード前に確認すること。
SELECT tenant_id, type FROM identity_verification_configuration WHERE payload->>'enabled' = 'false';
既存行のカラム値は移行しない。次にその設定を PUT したときにペイロードの値がカラムへ反映される。
4. 管理APIのユーザー検索で preferred_username が完全一致になった(Issue #1866 / PR #1867)
ユーザー一覧API(GET .../users)の preferred_username は前後ワイルドカードの部分一致でした。本バージョンから完全一致になります。
| Before | After | |
|---|---|---|
| 照合 | 部分一致(大文字小文字区別なし) | 完全一致 |
?preferred_username=ichiro | ichiro-ito も ito.ichiro もヒット | ヒットしない |
?preferred_username=ichiro-ito | ヒット | ヒット |
?preferred_username_like=ichiro | (パラメータ自体が無い) | ヒットする(従来の挙動と同一) |
4.1 影響(🔴 破壊的)
部分一致で呼んでいる管理画面・自動化は結果が変わります。 エラーにはならず、0 件が返る形で現れます。
preferred_username はテナントとプロバイダーの範囲で一意な識別子(uk_preferred_username)で、部分一致で探す対象ではありません。同じクラスの値は元から完全一致でした。
| 値 | 照合 |
|---|---|
email / phone_number / external_user_id / user_id | 元から完全一致 |
preferred_username | 部分一致だった(本変更で完全一致へ) |
name / given_name / family_name / middle_name / nickname | 部分一致のまま(変更なし) |
role / permission | 部分一致のまま(変更なし) |
認証時の引き当て(findByPreferredUsername)は元から完全一致で、検索だけが例外になっていました。
空の値にも注意してください。 ?preferred_username=(値が空)は、従来は前後ワイルドカードで全件に一致していましたが、本バージョンからは空文字との完全一致になり 0 件が返ります。検索フォームの全項目を空のまま送る管理画面は、未入力の項目を送らないようにしてください。空の値で 0 件になるのは、元から完全一致の email などと同じ挙動です。
4.2 移行手順
部分一致が必要なら preferred_username_like へ送り先を変えてください。 挙動は従来の preferred_username と同一(前後ワイルドカード・大文字小文字区別なし)です。
- GET .../users?preferred_username=ichiro
+ GET .../users?preferred_username_like=ichiro
管理画面が検索ボックスの入力をそのまま送っている場合、送り先のパラメータ名を変えるだけで運用者の体験は変わりません。
そのうえで、識別子として完全な値で引く呼び出し(自動化・API 直叩き)は preferred_username を使ってください。provider_id もあわせて渡すと一意キー uk_preferred_username (tenant_id, provider_id, preferred_username) が最後まで効き、桁違いに速くなります(4.4)。
人名で探す用途であれば name / given_name / family_name / nickname も部分一致のままです。
preferred_username_like は速くなりません一意キーに対する前後ワイルドカードの部分一致は索引が効かず、テナントの全ユーザーを評価します。これは従来と同じコストです。名前を分けた目的は、遅い経路を明示的な選択にすることであって、部分一致自体を速くするものではありません。
4.3 変わらないもの
- 他の検索パラメータの照合方式。上の表のとおり、変更したのは
preferred_usernameのみです - DB マイグレーション。索引の追加はありません。
provider_idを渡さない完全一致は一意キーの先頭列(tenant_id)までしか絞れないため、(tenant_id, preferred_username)の索引を Issue #1910 で追加する予定です - レスポンスの形。
list/total_count/limit/offsetは同じです - 部分一致そのものの挙動。
preferred_username_likeは従来のpreferred_usernameと同じ照合をします
4.4 なぜ変えたか
100 万行・平均行幅 1058 bytes・heap 1121MB での実測(performance-test/db-bench/bench_user_search.sh)。
| クエリ | Before(部分一致) | After(provider_id なし) | After(provider_id あり) |
|---|---|---|---|
| COUNT | 337〜903 ms | 28〜145 ms | 0.11 ms |
| 一覧 | 828〜1229 ms | 35 ms | 0.08 ms |
一意キーは (tenant_id, provider_id, preferred_username) の順で、PostgreSQL 15 は途中の列を飛ばして探索できません。そのため provider_id を渡さない完全一致は、索引上でテナントの全エントリを読みます(それでも部分一致より 1 桁速い)。provider_id なしでも一意キー並みに引けるよう、Issue #1910 で索引を追加します。
部分一致は前後ワイルドカードのため索引が原理的に効かず、ヒット件数に関係なくテナントの全行を評価していました。一覧APIは COUNT を先に実行してから一覧を引くため、1 回の検索でスキャンが 2 回走ります。
4.5 動作確認
| ケース | テスト |
|---|---|
| 完全一致で当たる / 部分一致では当たらない | e2e/.../organization/organization_user_search_preferred_username.test.js |
preferred_username_like が部分一致で当たる / 大文字小文字を区別しない | 同上 |
5. Spring Boot 4.1 への更新
⚙️ 内部・運用。 Spring Boot を 4.0.8 から 4.1.1 に上げた(Issue #1886)。4.0 系の OSS サポートは 2026-12-31 に終わるため、セキュリティ修正を受け続けられるようにするのが目的。
5.1 主な依存ライブラリの版
Spring Boot が管理する版のうち、変わったものは次のとおり。
| ライブラリ | 4.0.8 | 4.1.1 |
|---|---|---|
| Spring Security | 7.0.7 | 7.1.1 |
| Spring Session | 4.0.5 | 4.1.1 |
| Micrometer | 1.16.7 | 1.17.1 |
Spring Framework(7.0.9)・Tomcat(11.0.24)・Jackson(3.1.5)・Logback(1.5.38)は変わらない。公開済みのセキュリティアドバイザリ(2026-08-20 分)は 4.0.8 / 4.1.1 のどちらにも取り込まれている。
5.2 変わらないもの
- API・設定・DB:idp-server のコードの変更は無い。Spring Boot 4.0 で非推奨になった API は使っておらず、
application.yamlのプロパティにも 4.1 での名前変更・削除は無い(spring-boot-properties-migratorで起動時に確認) - ビルド・実行環境:Gradle 8.14 / JDK 21 のまま(4.1 の要件は Gradle 8.14 以上、Java 17 以上)