Remove mcp-gateway/USER_MANAGEMENT_SETUP.md
This commit is contained in:
parent
2b27a0dba2
commit
0e9745ab8c
1 changed files with 0 additions and 350 deletions
|
|
@ -1,350 +0,0 @@
|
|||
# User Management System Setup Guide
|
||||
|
||||
This guide explains how to integrate the user management system into your MCP Gateway, enabling per-user API key generation and MCP access control.
|
||||
|
||||
## Overview
|
||||
|
||||
The user management system provides:
|
||||
|
||||
- **User Creation & Management**: Create and manage users, enable/disable accounts
|
||||
- **API Key Generation**: Generate unique API keys with optional TTL (time-to-live)
|
||||
- **MCP Access Control**: Allow/block specific MCPs for each user (e.g., some users access only ERPNext, others access Wave + TrueNAS)
|
||||
- **Persistent Storage**: User data stored in JSON file, survives container restarts
|
||||
- **Web Dashboard**: Intuitive UI for managing users and API keys
|
||||
|
||||
## Files Created
|
||||
|
||||
1. **user_management.py** - Core user/API key management logic
|
||||
2. **user_routes.py** - REST API endpoints for user management
|
||||
3. **user_dashboard_ui.py** - Web dashboard with Vue.js UI
|
||||
4. **gateway_proxy_user_integration.py** - Integration instructions
|
||||
|
||||
## Installation Steps
|
||||
|
||||
### Step 1: Copy Files
|
||||
|
||||
The files are already created in `gateway-proxy/`:
|
||||
- `user_management.py`
|
||||
- `user_routes.py`
|
||||
- `user_dashboard_ui.py`
|
||||
|
||||
### Step 2: Update gateway_proxy.py
|
||||
|
||||
Add the import at line 33 (after existing imports):
|
||||
|
||||
```python
|
||||
from user_management import user_manager
|
||||
from user_routes import (
|
||||
create_user, list_users, get_user, delete_user, toggle_user,
|
||||
generate_api_key, revoke_api_key, set_mcp_access
|
||||
)
|
||||
from user_dashboard_ui import user_management_dashboard
|
||||
```
|
||||
|
||||
### Step 3: Update validate_bearer_token() Function
|
||||
|
||||
Replace the `validate_bearer_token()` function (around line 254) with:
|
||||
|
||||
```python
|
||||
def validate_bearer_token(request: Request) -> dict | None:
|
||||
auth_header = request.headers.get("Authorization", "")
|
||||
if not auth_header.startswith("Bearer "):
|
||||
return None
|
||||
token = auth_header[7:]
|
||||
|
||||
# Check static API key first
|
||||
if STATIC_API_KEY and token == STATIC_API_KEY:
|
||||
return {"client_id": "static", "scope": "mcp:tools", "user": "static"}
|
||||
|
||||
# Check user API key
|
||||
user_info = user_manager.validate_api_key(token)
|
||||
if user_info:
|
||||
return {
|
||||
"client_id": "api-key",
|
||||
"scope": "mcp:tools",
|
||||
"user": user_info['username'],
|
||||
"user_id": user_info['user_id'],
|
||||
"mcp_allowed": user_info['mcp_allowed'],
|
||||
"mcp_blocked": user_info['mcp_blocked']
|
||||
}
|
||||
|
||||
# Check OAuth token
|
||||
token_hash = _hash(token)
|
||||
info = ACCESS_TOKENS.get(token_hash)
|
||||
if not info:
|
||||
return None
|
||||
if info["expires_at"] < time.time():
|
||||
del ACCESS_TOKENS[token_hash]
|
||||
return None
|
||||
return info
|
||||
```
|
||||
|
||||
### Step 4: Add MCP Access Control to handle_mcp()
|
||||
|
||||
In the `handle_mcp()` function, after retrieving `token_info`, add this check:
|
||||
|
||||
```python
|
||||
# Check MCP access control
|
||||
if token_info and 'user' in token_info and token_info.get('client_id') == 'api-key':
|
||||
mcp_allowed = token_info.get('mcp_allowed', [])
|
||||
mcp_blocked = token_info.get('mcp_blocked', [])
|
||||
|
||||
# Check if user can access any backend (basic check)
|
||||
if not mcp_allowed and not mcp_blocked:
|
||||
# User has no restrictions, allow all
|
||||
pass
|
||||
elif mcp_blocked and len(mcp_blocked) == len(BACKENDS):
|
||||
return JSONResponse(
|
||||
{'error': 'access_denied', 'message': 'All MCPs are blocked for your user'},
|
||||
status_code=403
|
||||
)
|
||||
```
|
||||
|
||||
### Step 5: Update Routes List
|
||||
|
||||
Add these routes to the routes list before creating the app (around line 1012):
|
||||
|
||||
```python
|
||||
routes = [
|
||||
# ... existing well-known and OAuth routes ...
|
||||
|
||||
# MCP endpoint
|
||||
Route("/mcp", handle_mcp, methods=["GET", "HEAD", "POST", "DELETE"]),
|
||||
|
||||
# Monitoring
|
||||
Route("/health", health, methods=["GET"]),
|
||||
Route("/status", status, methods=["GET"]),
|
||||
|
||||
# Dashboard
|
||||
Route("/dashboard", dashboard, methods=["GET"]),
|
||||
Route("/dashboard/status", dashboard_status, methods=["GET"]),
|
||||
|
||||
# User Management - Enhanced Dashboard
|
||||
Route("/admin", user_management_dashboard, methods=["GET"]),
|
||||
|
||||
# User Management API
|
||||
Route("/users", create_user, methods=["POST"]),
|
||||
Route("/users", list_users, methods=["GET"]),
|
||||
Route("/users/{username}", get_user, methods=["GET"]),
|
||||
Route("/users/{username}", delete_user, methods=["DELETE"]),
|
||||
Route("/users/{username}/enable", toggle_user, methods=["PATCH"]),
|
||||
Route("/users/{username}/keys", generate_api_key, methods=["POST"]),
|
||||
Route("/users/{username}/mcp-access", set_mcp_access, methods=["PUT"]),
|
||||
Route("/keys/revoke", revoke_api_key, methods=["POST"]),
|
||||
]
|
||||
```
|
||||
|
||||
### Step 6: Update docker-compose.yml
|
||||
|
||||
Ensure the gateway service has a data volume for persistent storage:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
mcp-gateway:
|
||||
image: mcp-gateway:latest
|
||||
build:
|
||||
context: ./gateway-proxy
|
||||
dockerfile: Dockerfile
|
||||
container_name: mcp-gateway
|
||||
ports:
|
||||
- "4444:4444"
|
||||
environment:
|
||||
# ... existing environment variables ...
|
||||
USERS_DB_PATH: /data/users.json
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./gateway-proxy:/app
|
||||
depends_on:
|
||||
# ... existing dependencies ...
|
||||
```
|
||||
|
||||
### Step 7: Create Data Directory
|
||||
|
||||
```bash
|
||||
mkdir -p /sessions/vigilant-elegant-ramanujan/mnt/MCP\ Servers/mcp-gateway/data
|
||||
```
|
||||
|
||||
### Step 8: Restart Gateway
|
||||
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d mcp-gateway
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Access the Dashboard
|
||||
|
||||
Open your browser to:
|
||||
|
||||
```
|
||||
http://10.0.0.25:4444/admin
|
||||
```
|
||||
|
||||
### Create a User via API
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.0.0.25:4444/users \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"username": "alice",
|
||||
"email": "alice@example.com",
|
||||
"description": "Engineering team"
|
||||
}'
|
||||
```
|
||||
|
||||
### Generate an API Key
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.0.0.25:4444/users/alice/keys \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"key_name": "production-key",
|
||||
"ttl_days": 90
|
||||
}'
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"status": "created",
|
||||
"username": "alice",
|
||||
"api_key": "mcpgw_...",
|
||||
"note": "Save this key immediately — it will not be shown again"
|
||||
}
|
||||
```
|
||||
|
||||
### Configure MCP Access
|
||||
|
||||
```bash
|
||||
curl -X PUT http://10.0.0.25:4444/users/alice/mcp-access \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"allowed_mcps": ["erpnext", "wave"],
|
||||
"blocked_mcps": []
|
||||
}'
|
||||
```
|
||||
|
||||
This allows alice to access only ERPNext and Wave Finance MCPs.
|
||||
|
||||
### Use the API Key
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.0.0.25:4444/mcp \
|
||||
-H "Authorization: Bearer mcpgw_..." \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "initialize",
|
||||
"params": {
|
||||
"protocolVersion": "2024-11-05",
|
||||
"capabilities": {},
|
||||
"clientInfo": {"name": "test-client", "version": "1.0"}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
## Access Control Examples
|
||||
|
||||
### Example 1: Limited Access User
|
||||
|
||||
Create a user with access to only ERPNext:
|
||||
|
||||
```bash
|
||||
# Create user
|
||||
curl -X POST http://10.0.0.25:4444/users \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username": "erp-user", "description": "ERP access only"}'
|
||||
|
||||
# Generate key
|
||||
curl -X POST http://10.0.0.25:4444/users/erp-user/keys \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"key_name": "erp-only"}'
|
||||
|
||||
# Restrict to ERPNext
|
||||
curl -X PUT http://10.0.0.25:4444/users/erp-user/mcp-access \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"allowed_mcps": ["erpnext"]}'
|
||||
```
|
||||
|
||||
### Example 2: Block Specific MCPs
|
||||
|
||||
Create a user with access to everything except Home Assistant:
|
||||
|
||||
```bash
|
||||
curl -X PUT http://10.0.0.25:4444/users/alice/mcp-access \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"blocked_mcps": ["homeassistant"]}'
|
||||
```
|
||||
|
||||
### Example 3: Revoke an API Key
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.0.0.25:4444/keys/revoke \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"api_key": "mcpgw_..."}'
|
||||
```
|
||||
|
||||
## Database Schema
|
||||
|
||||
User data is stored in `/data/users.json` with the following structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"users": {
|
||||
"alice": {
|
||||
"user_id": "abc123...",
|
||||
"email": "alice@example.com",
|
||||
"description": "Engineering team",
|
||||
"created_at": "2026-03-31T12:00:00.000000",
|
||||
"enabled": true,
|
||||
"api_keys": ["hash1", "hash2"],
|
||||
"mcp_allowed": ["erpnext", "wave"],
|
||||
"mcp_blocked": [],
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
"api_keys": {
|
||||
"hash1": {
|
||||
"user_id": "abc123...",
|
||||
"username": "alice",
|
||||
"key_name": "prod-key",
|
||||
"created_at": "2026-03-31T12:00:00.000000",
|
||||
"expires_at": null,
|
||||
"revoked": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
1. **API Keys are Hashed**: Only SHA256 hashes are stored, never the actual key
|
||||
2. **One-Time Display**: Keys are shown only once during generation
|
||||
3. **TTL Support**: Keys can expire after N days
|
||||
4. **Revocation**: Keys can be revoked at any time
|
||||
5. **Per-User Access Control**: Each user has independent MCP restrictions
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Users/Keys Not Persisting After Restart
|
||||
|
||||
Check that:
|
||||
1. `/data` directory exists and is mounted in docker-compose.yml
|
||||
2. `/data` directory has write permissions
|
||||
3. `USERS_DB_PATH=/data/users.json` is set in environment
|
||||
|
||||
### API Key Not Working
|
||||
|
||||
1. Verify key hasn't been revoked: Check in dashboard
|
||||
2. Verify key hasn't expired: Check `expires_at` timestamp
|
||||
3. Verify user is enabled: Check `enabled` field in dashboard
|
||||
4. Check MCP access: Verify the user has access to the MCP they're trying to use
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Configure additional users for different teams/roles
|
||||
- Set up automated key rotation policies
|
||||
- Monitor API key usage via the dashboard
|
||||
- Integrate with your CI/CD for automated deployments
|
||||
Loading…
Reference in a new issue