- шаг схемы закрывает поверхность, которую хранилище приносит открытой: собственную регистрацию, вход по паролю и одноразовый код — без этого закрытие приёма обходилось двумя запросами - продление сессии выключено, срок семь суток: иначе отзыв доступа у провайдера до сервиса не доходит никогда - файл записи отдаётся вошедшему по токену файла — пересмотр ADR-2026-08-12-file-link-open-but-not-logged
68 lines
5.4 KiB
Markdown
68 lines
5.4 KiB
Markdown
# ✨ Пускать в приложение только после входа через OIDC
|
||
|
||
- **Тип:** feature
|
||
- **Категория:** Очередь
|
||
- **Зачем:** HTTP API открыт наружу без аутентификации: любой из интернета заводит задачи за наши деньги и читает чужие расшифровки по идентификатору.
|
||
- **Теги:** goal:multi-user
|
||
|
||
Двигает пункты 1 и 3 «Завершения» цели: неаутентифицированный запрос к записям
|
||
не проходит ни к странице, ни к API; вход идёт через OIDC у Authelia, а выход из
|
||
сессии работает.
|
||
|
||
Провайдер — Authelia по OIDC. Своей регистрации и своих паролей не делаем, это
|
||
граница из [паспорта](../../docs/passport.md). Разграничения записей по владельцу
|
||
здесь ещё нет: после входа видно всё, что видно сейчас, — этим занимается
|
||
`record-ownership`.
|
||
|
||
**Ответ провайдера разбирает PocketBase, а не наш код** — решено 2026-08-11
|
||
([adr](../../docs/adr/ADR-2026-08-11-pocketbase-storage-with-admin-panel.md)).
|
||
У её коллекции пользователей настраивается провайдер `oidc` с адресами Authelia,
|
||
и учётные записи заводятся сами; проверено на версии 0.39.10,
|
||
[docs/research/pocketbase.md](../../docs/research/pocketbase.md). Отсюда порядок:
|
||
задача идёт после `pocketbase-storage`, до неё настраивать нечего.
|
||
|
||
## Затрагивает
|
||
|
||
- настройка провайдера `oidc` у коллекции пользователей PocketBase: адреса
|
||
Authelia, идентификатор клиента, секрет, соответствие полей учётной записи;
|
||
- эндпоинты входа и выхода, которые PocketBase приносит своими;
|
||
- `POST /api/audio` и `GET /api/status/:id` — оба уходят за аутентификацию;
|
||
- `GET /health` и `GET /metrics` — остаются открытыми и сессии не требуют;
|
||
- хранение сессии: её ведёт PocketBase, и решить надо, чем она предъявляется
|
||
приложению;
|
||
- секция конфигурации под провайдера: адрес, идентификатор клиента, секрет;
|
||
- `docs/security.md` — периметр меняется, и первая его строка перестаёт быть
|
||
верной;
|
||
- `config.dist.toml` и `internal/config`.
|
||
|
||
## Критерии приёмки
|
||
|
||
- Запрос к `POST /api/audio` и `GET /api/status/:id` без сессии получает отказ, а
|
||
не заводит задачу и не отдаёт текст. Оракул — тест на обоих эндпоинтах без
|
||
куки: код ответа 401 либо 302 на вход, тело без данных задачи. Тот же тест
|
||
проверяет вторую сторону границы: `GET /health` и `GET /metrics` без куки
|
||
отвечают 200.
|
||
- Сессия переживает перезапуск приложения. Оракул — тест: запрос с прежней кукой
|
||
после пересоздания сервера проходит.
|
||
- Выход из сессии закрывает доступ. Оракул — тест: после выхода тот же запрос
|
||
получает отказ.
|
||
- Секрет провайдера не попадает ни в лог, ни в ответ. Оракул — тест на отсутствие
|
||
значения секрета в записанном выводе логгера.
|
||
- Первая строка `docs/security.md` описывает новый периметр. Оракул — `task
|
||
gate`, шаг `docs.py check`.
|
||
|
||
## Рамки
|
||
|
||
Владельца у записи здесь не заводим и выборку не сужаем: после входа видно
|
||
столько же, сколько сейчас. Инвариант «бот отвечает только тем, кто в белом
|
||
списке» не трогаем — он живёт до `telegram-account-link`. Панель администратора
|
||
тоже не трогаем: наружу её закрывает Authelia на обратном прокси, а это работа
|
||
выкладки.
|
||
|
||
`GET /health` и `GET /metrics` за аутентификацию не уходят — решено 2026-08-12.
|
||
Сессии нет ни у пробы здоровья, ни у сборщика Prometheus, и вход по личным
|
||
токенам эта задача не заводит. Наружу их закрывает то же правило обратного
|
||
прокси, что и панель администратора, — работа выкладки. Пока правило не
|
||
поставлено, `/metrics` отдаёт наружу объёмы работы сервиса: число задач, размеры
|
||
и длительности записей; содержимого расшифровок в них нет.
|