# 機能設計書 61-アクセス制御

## 概要

本ドキュメントは、LEGACY CMSにおけるアクセス制御機能の設計を記述する。本機能はACL（Access Control List）に基づき、ユーザーロールによるリソースへのアクセス権限チェックを実現する。

### 本機能の処理概要

本機能は、Zend FrameworkのZend_Aclコンポーネントを拡張したカスタムACLファクトリを使用して、ユーザーの権限チェックを行う。システム全体で一貫したアクセス制御を提供し、不正なアクセスからシステムを保護する。

**業務上の目的・背景**：CMSにおいて、コンテンツの編集・削除・公開などの操作は信頼できるユーザーに限定する必要がある。本機能により、管理者、編集者、一般ユーザーなど、異なるロールを持つユーザーに対して適切な権限を付与し、システムのセキュリティと運用の整合性を維持する。

**機能の利用シーン**：
- 管理画面へのログイン時のアクセス可否判定
- 記事・ページ・イベントなどのコンテンツ編集・削除時の権限チェック
- 新規コンテンツ作成時の権限確認
- ロール管理画面でのロール・権限の設定変更

**主要な処理内容**：
1. ユーザー認証後、グローバルACLオブジェクトを生成してビューに渡す
2. データベースからロール（users_roles）とリソース（users_resources）を取得
3. 権限情報（users_privileges）に基づいてロールとリソースの関係を設定
4. 各コントローラーアクションで `$this->view->acl->isAllowed()` を呼び出して権限チェック
5. 権限がない場合はエラー画面へフォワード

**関連システム・外部連携**：Zend_Aclコンポーネントと連携してACL機能を実現する。

**権限による制御**：本機能自体がシステム全体の権限制御を担う。ロールごとに許可されるリソース（操作）が異なり、データベースで管理される権限マッピングに基づいて判定を行う。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 29 | 404エラー画面 | 結果表示画面 | ページ未検出エラーの表示 |
| 30 | システムエラー画面 | 結果表示画面 | システムエラーの表示 |
| 31 | サイト閉鎖画面 | 結果表示画面 | メンテナンス中表示 |
| 32 | 管理ダッシュボード | 主画面 | 管理者権限チェックとダッシュボード表示 |
| 35 | 記事管理画面 | 参照画面 | 管理者権限チェック |
| 39 | 記事カテゴリ管理画面 | 参照画面 | 管理者権限チェック |
| 41 | ユーザー管理画面 | 参照画面 | 管理者権限チェック |
| 45 | ロール管理画面 | 主画面 | ユーザーロール一覧の管理 |
| 46 | ロール新規作成画面 | 主画面 | 新規ロールの作成処理 |
| 47 | ロール削除確認画面 | 主画面 | ロール削除の確認処理 |
| 48 | イベント管理画面 | 参照画面 | 管理者権限チェック |
| 52 | イベントカテゴリ管理画面 | 参照画面 | 管理者権限チェック |
| 56 | 会場管理画面 | 主画面 | 管理者権限チェックと会場管理 |
| 60 | ページ管理画面 | 参照画面 | 管理者権限チェック |
| 64 | メール管理画面 | 参照画面 | 管理者権限チェック |
| 67 | グループ管理画面 | 主画面 | 管理者権限チェック |
| 71 | ロール別メール画面 | 主画面 | 管理者権限チェック |
| 72 | ユーザー別メール画面 | 主画面 | 管理者権限チェック |
| 73 | 設定画面 | 主画面 | システム設定の一覧を表示 |
| 74 | 設定詳細画面 | 主画面 | 設定項目の詳細編集 |
| 75 | アセット管理画面 | 参照画面 | 管理者権限チェック |
| 85 | コメント管理画面 | 参照画面 | 管理者権限チェック |
| 87 | ローテーター管理画面 | 参照画面 | 管理者権限チェック |
| 91 | 管理者エラー画面 | 結果表示画面 | システムエラーの表示 |
| 92 | 管理者404エラー画面 | 結果表示画面 | ページ未検出エラーの表示 |
| 93 | 権限エラー画面 | 結果表示画面 | アクセス権限不足エラーの表示 |

## 機能種別

