一键导入
spec-external-integration
外部サービス連携(External Service Integration)機能の開発・修正を行う際に使用。HTTP Request Executor, MappingRule, OAuth/HMAC認証実装時に役立つ。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
外部サービス連携(External Service Integration)機能の開発・修正を行う際に使用。HTTP Request Executor, MappingRule, OAuth/HMAC認証実装時に役立つ。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
UserInfoエンドポイント(UserInfo Endpoint)機能の開発・修正を行う際に使用。UserInfo claims、scopeフィルタリング、verified_claims実装時に役立つ。
外部API認証ユースケースの設定ガイド。外部API連携(認証委譲、リスク判定、OTP等)の interaction 設計、identity_match_field、MFA 2段階目、previous_interaction のヒアリングと設定JSONを提供。
ユースケース別セットアップのエントリポイント。ユーザーにユースケースを選択してもらい、対応するスキル(use-case-login, use-case-mfa等)にルーティングする。共通ワークフロー、前提条件、組み合わせパターンの概要を提供。
認証機能(Authentication Policy, MFA)の開発・修正を行う際に使用。認証ポリシー、パスワード、OTP、FIDO2、条件付き認証実装時に役立つ。
セキュリティ・脆弱性対策の開発・テストを行う際に使用。OAuth/OIDC攻撃対策、認証識別子切り替え攻撃、Session Fixation、マルチテナント分離、セキュリティテスト実装時に役立つ。
FIDO2/WebAuthn/パスキー関連の実装・設定・ドキュメント・テストを扱う時に使用。パスキー登録、認証、管理、アテステーション検証に関する作業で自動的に呼び出される。
| name | spec-external-integration |
| description | 外部サービス連携(External Service Integration)機能の開発・修正を行う際に使用。HTTP Request Executor, MappingRule, OAuth/HMAC認証実装時に役立つ。 |
documentation/docs/content_03_concepts/06-security-extensions/concept-02-external-service-integration.md - 外部連携概念外部サービス連携は、HTTP経由で外部APIと連携する層。
libs/
└── idp-server-platform/ # プラットフォーム基盤
└── .../platform/
├── http/
│ ├── HttpRequestExecutor.java
│ └── retry/
│ └── RetryStrategy.java
├── mapper/
│ ├── MappingRule.java # マッピングルール
│ ├── FunctionSpec.java # 関数仕様
│ ├── ConditionSpec.java # 条件仕様
│ ├── TypeConverter.java # 型変換
│ ├── ObjectCompositor.java # オブジェクト合成
│ └── functions/
│ ├── FormatFunction.java
│ ├── TrimFunction.java
│ ├── ReplaceFunction.java
│ ├── RegexReplaceFunction.java
│ └── ... (その他のマッピング関数)
└── auth/
├── OAuth2Authenticator.java
└── HmacAuthenticator.java
idp-server-platform/mapper/MappingRule.java 内の実際の構造:
public class MappingRule {
String from; // JSONPathソース
Object staticValue; // 静的値(fromの代わり)
String to; // マッピング先
List<FunctionSpec> functions; // 変換関数
ConditionSpec condition; // 条件
public MappingRule(String from, String to) {
this.from = from;
this.to = to;
}
public MappingRule(
String from,
String to,
List<FunctionSpec> functions
) {
this.from = from;
this.to = to;
this.functions = functions;
}
}
{
"mapping_rules": [
{
"from": "$.response.user.id",
"to": "external_user_id"
},
{
"from": "$.response.user.roles",
"to": "custom_properties.roles",
"functions": [
{
"name": "join",
"args": {
"separator": ","
}
}
]
}
]
}
idp-server-platform/mapper/functions/ 内に実装:
| クラス | 説明 | 使用例 |
|---|---|---|
FormatFunction | テンプレート置換 | {"template": "Bearer {{value}}"} |
TrimFunction | 空白除去 | - |
ReplaceFunction | 文字列置換 | {"from": "a", "to": "b"} |
RegexReplaceFunction | 正規表現置換 | {"pattern": "...", "replacement": "..."} |
使用場所: Federation(userinfo_mapping_rules)、Identity Verification(mapping_rules)
認証設定(authentication-config)の execution.function により、response.body_mapping_rules で参照できるパスが異なる。
email_authentication_challenge, email_authentication, sms_authentication_challenge 等)executor が直接返す Map<String, Object> がマッピング対象。
マッピングコンテキスト:
$ → executor の contents() そのもの
// 成功時: executor は Map.of() を返す(空)→ static_value で補完
// エラー時: executor は {error, error_description} を返す
"response": {
"body_mapping_rules": [
{ "static_value": "sent", "to": "status", "condition": { "operation": "missing", "path": "$.error" } },
{ "from": "$.error", "to": "error", "condition": { "operation": "exists", "path": "$.error" } },
{ "from": "$.error_description", "to": "error_description", "condition": { "operation": "exists", "path": "$.error_description" } }
]
}
http_request)重要:
oauth_authorizationを使う場合、同じhttp_requestオブジェクトに"auth_type": "oauth2"が必須。これが無いと OAuth 認証が実行されない。
executor の結果は execution_http_request でラップされる。
マッピングコンテキスト:
$.execution_http_request.status_code → HTTP ステータスコード
$.execution_http_request.response_headers → レスポンスヘッダー
$.execution_http_request.response_body → レスポンスボディ
// 必要なフィールドだけ明示的にマッピングする(ワイルドカード禁止)
// NG: { "from": "$.execution_http_request.response_body", "to": "*" }
// → 外部サービスの内部データ(verification_code 等)がクライアントに漏洩するリスク
"response": {
"body_mapping_rules": [
{ "from": "$.execution_http_request.response_body.status", "to": "status" },
{ "from": "$.execution_http_request.response_body.message", "to": "message", "condition": { "operation": "exists", "path": "$.execution_http_request.response_body.message" } },
{ "from": "$.execution_http_request.response_body.error", "to": "error", "condition": { "operation": "exists", "path": "$.execution_http_request.response_body.error" } },
{ "from": "$.execution_http_request.response_body.error_description", "to": "error_description", "condition": { "operation": "exists", "path": "$.execution_http_request.response_body.error_description" } }
]
}
execution.http_request.body_mapping_rules(送信リクエストの組み立て)で参照できるパス:
$.request_body → クライアントからのリクエストボディ
$.request_attributes → HTTP リクエスト属性
$.interaction → previous_interaction で取得した前のインタラクションの保存データ
※ $.previous_interaction ではない
"http_request": {
"body_mapping_rules": [
{ "from": "$.request_body", "to": "*" },
{ "from": "$.interaction.transaction_id", "to": "transaction_id" }
]
}
チャレンジ→検証のような2段階フローで、チャレンジの結果を検証時に引き継ぐ:
// Step 1: チャレンジ — レスポンスから transaction_id を保存
"http_request_store": {
"key": "email-authentication-challenge",
"interaction_mapping_rules": [
{ "from": "$.response_body.transaction_id", "to": "transaction_id" }
]
}
// Step 2: 検証 — 保存した transaction_id を送信ボディに注入
"previous_interaction": { "key": "email-authentication-challenge" },
"http_request": {
"body_mapping_rules": [
{ "from": "$.request_body", "to": "*" },
{ "from": "$.interaction.transaction_id", "to": "transaction_id" }
]
}
interaction_mapping_rules の $.response_body は外部サービスの生レスポンスを参照する($.execution_http_request ではない)。
idp-server-platform/http/ 内:
HTTP Request Executorは、リトライロジックとRate Limiting対応を提供します。
外部HTTP通信でネットワーク例外が発生した場合、HttpResponseResolver.mapExceptionToStatusCode() が適切なHTTPステータスコードに変換する。
| 例外 | ステータスコード | 意味 | リトライ対象 |
|---|---|---|---|
ConnectException | 503 Service Unavailable | 接続確立不可(ホスト到達不能、ポート閉鎖等) | はい |
SocketTimeoutException | 504 Gateway Timeout | ソケットレベルのタイムアウト | はい |
HttpTimeoutException | 504 Gateway Timeout | HTTPクライアントレベルのタイムアウト | はい |
InterruptedException | 503 Service Unavailable | スレッド中断 | はい |
IOException | 502 Bad Gateway | その他のI/Oエラー | はい |
| その他の例外 | 500 Internal Server Error | 予期しないエラー | いいえ |
レスポンスボディ: エラー時は以下の構造で返却される:
{
"error": "network_error",
"error_description": "例外メッセージ",
"exception_type": "ConnectException",
"retry_info": {
"retryable": true,
"reason": "connection_failed",
"category": "network_connectivity"
}
}
実装クラス: HttpResponseResolver(idp-server-platform/.../http/HttpResponseResolver.java)
retry_configuration で外部API呼び出しのリトライ動作を制御する。
{
"retry_configuration": {
"max_retries": 3,
"retryable_status_codes": [502, 503, 504],
"idempotency_required": true,
"backoff_delays": ["PT1S", "PT2S", "PT4S"]
}
}
| 設定 | 説明 |
|---|---|
max_retries | 最大リトライ回数 |
retryable_status_codes | リトライ対象のHTTPステータスコード(上記の例外マッピング結果も対象) |
idempotency_required | true の場合 Idempotency-Key ヘッダーを自動付与 |
backoff_delays | リトライ間隔(ISO 8601 Duration) |
外部APIが401または403を返した場合、OAuthトークンを再取得して自動リトライする(HttpRequestExecutor 内蔵)。
外部APIの HTTP ステータスとレスポンスボディの内容から、idp-server 内部のステータスコードを導出する。「HTTP は 200 だがボディが失敗を示す」外部サービス(例: イントロスペクションが active: false)を失敗として扱いたい場合に使う。
[...] が正準。authentication-configurations と identity-verification-configurations で共通(#1500 で統一)。toMap()/GET 出力も配列。{"configs": [...]} も読み込み可能。JsonConverter 中央登録の HttpResponseResolveConfigsDeserializer(読み=両形式受理)と HttpResponseResolveConfigsSerializer(書き=常に配列出力)のペアにより、入力・GET・DB保存のすべてが配列に統一される。旧wrapperで保存済みのデータも、設定の再保存時に配列へ自動正規化(遅延移行)。新規は配列で書くこと。mapped_status_code が結果ステータスになる(HttpResponseResolver.findMatchingConfig())。どれもマッチしなければ実レスポンスのステータスがそのまま使われる。http_request オブジェクト直下(retry_configuration や body_mapping_rules と同階層)。"http_request": {
"url": "https://api.example.com/introspect",
"method": "POST",
"response_resolve_configs": [
{
"conditions": [
{ "path": "$.response_body.active", "operation": "eq", "value": false }
],
"match_mode": "ALL",
"mapped_status_code": 401
}
]
}
| フィールド | 説明 |
|---|---|
conditions | 条件リスト(ConditionDefinition: path / operation / value) |
match_mode | ALL(AND)または ANY(OR)。大文字小文字を問わず、未指定時は ALL |
mapped_status_code | マッチ時に割り当てる内部ステータスコード |
条件 path の評価コンテキスト(HttpResponseResolver.createResultContext() が snake_case で構築):
| パス | 内容 |
|---|---|
$.status_code | 外部レスポンスの HTTP ステータスコード |
$.response_headers.* | レスポンスヘッダー |
$.response_body.* | レスポンスボディ(配列ボディはリストとして展開) |
mapped_status_code が 400 以上かつ実ステータスと異なる場合、warn ログが出力される。function: http_request)では、解決後ステータスが 400 以上だと AuthenticationExecutionResult.error(status, ...) となり、そのステータスがクライアントへ伝播する。実装クラス: HttpResponseResolveConfig / HttpResponseResolveConfigs(内部ラッパー、フィールドは configs) / HttpResponseResolver(idp-server-platform/.../http/)
単一の http_request に加え、http_requests(複数形)で複数APIを順次呼び出すことができる。
| 設定キー | 用途 |
|---|---|
http_request | 1つのAPIを呼び出す |
http_requests | 複数のAPIを順次呼び出す(前のレスポンスを次のリクエストで参照可能) |
{
"http_requests": [
{
"url": "https://api.example.com/auth",
"method": "POST",
"body_mapping_rules": [
{ "from": "$.request_body.email", "to": "username" },
{ "from": "$.request_body.password", "to": "password" }
]
},
{
"url": "https://api.example.com/users/me",
"method": "GET",
"header_mapping_rules": [
{
"from": "$.execution_http_requests[0].response_body.token",
"to": "Authorization",
"functions": [{ "name": "format", "args": { "template": "Bearer {{value}}" } }]
}
]
}
]
}
前のAPIのレスポンスを次のAPIで参照する場合:
$.execution_http_requests[0].status_code → 1番目のAPIのステータスコード
$.execution_http_requests[0].response_body.* → 1番目のAPIのレスポンスボディ
$.execution_http_requests[0].response_headers.* → 1番目のAPIのレスポンスヘッダー
$.execution_http_requests[1].response_body.* → 2番目のAPIのレスポンスボディ
http_requests の場合、response.body_mapping_rules では全ステップの結果を参照できる:
"response": {
"body_mapping_rules": [
{ "from": "$.execution_http_requests[1].response_body.user_id", "to": "external_user_id" },
{ "from": "$.execution_http_requests[1].response_body.email", "to": "email" },
{ "from": "$.execution_http_requests[1].response_body.name", "to": "name" }
]
}
header_mapping_rules で使える関数:
| 関数 | 用途 | 例 |
|---|---|---|
format | テンプレート置換 | "Bearer {{value}}" |
random_string | ランダム文字列生成 | リクエストID、Nonce |
now | 現在時刻 | タイムスタンプ |
連鎖リクエストでは、途中のAPIが失敗した場合に後続のAPIは実行されない(早期終了)。response.body_mapping_rules の condition で成功/失敗を判定する:
{
"condition": { "operation": "eq", "path": "$.execution_http_requests[0].status_code", "value": 200 }
}
"to": "*" でリクエストボディ全体をそのまま転送する:
{ "from": "$.request_body", "to": "*" } // クライアントのリクエストをそのまま外部APIに転送
e2e/src/tests/
└── (外部連携は各機能のテスト内で検証)
├── integration/ida/ # Identity Verification外部連携
└── usecase/advance/ # Federation外部連携
# ビルド
./gradlew :libs:idp-server-platform:compileJava
# テスト
cd e2e && npm test -- integration/ida/
cd e2e && npm test -- usecase/advance/
from) が正しいか確認