Add user management and a settings page
This commit is contained in:
+242
@@ -0,0 +1,242 @@
|
||||
# User Management
|
||||
|
||||
Heartbeat supports optional user accounts with role-based access control per host. When no users are configured the server runs in **unauthenticated mode** — all existing behaviour is unchanged.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Users are defined in the server config file. Each host can have an **owner**, zero or more **managers**, and zero or more **monitors**. A **default owner** catches any host that does not name an explicit owner.
|
||||
|
||||
### Roles
|
||||
|
||||
| Role | Inherits | Permissions |
|
||||
|------|----------|-------------|
|
||||
| **monitor** | — | View host status, plugin data, alerts; acknowledge alerts they were notified for |
|
||||
| **manager** | monitor | + Queue commands (`/c`), trigger DNS re-registration (`/n`), queue upgrades (`/u`); add/remove monitors |
|
||||
| **owner** | manager | + Drop host (`/d`); add/remove managers; transfer ownership; update host access |
|
||||
| **admin** *(flag)* | owner on all hosts | Full access to every host and the user list |
|
||||
|
||||
`admin` is a flag on the user, not a per-host role. An admin user has owner-level access on every host without being listed as owner/manager/monitor.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Defining users
|
||||
|
||||
```yaml
|
||||
users:
|
||||
andreas:
|
||||
full_name: Andreas Wrede
|
||||
avatar: /path/to/avatar.png # file path, URL, or base64 data URI (optional)
|
||||
password: pbkdf2:sha256:... # generated with: hbd passwd andreas
|
||||
admin: true # optional — grants server-wide owner access
|
||||
|
||||
bob:
|
||||
full_name: Bob Smith
|
||||
password: pbkdf2:sha256:...
|
||||
notification_channels: [pushover_standard]
|
||||
|
||||
carol:
|
||||
full_name: Carol Jones
|
||||
password: pbkdf2:sha256:...
|
||||
|
||||
default_owner: andreas # owns hosts with no explicit owner
|
||||
# falls back to the first admin user if omitted
|
||||
```
|
||||
|
||||
### Assigning roles to hosts
|
||||
|
||||
```yaml
|
||||
hosts:
|
||||
webserver01:
|
||||
owner: andreas
|
||||
managers: [bob]
|
||||
monitors: [carol]
|
||||
threshold_config: default
|
||||
watch: true
|
||||
notification_channels: [pushover_standard]
|
||||
|
||||
unattended-host: # no owner → owned by default_owner
|
||||
threshold_config: default
|
||||
watch: true
|
||||
```
|
||||
|
||||
### Generating a password hash
|
||||
|
||||
```bash
|
||||
hbd passwd andreas
|
||||
```
|
||||
|
||||
Enter and confirm the password when prompted. Paste the printed hash into the config file under the user's `password` key.
|
||||
|
||||
You can also generate a hash non-interactively from Python:
|
||||
|
||||
```python
|
||||
from hbd.server.users import hash_password
|
||||
print(hash_password("mysecret"))
|
||||
```
|
||||
|
||||
Passwords are stored as PBKDF2-HMAC-SHA256 hashes (260 000 iterations). No third-party libraries are required — only Python's standard `hashlib`.
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
When at least one user is defined, every request must be authenticated. Unauthenticated requests to HTML pages are redirected to `/login`; unauthenticated API requests receive `401 Unauthorized`.
|
||||
|
||||
### Browser login
|
||||
|
||||
Navigate to any page — you will be redirected to `/login` automatically. After submitting valid credentials the server sets an `hbd_session` cookie (HttpOnly, SameSite=Lax, 24 h lifetime). All subsequent requests, including JavaScript `fetch()` calls on the dashboards, carry the cookie automatically.
|
||||
|
||||
To log out, visit `/logout`.
|
||||
|
||||
### API / programmatic login
|
||||
|
||||
```bash
|
||||
# Log in and capture the token
|
||||
TOKEN=$(curl -s -X POST http://localhost:50004/api/0/auth/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"username":"andreas","password":"mysecret"}' | jq -r .token)
|
||||
|
||||
# Use the token in subsequent requests
|
||||
curl -H "Authorization: Bearer $TOKEN" http://localhost:50004/api/0/hosts
|
||||
```
|
||||
|
||||
The token is identical to the session cookie value — both mechanisms work simultaneously.
|
||||
|
||||
```bash
|
||||
# Log out
|
||||
curl -s -X POST http://localhost:50004/api/0/auth/logout \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Authentication
|
||||
|
||||
#### POST /api/0/auth/login
|
||||
Obtain a session token.
|
||||
|
||||
**Request body:**
|
||||
```json
|
||||
{ "username": "andreas", "password": "mysecret" }
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{ "token": "<opaque-hex-token>", "username": "andreas" }
|
||||
```
|
||||
Also sets the `hbd_session` cookie for browser clients.
|
||||
|
||||
**Status codes:** `200 OK`, `401 Unauthorized`, `404` (auth not configured)
|
||||
|
||||
---
|
||||
|
||||
#### POST /api/0/auth/logout
|
||||
Invalidate the current session.
|
||||
|
||||
**Headers:** `Authorization: Bearer <token>` or cookie
|
||||
|
||||
**Response:** `{ "success": true }`
|
||||
|
||||
---
|
||||
|
||||
### Users
|
||||
|
||||
#### GET /api/0/users
|
||||
List all users. **Admin only.**
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{ "username": "andreas", "full_name": "Andreas Wrede", "avatar": "", "admin": true, "notification_channels": [] },
|
||||
{ "username": "bob", "full_name": "Bob Smith", "avatar": "", "admin": false, "notification_channels": ["pushover_standard"] }
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### GET /api/0/users/me
|
||||
Return the currently authenticated user's profile.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{ "username": "carol", "full_name": "Carol Jones", "avatar": "", "admin": false, "notification_channels": [] }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Host Access
|
||||
|
||||
#### GET /api/0/hosts/{hostname}/access
|
||||
Return owner/managers/monitors for a host. Requires at least **monitor** role.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"owner": "andreas",
|
||||
"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 in memory. They are not written back to the config file — reload (`SIGHUP`) will re-apply config values. To make changes permanent, update the config file.
|
||||
|
||||
---
|
||||
|
||||
## Host visibility
|
||||
|
||||
When users are configured, `GET /api/0/hosts` only returns hosts the authenticated user has at least monitor access to. Admins see all hosts.
|
||||
|
||||
---
|
||||
|
||||
## Config reload
|
||||
|
||||
On `SIGHUP`, the server reloads the config file, re-loads the user registry, and re-applies `owner`/`managers`/`monitors` from config to all known hosts. Existing sessions remain valid after a reload.
|
||||
|
||||
---
|
||||
|
||||
## No-auth mode
|
||||
|
||||
If `users:` is absent or empty, the server starts in **unauthenticated mode**:
|
||||
|
||||
- No login required — all pages and API endpoints are accessible without credentials.
|
||||
- All permission checks pass unconditionally.
|
||||
- `/login`, `/logout`, and the auth/user API endpoints return `404`.
|
||||
|
||||
This preserves full backwards compatibility with existing deployments.
|
||||
|
||||
---
|
||||
|
||||
## Security notes
|
||||
|
||||
- Session tokens are 64-character cryptographically random hex strings (`secrets.token_hex(32)`).
|
||||
- Sessions expire after 24 hours (configurable via `users_mod.SESSION_TTL`).
|
||||
- Cookies are `HttpOnly` and `SameSite=Lax` — they are not accessible to JavaScript and are not sent on cross-site requests.
|
||||
- The HTTP API does not yet enforce TLS. For production use, place hbd behind a TLS-terminating reverse proxy (nginx, Caddy, etc.) or enable WSS.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [HTTP API Documentation](HTTP_API.md)
|
||||
- [Notifications](NOTIFICATIONS.md)
|
||||
- Configuration example: `hbd/config_example.yaml`
|
||||
Reference in New Issue
Block a user