# 機能設計書 9-SAML設定

## 概要

本ドキュメントは、ChatwootシステムにおけるSAML設定機能の設計を記載する。エンタープライズ向けSAML SSO設定の管理を実現する。

### 本機能の処理概要

本機能は、アカウント単位でSAML IdP（Identity Provider）との連携設定を管理し、企業のシングルサインオン環境との統合を可能にする。

**業務上の目的・背景**：エンタープライズ環境では、組織の既存ID管理システム（Okta、Azure AD、OneLogin等）を使用したシングルサインオンが必須となる。本機能により、管理者はSAML IdPの設定（SSO URL、証明書、エンティティID）を管理し、組織のユーザーがIdP経由でChatwootにログインできるようにする。

**機能の利用シーン**：
- IT管理者がSAML IdPの設定を登録
- SAML証明書の更新
- ロールマッピングの設定
- SAML設定の削除（SSO無効化）

**主要な処理内容**：
1. SAML設定の作成（SSO URL、証明書、エンティティID）
2. SAML設定の表示・更新
3. ロールマッピングの設定
4. SP（Service Provider）エンティティIDの自動生成
5. SAML設定の削除

**関連システム・外部連携**：
- SAML 2.0 IdP（Okta、Azure AD、OneLogin、Google Workspace等）
- X.509証明書（IdP署名検証）

**権限による制御**：SAML設定はadministratorロールのみ操作可能。Enterprise版のみ利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 79 | セキュリティ設定画面 | 主画面 | エンタープライズSAML設定 |

## 機能種別

CRUD操作 / セキュリティ設定

## 入力仕様

### 入力パラメータ

#### SAML設定作成・更新

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| sso_url | String | Yes | IdPのSSOエンドポイントURL | 必須 |
| certificate | String | Yes | IdPのX.509証明書（PEM形式） | 有効なX.509証明書 |
| idp_entity_id | String | Yes | IdPのエンティティID | 必須 |
| sp_entity_id | String | No | SPのエンティティID | 自動生成（未指定時） |
| role_mappings | Hash | No | IdPロールからChatwootロールへのマッピング | - |

### 入力データソース

- 画面入力（セキュリティ設定画面）
- IdP管理画面から取得した設定値

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | SAML設定ID |
| sso_url | String | IdPのSSOエンドポイントURL |
| certificate | String | IdPのX.509証明書 |
| idp_entity_id | String | IdPのエンティティID |
| sp_entity_id | String | SPのエンティティID |
| role_mappings | Hash | ロールマッピング |
| saml_enabled | Boolean | SAML有効状態 |
| certificate_fingerprint | String | 証明書フィンガープリント（SHA1） |

### 出力先

- データベース（account_saml_settingsテーブル）
- HTTPレスポンスボディ（JSON形式）

## 処理フロー

### 処理シーケンス

```
【SAML設定作成フロー】
1. 設定作成要求
   └─ SamlSettingsController#create
   └─ administratorロール確認

2. 機能有効確認
   └─ check_saml_sso_enabled（グローバル設定）
   └─ check_saml_feature_enabled（アカウント機能フラグ）

3. SAML設定作成
   └─ Current.account.build_saml_settings
   └─ 証明書検証（X.509形式）
   └─ sp_entity_id自動生成（未指定時）
   └─ @saml_settings.save

4. アカウントユーザー更新
   └─ after_create_commit :update_account_users_provider
   └─ Saml::UpdateAccountUsersProviderJob（providerを'saml'に更新）

【SAML設定削除フロー】
5. 設定削除要求
   └─ SamlSettingsController#destroy
   └─ @saml_settings.destroy!

6. アカウントユーザーリセット
   └─ after_destroy_commit :reset_account_users_provider
   └─ Saml::UpdateAccountUsersProviderJob（providerを'email'に更新）
```

### フローチャート

