diff --git a/docs/gns3-copilot/README.md b/docs/gns3-copilot/README.md new file mode 100644 index 000000000..a0eb27373 --- /dev/null +++ b/docs/gns3-copilot/README.md @@ -0,0 +1,136 @@ +# GNS3 AI Copilot Documentation + +This directory contains design documentation, implementation guides, and future plans for the GNS3 AI Copilot feature. + +## Directory Structure + +``` +docs/gns3-copilot/ +├── README.md # This file +├── implemented/ # Implemented features and designs +│ ├── chat-api.md # Chat API design (SSE, session management) +│ ├── llm-model-configs.md # LLM model configuration system +│ ├── command-security.md # Command security and filtering +│ └── context-window-management.md # Context window optimization +├── todo/ # Planned features and designs +│ ├── jinja2-config-templates-system.md # Config template system +│ ├── config-templates-implementation-guide.md # Template implementation +│ ├── ai-prompting-for-config-templates.md # AI prompts for templates +│ ├── acl-web-ui-implementation-guide.md # ACL/ACL Web UI +│ ├── hitl-implementation-plan.md # HITL (Human-in-the-Loop) +│ ├── vision-topology-creation.md # Vision-based topology +│ └── ... # More planned features +└── guides/ # User and developer guides (TBD) +``` + +## Implemented Features + +### Chat API (`implemented/chat-api.md`) +The core Chat API that enables AI-powered conversations within GNS3 projects. + +**Key Features:** +- Server-Sent Events (SSE) for streaming responses +- Project-level session isolation +- Session management (CRUD operations) +- Statistics tracking (messages, tokens, LLM calls) +- User-level LLM configuration + +**Status:** ✅ Implemented + +### LLM Model Configs (`implemented/llm-model-configs.md`) +Multi-level LLM model configuration system. + +**Key Features:** +- System-wide defaults +- Group-level configurations +- User-level overrides +- Runtime parameter adjustment +- Model provider abstraction + +**Status:** ✅ Implemented + +### Command Security (`implemented/command-security.md`) +Security framework for AI-generated commands. + +**Key Features:** +- Command filtering and validation +- Dangerous operation detection +- HITL (Human-in-the-Loop) confirmations +- Audit logging + +**Status:** ✅ Implemented + +### Context Window Management (`implemented/context-window-management.md`) +Optimization strategies for handling large project contexts. + +**Key Features:** +- Intelligent content filtering +- Token usage optimization +- Summary generation +- Context compression + +**Status:** ✅ Implemented + +## Planned Features + +### Jinja2 Configuration Templates (`todo/jinja2-config-templates-system.md`) +Template-based configuration generation system. + +**Planned Features:** +- Vendor-specific templates (Cisco, Juniper, Huawei, etc.) +- JSON schema validation +- AI generates structured data → Templates render configs +- Multi-vendor support + +**Status:** 📋 Design Complete, Implementation Pending + +### ACL Web UI (`todo/acl-web-ui-implementation-guide.md`) +Web-based ACL (Access Control List) management interface. + +**Status:** 📋 Design Complete + +### HITL Implementation (`todo/hitl-implementation-plan.md`) +Enhanced Human-in-the-Loop confirmation workflows. + +**Status:** 📋 Design Complete + +### Vision Topology Creation (`todo/vision-topology-creation.md`) +Create network topologies from images/diagrams. + +**Status:** 📋 Design Complete + +## Contributing + +When adding new documentation: + +1. **Design Phase:** Add new documents to `todo/` +2. **Implementation:** Move to `implemented/` when feature is complete +3. **Naming:** + - `todo/`: Use descriptive names like `{feature}-implementation-guide.md` + - `implemented/`: Use concise names like `{feature}.md` + +## Document Status Legend + +| Status | Description | +|--------|-------------| +| ✅ Implemented | Feature is fully implemented and deployed | +| 📋 Design Complete | Design is done, awaiting implementation | +| 🚧 In Progress | Currently being implemented | +| 💡 Proposed | Initial idea or proposal | + +## Related Documentation + +- [GNS3 Server API Documentation](https://api.gns3.com/) +- [GNS3 Web UI Documentation](https://docs.gns3.com/) +- [LangGraph Documentation](https://langchain-ai.github.io/langgraph/) +- [FastAPI Documentation](https://fastapi.tiangolo.com/) + +## Quick Links + +- **Current Feature Branch:** `feature/ai-copilot-bridge` +- **Main Branch:** `master` +- **Issue Tracker:** [GitHub Issues](https://github.com/GNS3/gns3-server/issues) + +--- + +_Last updated: 2026-03-10_ diff --git a/docs/gns3-copilot/ai-chat-api-design.md b/docs/gns3-copilot/implemented/chat-api.md similarity index 100% rename from docs/gns3-copilot/ai-chat-api-design.md rename to docs/gns3-copilot/implemented/chat-api.md diff --git a/docs/gns3-copilot/command-security.md b/docs/gns3-copilot/implemented/command-security.md similarity index 100% rename from docs/gns3-copilot/command-security.md rename to docs/gns3-copilot/implemented/command-security.md diff --git a/docs/gns3-copilot/context-window-management.md b/docs/gns3-copilot/implemented/context-window-management.md similarity index 100% rename from docs/gns3-copilot/context-window-management.md rename to docs/gns3-copilot/implemented/context-window-management.md diff --git a/docs/gns3-copilot/llm-model-configs-api.md b/docs/gns3-copilot/implemented/llm-model-configs.md similarity index 100% rename from docs/gns3-copilot/llm-model-configs-api.md rename to docs/gns3-copilot/implemented/llm-model-configs.md diff --git a/docs/gns3-copilot/todo/acl-web-ui-implementation-guide.md b/docs/gns3-copilot/todo/acl-web-ui-implementation-guide.md deleted file mode 100644 index ead926d9a..000000000 --- a/docs/gns3-copilot/todo/acl-web-ui-implementation-guide.md +++ /dev/null @@ -1,1235 +0,0 @@ -# ACL Web UI Implementation Guide - -**Document Status**: Design Phase -**Priority**: High -**Created**: 2026-03-06 -**Target Audience**: Frontend Developers - ---- - -## Table of Contents - -- [Feature Overview](#feature-overview) -- [API Endpoints Details](#api-endpoints-details) -- [Data Structures](#data-structures) -- [Frontend Implementation Guide](#frontend-implementation-guide) -- [UI/UX Design Recommendations](#uiux-design-recommendations) -- [Common Scenarios](#common-scenarios) -- [Error Handling](#error-handling) -- [Example Code](#example-code) - ---- - -## Feature Overview - -### Objective - -Implement ACL (Access Control List) management functionality in the GNS3 Web UI, allowing administrators to manage user permissions through a graphical interface. - -### Core Features - -1. **View ACL List** - Display all ACEs (Access Control Entries) -2. **Create ACE** - Add new access control entries -3. **Edit ACE** - Modify existing ACE properties -4. **Delete ACE** - Remove unwanted access control entries -5. **Get Available Endpoints** - Retrieve list of resources that can be configured with ACL - -### User Flow - -``` -Administrator Login - ↓ -Navigate to "Permission Management" page - ↓ -View existing ACL list - ↓ -Select action: - - Create new ACE → Fill form → Submit - - Edit existing ACE → Modify form → Save - - Delete ACE → Confirm → Delete -``` - ---- - -## API Endpoints Details - -### Base URL - -``` -http://localhost:3080/v3/access/aces -``` - -### 1. Get All ACEs - -**Endpoint**: `GET /v3/access/aces` - -**Privilege**: `ACE.Audit` - -**Request Example**: -```javascript -const response = await fetch('/v3/access/aces', { - headers: { - 'Authorization': `Bearer ${token}` - } -}); -const aces = await response.json(); -``` - -**Response Example**: -```json -[ - { - "ace_id": "550e8400-e29b-41d4-a716-446655440000", - "path": "/projects", - "user_id": "650e8400-e29b-41d4-a716-446655440001", - "group_id": null, - "role_id": "750e8400-e29b-41d4-a716-446655440002", - "allowed": true, - "propagate": true, - "ace_type": "user", - "created_at": "2026-03-06T10:00:00Z", - "updated_at": "2026-03-06T10:00:00Z" - } -] -``` - ---- - -### 2. Get Single ACE - -**Endpoint**: `GET /v3/access/aces/{ace_id}` - -**Privilege**: `ACE.Audit` - -**Request Example**: -```javascript -const response = await fetch(`/v3/access/aces/${aceId}`, { - headers: { - 'Authorization': `Bearer ${token}` - } -}); -const ace = await response.json(); -``` - ---- - -### 3. Create ACE - -**Endpoint**: `POST /v3/access/aces` - -**Privilege**: `ACE.Allocate` - -**Request Example**: -```javascript -const newAce = { - path: "/projects", - user_id: "550e8400-e29b-41d4-a716-446655440000", - role_id: "750e8400-e29b-41d4-a716-446655440002", - allowed: true, - propagate: true -}; - -const response = await fetch('/v3/access/aces', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify(newAce) -}); -const createdAce = await response.json(); -``` - -**Response**: `201 Created` + Created ACE object - ---- - -### 4. Update ACE ⭐ Core Feature - -**Endpoint**: `PUT /v3/access/aces/{ace_id}` - -**Privilege**: `ACE.Modify` - -**Request Example**: -```javascript -const updatedAce = { - path: "/projects/updated", - allowed: false, - propagate: false -}; - -const response = await fetch(`/v3/access/aces/${aceId}`, { - method: 'PUT', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify(updatedAce) -}); -const updated = await response.json(); -``` - -**Important**: -- Supports **partial updates** - only submit fields to modify -- `user_id` and `group_id` cannot both be present (choose one) -- `path` must match an existing API endpoint - ---- - -### 5. Delete ACE - -**Endpoint**: `DELETE /v3/access/aces/{ace_id}` - -**Privilege**: `ACE.Allocate` - -**Request Example**: -```javascript -const response = await fetch(`/v3/access/aces/${aceId}`, { - method: 'DELETE', - headers: { - 'Authorization': `Bearer ${token}` - } -}); -// Response: 204 No Content -``` - ---- - -### 6. Get Available Endpoints (for Path Selection) - -**Endpoint**: `GET /v3/access/aces/endpoints` - -**Privilege**: `ACE.Audit` - -**Request Example**: -```javascript -const response = await fetch('/v3/access/aces/endpoints', { - headers: { - 'Authorization': `Bearer ${token}` - } -}); -const endpoints = await response.json(); -``` - -**Response Example**: -```json -[ - { - "endpoint": "/", - "name": "All endpoints", - "endpoint_type": "root" - }, - { - "endpoint": "/projects", - "name": "All projects", - "endpoint_type": "project" - }, - { - "endpoint": "/projects/123e4567-e89b-12d3-a456-426614174000", - "name": "Project \"My Project\"", - "endpoint_type": "project" - }, - { - "endpoint": "/projects/123e4567-e89b-12d3-a456-426614174000/nodes", - "name": "All nodes in project \"My Project\"", - "endpoint_type": "node" - }, - { - "endpoint": "/pools", - "name": "All resource pools", - "endpoint_type": "pool" - } -] -``` - ---- - -### 7. Get Related Data - -#### Get Users List - -**Endpoint**: `GET /v3/access/users` - -**Privilege**: `User.Audit` - -```javascript -const response = await fetch('/v3/access/users', { - headers: { 'Authorization': `Bearer ${token}` } -}); -const users = await response.json(); -``` - -#### Get User Groups List - -**Endpoint**: `GET /v3/access/groups` - -**Privilege**: `Group.Audit` - -```javascript -const response = await fetch('/v3/access/groups', { - headers: { 'Authorization': `Bearer ${token}` } -}); -const groups = await response.json(); -``` - -#### Get Roles List - -**Endpoint**: `GET /v3/access/roles` - -**Privilege**: `Role.Audit` - -```javascript -const response = await fetch('/v3/access/roles', { - headers: { 'Authorization': `Bearer ${token}` } -}); -const roles = await response.json(); -``` - ---- - -## Data Structures - -### ACE Object - -```typescript -interface ACE { - ace_id: string; // UUID - path: string; // Resource path, e.g., "/projects" - user_id?: string; // User ID (choose one with group_id) - group_id?: string; // User group ID (choose one with user_id) - role_id: string; // Role ID - allowed: boolean; // Whether allowed (default true) - propagate: boolean; // Whether to propagate to child paths (default true) - ace_type: "user" | "group"; // "user" or "group" - created_at: string; // ISO 8601 timestamp - updated_at: string; // ISO 8601 timestamp -} -``` - -### ACECreate (Creating ACE) - -```typescript -interface ACECreate { - path: string; - user_id?: string; - group_id?: string; - role_id: string; - allowed?: boolean; - propagate?: boolean; -} -``` - -### ACEUpdate (Updating ACE) - -```typescript -interface ACEUpdate { - path?: string; - user_id?: string; - group_id?: string; - role_id?: string; - allowed?: boolean; - propagate?: boolean; -} -``` - -### Endpoint Object - -```typescript -interface Endpoint { - endpoint: string; // Endpoint path - name: string; // Display name - endpoint_type: string; // "root" | "project" | "node" | "link" | "user" | "group" | "role" | "pool" -} -``` - ---- - -## Frontend Implementation Guide - -### Recommended Tech Stack - -- **Framework**: React / Vue / Angular -- **State Management**: Redux / Vuex / NgRx -- **UI Components**: Material-UI / Ant Design / Element Plus -- **HTTP Client**: Axios / Fetch API - -### Core Component Design - -#### 1. ACE List Component - -``` - - ├── # Filter - ├── # ACE table - │ ├── - │ ├── - │ └── ... - └── # Create button -``` - -#### 2. ACE Form Component (Create/Edit) - -``` - # or mode="edit" - ├── # Path selector - ├── # User/group selector - ├── # Role selector - ├── # Allow/deny toggle - ├── # Propagate switch - └── -``` - -#### 3. Endpoint Selector Component - -``` - - ├── # Tree structure showing endpoints - │ ├── - │ ├── - │ └── ... - └── # Search box -``` - ---- - -### State Management - -```typescript -// Redux example -interface ACLState { - aces: ACE[]; - endpoints: Endpoint[]; - users: User[]; - groups: Group[]; - roles: Role[]; - loading: boolean; - error: string | null; -} - -// Actions -const loadACEs = () => async (dispatch) => { - dispatch({ type: 'ACL_LOAD_START' }); - try { - const aces = await api.getACEs(); - dispatch({ type: 'ACL_LOAD_SUCCESS', payload: aces }); - } catch (error) { - dispatch({ type: 'ACL_LOAD_ERROR', payload: error.message }); - } -}; - -const createACE = (ace: ACECreate) => async (dispatch) => { - const newAce = await api.createACE(ace); - dispatch({ type: 'ACL_CREATE_SUCCESS', payload: newAce }); -}; - -const updateACE = (aceId: string, updates: ACEUpdate) => async (dispatch) => { - const updated = await api.updateACE(aceId, updates); - dispatch({ type: 'ACL_UPDATE_SUCCESS', payload: updated }); -}; - -const deleteACE = (aceId: string) => async (dispatch) => { - await api.deleteACE(aceId); - dispatch({ type: 'ACL_DELETE_SUCCESS', payload: aceId }); -}; -``` - ---- - -## UI/UX Design Recommendations - -### 1. List Page Layout - -``` -┌─────────────────────────────────────────────────────────┐ -│ Permission Management [New ACE] │ -├─────────────────────────────────────────────────────────┤ -│ Filters: [User/Group] [Role] [Path Type] [Status] │ -├─────────────────────────────────────────────────────────┤ -│ ┌───────────────────────────────────────────────────┐ │ -│ │ Path │ User/Group │ Role │ Allow │ Action│ │ -│ ├───────────────────────────────────────────────────┤ │ -│ │ /projects │ user1 │ User │ ✓ │ Edit │ │ -│ │ /projects/123 │ group1 │ Auditor│ ✓ │ Edit │ │ -│ │ /pools/456 │ user2 │ User │ ✗ │ Edit │ │ -│ └───────────────────────────────────────────────────┘ │ -│ [Load More] │ -└─────────────────────────────────────────────────────────┘ -``` - -### 2. Create/Edit Form - -``` -┌────────────────────────────────────────────┐ -│ New Access Control Entry (ACE) [Cancel]│ -├────────────────────────────────────────────┤ -│ │ -│ Resource Path * │ -│ ┌──────────────────────────────────────┐ │ -│ │ ▼ Select Endpoint [Search]│ │ -│ └──────────────────────────────────────┘ │ -│ Hint: Select the resource path to control │ -│ │ -│ Apply To * │ -│ ○ User □ User Group │ -│ ┌──────────────────────────────────────┐ │ -│ │ ▼ Select User │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ Role * │ -│ ┌──────────────────────────────────────┐ │ -│ │ User ▼ │ │ -│ └──────────────────────────────────────┘ │ -│ Note: This role includes Project.Audit │ -│ and other privileges │ -│ │ -│ Permission Settings │ -│ ○ Allow Access ● Deny Access │ -│ │ -│ □ Propagate to Child Paths │ -│ Note: When checked, permission applies │ -│ to all child resources │ -│ │ -│ [Cancel] [Save] │ -└────────────────────────────────────────────┘ -``` - -### 3. Endpoint Selector (Tree Structure) - -``` -┌────────────────────────────────────────────┐ -│ Select Resource Path [Search] │ -├────────────────────────────────────────────┤ -│ 📁 / (All endpoints) │ -│ 📁 /projects (All projects) │ -│ 📁 My Project │ -│ 📁 /nodes (All nodes) │ -│ 📄 Router1 │ -│ 📄 Switch1 │ -│ 📁 /links (All links) │ -│ 📁 /pools (All resource pools) │ -│ 📄 Production Pool │ -│ 📁 /templates (All templates) │ -└────────────────────────────────────────────┘ -``` - -### 4. Interaction Design Points - -#### Loading States -```javascript -// Show skeleton screen - - -// Or progress bar - -``` - -#### Error Messages -```javascript -// Form validation error - - Path cannot be empty - - -// API error - -``` - -#### Confirmation Dialog -```javascript -// Delete confirmation - - Confirm Delete - - Are you sure you want to delete this ACE? This action cannot be undone. - - - - - - -``` - ---- - -## Common Scenarios - -### Scenario 1: Create User-Level ACE - -```javascript -async function createUserACE() { - const newAce = { - path: "/projects", - user_id: selectedUserId, - role_id: userRoleId, - allowed: true, - propagate: true - }; - - try { - const ace = await api.createACE(newAce); - showSuccess('ACE created successfully'); - loadACEList(); // Refresh list - } catch (error) { - showError(`Creation failed: ${error.message}`); - } -} -``` - -### Scenario 2: Create Group-Level ACE - -```javascript -async function createGroupACE() { - const newAce = { - path: "/templates", - group_id: usersGroupId, - role_id: userRoleId, - allowed: true, - propagate: false - }; - - try { - const ace = await api.createACE(newAce); - showSuccess('Group ACE created successfully'); - loadACEList(); - } catch (error) { - showError(`Creation failed: ${error.message}`); - } -} -``` - -### Scenario 3: Edit Existing ACE - -```javascript -async function editACE(aceId, updates) { - try { - const updated = await api.updateACE(aceId, updates); - showSuccess('ACE updated successfully'); - loadACEList(); - } catch (error) { - showError(`Update failed: ${error.message}`); - } -} - -// Example: Toggle allowed status -async function toggleAllowed(ace) { - await editACE(ace.ace_id, { - allowed: !ace.allowed - }); -} - -// Example: Change path -async function changePath(aceId, newPath) { - await editACE(aceId, { - path: newPath - }); -} -``` - -### Scenario 4: Delete ACE - -```javascript -async function deleteACE(aceId) { - if (!confirm('Are you sure you want to delete this ACE?')) { - return; - } - - try { - await api.deleteACE(aceId); - showSuccess('ACE deleted successfully'); - loadACEList(); - } catch (error) { - showError(`Deletion failed: ${error.message}`); - } -} -``` - -### Scenario 5: Batch Operations - -```javascript -// Batch delete -async function batchDelete(aceIds) { - const promises = aceIds.map(id => api.deleteACE(id)); - await Promise.all(promises); - showSuccess(`Deleted ${aceIds.length} ACEs`); - loadACEList(); -} - -// Batch toggle allowed status -async function batchToggleAllowed(aceIds, allowed) { - const promises = aceIds.map(id => - api.updateACE(id, { allowed }) - ); - await Promise.all(promises); - showSuccess(`Updated ${aceIds.length} ACEs`); - loadACEList(); -} -``` - ---- - -## Error Handling - -### Common Error Types - -| HTTP Status | Error Description | Handling | -|-------------|-------------------|----------| -| 400 Bad Request | Path doesn't match any endpoint | Prompt user to select valid path | -| 400 Bad Request | Both user_id and group_id present | Prompt user to choose one | -| 403 Forbidden | Insufficient privileges | Prompt user to contact administrator | -| 404 Not Found | ACE doesn't exist | Refresh list, notify resource deleted | -| 422 Unprocessable Entity | Validation failed | Display specific field errors | - -### Error Handling Example - -```javascript -async function handleAPICall(apiFunction) { - try { - const result = await apiFunction(); - return { success: true, data: result }; - } catch (error) { - if (error.response) { - const { status, data } = error.response; - - switch (status) { - case 400: - return { - success: false, - error: data.detail || 'Invalid request parameters' - }; - - case 403: - return { - success: false, - error: 'Insufficient privileges, please contact administrator' - }; - - case 404: - return { - success: false, - error: 'Resource not found, may have been deleted' - }; - - case 422: - return { - success: false, - error: formatValidationError(data.detail) - }; - - default: - return { - success: false, - error: 'Unknown error, please try again later' - }; - } - } - - return { - success: false, - error: 'Network error, please check connection' - }; - } -} - -function formatValidationError(errors) { - // Format validation error messages - return errors.map(err => err.msg).join(', '); -} -``` - ---- - -## Example Code - -### Complete React Component Example - -```jsx -import React, { useState, useEffect } from 'react'; -import { - Table, - Button, - Dialog, - DialogTitle, - DialogContent, - DialogActions, - Select, - MenuItem, - Switch, - FormControlLabel, - TextField, - IconButton -} from '@mui/material'; -import { Edit, Delete, Add } from '@mui/icons-material'; - -// API Client -const api = { - async getACEs(token) { - const res = await fetch('/v3/access/aces', { - headers: { 'Authorization': `Bearer ${token}` } - }); - if (!res.ok) throw new Error(res.statusText); - return res.json(); - }, - - async getEndpoints(token) { - const res = await fetch('/v3/access/aces/endpoints', { - headers: { 'Authorization': `Bearer ${token}` } - }); - if (!res.ok) throw new Error(res.statusText); - return res.json(); - }, - - async getUsers(token) { - const res = await fetch('/v3/access/users', { - headers: { 'Authorization': `Bearer ${token}` } - }); - if (!res.ok) throw new Error(res.statusText); - return res.json(); - }, - - async getGroups(token) { - const res = await fetch('/v3/access/groups', { - headers: { 'Authorization': `Bearer ${token}` } - }); - if (!res.ok) throw new Error(res.statusText); - return res.json(); - }, - - async getRoles(token) { - const res = await fetch('/v3/access/roles', { - headers: { 'Authorization': `Bearer ${token}` } - }); - if (!res.ok) throw new Error(res.statusText); - return res.json(); - }, - - async createACE(token, data) { - const res = await fetch('/v3/access/aces', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify(data) - }); - if (!res.ok) { - const error = await res.json(); - throw new Error(error.detail || 'Creation failed'); - } - return res.json(); - }, - - async updateACE(token, aceId, data) { - const res = await fetch(`/v3/access/aces/${aceId}`, { - method: 'PUT', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify(data) - }); - if (!res.ok) { - const error = await res.json(); - throw new Error(error.detail || 'Update failed'); - } - return res.json(); - }, - - async deleteACE(token, aceId) { - const res = await fetch(`/v3/access/aces/${aceId}`, { - method: 'DELETE', - headers: { 'Authorization': `Bearer ${token}` } - }); - if (!res.ok) throw new Error('Deletion failed'); - } -}; - -// ACE Form Component -function ACEForm({ token, ace, onSave, onCancel }) { - const [endpoints, setEndpoints] = useState([]); - const [users, setUsers] = useState([]); - const [groups, setGroups] = useState([]); - const [roles, setRoles] = useState([]); - const [formData, setFormData] = useState({ - path: ace?.path || '', - user_id: ace?.user_id || '', - group_id: ace?.group_id || '', - role_id: ace?.role_id || '', - allowed: ace?.allowed ?? true, - propagate: ace?.propagate ?? true, - ace_type: ace?.ace_type || 'user' - }); - - useEffect(() => { - Promise.all([ - api.getEndpoints(token), - api.getUsers(token), - api.getGroups(token), - api.getRoles(token) - ]).then(([endpoints, users, groups, roles]) => { - setEndpoints(endpoints); - setUsers(users); - setGroups(groups); - setRoles(roles); - }); - }, [token]); - - const handleSubmit = async (e) => { - e.preventDefault(); - - const data = { - ...formData, - [formData.ace_type === 'user' ? 'user_id' : 'group_id']: - formData.ace_type === 'user' ? formData.user_id : formData.group_id - }; - delete data.ace_type; - delete data.user_id; - delete data.group_id; - - if (formData.ace_type === 'user') { - data.user_id = formData.user_id; - } else { - data.group_id = formData.group_id; - } - - try { - if (ace) { - await api.updateACE(token, ace.ace_id, data); - } else { - await api.createACE(token, data); - } - onSave(); - } catch (error) { - alert(error.message); - } - }; - - return ( -
- - {/* Path Selection */} - setFormData({ ...formData, path: e.target.value })} - fullWidth - margin="normal" - required - > - {endpoints.map((ep) => ( - - {ep.name} - - ))} - - - {/* User/Group Selection */} - - - {formData.ace_type === 'user' ? ( - setFormData({ ...formData, user_id: e.target.value })} - fullWidth - margin="normal" - required - > - {users.map((user) => ( - - {user.username} - - ))} - - ) : ( - setFormData({ ...formData, group_id: e.target.value })} - fullWidth - margin="normal" - required - > - {groups.map((group) => ( - - {group.name} - - ))} - - )} - - {/* Role Selection */} - setFormData({ ...formData, role_id: e.target.value })} - fullWidth - margin="normal" - required - > - {roles.map((role) => ( - - {role.name} - - ))} - - - {/* Allow/Deny */} - setFormData({ ...formData, allowed: e.target.checked })} - /> - } - label={formData.allowed ? 'Allow Access' : 'Deny Access'} - /> - - {/* Propagate */} - setFormData({ ...formData, propagate: e.target.checked })} - /> - } - label="Propagate to Child Paths" - /> - - - - - - -
- ); -} - -// ACE List Component -export default function ACLManagement({ token }) { - const [aces, setAces] = useState([]); - const [loading, setLoading] = useState(false); - const [dialogOpen, setDialogOpen] = useState(false); - const [editingACE, setEditingACE] = useState(null); - - const loadACEs = async () => { - setLoading(true); - try { - const data = await api.getACEs(token); - setAces(data); - } catch (error) { - alert(`Loading failed: ${error.message}`); - } finally { - setLoading(false); - } - }; - - useEffect(() => { - loadACEs(); - }, [token]); - - const handleCreate = () => { - setEditingACE(null); - setDialogOpen(true); - }; - - const handleEdit = (ace) => { - setEditingACE(ace); - setDialogOpen(true); - }; - - const handleDelete = async (aceId) => { - if (!confirm('Are you sure you want to delete this ACE?')) return; - - try { - await api.deleteACE(token, aceId); - loadACEs(); - } catch (error) { - alert(`Deletion failed: ${error.message}`); - } - }; - - const handleSave = () => { - setDialogOpen(false); - loadACEs(); - }; - - return ( -
-
-

