# 機能設計書 178-MFA設定

## 概要

本ドキュメントは、Chatwootにおける多要素認証（MFA/2FA）設定機能の設計仕様を定義する。この機能は、ユーザーがTOTP（Time-based One-Time Password）ベースの2要素認証を有効化・無効化するためのAPIを提供する。

### 本機能の処理概要

**業務上の目的・背景**：
カスタマーサポートシステムでは、顧客データや会話履歴などの機密情報を扱うため、セキュリティの強化が重要である。多要素認証により、パスワード漏洩時でも不正アクセスを防止できる。Chatwootでは、Google AuthenticatorやAuthyなどのTOTPアプリを使用した2要素認証をサポートする。

**機能の利用シーン**：
- ユーザーがセキュリティ強化のためにMFAを有効化する場合
- MFAの設定後、TOTPコードを検証して有効化を完了する場合
- ユーザーがMFAを無効化したい場合（パスワード検証必須）
- MFAの現在の状態を確認する場合

**主要な処理内容**：
1. MFA機能の利用可能性確認
2. OTPシークレットの生成とプロビジョニングURI提供
3. TOTPコードの検証とMFA有効化
4. MFAの無効化（パスワード検証必須）
5. MFA状態の取得

**関連システム・外部連携**：
- TOTP: RFC 6238準拠のワンタイムパスワード生成
- QRコード: プロビジョニングURI用のQRコード生成（クライアント側）

**権限による制御**：
認証済みユーザーのみが自身のMFA設定を管理可能。システム全体でMFA機能が有効である必要がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 90 | MFA設定画面 | 主画面 | MFA有効化・無効化 |
| 89 | プロフィール設定画面 | 遷移元 | MFA設定画面への遷移 |

## 機能種別

セキュリティ設定 / 認証管理

## 入力仕様

### 入力パラメータ

#### showアクション
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| なし | - | - | 認証トークンのみで識別 | - |

#### createアクション（MFA有効化開始）
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| なし | - | - | 認証トークンのみで識別 | - |

#### verifyアクション（MFA有効化完了）
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| otp_code | String | Yes | 6桁のTOTPコード | 有効なOTPコード |

#### destroyアクション（MFA無効化）
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| otp_code | String | Yes | 6桁のTOTPコード | 有効なOTPコード |
| password | String | Yes | 現在のパスワード | 正しいパスワード |

### 入力データソース

- フロントエンド画面からのJSON形式リクエスト
- 認証トークンからのユーザー識別

## 出力仕様

### 出力データ

#### showアクション
| 項目名 | 型 | 説明 |
|--------|-----|------|
| feature_available | Boolean | MFA機能が利用可能か |
| enabled | Boolean | MFAが有効化されているか |
| backup_codes_generated | Boolean | バックアップコードが生成済みか |

#### createアクション
| 項目名 | 型 | 説明 |
|--------|-----|------|
| provisioning_url | String | TOTP用プロビジョニングURI |
| secret | String | OTPシークレット |

#### verifyアクション
| 項目名 | 型 | 説明 |
|--------|-----|------|
| enabled | Boolean | MFAが有効化されたか |
| backup_codes | Array | 生成されたバックアップコード（初回のみ） |

#### destroyアクション
| 項目名 | 型 | 説明 |
|--------|-----|------|
| enabled | Boolean | MFAの状態（false） |

### 出力先

- JSON形式でHTTPレスポンスとして返却

## 処理フロー

### 処理シーケンス

```
【MFA有効化フロー】
1. create: OTPシークレット生成
   └─ provisioning_urlとsecretを返却
2. ユーザーがTOTPアプリでシークレットを登録
3. verify: TOTPコード検証
   └─ 成功時: otp_required_for_login=true、バックアップコード生成

【MFA無効化フロー】
1. destroy: パスワードとTOTPコード検証
   └─ 成功時: OTP関連フィールドをクリア
```

### フローチャート

