docs: update RBAC user isolation roadmap and add design memory

Updated the roadmap document to reflect the implemented three-step
permission check logic in the feature/simple-user-isolation branch.

Added comprehensive design memory documenting:
- Core problem and design conflicts
- Three-step permission check implementation
- Key design decisions and advantages
- Use cases and scenarios
- Design evolution process
This commit is contained in:
YueGuobin committed 2026-05-26 12:46:36 +08:00
1 parent ee36a9aec2
commit 9e5423f3f1
2 files changed
+337 -68

No files matched your search

@@ -8,13 +8,13 @@ GNS3 3.0 ships with a complete RBAC framework (ACE + Role + Privilege models), b
- List endpoints return unfiltered results
- Two GET endpoints have RBAC checks bypassed via FIXME
This document tracks the incremental work to close those gaps. Each phase is independent and deployable.
**This document has been updated to reflect the implemented solution in `feature/simple-user-isolation` branch.**
## Current State
| Resource | Route Check | List Filtering | Auto-ACE on Create | ACE Cleanup on Delete |
|---|---|---|---|---|
| Project | `Project.Audit/Modify/Allocate` | Partial — pool isolation exists but non-pool projects leak | **Missing** | Done |
| Project | `Project.Audit/Modify/Allocate` | **Implemented** — Three-step filtering | **Not needed** | Done |
| Template | `Template.Audit` **FIXME** | None — all templates returned | **Missing** | Done |
| Node | `Node.Audit/Modify/Allocate` | N/A (inherits project) | Inherits project | N/A |
| Link | `Link.Audit/Modify/Allocate` | N/A (inherits project) | Inherits project | N/A |
@@ -25,7 +25,49 @@ This document tracks the incremental work to close those gaps. Each phase is ind
| Appliance | `Appliance.Audit/Allocate` | None — all appliances returned | N/A (builtin) | N/A |
| Symbol | `Symbol.Audit/Allocate` | None — all symbols returned | N/A (builtin) | N/A |
## Architecture
## Implemented Solution: Project Isolation
### Three-Step Permission Check Logic
**Status**: ✅ Implemented in `feature/simple-user-isolation` branch
```python
# Step 1: ACE check - basic access permission
# Get projects user has ACE for
ace_projects = []
for project in controller.projects.values():
project_path = f"/projects/{project.id}"
if await rbac_repo.check_user_has_privilege(current_user.user_id, project_path, "Project.Audit"):
ace_projects.append(project)
# Step 2: Filter ace_projects by created_by - user's own projects
# Project sharing is only available through resource pools
user_projects = [p.asdict() for p in ace_projects if p.created_by == current_user.username]
projects.extend(user_projects)
# Step 3: Resource pool projects
# Projects shared through resource pools
user_pool_resources = await rbac_repo.get_user_pool_resources(current_user.user_id, "Project.Audit")
project_ids_in_pools = [str(r.resource_id) for r in user_pool_resources if r.resource_type == "project"]
pool_projects = [p.asdict() for p in controller.projects.values() if p.id in project_ids_in_pools]
projects.extend(pool_projects)
```
### Key Design Principles
1. **ACE for basic access control**: Controls whether user can access the system
2. **created_by for user isolation**: Controls which specific resources user can access
3. **Resource pools for project sharing**: The only mechanism for sharing projects between users
4. **No direct ACE sharing**: Users cannot configure ACE directly on specific projects to share them
### Advantages of This Approach
- **Fault tolerance**: Even with broad ACE configuration (`path: "/" + propagate: true`), user isolation remains effective
- **Clear separation**: Basic access, data ownership, and team sharing are clearly separated
- **Simple mechanism**: No complex auto-ACE or seen_project_ids tracking required
- **Performance**: Leverages existing created_by field, no schema changes needed
## Updated Architecture
```mermaid
graph TD
@@ -33,30 +75,30 @@ graph TD
WebUI
CLI
end
subgraph "Controller API"
Auth[get_current_active_user]
PrivCheck[has_privilege]
Routes[Resource Routes]
AutoACE[auto-ACE on create]
ListFilter[ACE-based list filtering]
ACE_Check[Step 1: ACE Check]
Owner_Filter[Step 2: Filter by created_by]
Pool_Check[Step 3: Resource Pools]
end
subgraph "RBAC Engine"
ACE[(ACE table)]
Role[(Role table)]
Privilege[(Privilege table)]
Checker[check_user_has_privilege]
end
WebUI --> Auth
CLI --> Auth
Auth --> Routes
Routes --> PrivCheck
Routes --> AutoACE
Routes --> ListFilter
PrivCheck --> Checker
ListFilter --> Checker
Routes --> ACE_Check
ACE_Check --> Checker
ACE_Check --> Owner_Filter
Owner_Filter --> Pool_Check
Pool_Check --> Checker
Checker --> ACE
Checker --> Role
Role --> Privilege
@@ -64,53 +106,48 @@ graph TD
## Business Process
### Project creation with auto-ACE
```mermaid
sequenceDiagram
actor U as User
participant API as POST /projects
participant Ctrl as Controller
participant ACE as ACE Table
U->>API: Create project
API->>API: has_privilege("Project.Allocate")
API->>Ctrl: add_project()
Ctrl-->>API: project
API->>ACE: create ACE<br/>(user=creator, role=User,<br/>path=/projects/{id})
API-->>U: 201 + project
```
### Project listing with ACE filtering
### Project listing with three-step filtering
```mermaid
sequenceDiagram
actor U as User
participant API as GET /projects
participant Ctrl as Controller
participant ACE as ACE Table
participant Controller as Controller
participant RBAC as RBAC Engine
U->>API: List projects
API->>API: get_current_active_user (not superadmin)
API->>RBAC: Step 1: ACE check on each project
loop Each project
API->>ACE: check_user_has_privilege(user, path, "Project.Audit")
ACE-->>API: True/False
RBAC-->>API: ACE results
end
API-->>U: filtered list
API->>API: Step 2: Filter by created_by
API-->>U: User's own projects
API->>RBAC: Step 3: Resource pool projects
RBAC-->>API: Pool projects
API-->>U: Combined list (own + pool)
```
## Phased Plan
## Updated Phased Plan
### Phase 1 — MVP: Project isolation
### ✅ Phase 1 — MVP: Project isolation (COMPLETED)
**Goal**: Users only see projects they created or were granted access to.
**Goal**: Users only see projects they created or were granted access to through resource pools.
| Task | Files | Detail |
|---|---|---|
| Auto-ACE on project create | `projects.py` — `create_project()` | After `add_project()`, create ACE: user=creator, role=User, path=`/projects/{id}` |
| Fix project list filtering | `projects.py` — `get_projects()` | Remove "sees all non-pool projects" path. Return only projects passing ACE check. |
| Task | Files | Status | Detail |
|---|---|---|---|
| Fix project list filtering | `projects.py` — `get_projects()` | ✅ **Implemented** | Three-step filtering: ACE check → created_by filter → resource pools |
**Estimate**: 2 files, ~30 lines changed.
**Result**:
- ✅ Users can only see projects they created
- ✅ Team collaboration through resource pools works
- ✅ Fault tolerance: Works correctly even with broad ACE configurations
- ✅ No schema changes required
- ✅ ~30 lines changed
### Phase 2 — Template isolation
@@ -118,9 +155,8 @@ sequenceDiagram
| Task | Files | Detail |
|---|---|---|
| Auto-ACE on template create | `templates.py` — `create_template()` | Same pattern as project |
| Fix template list filtering | `templates.py` — `get_templates()` | Filter by ACE; builtin templates always visible |
| Uncomment `Template.Audit` | `templates.py` lines 75, 167 | Restore `has_privilege("Template.Audit")` |
| Apply same pattern to templates | `templates.py` — `get_templates()` | Use same three-step filtering as projects |
| Uncomment `Template.Audit` | `templates.py` | Restore `has_privilege("Template.Audit")` checks |
**Dependency**: Web UI must handle 403 from `GET /templates/{id}`. Mitigation: keep builtin templates unconditionally visible so the UI always has data.
@@ -130,8 +166,8 @@ sequenceDiagram
| Task | Files |
|---|---|
| Auto-ACE on image upload | `images.py` — `upload_image()` |
| Fix image list filtering | `images.py` — `get_images()` |
| Apply same pattern to images | `images.py` — `get_images()` |
| Fix image list filtering | `images.py` |
| ACE cleanup on delete | `images.py` — `delete_image()` |
### Phase 4 — Default ACE for "Users" group (optional)
@@ -145,35 +181,66 @@ sequenceDiagram
## API Endpoints Changed
### Phase 1
### Phase 1 (Implemented)
| Method | Path | Change |
|---|---|---|
| `POST` | `/v3/projects` | Auto-create ACE for creator |
| `GET` | `/v3/projects` | Filter by user ACEs |
| `GET` | `/v3/projects` | Three-step filtering: ACE → created_by → resource pools |
### Phase 2
### Phase 2 (Planned)
| Method | Path | Change |
|---|---|---|
| `POST` | `/v3/templates` | Auto-create ACE for creator |
| `GET` | `/v3/templates` | Filter by user ACEs + builtin |
| `GET` | `/v3/templates` | Apply same three-step filtering |
| `GET` | `/v3/templates/{id}` | Restore `Template.Audit` check |
## Design Decisions
## Key Design Decisions
1. **Compute stays shared**: Computes are infrastructure, not user-owned. The `Compute.Audit` FIXME stays — all authenticated users see computes.
1. **Project sharing through resource pools only**: Users cannot configure ACE directly to share specific projects. All sharing must go through resource pools. This prevents permission configuration chaos and maintains clear ownership semantics.
2. **No DB migration required**: All phases use the existing ACE/role/privilege tables. No schema changes.
2. **No auto-ACE required**: The three-step filtering logic works without needing automatic ACE creation on project creation. The created_by field provides sufficient ownership information.
3. **Performance**: Project list filtering is O(n) — iterates all projects and checks ACE per project. Acceptable for < 500 projects. Can optimize later with direct ACE path queries.
3. **Fault-tolerant to ACE configuration**: Even if administrators configure broad ACE permissions (like `path: "/" + propagate: true`), user isolation remains effective because Step 2 filters by created_by.
4. **The FIXME dependency**: `Template.Audit` was commented out because web UI crashes on 403. Fix requires either (a) auto-ACE so users own their templates, or (b) web UI 403 handling.
4. **No DB migration required**: Uses existing ACE/role/privilege tables and created_by field. No schema changes needed.
## References
5. **Performance**: Project list filtering is O(n) where n is the total number of projects. Each project requires one ACE check. Acceptable for < 500 projects. Can optimize later with batch ACE queries if needed.
- Discussion: https://github.com/GNS3/gns3-server/discussions/1949
- RBAC models: `gns3server/db/models/acl.py`, `roles.py`, `privileges.py`
- RBAC repository: `gns3server/db/repositories/rbac.py`
- Auth dependency: `gns3server/api/routes/controller/dependencies/authentication.py`
- RBAC dependency: `gns3server/api/routes/controller/dependencies/rbac.py`
## Updated References
- **Implementation**: `gns3server/api/routes/controller/projects.py` (feature/simple-user-isolation branch)
- **Discussion**: https://github.com/GNS3/gns3-server/discussions/1949
- **RBAC models**: `gns3server/db/models/acl.py`, `roles.py`, `privileges.py`
- **RBAC repository**: `gns3server/db/repositories/rbac.py`
- **Auth dependency**: `gns3server/api/routes/controller/dependencies/authentication.py`
- **RBAC dependency**: `gns3server/api/routes/controller/dependencies/rbac.py`
- **Resource pools**: `gns3server/db/models/pools.py` and `gns3server/db/repositories/pools.py`
## Implementation Notes
### What Was Implemented
The `feature/simple-user-isolation` branch implements a robust user isolation mechanism that:
1. **Integrates with existing RBAC framework** without breaking changes
2. **Leverages the created_by field** that already exists in the Project model
3. **Uses three-step pipeline filtering** to avoid complex seen_project_ids tracking
4. **Supports team collaboration** through existing resource pool functionality
5. **Is fault-tolerant to ACE misconfiguration** - broad ACE permissions don't break user isolation
### What Was Not Implemented
The original roadmap's Phase 1 included auto-ACE creation on project creation. This was determined to be unnecessary because:
- The three-step filtering logic achieves user isolation without auto-ACE
- Auto-ACE would add complexity without significant benefit
- Project sharing through resource pools is cleaner than direct ACE configuration
### Future Work
The same three-step filtering pattern can be applied to:
- **Templates**: Replace the FIXME comment with proper filtering logic
- **Images**: Apply the same pattern for user image isolation
- **Other resources**: Extend the pattern as needed
This implementation provides a solid foundation for user isolation in GNS3 3.0+ while maintaining compatibility with the existing RBAC framework.