Access Control List (ACL)

- -
- - {loading ? ( -

Loading...

- ) : ( - - - - - - - - - - - - - {aces.map((ace) => ( - - - - - - - - - ))} - -
PathUser/GroupRoleAllowedPropagateActions
{ace.path}{ace.ace_type === 'user' ? ace.user_id : ace.group_id}{ace.role_id}{ace.allowed ? '✓' : '✗'}{ace.propagate ? '✓' : '✗'} - handleEdit(ace)}> - - - handleDelete(ace.ace_id)}> - - -
- )} - - setDialogOpen(false)} maxWidth="md" fullWidth> - {editingACE ? 'Edit ACE' : 'New ACE'} - setDialogOpen(false)} - /> - -
- ); -} -``` - ---- - -## Implementation Checklist - -### Basic Features -- [ ] Fetch and display ACE list -- [ ] Create new ACE -- [ ] Edit existing ACE -- [ ] Delete ACE -- [ ] Fetch and display available endpoints - -### Form Features -- [ ] Path selector (dropdown/tree) -- [ ] User/group selector -- [ ] Role selector -- [ ] Allow/deny toggle -- [ ] Propagate switch -- [ ] Form validation - -### User Experience -- [ ] Loading state display -- [ ] Error notifications -- [ ] Success notifications -- [ ] Delete confirmation dialog -- [ ] List filtering/search - -### Advanced Features -- [ ] Batch operations -- [ ] ACE export/import -- [ ] Permission preview -- [ ] Change history - ---- - -## References - -### Related Documentation -- [RBAC + ACL Permission System Implementation Guide](../gns3-server/rbac-acl-权限系统实现说明.md) -- [RBAC + ACL Implementation Guide](../gns3-server/rbac-acl-implementation-guide.md) - -### API Specifications -- OpenAPI/Swagger: `/static/swagger-ui-bundle.js` -- ReDoc: `/static/redoc.standalone.js` - -### Test Data -```javascript -// Example ACEs for testing -const exampleACEs = [ - { - path: "/projects", - ace_type: "user", - user_id: "admin-user-id", - role_id: "user-role-id", - allowed: true, - propagate: true - }, - { - path: "/projects/sensitive", - ace_type: "group", - group_id: "auditors-group-id", - role_id: "auditor-role-id", - allowed: false, - propagate: false - } -]; -``` - ---- - -**Document Version**: 1.0 -**Last Updated**: 2026-03-06 - - ---- - -## License - -**Copyright © 2025 Yue Guobin (岳国宾)** - -This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 -International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). - -![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) - -### Summary - -You are free to: - -- **Share** — Copy and redistribute the material in any medium or format -- **Adapt** — Remix, transform, and build upon the material for any purpose - -Under the following terms: - -- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide - a link to the license, and indicate if changes were made. -- **ShareAlike** — If you remix, transform, or build upon the material, you must - distribute your contributions under the **same license** (CC BY-SA 4.0). - -Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) - diff --git a/docs/gns3-copilot/todo/ai-prompting-for-config-templates.md b/docs/gns3-copilot/todo/ai-prompting-for-config-templates.md index a0bee83bf..6245f4cee 100644 --- a/docs/gns3-copilot/todo/ai-prompting-for-config-templates.md +++ b/docs/gns3-copilot/todo/ai-prompting-for-config-templates.md @@ -795,3 +795,30 @@ test_cases = [ | Assume vendor/OS | Ask or detect from node | | Mix features in one dict | Separate by feature key | | Use string for numbers | Use int: `process_id: 100` not `"process_id": "100"` | + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) diff --git a/docs/gns3-copilot/todo/config-templates-implementation-guide.md b/docs/gns3-copilot/todo/config-templates-implementation-guide.md index b4ffb3139..8e9859636 100644 --- a/docs/gns3-copilot/todo/config-templates-implementation-guide.md +++ b/docs/gns3-copilot/todo/config-templates-implementation-guide.md @@ -707,3 +707,30 @@ Solution: Check if feature flag "enabled" is set to True ``` Solution: Review template logic, check conditional statements ``` + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) diff --git a/docs/gns3-copilot/todo/jinja2-config-templates-system.md b/docs/gns3-copilot/todo/jinja2-config-templates-system.md index 68d1b2164..af7c766e6 100644 --- a/docs/gns3-copilot/todo/jinja2-config-templates-system.md +++ b/docs/gns3-copilot/todo/jinja2-config-templates-system.md @@ -1082,3 +1082,31 @@ include network 192.168.1.0/24 in area 0. Output as structured JSON data." ``` Then the agent calls `render_device_config` tool to get the actual configuration. + + +--- + +## License + +**Copyright © 2025 Yue Guobin (岳国宾)** + +This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 +International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). + +![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) + +### Summary + +You are free to: + +- **Share** — Copy and redistribute the material in any medium or format +- **Adapt** — Remix, transform, and build upon the material for any purpose + +Under the following terms: + +- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide + a link to the license, and indicate if changes were made. +- **ShareAlike** — If you remix, transform, or build upon the material, you must + distribute your contributions under the **same license** (CC BY-SA 4.0). + +Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md) diff --git a/docs/gns3-server/rbac-acl-权限系统实现说明.md b/docs/gns3-server/rbac-acl-权限系统实现说明.md deleted file mode 100644 index 2967211fc..000000000 --- a/docs/gns3-server/rbac-acl-权限系统实现说明.md +++ /dev/null @@ -1,571 +0,0 @@ -# GNS3 RBAC + ACL 权限系统实现说明 - -**文档版本**: 1.0 -**创建日期**: 2026-03-06 -**适用版本**: GNS3 Server v3.0+ - ---- - -## 目录 - -- [系统概述](#系统概述) -- [核心概念](#核心概念) -- [数据模型](#数据模型) -- [权限检查流程](#权限检查流程) -- [使用示例](#使用示例) -- [最佳实践](#最佳实践) -- [常见问题](#常见问题) - ---- - -## 系统概述 - -GNS3 Server 实现了一个**两层权限控制系统**,结合了 **RBAC**(基于角色的访问控制)和 **ACL**(访问控制列表)的特性: - -``` -┌─────────────────────────────────────────────────────┐ -│ 第 1 层:RBAC (定义能力) │ -│ │ -│ 角色 → 权限 │ -│ 回答问题:"用户能做什么操作?" │ -└─────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────┐ -│ 第 2 层:ACL (明确授权) │ -│ │ -│ 默认:拒绝所有 (Deny All) │ -│ 除非:ACE 明确允许 (Explicitly Allow) │ -│ 回答问题:"能在哪些资源上使用这些操作?" │ -└─────────────────────────────────────────────────────┘ -``` - -### 核心原则 - -**默认拒绝,明确允许** - -就像网络设备的 ACL,默认情况下拒绝所有访问请求,除非有明确的 ACE(访问控制条目)允许。 - -``` -没有 ACE → ❌ 拒绝访问 -有 ACE (allowed=False) → ❌ 拒绝访问 -有 ACE (allowed=True) → ✅ 允许访问 -``` - ---- - -## 核心概念 - -### 1. 权限 (Privilege) - -权限定义了用户可以执行的操作。 - -```python -权限命名格式: <资源>.<操作> - -示例: -- Project.Audit # 查看项目 -- Project.Allocate # 创建/删除项目 -- Project.Modify # 修改项目 -- Node.Console # 访问节点控制台 -- Link.Capture # 捕获链路流量 -``` - -**预定义权限**: 38 个内置权限(详见 `gns3server/db/models/privileges.py`) - -### 2. 角色 (Role) - -角色是权限的集合,用于简化权限管理。 - -```python -内置角色: -- Administrator: 所有权限 -- User: 项目、节点、链路、快照等常用权限 -- Auditor: 只读权限 (*.Audit) -- Template manager: 模板和符号管理 -- User manager: 用户和组管理 -- ACL manager: 角色和 ACE 管理 -- No Access: 无任何权限 -``` - -### 3. 用户组 (User Group) - -用户组用于批量管理用户。 - -```python -内置组: -- Administrators: 管理员组 -- Users: 普通用户组 -``` - -### 4. ACE (Access Control Entry) - -ACE 是访问控制的核心,定义了**在哪些资源上可以使用哪些角色**。 - -```python -ACE 结构: -{ - "path": "/projects", # 资源路径 - "user_id": "uuid", # 用户 ID (与 group_id 二选一) - "group_id": "uuid", # 用户组 ID (与 user_id 二选一) - "role_id": "uuid", # 角色 ID - "allowed": true, # 是否允许 (默认 true) - "propagate": true, # 是否传播到子路径 (默认 true) - "ace_type": "user" # "user" 或 "group" -} -``` - -**重要**: -- `path`: 使用文件系统风格的路径,如 `/projects`、`/projects/123` -- `role_id`: ACE 关联的角色,角色定义了可用权限 -- `allowed`: 显式允许或拒绝(默认 true) -- `propagate`: 权限是否继承到子路径(默认 true) - ---- - -## 数据模型 - -### 实体关系 - -``` -User ────< UserGroup > (many-to-many via user_group_map) - │ │ - │ └───< ACE (group_id) - │ - └───< ACE (user_id) - │ - ├── path (资源路径) - ├── role → Role → Privilege (权限) - ├── allowed (允许/拒绝) - └── propagate (是否传播) -``` - -### 数据库表 - -| 表名 | 说明 | 关键字段 | -|------|------|----------| -| `users` | 用户 | `user_id`, `username`, `is_superadmin` | -| `user_groups` | 用户组 | `user_group_id`, `name` | -| `roles` | 角色 | `role_id`, `name`, `is_builtin` | -| `privileges` | 权限 | `privilege_id`, `name` | -| `acl` (ACE) | 访问控制条目 | `ace_id`, `path`, `user_id`, `group_id`, `role_id`, `allowed`, `propagate` | -| `privilege_role_map` | 角色-权限关联 | `privilege_id`, `role_id` | -| `user_group_map` | 用户-组关联 | `user_id`, `user_group_id` | - ---- - -## 权限检查流程 - -### 完整流程图 - -``` -用户请求: GET /projects/123,需要 Project.Audit 权限 - ↓ -┌─────────────────────────────────────────────────────┐ -│ 1. 提取请求信息 │ -│ - 用户 ID │ -│ - 路径: /projects/123 │ -│ - 所需权限: Project.Audit │ -└─────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────┐ -│ 2. 特殊检查: Superadmin │ -│ 如果 is_superadmin = True │ -│ → ✅ 直接允许(绕过 RBAC + ACL) │ -└─────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────┐ -│ 3. 查询用户 ACE │ -│ SELECT * FROM ace │ -│ JOIN privilege_role_map ON ace.role_id = ... │ -│ JOIN privileges ON ... │ -│ WHERE │ -│ ace.user_id = │ -│ AND privileges.name = 'Project.Audit' │ -│ AND ace.path 匹配 /projects/123 │ -└─────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────┐ -│ 4. 检查用户 ACE │ -│ 如果找到匹配的 ACE: │ -│ - if allowed = False → ❌ 拒绝 │ -│ - if allowed = True → ✅ 允许 │ -│ 如果没找到: │ -│ → 继续检查组 ACE │ -└─────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────┐ -│ 5. 查询组 ACE │ -│ 查询用户所属的所有组的 ACE │ -│ (查询逻辑与用户 ACE 相同) │ -└─────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────┐ -│ 6. 检查组 ACE │ -│ 如果找到匹配的组 ACE: │ -│ - if allowed = False → ❌ 拒绝 │ -│ - if allowed = True → ✅ 允许 │ -│ 如果没找到: │ -│ → ❌ 拒绝访问(默认拒绝所有) │ -└─────────────────────────────────────────────────────┘ -``` - -### 路径匹配规则 - -路径匹配遵循**从具体到通用**的原则: - -``` -请求路径: /projects/123/nodes/456 - -检查顺序: -1. /projects/123/nodes/456 (最具体) -2. /projects/123/nodes -3. /projects/123 -4. /projects -5. / (最通用) -``` - -**propagate 参数的影响**: - -```python -# ACE 1: path="/projects", propagate=True -✅ 允许访问: /projects, /projects/123, /projects/123/nodes -# 权限传播到所有子路径 - -# ACE 2: path="/projects", propagate=False -✅ 允许访问: /projects -❌ 拒绝访问: /projects/123, /projects/123/nodes -# 权限不传播,只允许精确匹配 -``` - ---- - -## 使用示例 - -### 场景 1: 允许用户访问所有项目 - -```python -# 创建 ACE -POST /v3/access/aces -{ - "path": "/projects", - "user_id": "550e8400-e29b-41d4-a716-446655440000", - "role_id": "", - "allowed": true, - "propagate": true -} - -# 结果: 用户可以访问所有项目 (/projects/*) -``` - -### 场景 2: 允许用户只访问特定项目 - -```python -# 创建 ACE(精确路径) -POST /v3/access/aces -{ - "path": "/projects/my-project-id", - "user_id": "550e8400-e29b-41d4-a716-446655440000", - "role_id": "", - "allowed": true, - "propagate": false -} - -# 结果: 用户只能访问 /projects/my-project-id -# 不能访问其他项目 -``` - -### 场景 3: 使用组权限 - -```python -# 为组创建 ACE -POST /v3/access/aces -{ - "path": "/projects", - "group_id": "", - "role_id": "", - "allowed": true, - "propagate": true -} - -# 结果: "Users" 组的所有成员都可以访问所有项目 -``` - -### 场景 4: 显式拒绝特定资源 - -```python -# 用户可以访问所有项目 -ACE: path="/projects", user=A, allowed=true, propagate=true - -# 但拒绝访问某个秘密项目 -ACE: path="/projects/secret", user=A, allowed=false - -# 结果: 用户可以访问所有项目,除了 /projects/secret -``` - -### 场景 5: 使用资源池 - -```python -# 为用户分配资源池访问权限 -POST /v3/access/aces -{ - "path": "/pools/pool-123", - "user_id": "550e8400-e29b-41d4-a716-446655440000", - "role_id": "", - "allowed": true, - "propagate": true -} - -# 结果: 用户可以访问 pool-123 中的所有资源 -``` - ---- - -## 最佳实践 - -### 1. 使用组管理权限(推荐) - -**推荐** ✅: -```python -# 为 "Users" 组创建 ACE -ACE(path="/projects", group="Users", role="User", allowed=true) -``` - -**不推荐** ❌: -```python -# 为每个用户单独创建 ACE -ACE(path="/projects", user="user1", role="User", allowed=true) -ACE(path="/projects", user="user2", role="User", allowed=true) -ACE(path="/projects", user="user3", role="User", allowed=true) -# ... 为数百个用户重复 -``` - -### 2. 使用 propagate 减少配置 - -**推荐** ✅: -```python -# 使用 propagate=True -ACE(path="/projects", group="Users", role="User", allowed=true, propagate=true) -# 一个 ACE 覆盖所有项目和子资源 -``` - -**不推荐** ❌: -```python -# 为每个项目单独创建 ACE -ACE(path="/projects/1", group="Users", role="User", allowed=true) -ACE(path="/projects/2", group="Users", role="User", allowed=true) -ACE(path="/projects/3", group="Users", role="User", allowed=true) -# ... 难以维护 -``` - -### 3. 使用默认 ACE - -**问题**: 新安装的系统,默认没有任何 ACE,用户无法访问任何资源。 - -**解决方案**: 为默认用户组创建默认 ACE - -```python -# 初始化脚本 -async def create_default_aces(): - users_group = await get_group_by_name("Users") - user_role = await get_role_by_name("User") - - # 为 "Users" 组创建默认 ACE - await create_ace({ - "path": "/", - "group_id": users_group.id, - "role_id": user_role.id, - "allowed": true, - "propagate": true - }) -``` - -### 4. 审计权限配置 - -定期检查 ACE 配置: - -```python -# 查询所有 ACE -GET /v3/access/aces - -# 检查用户的实际权限 -GET /v3/access/users/me -# 返回用户所属组、可访问池、ACE 列表 -``` - ---- - -## 常见问题 - -### Q1: 为什么用户有角色权限,但无法访问资源? - -**A**: 这是最常见的问题。RBAC 定义了"能做什么",但 ACL 限定了"能在哪里做"。 - -**检查清单**: -1. 用户是否有匹配的 ACE? -2. ACE 的 `path` 是否匹配请求路径? -3. ACE 的 `allowed` 是否为 `true`? -4. ACE 关联的 `role` 是否有所需权限? - -```bash -# 检查用户的 ACE -curl -X GET http://localhost:3080/v3/access/aces \ - -H "Authorization: Bearer " - -# 检查用户的组 -curl -X GET http://localhost:3080/v3/access/users/me \ - -H "Authorization: Bearer " -``` - -### Q2: propagate 参数有什么用? - -**A**: `propagate` 控制权限是否继承到子路径。 - -- `propagate=true`: 权限传播到所有子路径 -- `propagate=false`: 权限只应用于精确路径 - -``` -ACE: path="/projects", propagate=true -→ 允许: /projects, /projects/1, /projects/1/nodes, ... - -ACE: path="/projects", propagate=false -→ 允许: /projects -→ 拒绝: /projects/1, /projects/1/nodes, ... -``` - -### Q3: 用户 ACE 和组 ACE 的优先级? - -**A**: 用户 ACE 优先于组 ACE。 - -```python -# 用户 ACE -ACE(path="/projects", user=A, role=Auditor, allowed=true) - -# 组 ACE(同一用户的组) -ACE(path="/projects", group=Users, role=User, allowed=true) - -# 结果: 用户 ACE 优先,用户使用 Auditor 角色 -``` - -### Q4: 如何拒绝访问特定资源? - -**A**: 创建 `allowed=false` 的 ACE。 - -```python -# 用户可以访问所有项目 -ACE(path="/projects", user=A, role=User, allowed=true, propagate=true) - -# 但拒绝访问秘密项目 -ACE(path="/projects/secret", user=A, role=User, allowed=false) -``` - -**注意**: 拒绝 ACE 的路径必须更具体(更长的路径)。 - -### Q5: Superadmin 是否受 RBAC + ACL 限制? - -**A**: 不受限制。`is_superadmin=true` 的用户绕过所有权限检查。 - -```python -# Superadmin -{ - "username": "admin", - "is_superadmin": true -} - -# 访问任何资源都不需要 ACE -``` - -### Q6: 资源池的路径格式是什么? - -**A**: 资源池使用 `/pools/{pool_id}` 格式。 - -```python -# 为用户分配资源池访问权限 -ACE(path="/pools/pool-123", user=A, role=User, allowed=true) - -# 池中的项目路径 -# /pools/pool-123/projects/project-1 -``` - -**注意**: 代码中有 `/pool` 和 `/pools` 的不一致问题,建议使用 `/pools`(复数形式)。 - -### Q7: 如何调试权限问题? - -**A**: 启用调试日志并检查权限检查流程。 - -```python -# 启用调试日志 -import logging -logging.getLogger("gns3server.db.repositories.rbac").setLevel(logging.DEBUG) - -# 查看日志 -# DEBUG:gns3server.db.repositories.rbac:Checking user admin has privilege Project.Audit on '/projects/123' -``` - ---- - -## API 参考 - -### 权限检查相关的 API 端点 - -| 端点 | 方法 | 说明 | 所需权限 | -|------|------|------|----------| -| `/v3/access/users/me` | GET | 获取当前用户信息(包含组、池、ACE) | 无(认证用户) | -| `/v3/access/users` | GET | 获取所有用户 | User.Audit | -| `/v3/access/users/{user_id}` | GET | 获取指定用户 | User.Audit | -| `/v3/access/groups` | GET | 获取所有组 | Group.Audit | -| `/v3/access/roles` | GET | 获取所有角色 | Role.Audit | -| `/v3/access/privileges` | GET | 获取所有权限 | Role.Audit | -| `/v3/access/aces` | GET | 获取所有 ACE | ACE.Audit | -| `/v3/access/aces` | POST | 创建 ACE | ACE.Allocate | -| `/v3/access/aces/{ace_id}` | PUT | 更新 ACE | ACE.Modify | -| `/v3/access/aces/{ace_id}` | DELETE | 删除 ACE | ACE.Allocate | - ---- - -## 代码位置参考 - -| 组件 | 文件路径 | -|------|----------| -| 数据模型 | `gns3server/db/models/` | -| - 用户和组 | `users.py` | -| - 角色和权限 | `roles.py`, `privileges.py` | -| - ACE | `acl.py` | -| RBAC 仓库 | `gns3server/db/repositories/rbac.py` | -| 权限检查依赖 | `gns3server/api/routes/controller/dependencies/rbac.py` | -| API 路由 | `gns3server/api/routes/controller/` | -| - 用户路由 | `users.py` | -| - RBAC 路由 | `roles.py`, `acl.py` | -| Schemas | `gns3server/schemas/controller/rbac.py` | - ---- - -## 总结 - -GNS3 的 RBAC + ACL 系统是一个强大且灵活的权限控制框架: - -### 关键要点 - -1. **两层防护**: RBAC 定义能力,ACL 限定范围 -2. **默认拒绝**: 没有 ACE = 拒绝访问 -3. **明确允许**: 必须有 ACE(allowed=true)才能访问 -4. **角色优先**: ACE 通过角色授予权限 -5. **路径继承**: propagate 控制权限传播 - -### 设计优势 - -- ✅ 细粒度控制:精确到具体资源的权限 -- ✅ 灵活性强:支持用户和组级别的权限 -- ✅ 集中管理:通过角色集中定义权限 -- ✅ 安全性高:默认拒绝所有,显式允许 - -### 注意事项 - -- ⚠️ 新系统需要创建默认 ACE -- ⚠️ 必须为每个用户/组配置 ACE -- ⚠️ 定期审计权限配置 -- ⚠️ Superadmin 绕过所有限制 - ---- - -**文档版本**: 1.0 -**最后更新**: 2026-03-06