```mermaid
flowchart TD
    A[MFA設定リクエスト] --> B{MFA機能有効?}
    B -->|No| C[403 Forbidden]
    B -->|Yes| D{アクション種別}

    D -->|show| E[MFA状態返却]

    D -->|create| F{既にMFA有効?}
    F -->|Yes| G[エラー返却]
    F -->|No| H[OTPシークレット生成]
    H --> I[provisioning_url返却]

    D -->|verify| J{OTPコード有効?}
    J -->|No| K[エラー返却]
    J -->|Yes| L[MFA有効化]
    L --> M{バックアップコード済?}
    M -->|No| N[バックアップコード生成]
    M -->|Yes| O[完了]
    N --> O

    D -->|destroy| P{MFA有効?}
    P -->|No| Q[エラー返却]
    P -->|Yes| R{パスワード正しい?}
    R -->|No| S[エラー返却]
    R -->|Yes| T{OTPコード有効?}
    T -->|No| U[エラー返却]
    T -->|Yes| V[MFA無効化]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-178-01 | 機能可用性チェック | Chatwoot.mfa_enabled?がfalseの場合は403を返却 | 全アクション |
| BR-178-02 | 二重有効化防止 | 既にMFAが有効な場合はcreate/verifyを拒否 | create/verifyアクション |
| BR-178-03 | 無効化時の検証 | MFA無効化にはパスワードとOTPコードの両方が必要 | destroyアクション |
| BR-178-04 | バックアップコード自動生成 | MFA有効化時にバックアップコードが未生成なら自動生成 | verifyアクション |
| BR-178-05 | OTPシークレット暗号化 | otp_secretは暗号化して保存 | 保存時 |

### 計算ロジック

**プロビジョニングURI生成**:
```ruby
"otpauth://totp/#{label}?secret=#{secret}&issuer=Chatwoot"
```

**TOTPコード検証**:
- RFC 6238準拠の30秒間隔
- consumed_timestepで再利用攻撃を防止

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| MFA有効化開始 | users | UPDATE | otp_secretの設定 |
| MFA有効化完了 | users | UPDATE | otp_required_for_login=true、バックアップコード設定 |
| MFA無効化 | users | UPDATE | OTP関連フィールドのクリア |

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

#### users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE (create) | otp_secret | User.generate_otp_secret | 暗号化して保存 |
| UPDATE (verify) | otp_required_for_login | true | MFA有効フラグ |
| UPDATE (verify) | otp_backup_codes | 10個のコード配列 | 暗号化して保存 |
| UPDATE (destroy) | otp_secret | nil | クリア |
| UPDATE (destroy) | otp_required_for_login | false | 無効化 |
| UPDATE (destroy) | otp_backup_codes | nil | クリア |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | Unauthorized | 認証トークンが無効 | 再ログイン |
| 403 | Forbidden | MFA機能が無効 | システム管理者に連絡 |
| 422 | Unprocessable Entity | 既にMFAが有効（create時） | verifyまたはdestroyを使用 |
| 422 | Unprocessable Entity | MFAが無効（destroy時） | createを使用 |
| 422 | Unprocessable Entity | OTPコードが無効 | 正しいコードを入力 |
| 422 | Unprocessable Entity | パスワードが不正 | 正しいパスワードを入力 |

### リトライ仕様

特になし（OTPコードの再入力で対応）

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

verify_and_activate!はトランザクション内で実行され、MFA有効化とバックアップコード生成がアトミックに処理される。

## パフォーマンス要件

- レスポンス時間: 500ms以内

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

- OTPシークレットは暗号化して保存（encrypts :otp_secret）
- バックアップコードは暗号化して保存（encrypts :otp_backup_codes）
- MFA無効化にはパスワード検証が必須
- タイミング攻撃対策（constant-time比較）
- OTPコードの再利用防止（consumed_timestep）

## 備考

- Chatwoot.mfa_enabled?で機能の有効/無効を判定
- バックアップコードは10個生成、各8文字の16進数

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | user.rb | `app/models/user.rb` | MFA関連カラム（otp_secret, otp_required_for_login, otp_backup_codes等） |

**読解のコツ**: Userモデルのスキーマコメント（21-23行目）を参照。otp_secret、otp_backup_codesは暗号化される（83-84行目）。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | mfa_controller.rb | `app/controllers/api/v1/profile/mfa_controller.rb` | MFAコントローラーの全アクション |

**主要処理フロー**:
1. **2行目**: `before_action :check_mfa_feature_available` - MFA機能の利用可能性チェック
2. **3-4行目**: MFA有効/無効状態に基づくアクション制限
3. **5-6行目**: OTPコード・パスワード検証
4. **10-12行目**: `create` - OTPシークレット生成
5. **14-16行目**: `verify` - MFA有効化とバックアップコード生成
6. **18-20行目**: `destroy` - MFA無効化

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | management_service.rb | `app/services/mfa/management_service.rb` | MFA管理の核心ロジック |
| 3-2 | authentication_service.rb | `app/services/mfa/authentication_service.rb` | OTPコード認証ロジック |

**主要処理フロー**:
- **management_service.rb 4-7行目**: `enable_two_factor!` - OTPシークレット生成・保存
- **management_service.rb 9-14行目**: `disable_two_factor!` - MFA関連フィールドのクリア
- **management_service.rb 16-21行目**: `verify_and_activate!` - MFA有効化とバックアップコード生成
- **management_service.rb 31-36行目**: `generate_backup_codes!` - バックアップコード生成

#### Step 4: ビューテンプレートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | show.json.jbuilder | `app/views/api/v1/profile/mfa/show.json.jbuilder` | MFA状態レスポンス |
| 4-2 | create.json.jbuilder | `app/views/api/v1/profile/mfa/create.json.jbuilder` | プロビジョニング情報 |
| 4-3 | verify.json.jbuilder | `app/views/api/v1/profile/mfa/verify.json.jbuilder` | 有効化完了レスポンス |

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

```
Api::V1::Profile::MfaController
    │
    ├─ show
    │      └─ JBuilder (show.json.jbuilder)
    │
    ├─ create
    │      └─ Mfa::ManagementService#enable_two_factor!
    │             └─ User.generate_otp_secret
    │             └─ users UPDATE (otp_secret)
    │
    ├─ verify
    │      ├─ Mfa::AuthenticationService#authenticate
    │      │      └─ User#validate_and_consume_otp!
    │      └─ Mfa::ManagementService#verify_and_activate!
    │             └─ users UPDATE (otp_required_for_login, otp_backup_codes)
    │
    └─ destroy
           ├─ User#valid_password?
           ├─ Mfa::AuthenticationService#authenticate
           └─ Mfa::ManagementService#disable_two_factor!
                  └─ users UPDATE (otp_secret=nil, otp_required_for_login=false, otp_backup_codes=nil)