```mermaid
flowchart TD
    A[SAML設定作成要求] --> B{administrator?}
    B -->|No| C[403 Forbidden]
    B -->|Yes| D{SAML SSO有効?}
    D -->|No| E[403: SSO not enabled]
    D -->|Yes| F{SAML機能有効?}
    F -->|No| G[403: Feature not enabled]
    F -->|Yes| H[build_saml_settings]
    H --> I{証明書有効?}
    I -->|No| J[422: Invalid certificate]
    I -->|Yes| K{sp_entity_id指定?}
    K -->|No| L[sp_entity_id自動生成]
    K -->|Yes| M[設定保存]
    L --> M
    M --> N[UpdateAccountUsersProviderJob]
    N --> O[200 OK + 設定情報]

    P[SAML設定削除要求] --> Q{administrator?}
    Q -->|No| R[403 Forbidden]
    Q -->|Yes| S[destroy!]
    S --> T[reset_account_users_provider]
    T --> U[204 No Content]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | Enterprise限定 | SAML設定はEnterprise版のみ利用可能 | 全操作 |
| BR-002 | グローバル設定 | ENABLE_SAML_SSO_LOGINがtrueの場合のみ利用可能 | 全操作 |
| BR-003 | 機能フラグ | アカウントでSAML機能が有効な場合のみ利用可能 | 全操作 |
| BR-004 | 証明書検証 | X.509形式の有効な証明書のみ登録可能 | 設定作成・更新時 |
| BR-005 | SP Entity ID自動生成 | 未指定時は`{FRONTEND_URL}/saml/sp/{account_id}`形式で生成 | 設定作成時 |
| BR-006 | プロバイダー更新 | SAML有効化時、アカウントユーザーのproviderを'saml'に更新 | 設定作成時 |
| BR-007 | プロバイダーリセット | SAML無効化時、アカウントユーザーのproviderを'email'に更新 | 設定削除時 |

### 計算ロジック

- **SP Entity ID**: `{FRONTEND_URL}/saml/sp/{account_id}`
- **証明書フィンガープリント**: OpenSSL::Digest::SHA1でDER形式の証明書をハッシュ化、コロン区切り大文字形式

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| SAML設定作成 | account_saml_settings | INSERT | 新規SAML設定レコード作成 |
| SAML設定取得 | account_saml_settings | SELECT | SAML設定情報取得 |
| SAML設定更新 | account_saml_settings | UPDATE | SAML設定情報更新 |
| SAML設定削除 | account_saml_settings | DELETE | SAML設定レコード削除 |
| ユーザープロバイダー更新 | users | UPDATE | provider カラム更新（非同期） |

### テーブル別操作詳細

#### account_saml_settings

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | account_id | Current.account.id | 必須、外部キー |
| INSERT/UPDATE | sso_url | パラメータ値 | 必須 |
| INSERT/UPDATE | certificate | パラメータ値（PEM形式） | 必須 |
| INSERT/UPDATE | idp_entity_id | パラメータ値 | 必須 |
| INSERT/UPDATE | sp_entity_id | パラメータ値または自動生成 | - |
| INSERT/UPDATE | role_mappings | パラメータ値（JSON） | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | SAML SSO無効（グローバル） | 管理者に連絡 |
| 403 | Forbidden | SAML機能無効（アカウント） | Enterprise契約を確認 |
| 403 | Forbidden | 権限不足 | administrator権限で再試行 |
| 422 | Unprocessable Entity | 証明書が無効なX.509形式 | 正しい証明書で再試行 |
| 422 | Unprocessable Entity | 必須パラメータ不足 | 必須項目を入力 |

### リトライ仕様

- 証明書検証失敗時は正しい証明書で再試行
- 必須パラメータ不足時は入力後再試行

## トランザクション仕様

- SAML設定の作成・更新は単一トランザクション
- アカウントユーザーのプロバイダー更新は非同期ジョブで実行

## パフォーマンス要件

- SAML設定取得: 100ms以内
- SAML設定作成・更新: 500ms以内
- プロバイダー更新ジョブ: バックグラウンド実行

## セキュリティ考慮事項

- SAML設定はadministratorのみ操作可能
- 証明書は有効なX.509形式のみ受け入れ
- SP Entity IDは予測困難なURLで生成
- SAML認証はruby-saml gemの署名検証に依存

## 備考

- Enterprise版限定機能
- グローバル設定ENABLE_SAML_SSO_LOGINで機能自体の有効/無効を制御
- アカウント機能フラグ'saml'で個別アカウントの利用可否を制御

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

SAML設定のテーブル構造とモデル定義を把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | account_saml_settings.rb | `enterprise/app/models/account_saml_settings.rb` | SAML設定モデルの構造 |

**読解のコツ**:
- 1-18行目: スキーマ定義（sso_url, certificate, idp_entity_id, sp_entity_id, role_mappings）
- 22-26行目: バリデーション（必須項目、証明書検証）
- 28行目: before_validation :set_sp_entity_id（SP Entity ID自動生成）
- 30-31行目: after_create_commit/after_destroy_commit（プロバイダー更新）
- 72-78行目: certificate_must_be_valid_x509（証明書検証）

#### Step 2: エントリーポイントを理解する

SAML設定コントローラーの処理フローを把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | saml_settings_controller.rb | `enterprise/app/controllers/api/v1/accounts/saml_settings_controller.rb` | CRUD アクション |

**主要処理フロー**:
1. **2-5行目**: before_actionでの権限・機能チェック
2. **9-15行目**: createアクションでSAML設定作成
3. **17-23行目**: updateアクションでSAML設定更新
4. **25-28行目**: destroyアクションでSAML設定削除
5. **52-56行目**: check_saml_feature_enabled（機能フラグチェック）
6. **58-62行目**: check_saml_sso_enabled（グローバル設定チェック）

#### Step 3: プロバイダー更新ジョブを理解する

SAML有効化/無効化時のユーザープロバイダー更新を把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | update_account_users_provider_job.rb | `enterprise/app/jobs/saml/update_account_users_provider_job.rb` | プロバイダー一括更新 |

### プログラム呼び出し階層図

```
Api::V1::Accounts::SamlSettingsController#create
    │
    ├─ check_saml_sso_enabled
    │      └─ GlobalConfigService.load('ENABLE_SAML_SSO_LOGIN')
    │
    ├─ check_saml_feature_enabled
    │      └─ Current.account.feature_enabled?('saml')
    │
    ├─ check_authorization
    │      └─ authorize(AccountSamlSettings)
    │
    └─ @saml_settings.save
           │
           ├─ before_validation :set_sp_entity_id
           │      └─ "{FRONTEND_URL}/saml/sp/{account_id}"
           │
           ├─ validate :certificate_must_be_valid_x509
           │      └─ OpenSSL::X509::Certificate.new(certificate)
           │
           └─ after_create_commit :update_account_users_provider
                  └─ Saml::UpdateAccountUsersProviderJob.perform_later(account_id, 'saml')
