diff --git a/CHANGELOG.md b/CHANGELOG.md index 6165555..1138e19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +# v1.30.2 + +### Fixed + +- **Outbound mail (test email, invites, password resets, OTP-by-email, notifications) could be rejected by the SMTP relay with `554 5.7.1 ... Sender is not same as SMTP authenticate username`.** Many authenticated relays require the `From` address to match the authenticated account or they refuse the send outright. `models/email.js` fell back to a hardcoded `noreply@theta42.com` when `smtp.from` wasn't set, which no relay ever authorized this account to send as. It now falls back to `smtp.user` first — the address the account can actually prove it owns — before the hardcoded placeholder. +- **Catalog page card titles read icon-then-name.** Swapped to name-then-icon so the resource name leads. + +### Docs + +- `docs/configuration.md` didn't mention that OpenBao + the live Configuration UI sit above the four file/env config layers and win the merge — added. +- `docs/plugins.md` listed 3 of 4 discovery plugin types (missing `docker`) and didn't mention the `messaging` plugin category (`twilio`, `webhook`) at all — added both. +- `docs/vault.md` had no navigation (no frontmatter, no back-link, unreachable from the docs index) and described OpenBao as running in dev mode with API access via the root token — both wrong for a real deployment. Fixed navigation and corrected to describe the actual production setup (unsealed OpenBao, server-side scoped-token injection, personal API tokens for programmatic access). +- `docs/discovery.md` was unreachable from the docs index and missing its back-link — both fixed. +- `README.md`'s required-groups list was missing `app_sso_directory_admin` (gates Directory/Plugins/Agent admin). + # v1.30.1 ### Fixed diff --git a/README.md b/README.md index 1e7366e..e76a63c 100755 --- a/README.md +++ b/README.md @@ -200,7 +200,8 @@ If you are pointing the app at your own existing LDAP server, see `pw-sha2`, `ppolicy`, `memberof`, and `refint` modules plus a small custom schema. The bundled Docker image and `install.sh` set all of that up for you. Required groups: `app_sso_admin` (full admin), `app_sso_oauth_admin` (manage -OAuth clients only), `app_sso_invite` (invitation management) — see +OAuth clients only), `app_sso_invite` (invitation management), +`app_sso_directory_admin` (Directory/Plugins/Agent admin) — see DEPLOYMENT.md for the full setup. ## Development diff --git a/docs/configuration.md b/docs/configuration.md index 1e6c36c..0a5c106 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -16,13 +16,27 @@ deep-merges, in order (later wins): `localhost`, `SSO Manager`). 2. `conf/.js` — optional, environment-specific. 3. `conf/secrets.js` — gitignored; secrets + per-deployment values. -4. **`app_*` environment variables** — the highest-precedence layer. +4. **`app_*` environment variables** — the highest-precedence layer among these + four. Any env var whose name starts with `app_` overrides the merged config. The rest of the name splits on **double-underscore** (`__`) into a nested path. Values are `JSON.parse`-coerced when possible (numbers, booleans, null, JSON) and kept as raw strings otherwise. +### A fifth, higher-precedence layer: OpenBao + the Configuration UI + +In a theta-suite deployment, `@simpleworkjs/bao-conf`'s `init()` deep-merges +`secret/sso-manager/conf` (from OpenBao) over the four layers above at boot — +this is the layer `setup.sh`/theta-suite actually manages, and it wins over +everything else here. On top of that, the admin **Configuration** page in the +UI writes straight to `secret/sso-manager/conf` (via `routes/api_conf.js`) +and applies the change to the live `conf` object immediately +(`applyToLiveConf`) — no restart, and it bypasses `conf/secrets.js` entirely. +If a value isn't behaving the way `conf/secrets.js` says it should, check the +Configuration UI / OpenBao before assuming a file edit didn't take — it's +almost certainly OpenBao (or a live UI edit) winning the merge. + ## Examples | Env var | Sets | Type | diff --git a/docs/discovery.md b/docs/discovery.md index 17c41b5..0a4008c 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -6,6 +6,8 @@ nav_order: 6 # Discovery & Inventory +[← Back to Home](index.html) + The Directory holds two different kinds of thing, and the distinction matters for every consumer of the directory: diff --git a/docs/images/dashboard.png b/docs/images/dashboard.png index 18b4a81..04fa9f5 100644 Binary files a/docs/images/dashboard.png and b/docs/images/dashboard.png differ diff --git a/docs/images/directory.png b/docs/images/directory.png index 9b1a4b3..7fa637d 100644 Binary files a/docs/images/directory.png and b/docs/images/directory.png differ diff --git a/docs/images/groups.png b/docs/images/groups.png index ffcb461..d223a88 100644 Binary files a/docs/images/groups.png and b/docs/images/groups.png differ diff --git a/docs/images/oauth-clients.png b/docs/images/oauth-clients.png index e8790d5..1c10e6b 100644 Binary files a/docs/images/oauth-clients.png and b/docs/images/oauth-clients.png differ diff --git a/docs/images/users.png b/docs/images/users.png index 60be54a..9e3983a 100644 Binary files a/docs/images/users.png and b/docs/images/users.png differ diff --git a/docs/index.md b/docs/index.md index defeaa5..a4dabc0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -60,7 +60,10 @@ backend, that's the niche. run the pieces separately via `app_*` env config. - **Geo-Location Scaling** — built-in support for N-Way Multi-Master OpenLDAP [replication](replication.html) across physical sites. - **[Directory & Inventory](directory.html)** — map sites, hosts, and services as a graph with rich metadata (IP/MAC, OS/kernel, ports, git repos), auto-provisioned access groups, and automatic registration from theta-env and ldap-client. Drives directory-aware tools like the [SSH jump host](https://theta42.github.io/jump-host/). +- **[Discovery](discovery.html)** — the catalog-vs-discovered distinction, how scanned assets are matched/merged into existing resources, and how a discovery gets promoted into the catalog (and becomes reachable through the jump host). - **[Theta Agent & Endpoint C2](agents.html)** — 2-way Go daemon (`theta-agent`) for real-time telemetry (CPU, RAM, Disk, ZFS, GPU), automated host discovery, SSSD/LDAP configuration, and local capability-controlled management operations. +- **[Vault secrets](vault.html)** — an OpenBao-backed key-value store built into the UI, for stashing passwords/API keys/credentials with encryption and access control. +- **[API tokens](concepts-api-tokens.html)** — self-service personal access tokens for calling the management API from scripts/CI without a browser session. ## Get it diff --git a/docs/plugins.md b/docs/plugins.md index 1070fa4..fe7b182 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -17,11 +17,25 @@ needs theta-suite ≥ v1.30.1 (which grants the `sso-broker` OpenBao policy A plugin type is a module under `nodejs/plugins//.js`. The filename basename (without `.js`) is the `type`; the parent directory is the -`category`. The built-ins ship under `plugins/discovery/`: +`category`. Two built-in categories ship today: + +**`discovery`** — scheduled scans that sync external assets into the +directory catalog: - `proxmox` — Proxmox VE (URL + API token) - `unifi` — UniFi Network controller (URL + username/password) - `nmap` — nmap OS + port scan (a target range; no credentials) +- `docker` — Docker daemon discovery (containers as directory resources) + +**`messaging`** — on-demand delivery for alerts, 2FA codes, and +notifications: + +- `twilio` — Twilio SMS +- `webhook` — universal REST webhook (custom JSON payload to Slack, Teams, + Discord, or any HTTP endpoint) + +If no messaging plugin instance is enabled, the system falls back to the +legacy `voipms` integration configured directly in the SSO secrets. ### What the Proxmox plugin produces diff --git a/docs/vault.md b/docs/vault.md index 29fec4f..8dd758d 100644 --- a/docs/vault.md +++ b/docs/vault.md @@ -1,5 +1,13 @@ +--- +layout: default +title: Vault Secrets +description: OpenBao-backed personal, shared, and external-app secret storage built into the SSO Manager UI. +--- + # Vault Secrets Management +[← Back to Home](index.html) + The Vault Secrets feature integrates with OpenBao to provide a secure key-value store for your environment. It allows you to store sensitive information like passwords, API keys, and credentials, ensuring they are encrypted and access-controlled. ## Usage @@ -26,7 +34,14 @@ You can access the Vault UI from the application's top navigation bar. ### OpenBao Integration -The secrets are stored in an OpenBao backend configured in development mode. The default KV (Key-Value) version 2 engine is mounted at `secret/`. The built-in UI uses the `/api/vault/secret/` API endpoints to interact with OpenBao. +The secrets are stored in a real, initialized-and-unsealed OpenBao backend +(`setup.sh` handles init/unseal on first run) — not OpenBao's ephemeral dev +mode, which auto-unseals with an in-memory store and loses everything on +restart. The default KV (Key-Value) version 2 engine is mounted at `secret/`. +The built-in UI proxies through `/api/vault/secret/…`, authenticated the same +way as the rest of the app (session cookie or a personal API token) — the +server resolves your OpenBao access itself and injects the right scoped +token; you never see or handle a raw OpenBao token as a UI user. ## Apps tab (admin) @@ -48,9 +63,24 @@ The **Shared** tab lets you share a secret with another user (or app) without co ## API Access -If you need to programmatically access the secrets, you can interact directly with the OpenBao API using the root token (in dev mode): +To read your own secrets programmatically, call the `/api/vault` proxy with +a [personal API token](concepts-api-tokens.html) — **not** a raw OpenBao +token. The server authenticates the request, resolves your own scoped +OpenBao access, and injects the real `X-Vault-Token` itself: ```bash -# Example: Read a secret via the API -curl -H "X-Vault-Token: root" -H "Authorization: Bearer " http:///api/vault/secret/data/ +# Example: Read a secret via the API (KV-v2, so the path includes /data/) +curl -H "Authorization: Bearer sso__" \ + https:///api/vault/secret/data/ ``` + +An **external app** reading its own config uses the scoped token minted for +it on the **Apps** tab instead of a personal token — see *Apps tab (admin)* +above for how that token is minted and what it's confined to. + +Using the OpenBao **root token** directly (bypassing the SSO entirely) is +never the intended path for day-to-day secret access — it's an +operator/maintenance credential (seeding, disaster recovery), kept in +`setup.env` and never passed to a service container. See +[theta-env's Secrets doc](https://theta42.github.io/theta-env/secrets.html) +for the full token/policy model. diff --git a/nodejs/models/email.js b/nodejs/models/email.js index 80bb7ee..5870f7b 100644 --- a/nodejs/models/email.js +++ b/nodejs/models/email.js @@ -33,8 +33,15 @@ Mail.send = function(to, subject, message, from){ var transporter = nodemailer.createTransport(transportOpts); + // Most authenticated SMTP relays (and this bit the field: "554 5.7.1 + // ...: Sender is not same as SMTP authenticate username") require the + // envelope/header From to equal the authenticated user, or reject the + // send outright. If the operator hasn't set an explicit smtp.from, + // defaulting to the SMTP username is far more likely to actually send + // than a made-up noreply@theta42.com address that no relay authorized + // this account to send as. var mailOpts = { - from: from || conf.smtp.from || `${conf.name} Accounts `, + from: from || conf.smtp.from || conf.smtp.user || `${conf.name} Accounts `, to: to, subject: subject, html: message diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index bd5e400..295eb9a 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,12 +1,12 @@ { "name": "t42-sso-manager", - "version": "1.30.1", + "version": "1.30.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "t42-sso-manager", - "version": "1.30.1", + "version": "1.30.2", "license": "MIT", "dependencies": { "@fortawesome/fontawesome-free": "^7.3.0", diff --git a/nodejs/package.json b/nodejs/package.json index 32668d1..7fc1e0e 100755 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -1,6 +1,6 @@ { "name": "t42-sso-manager", - "version": "1.30.1", + "version": "1.30.2", "description": "A very simple LDAP management and SSO system", "author": [ { diff --git a/nodejs/views/landing.ejs b/nodejs/views/landing.ejs index 0b7db71..947e1cf 100644 --- a/nodejs/views/landing.ejs +++ b/nodejs/views/landing.ejs @@ -206,8 +206,8 @@ return '
' + '
' + '
' - + iconHtml + '' + esc(r.name) + '' + + iconHtml + '
' + '
' + esc(r.kind) + (md.subType ? ' · ' + esc(md.subType) : '') + '' + badges + '
'