```

### データフロー図

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

【MFA有効化フロー】
POST /mfa (create) ───▶ ManagementService#enable_two_factor! ───▶ {provisioning_url, secret}
                              │
                              └─▶ users UPDATE (otp_secret)

POST /mfa/verify ─────▶ AuthenticationService#authenticate ───▶ {enabled, backup_codes}
(otp_code)                    │
                              └─▶ ManagementService#verify_and_activate!
                                    └─▶ users UPDATE (otp_required_for_login, otp_backup_codes)

【MFA無効化フロー】
DELETE /mfa ──────────▶ valid_password? + authenticate ───▶ {enabled: false}
(otp_code, password)         │
                              └─▶ ManagementService#disable_two_factor!
                                    └─▶ users UPDATE (clear OTP fields)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mfa_controller.rb | `app/controllers/api/v1/profile/mfa_controller.rb` | コントローラー | MFA APIのエントリーポイント |
| management_service.rb | `app/services/mfa/management_service.rb` | サービス | MFA管理の核心ロジック |
| authentication_service.rb | `app/services/mfa/authentication_service.rb` | サービス | OTPコード認証ロジック |
| user.rb | `app/models/user.rb` | モデル | MFA関連カラム、暗号化設定 |
| show.json.jbuilder | `app/views/api/v1/profile/mfa/show.json.jbuilder` | ビュー | MFA状態レスポンス |
| create.json.jbuilder | `app/views/api/v1/profile/mfa/create.json.jbuilder` | ビュー | プロビジョニング情報 |
| verify.json.jbuilder | `app/views/api/v1/profile/mfa/verify.json.jbuilder` | ビュー | 有効化完了レスポンス |
| destroy.json.jbuilder | `app/views/api/v1/profile/mfa/destroy.json.jbuilder` | ビュー | 無効化完了レスポンス |
| backup_codes.json.jbuilder | `app/views/api/v1/profile/mfa/backup_codes.json.jbuilder` | ビュー | バックアップコードレスポンス |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（379-384行目） |
