Document the PHP api layer and fix what documenting it exposed
Writing down what each endpoint actually guarantees made the places it didn't obvious — shell arguments reaching a crontab or a bash -c unescaped, master.conf written without tmp+rename, and conf edits that could be saved without ever being parsed.
This commit is contained in:
@@ -1,4 +1,93 @@
|
||||
<?php
|
||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||
// PURPOSE
|
||||
// Auth stack endpoint. The single URL behind the auth tab, covering all three services it
|
||||
// manages: Nginx Proxy Manager proxy hosts and certificates, lldap users and groups, and
|
||||
// Authelia access rules.
|
||||
//
|
||||
// OPERATIONAL MODEL
|
||||
// Read and write share one URL, split on HTTP method. GET serves the five read actions and
|
||||
// is always safe. POST carries an action naming exactly one library call. Anything that is
|
||||
// neither GET nor POST is refused with 405 before a parameter is read.
|
||||
//
|
||||
// Three services, one endpoint, because they are one subject. The auth stack is HOST1's
|
||||
// source of truth for identity, and a change in one service usually accompanies a change in
|
||||
// another — a new lldap user is only useful once an Authelia rule and an NPM host exist for
|
||||
// it. Splitting them into three endpoints would split one page's work across three files
|
||||
// with three copies of the same dispatch.
|
||||
//
|
||||
// DESIGN PRINCIPLES
|
||||
// Both dispatches are closed match expressions.
|
||||
// Every action maps to one named library call, and an unrecognised action falls to a
|
||||
// default arm that returns an error. No part of the request is ever used to construct a
|
||||
// function name, so the action list is the complete set of things this endpoint can do.
|
||||
//
|
||||
// The endpoint holds no auth logic of its own.
|
||||
// Token acquisition, API dialects, config parsing and the Authelia container restart
|
||||
// all live in include/auth.php. This file is dispatch and nothing else, which is what
|
||||
// keeps the credential handling in one auditable place.
|
||||
//
|
||||
// Structured payloads arrive as JSON in a form field.
|
||||
// Proxy definitions and rule sets are nested, so they are passed as encoded JSON rather
|
||||
// than flattened into form keys — a rule set does not survive form encoding intact.
|
||||
//
|
||||
// OPERATIONAL SAFEGUARDS
|
||||
// Wrong method is refused with a status code, not just a body, so a mistaken caller fails
|
||||
// visibly rather than parsing an error object as data.
|
||||
//
|
||||
// Every parameter is optional and typed at the call site.
|
||||
// (int) casts on ids, ?? '' on strings, ?? '0' === '1' on flags. A malformed POST
|
||||
// reaches the library as zeros and empty strings — which the library rejects — rather
|
||||
// than raising undefined-index warnings into the JSON body and corrupting the response.
|
||||
//
|
||||
// Malformed JSON degrades to an empty structure.
|
||||
// json_decode with ?: [] on both data and rules. A truncated payload becomes an empty
|
||||
// set the library refuses, not a partial one it might act on.
|
||||
//
|
||||
// Credentials pass through, and are never returned.
|
||||
// lldap_set_password and lldap_create_user accept a password and hand it straight to
|
||||
// the library. No action in either dispatch returns a stored credential, and nothing
|
||||
// here writes one to a log.
|
||||
//
|
||||
// The destructive actions are POST-only by construction.
|
||||
// Delete of a proxy, a user, or a group exists only in the POST match. The GET arm has
|
||||
// five read actions and no others, so no link or prefetch can reach a delete.
|
||||
//
|
||||
// Authelia rule writes are atomic and refuse to create.
|
||||
// The library writes .vv.tmp and renames, and returns 'Config not found' rather than
|
||||
// authoring a fresh config — a config it created would carry no rules and a default
|
||||
// policy, which is an accidental open door.
|
||||
//
|
||||
// Known gap: no CSRF token is validated on the POST actions.
|
||||
// The endpoint is guarded by the Unraid WebGUI session alone, and this is the highest-
|
||||
// value endpoint in the plugin to reach — it can create a user and open a proxy host.
|
||||
// Shared with the rest of the api layer; see the CSRF note in README-unraid.md.
|
||||
//
|
||||
// REQUEST
|
||||
// GET ?action=npm_proxies | npm_certs | lldap_users | lldap_groups | authelia_rules
|
||||
// POST action=npm_create data=<JSON>
|
||||
// POST action=npm_update id, data=<JSON>
|
||||
// POST action=npm_delete id
|
||||
// POST action=npm_toggle id, enabled=0|1
|
||||
// POST action=lldap_create_user uid, email, display_name, password
|
||||
// POST action=lldap_update_user uid, email, display_name
|
||||
// POST action=lldap_delete_user uid
|
||||
// POST action=lldap_set_password uid, password
|
||||
// POST action=lldap_create_group name
|
||||
// POST action=lldap_delete_group id
|
||||
// POST action=lldap_add_to_group uid, gid
|
||||
// POST action=lldap_remove_from_group uid, gid
|
||||
// POST action=authelia_save rules=<JSON>, default_policy
|
||||
//
|
||||
// RESPONSE
|
||||
// Whatever the invoked library call returns — ['ok' => bool] with a payload or an error,
|
||||
// or an _err key on a failed remote call. npm_certs is wrapped as {"ok":true,"certs":[…]}.
|
||||
// {"ok":false,"error":"Unknown action: …"} for anything outside the lists above.
|
||||
//
|
||||
// DEPENDS ON
|
||||
// include/auth.php vv_npm_*(), vv_lldap_*(), vv_authelia_read_rules(),
|
||||
// vv_authelia_write_rules()
|
||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||
header('Content-Type: application/json');
|
||||
require_once dirname(__DIR__) . '/include/auth.php';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user