バリデーション / アクセス制御（ACL）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| user_role | int | Yes | ユーザーのロールID | 数値、users_rolesテーブルに存在するrole_id |
| resource | string | Yes | チェック対象のリソース名 | 文字列、users_resourcesテーブルに存在するres_resource |

### 入力データソース

- セッションストレージ（Zend_Auth）から取得したユーザー情報のロールID
- コントローラーで指定するリソース名（ハードコード）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| isAllowed | boolean | 指定されたロールがリソースにアクセス可能かどうか |
| hasRole | boolean | 指定されたロールがACLに登録されているかどうか |

### 出力先

- コントローラーでの条件分岐に使用
- ビューテンプレートでのUI表示制御

## 処理フロー

### 処理シーケンス

```
1. ユーザー認証確認
   └─ Zend_Auth::hasIdentity()で認証状態をチェック

2. グローバルACLオブジェクト生成
   └─ CMS_Acl_Factory::createGlobalAcl()を呼び出し

3. ロール情報の取得
   └─ users_rolesテーブルから全ロールを取得しACLに追加

4. リソース情報の取得
   └─ users_resourcesテーブルから全リソースを取得しACLに追加

5. 権限マッピングの設定
   └─ users_privilegesテーブルから権限情報を取得し、ロールとリソースの関係を設定

6. ACLオブジェクトをビューに渡す
   └─ $view->acl に設定

7. 各アクションで権限チェック
   └─ $this->view->acl->isAllowed($role, $resource)を呼び出し

8. 権限がない場合はエラー画面へフォワード
   └─ $this->_forward('privileges','error','admin')
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{認証済み?}
    B -->|No| C[ログイン画面へリダイレクト]
    B -->|Yes| D[グローバルACL生成]
    D --> E[ロール・リソース・権限を読み込み]
    E --> F{gadmin権限あり?}
    F -->|No| G[権限エラー画面へ]
    F -->|Yes| H[アクション実行前の権限チェック]
    H --> I{対象リソースの権限あり?}
    I -->|No| G
    I -->|Yes| J[アクション処理実行]
    J --> K[結果表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-61-01 | 管理画面アクセス権限 | gadminリソースへのアクセス権がないユーザーは管理画面にアクセスできない | 管理画面へのアクセス時 |
| BR-61-02 | 階層的権限チェック | モジュールレベルの権限（例: aarticles）がなければ、個別操作権限（例: aarticleedit）があっても操作不可 | 各操作実行時 |
| BR-61-03 | スーパー管理者ロール | ロールID=3（Administrator）は全てのリソースへのアクセス権を持つ | 常時 |
| BR-61-04 | ロール削除時の権限削除 | ロール削除時は関連するusers_privilegesレコードも削除される | ロール削除時 |
| BR-61-05 | ロール継承 | 新規ロール作成時に既存ロールの権限を継承可能 | ロール新規作成時 |

### 計算ロジック

権限判定は以下のロジックで行われる:

1. ACLオブジェクトにロールとリソースが登録されているか確認
2. users_privilegesテーブルで該当ロールとリソースの組み合わせが存在するか確認
3. 存在すればtrue、存在しなければfalseを返す

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ACL生成 | users_roles | SELECT | 全ロールを取得 |
| ACL生成 | users_resources | SELECT | 全リソースを取得 |
| ACL生成 | users_privileges | SELECT | 全権限マッピングを取得 |
| ロール保存 | users_roles | UPDATE | ロール情報の更新 |
| ロール保存 | users_privileges | DELETE | 既存権限の削除 |
| ロール保存 | users_privileges | INSERT | 新規権限の追加 |
| ロール新規作成 | users_roles | INSERT | 新規ロールの追加 |
| ロール新規作成 | users_privileges | INSERT | 継承元ロールの権限をコピー |
| ロール削除 | users_roles | DELETE | ロールの削除 |
| ロール削除 | users_privileges | DELETE | 関連権限の削除 |
| ロール削除 | users | UPDATE | 削除ロールのユーザーを移動先ロールに変更 |

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

#### users_roles

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | role_id, role_title, role_colour | 全レコード | ACL生成時 |
| INSERT | role_title, role_colour | フォーム入力値 | ロール新規作成時 |
| UPDATE | role_title, role_colour | フォーム入力値、WHERE role_id = ? | ロール編集時 |
| DELETE | - | WHERE role_id = ? | ロール削除時 |

#### users_resources

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | res_resource, res_module, res_group, res_description | 全レコード | ACL生成時 |

#### users_privileges

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | prv_resource, prv_role | 全レコード | ACL生成時 |
| SELECT | prv_resource | WHERE prv_role = ? | ロール編集画面でのチェックボックス初期値 |
| DELETE | - | WHERE prv_role = ? | ロール保存・削除時 |
| INSERT | prv_resource, prv_role | フォーム入力値（チェックされたリソース） | ロール保存時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 権限エラー | isAllowed()がfalseを返した場合 | error/privilegesアクションへフォワード |
| - | 認証エラー | 未認証状態で管理画面にアクセス | auth/loginへリダイレクト |
| - | ロール不存在 | 指定されたロールがACLに存在しない | hasRole()チェックでfalseを返す |

### リトライ仕様

本機能ではリトライは不要。権限エラーはユーザーへの通知で対処する。

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

ロール保存・削除時は複数テーブルを更新するが、明示的なトランザクション制御は実装されていない。データ整合性はアプリケーションロジックで担保している。

## パフォーマンス要件

- ACL生成はリクエストごとに実行されるため、テーブルサイズが増加しても高速に処理できる必要がある
- 現状の実装では全ロール・リソース・権限を取得しているため、大規模運用時はキャッシュの検討が必要

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

- 権限チェックは全ての管理画面アクションで実施
- ロールID=3（Administrator）は特権ロールとして全権限を持つ
- 権限がない操作へのアクセス試行はエラー画面へ遷移させ、操作内容は実行されない
- フロントエンド（ビュー）でも権限に基づいてボタン・リンクの表示/非表示を制御

## 備考

- 本機能はZend_Aclコンポーネントをラップした独自実装（CMS_Acl_Factory）
- リソース名は各モジュールで規約に従って命名（例: aarticles = 記事モジュール全般、aarticleedit = 記事編集）
- ビューヘルパー（UPrvForm）でロール編集フォームのチェックボックス生成をサポート

---

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

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

### 推奨読解順序

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

まず、ACLシステムで使用されるデータベーステーブル構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | database.sql | `database.sql` | users_roles、users_resources、users_privilegesテーブルの構造を確認 |

**読解のコツ**: 3つのテーブルの関係を理解する。users_rolesはロール定義、users_resourcesはアクセス制御対象の操作、users_privilegesはロールとリソースの多対多関係を表す。

#### Step 2: ACLファクトリを理解する

ACLオブジェクトを生成するファクトリクラスの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Factory.php | `library/CMS/Acl/Factory.php` | createGlobalAcl()メソッドでの全ACL構築ロジック |

**主要処理フロー**:
1. **15-36行目**: createResourceAcl() - 特定リソース用ACLの生成（個別用途）
2. **42-82行目**: createGlobalAcl() - グローバルACLの生成（メイン処理）
   - **53-68行目**: ロールとリソースをZend_Aclに登録
   - **70-79行目**: 権限マッピングをallow()で設定

#### Step 3: 管理画面ベースコントローラーを理解する

全管理画面コントローラーの親クラスでACLがどう初期化されるか確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Admin.php | `library/CMS/Controller/Action/Admin.php` | preDispatch()でのACL初期化 |

**主要処理フロー**:
- **17-59行目**: preDispatch() - 各アクション実行前に呼ばれる処理
  - **47-48行目**: Zend_Authで認証状態を確認
  - **52-53行目**: CMS_Acl_Factoryでグローバルaclを生成しビューに設定
  - **54-56行目**: gadmin権限をチェック、なければエラー画面へ

#### Step 4: 具体的なコントローラーでの権限チェックを理解する

実際のコントローラーでどのように権限チェックが行われているか確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ArticlesController.php | `application/modules/admin/controllers/ArticlesController.php` | 各アクションでのisAllowed()呼び出しパターン |

**主要処理フロー**:
- **32行目**: manageAction() - モジュール権限チェック `isAllowed($role, 'aarticles')`
- **57行目**: editAction() - 複合権限チェック `isAllowed($role, 'aarticles') & isAllowed($role, 'aarticleedit')`
- **47行目**: 権限なしの場合 `$this->_forward('privileges','error','admin')`

#### Step 5: ビューでの権限チェックを理解する

ビューテンプレートでどのようにUI表示を制御しているか確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | admin.phtml | `application/layouts/admin.phtml` | メニュー表示での権限チェック |
| 5-2 | manage.phtml | `application/modules/admin/views/scripts/articles/manage.phtml` | ボタン表示での権限チェック |

**主要処理フロー**:
- admin.phtml **63-69行目**: メニュー項目の表示/非表示制御
  ```php
  if($this->acl->hasRole($this->user->user_role) && $this->acl->isAllowed($this->user->user_role, 'aarticles'))
  ```
- manage.phtml **41-42行目**: 機能ボタンの表示/非表示制御

#### Step 6: ロール管理機能を理解する

ロールの作成・編集・削除処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | UsersController.php | `application/modules/admin/controllers/UsersController.php` | roleAction(), rolesaveAction(), rolenewAction(), roledeleteAction() |

**主要処理フロー**:
- **752-784行目**: roleAction() - ロール編集画面表示
- **789-902行目**: rolesaveAction() - ロール保存、権限の再設定
  - **840行目**: 既存権限を削除 `$registry->db->delete('users_privileges', 'prv_role = '.$this->view->role)`
  - **846-857行目**: 新しい権限を登録
- **907-1007行目**: rolenewAction() - ロール新規作成、継承機能
- **1012-1096行目**: roledeleteAction() - ロール削除、ユーザー移動

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

```
CMS_Controller_Action_Admin::preDispatch()
    │
    ├─ Zend_Auth::hasIdentity()
    │
    ├─ CMS_Acl_Factory::createGlobalAcl()
    │      ├─ $registry->db->select()->from('users_roles')
    │      ├─ $registry->db->select()->from('users_resources')
    │      ├─ $registry->db->select()->from('users_privileges')
    │      ├─ Zend_Acl::addRole()
    │      ├─ Zend_Acl::add() [リソース追加]
    │      └─ Zend_Acl::allow()
    │
    └─ Zend_Acl::isAllowed() [gadmin権限チェック]