```

### データフロー図

```
[入力]                    [処理]                         [出力]

【SAML設定作成】
sso_url ──────────────▶ SamlSettingsController#create
certificate                     │
idp_entity_id                   ▼
sp_entity_id      ────▶ build_saml_settings
role_mappings                   │
                                ├─ set_sp_entity_id ──────▶ sp_entity_id (自動生成)
                                │
                                ├─ certificate検証 ───────▶ [有効/無効]
                                │
                                └─ save ──────────────────▶ account_saml_settings (DB)
                                       │
                                       ▼
                          UpdateAccountUsersProviderJob
                                       │
                                       ▼
                          users.update(provider: 'saml') ─▶ users (DB)
                                       │
                                       ▼
                          200 OK + 設定情報 ──────────────▶ JSON Response

【SAML設定削除】
DELETE要求 ───────────▶ SamlSettingsController#destroy
                                │
                                ▼
                          destroy! ───────────────────────▶ account_saml_settings (DELETE)
                                │
                                ▼
                          reset_account_users_provider
                                │
                                ▼
                          users.update(provider: 'email') ▶ users (DB)
                                │
                                ▼
                          204 No Content ─────────────────▶ Response
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| account_saml_settings.rb | `enterprise/app/models/account_saml_settings.rb` | モデル | SAML設定エンティティ |
| saml_settings_controller.rb | `enterprise/app/controllers/api/v1/accounts/saml_settings_controller.rb` | コントローラー | SAML設定API |
| update_account_users_provider_job.rb | `enterprise/app/jobs/saml/update_account_users_provider_job.rb` | ジョブ | プロバイダー一括更新 |
| account.rb | `enterprise/app/models/enterprise/account.rb` | モデル拡張 | has_one :saml_settings |
| routes.rb | `config/routes.rb` | 設定 | SAML設定ルート定義（85行目） |
| show.json.jbuilder | `enterprise/app/views/api/v1/accounts/saml_settings/show.json.jbuilder` | ビュー | SAML設定レスポンス |
