Add user management and a settings page

This commit is contained in:
2026-04-08 16:21:46 -04:00
parent 3232239a85
commit d77277857f
23 changed files with 2477 additions and 201 deletions
+105 -4
View File
@@ -15,12 +15,49 @@ Default port is `50004` (configurable via `hbd_port` in configuration).
---
## Authentication
When [user accounts are configured](USERS.md), every request must be authenticated.
- **Browser requests** to HTML pages are redirected to `/login` automatically. JavaScript `fetch()` calls on the dashboards send the session cookie automatically — no JS changes are needed.
- **API / programmatic requests** must include the token in an `Authorization: Bearer <token>` header or an `X-Auth-Token` header.
Unauthenticated API requests receive `401 Unauthorized`. When no users are configured the server runs in unauthenticated mode and all endpoints are open.
### Login
```bash
TOKEN=$(curl -s -X POST http://localhost:50004/api/0/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"alice","password":"secret"}' | jq -r .token)
curl -H "Authorization: Bearer $TOKEN" http://localhost:50004/api/0/hosts
```
See [User Management](USERS.md) for full authentication documentation.
---
## API Endpoints
### Authentication
| Method | Path | Description | Auth required |
|--------|------|-------------|---------------|
| `POST` | `/api/0/auth/login` | Obtain session token | No |
| `POST` | `/api/0/auth/logout` | Invalidate session | Token |
### Users
| Method | Path | Description | Role |
|--------|------|-------------|------|
| `GET` | `/api/0/users` | List all users | Admin |
| `GET` | `/api/0/users/me` | Own profile | Authenticated |
### Host Management
#### GET /api/0/hosts
Get list of all monitored hosts with their state information.
Get list of all monitored hosts with their state information. When auth is enabled, only hosts the caller has at least **monitor** access to are returned.
**Response:**
```json
@@ -28,6 +65,9 @@ Get list of all monitored hosts with their state information.
{
"name": "webserver01",
"dyn": false,
"owner": "alice",
"managers": ["bob"],
"monitors": ["carol"],
"connections": [...]
}
]
@@ -137,6 +177,32 @@ curl http://localhost:50004/api/0/hosts/database01/plugins/disk_monitor
---
### Host Access
#### GET /api/0/hosts/{hostname}/access
Get owner/managers/monitors for a host. Requires **monitor** role or higher.
**Response:**
```json
{
"owner": "alice",
"managers": ["bob"],
"monitors": ["carol"]
}
```
#### PUT /api/0/hosts/{hostname}/access
Update owner/managers/monitors. Requires **owner** role or admin.
**Request body** (all fields optional):
```json
{ "owner": "bob", "managers": ["carol"], "monitors": [] }
```
Changes take effect immediately but are not written back to the config file. Update the config file and send `SIGHUP` to make them permanent.
---
### Alert Endpoints
#### GET /api/0/hosts/{hostname}/alerts
@@ -226,6 +292,16 @@ curl http://localhost:50004/api/0/alerts | jq .
## Web UI Pages
### Login
**URL:** `/login`
Shown automatically when a browser request is made without a valid session (when users are configured). After successful login the browser is redirected to the originally requested page.
### Logout
**URL:** `/logout`
Clears the session cookie and redirects to `/login`.
### Live Dashboard
**URL:** `/live`
@@ -288,7 +364,13 @@ Comprehensive alert monitoring:
#!/bin/bash
# Check for critical alerts and send notification
RESPONSE=$(curl -s http://localhost:50004/api/0/alerts)
# Log in first (when auth is configured)
TOKEN=$(curl -s -X POST http://localhost:50004/api/0/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"monitor","password":"secret"}' | jq -r .token)
AUTH="-H \"Authorization: Bearer $TOKEN\""
RESPONSE=$(curl -s $AUTH http://localhost:50004/api/0/alerts)
CRITICAL_COUNT=$(echo "$RESPONSE" | jq '.summary.critical')
if [ "$CRITICAL_COUNT" -gt 0 ]; then
@@ -305,8 +387,16 @@ fi
import requests
import json
BASE = 'http://localhost:50004'
# Log in (skip if auth not configured)
resp = requests.post(f'{BASE}/api/0/auth/login',
json={"username": "alice", "password": "secret"})
token = resp.json().get("token")
headers = {"Authorization": f"Bearer {token}"} if token else {}
# Get all plugin data for a host
response = requests.get('http://localhost:50004/api/0/hosts/webserver01/plugins')
response = requests.get(f'{BASE}/api/0/hosts/webserver01/plugins', headers=headers)
data = response.json()
print(f"Host: {data['hostname']}")
@@ -318,7 +408,7 @@ for plugin, info in data['plugins'].items():
print(f" {metric}: {value}")
# Check for alerts
response = requests.get('http://localhost:50004/api/0/alerts')
response = requests.get(f'{BASE}/api/0/alerts', headers=headers)
alerts = response.json()
if alerts['summary']['critical'] > 0:
@@ -389,6 +479,8 @@ API errors return appropriate HTTP status codes with JSON:
**Common Status Codes:**
- `200 OK` - Success
- `400 Bad Request` - Invalid parameters
- `401 Unauthorized` - Missing or invalid session token
- `403 Forbidden` - Authenticated but insufficient role
- `404 Not Found` - Resource not found
- `500 Internal Server Error` - Server error
@@ -506,6 +598,14 @@ for route in list(app.router.routes()):
## Troubleshooting
### API Returns 401
- Auth is configured — include `Authorization: Bearer <token>` header
- Token may have expired (24 h TTL) — log in again
### API Returns 403
- Authenticated user lacks the required role for this host/action
- Check host's `owner`, `managers`, `monitors` config
### API Returns 404
- Verify hostname in URL matches actual host name
- Check host is sending heartbeats: `curl http://localhost:50004/api/0/hosts`
@@ -525,6 +625,7 @@ for route in list(app.router.routes()):
## See Also
- [User Management](USERS.md)
- [Plugin Development Guide](PLUGIN_DEVELOPMENT.md)
- [Threshold Alerting Documentation](THRESHOLD_ALERTING.md)
- [Message Journal Documentation](MESSAGE_JOURNAL.md)