# 機能設計書 49-ログイン認証

## 概要

本ドキュメントは、Etherpadにおけるログイン認証機能の詳細設計を記載したものである。この機能は、ユーザー名とパスワードによる認証処理を行い、OAuth2フローにおけるログインプロンプトを処理する。

### 本機能の処理概要

**業務上の目的・背景**：
OAuth2/OpenID Connect認証フローにおいて、ユーザーの身元確認は重要なステップである。この機能は、ログインフォームから送信されたユーザー名とパスワードを検証し、認証成功時にはOIDCセッションを確立する。これにより、セキュアなユーザー認証とシングルサインオンが実現される。

**機能の利用シーン**：
- OAuth2認可フローでのユーザー認証
- 管理画面へのログイン（Basic認証としても機能）
- グループパッドへのアクセス時の認証

**主要な処理内容**：
1. ログインフォームからユーザー名・パスワードを受信
2. settings.usersに定義されたユーザー情報との照合
3. 認証成功時のOIDCインタラクション完了処理
4. 認証失敗時のエラーレスポンス

**関連システム・外部連携**：
- oidc-providerライブラリとの連携
- settings.jsonでのユーザー定義
- フロントエンドのログインフォーム

**権限による制御**：
- is_admin: trueのユーザーは管理者として認識される

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | SSO ログイン画面 | 主機能 | ユーザー名とパスワードを入力して認証処理 |
| 6 | 管理者ログイン画面 | 主機能 | 管理者のユーザー名とパスワードでBasic認証を実行 |

## 機能種別

認証処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| login | string | Yes | ユーザー名 | settings.usersに存在すること |
| password | string | Yes | パスワード | ユーザーのパスワードと一致すること |

### 入力データソース

- REST API: `POST /interaction/:uid`
- フォームデータ（multipart/form-data）

## 出力仕様

### 出力データ（成功時）

OAuth2認可フローのリダイレクト（認可コード付き）

### 出力データ（失敗時）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| error | string | エラーメッセージ（"Invalid login"） |

### 出力先

- 成功時: リダイレクト（redirect_uriへ）
- 失敗時: HTTP Response（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. ログインフォーム送信
   └─ POST /interaction/:uid にユーザー名・パスワードを送信

2. フォームデータ解析
   └─ IncomingFormでフォームデータをパース

3. OIDCインタラクション詳細取得
   └─ oidc.interactionDetails でセッション情報取得

4. プロンプト種別確認
   └─ prompt.name === 'login' を確認

5. ユーザー認証
   └─ settings.usersからユーザー検索
   └─ ユーザー名とパスワードの照合

6. 認証結果処理
   ├─ 成功: oidc.interactionFinished で認証完了
   └─ 失敗: エラーレスポンス返却

7. 認可フロー継続
   └─ 同意画面または認可コード発行へ
```

### フローチャート

```mermaid
flowchart TD
    A[ログインフォーム送信] --> B[フォームデータ解析]
    B --> C[インタラクション詳細取得]
    C --> D{prompt.name === 'login'?}
    D -->|No| E[他のプロンプト処理]
    D -->|Yes| F[settings.usersでユーザー検索]
    F --> G{ユーザー存在 && パスワード一致?}
    G -->|No| H[エラー: Invalid login]
    G -->|Yes| I[interactionFinished]
    I --> J[認可フロー継続]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-49-01 | ユーザー定義 | settings.usersに定義されたユーザーのみログイン可能 | 常時 |
| BR-49-02 | パスワード照合 | パスワードは平文で比較（ハッシュ化なし） | 常時 |
| BR-49-03 | アカウントID | ユーザー名がaccountIdとして使用される | 認証成功時 |
| BR-49-04 | セッション統合なし | mergeWithLastSubmission: falseで新規セッション | 認証成功時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| セッション保存 | LRUCache（メモリ） | INSERT/UPDATE | OIDCセッション情報 |

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

OIDCセッションはLRUCacheベースのメモリストレージに保存される

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Invalid login | ユーザー名が存在しない | 正しいユーザー名を入力 |
| - | Invalid login | パスワードが一致しない | 正しいパスワードを入力 |
| 500 | サーバーエラー | 内部処理エラー | サーバーログを確認 |

### リトライ仕様

ログイン失敗時は同じフォームで再試行可能

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

OIDCセッションはメモリベースのため、トランザクション管理なし

## パフォーマンス要件

- 認証処理: 100ms以内
- ユーザー数が少ない前提（配列検索）

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

- パスワードは設定ファイルに平文で保存される（要改善）
- ブルートフォース攻撃対策としてレート制限推奨
- HTTPSでの通信を推奨
- 認証失敗時のレスポンスは詳細を含まない

## 備考

- パスワードのハッシュ化は未実装（settings.jsonに平文保存）
- ロックアウト機能は未実装
- 認証成功後はOAuth2フローの次のステップ（同意または認可コード発行）に進む

---

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

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

### 推奨読解順序

#### Step 1: エンドポイントを理解する

POST /interaction/:uid エンドポイントを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | OAuth2Provider.ts | `src/node/security/OAuth2Provider.ts` | インタラクションエンドポイント |

**読解のコツ**:
- **157-227行目**: POST /interaction/:uid の全体像
- **158-161行目**: フォームデータのパース
- **162行目**: interactionDetailsでセッション情報取得

#### Step 2: ログイン処理を理解する

prompt.name === 'login' の処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | OAuth2Provider.ts | `src/node/security/OAuth2Provider.ts` | ログイン処理ブロック |

**主要処理フロー**:
- **167-189行目**: ログイン処理ブロック
- **168-177行目**: settings.usersからユーザー配列を生成
- **178行目**: ユーザー名・パスワード照合
- **179-182行目**: 認証失敗時のエラーレスポンス
- **184-188行目**: 認証成功時のinteractionFinished呼び出し

#### Step 3: ログイン画面表示を理解する

GET /interaction/:uid のログイン画面リダイレクトを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | OAuth2Provider.ts | `src/node/security/OAuth2Provider.ts` | ログイン画面リダイレクト |

**主要処理フロー**:
- **230-259行目**: GET /interaction/:uid
- **238-244行目**: prompt.name === 'login' でログイン画面にリダイレクト
- **240-243行目**: /views/login.html へリダイレクト

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

```
GET /interaction/:uid (ログイン画面表示)
    │
    ├─ oidc.interactionDetails(req, res)
    │      └─ セッション情報取得
    │
    └─ res.redirect('/views/login.html')

POST /interaction/:uid (ログイン処理)
    │
    ├─ IncomingForm.parse(req)
    │      └─ {login, password} 取得
    │
    ├─ oidc.interactionDetails(req, res)
    │      └─ prompt, params, session 取得
    │
    ├─ settings.users から usersArray1 生成
    │
    ├─ usersArray1.find() でユーザー検索
    │      └─ username === login && password === password
    │
    └─ oidc.interactionFinished(req, res, {login: {accountId}})
```

### データフロー図

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

login (string)      ───┐
                       ├───▶  POST /interaction/:uid  ───▶  リダイレクト
password (string)   ───┘              │                     または
                                      ▼                     エラーJSON
                             settings.users照合
                                      │
                                      ▼
                             interactionFinished
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| OAuth2Provider.ts | `src/node/security/OAuth2Provider.ts` | ソース | ログイン処理の実装 |
| login.html | `src/static/oidc/login.html` | 静的ファイル | ログインフォーム画面 |
| Settings.ts | `src/node/utils/Settings.ts` | ソース | ユーザー設定読み込み |
| OIDCAdapter.ts | `src/node/security/OIDCAdapter.ts` | ソース | セッション保存 |