[各コントローラーアクション]
    │
    └─ Zend_Acl::isAllowed() [個別権限チェック]
           │
           ├─ [許可] → アクション処理実行
           │
           └─ [拒否] → ErrorController::privilegesAction()
```

### データフロー図

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

users_roles ────────┐
                    │
users_resources ────┼──▶ CMS_Acl_Factory ──▶ Zend_Acl ──▶ $view->acl
                    │    ::createGlobalAcl()
users_privileges ───┘

                                                              │
                                                              ▼
user_role (セッション) ──▶ Zend_Acl::isAllowed() ──▶ true/false
resource (コード内定数) ─┘
                                                              │
                                                              ▼
                                                    [許可] アクション実行
                                                    [拒否] エラー画面表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Factory.php | `library/CMS/Acl/Factory.php` | ソース | ACLファクトリクラス、ACLオブジェクト生成 |
| Admin.php | `library/CMS/Controller/Action/Admin.php` | ソース | 管理画面コントローラー基底クラス、ACL初期化 |
| ArticlesController.php | `application/modules/admin/controllers/ArticlesController.php` | ソース | 記事管理コントローラー、権限チェック実装例 |
| UsersController.php | `application/modules/admin/controllers/UsersController.php` | ソース | ユーザー・ロール管理コントローラー |
| admin.phtml | `application/layouts/admin.phtml` | テンプレート | 管理画面レイアウト、メニュー権限制御 |
| manage.phtml | `application/modules/admin/views/scripts/articles/manage.phtml` | テンプレート | 記事一覧画面、ボタン権限制御 |
| role.phtml | `application/modules/admin/views/scripts/users/role.phtml` | テンプレート | ロール編集画面 |
| UPrvForm.php | `application/modules/admin/views/helpers/UPrvForm.php` | ソース | ロール編集フォームヘルパー |
| database.sql | `database.sql` | SQL | データベーススキーマ定義 |
