tasks: вход переезжает на заголовки прокси, пять задач про OIDC закрыты
- заведена `trusted-header-login` и поставлена в голову очереди - пять задач про механику OIDC закрыты как отменённые ею - `dev-run-task` и `api-tokens` переписаны под новый вход
This commit is contained in:
@@ -2,17 +2,24 @@
|
||||
|
||||
- **Тип:** feature
|
||||
- **Категория:** Очередь — Второй способ представиться ставится на готовые владельца и контракт, иначе форма ошибки переписывается дважды.
|
||||
- **Зачем:** Вход через OIDC закрывает API целиком, а скрипту браузерная сессия недоступна: автоматизировать загрузку станет нечем.
|
||||
- **Зачем:** Скрипту недоступны ни браузерная сессия, ни вход у Authelia: домен целиком стоит за прокси, и автоматизировать загрузку нечем.
|
||||
|
||||
Запрос без токена не проходит, а скрипт ходит в API по токену, выпущенному
|
||||
пользователем, и видит ровно его записи.
|
||||
|
||||
Половина работы при этом лежит на контуре: домен целиком стоит за `forward_auth`
|
||||
Authelia, и запрос скрипта не доходит до сервиса вовсе — его отбивает прокси.
|
||||
Значит адресам API нужно правило, пропускающее их к сервису, а сервис судит
|
||||
токен сам. Правило живёт в `pet-project-server`, вне этого репозитория.
|
||||
|
||||
Токен принадлежит учётной записи и даёт ровно её права: записи, заведённые по
|
||||
токену, видны владельцу в приложении, и наоборот.
|
||||
|
||||
## Затрагивает
|
||||
|
||||
- заголовок авторизации у всех адресов приложения `/app/`;
|
||||
- заголовок авторизации у всех адресов приложения `/app/` и его отношение к
|
||||
заголовку, который ставит прокси: два способа представиться и один владелец;
|
||||
- правило Authelia, пропускающее адреса API мимо входа, — в `pet-project-server`;
|
||||
- таблица токенов: владелец, имя, отпечаток, время выпуска и последнего
|
||||
обращения, и её миграция;
|
||||
- адреса выпуска, перечня и отзыва токена — `/app/me/tokens`;
|
||||
@@ -35,6 +42,7 @@
|
||||
|
||||
Учётные записи по-прежнему заводит Authelia — свою регистрацию не делаем.
|
||||
Сроков жизни и областей действия у токена не заводим: он даёт права владельца
|
||||
целиком. Берётся после `oidc-login`: до неё представляться некому. Экрана выпуска здесь
|
||||
целиком. Берётся после `trusted-header-login`: до неё представляться некому, а
|
||||
она же решает, какому источнику сервис верит. Экрана выпуска здесь
|
||||
нет — приложения ещё не существует, токен выпускается запросом к API; место
|
||||
токена на экране настроек заводит `settings-screen`.
|
||||
|
||||
+22
-18
@@ -1,18 +1,22 @@
|
||||
# 🧹 Поднимать сервис и заглушку одной командой
|
||||
# 🧹 Поднимать сервис для локальной работы одной командой
|
||||
|
||||
- **Тип:** chore
|
||||
- **Категория:** Очередь — оснастка локального прогона: без неё каждую проверку начинают с двух терминалов и ручной уборки
|
||||
- **Зачем:** Локальная проверка требует двух терминалов, ручной остановки обоих процессов и чистки каталога данных; учётную запись заводят проходом по браузеру, а владельца панели — по одноразовой ссылке из журнала.
|
||||
- **Зачем:** Локальная проверка требует ручной чистки каталога данных и остановки процесса, а владельца панели заводят по одноразовой ссылке из журнала.
|
||||
|
||||
Шаг `task dev CONFIG=<путь> USER=<почта>` поднимает сервис и подставной
|
||||
провайдер OIDC разом, кладёт данные во временный каталог, заводит учётные записи
|
||||
и гасит оба процесса по Ctrl+C.
|
||||
Шаг `task dev CONFIG=<путь> USER=<имя>` поднимает сервис, кладёт данные во
|
||||
временный каталог, заводит владельца панели и гасит процесс по Ctrl+C.
|
||||
|
||||
Работа состоит из двух частей, и они едут одним коммитом: инструмент
|
||||
`cmd/devadmin` и шаг `dev`, который его зовёт. Порознь они не нужны — шаг без
|
||||
инструмента не заведёт владельца панели, инструмент без шага останется вызовом,
|
||||
который никто не делает.
|
||||
|
||||
Заглушки провайдера здесь больше нет: вход переезжает на доверенные заголовки
|
||||
задачей `trusted-header-login`, и обычная учётная запись заводится первым же
|
||||
запросом с заголовком. Каким способом заголовок попадает в запрос на машине без
|
||||
прокси, решает та задача; этот шаг её решение только зовёт.
|
||||
|
||||
Задуманное устройство:
|
||||
|
||||
- конфиг пишет человек и передаёт путём — шаг его не сочиняет;
|
||||
@@ -21,13 +25,12 @@
|
||||
того, что написано в конфиге. Временное живёт в `/tmp` — в `data/` писать
|
||||
запрещено (CLAUDE.md, «Запреты»);
|
||||
- владельца панели заводит `cmd/devadmin` — отдельный main-пакет рядом с
|
||||
`cmd/oidcstub`, в образ он не едет. Базу открывает тем же `pbrepo.New`, что и
|
||||
`cmd/transcriber`, в образ он не едет. Базу открывает тем же `pbrepo.New`, что и
|
||||
сервис, и потому получает её со схемой целиком; зовётся до подъёма сервиса, на
|
||||
пустом каталоге. Пароль существующего владельца не переписывает;
|
||||
- шаг заводит обычную учётную запись входом: поднимает `cmd/oidcstub` с
|
||||
`-email` из `USER`, сам проходит цепочку входа и тем создаёт запись;
|
||||
- оба процесса идут одной группой, `trap` на `INT` и `TERM` гасит их разом,
|
||||
`wait` держит терминал.
|
||||
- обычная учётная запись заводится первым запросом с заголовком: имя берётся из
|
||||
`USER`, и заводить её отдельно шагу не нужно;
|
||||
- `trap` на `INT` и `TERM` гасит процесс, `wait` держит терминал.
|
||||
|
||||
## Затрагивает
|
||||
|
||||
@@ -41,14 +44,14 @@
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
- Команда поднимает оба процесса и печатает адрес, по которому открывать
|
||||
приложение. Оракул: прогон с тестовым конфигом — сервис и заглушка слушают свои
|
||||
порты.
|
||||
- Ctrl+C гасит обоих и не оставляет висящих процессов. Оракул: `pgrep` по обоим
|
||||
именам после остановки — пусто.
|
||||
- После запуска в базе есть учётная запись с переданной почтой, а владелец панели
|
||||
входит своим паролем. Оракул: запрос к коллекции пользователей во временной базе
|
||||
и вход по `auth-with-password` в коллекцию владельцев.
|
||||
- Команда поднимает сервис и печатает адрес, по которому открывать приложение,
|
||||
вместе со способом представиться. Оракул: прогон с тестовым конфигом — сервис
|
||||
слушает свой порт, названный адрес отвечает.
|
||||
- Ctrl+C гасит процесс и не оставляет висящих. Оракул: `pgrep` по имени после
|
||||
остановки — пусто.
|
||||
- Владелец панели входит своим паролем, а первый запрос с именем из `USER`
|
||||
заводит учётную запись. Оракул: вход по `auth-with-password` в коллекцию
|
||||
владельцев и запрос к коллекции пользователей во временной базе.
|
||||
- Каталог данных лежит во временном месте, а `data/` не тронут. Оракул: путь базы
|
||||
из журнала подъёма и `git status` после прогона.
|
||||
- `task gate` остаётся зелёным, скрипт проходит `shellcheck`, а образ не получает
|
||||
@@ -57,6 +60,7 @@
|
||||
## Рамки
|
||||
|
||||
Шаг локальный: наружу не ходит, боевых ключей не требует и в образ не попадает.
|
||||
Идёт после `trusted-header-login` — до неё локальный вход устроен иначе.
|
||||
Пароль владельца в конфиг **не заводится** — требование спеки `storage` «Пароль
|
||||
владельца от панели не лежит в конфигурации» остаётся в силе, и работа его не
|
||||
трогает. Распознавание при выдуманных ключах не работает — это остаётся как есть,
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# 🔬 Четыре недоказанные гипотезы о поверхности входа
|
||||
|
||||
- **Тип:** research
|
||||
- **Категория:** Очередь — Разведка закрывает тему входа последней: остальные три задачи меняют то, что она проверяет.
|
||||
- **Зачем:** Ревью назвало четыре пути, которых не смогло ни подтвердить, ни опровергнуть: браузера и живого провайдера в прогоне не было.
|
||||
|
||||
Откуда — отчёт триажа ревью задачи `oidc-login` 2026-08-12,
|
||||
[review/report.md](../../openspec/changes/archive/2026-08-12-oidc-login/review/report.md),
|
||||
раздел «Гипотезы без доказательства». Каждая либо становится задачей, либо
|
||||
закрывается с причиной; сегодня они не то и не другое.
|
||||
|
||||
## Вопрос
|
||||
|
||||
Работает ли хоть один из четырёх путей на самом деле, и если да — чего стоит
|
||||
каждый?
|
||||
|
||||
1. **Выход по чужой ссылке.** Адрес выхода сессии не требует и на запросе с
|
||||
чужого сайта отвечает успехом, убирая куку. Применит ли браузер эту куку при
|
||||
ограничении `SameSite=Lax` — по коду не выяснить. Если применит, человека
|
||||
выкидывает молча, а унесённое значение остаётся годным.
|
||||
2. **Слияние двух учётных записей провайдера с одной почтой.** Обмен ищет запись
|
||||
по неизменяемому признаку провайдера, а не найдя — по адресу почты. Выдаст ли
|
||||
Authelia двум разным субъектам один адрес, зависит от её настройки.
|
||||
3. **Поле снимка в ответе провайдера тянет данные наружу.** Оно сопоставлено
|
||||
файловому полю учётной записи, и библиотека скачивает названный там адрес —
|
||||
до потолка размера записи. Шлёт ли Authelia это поле и кто им управляет,
|
||||
неизвестно.
|
||||
4. **Анонимный запрос подтверждения почты.** Адрес отвечает успехом и заставляет
|
||||
сервис слать почту. Почта не настроена, и потолка числа запросов нет.
|
||||
|
||||
## Куда ляжет ответ
|
||||
|
||||
- подтверждённый путь — задачей в беклоге, и она называет эту разведку;
|
||||
- опровергнутый — строкой в `docs/security.md`, раздел «Что вне модели» либо
|
||||
«Что разграничивает доступ», чтобы следующее ревью не открывало его заново;
|
||||
- то, что зависит от настройки Authelia, — строкой там же, с указанием, какая
|
||||
именно настройка это решает.
|
||||
|
||||
## Рамки
|
||||
|
||||
Смотрим только четыре названных пути. Первый требует настоящего браузера, второй
|
||||
и третий — настоящей Authelia либо её настройки из `pet-project-server`;
|
||||
четвёртый воспроизводится своим прогоном без внешних систем и потому берётся
|
||||
первым. Прогонов на боевом контуре не делаем.
|
||||
@@ -1,38 +0,0 @@
|
||||
# ✨ Строить адрес входа из настроек коллекции, а не из конфига
|
||||
|
||||
- **Тип:** feature
|
||||
- **Категория:** Очередь — Замыкает тройку правок обработчиков входа.
|
||||
- **Зачем:** Первая половина входа собрана руками из конфига и на настройки провайдера не смотрит, вторая берётся из коллекции: обновление библиотеки изменит только вторую половину.
|
||||
|
||||
Найдено ревью задачи `oidc-login` 2026-08-12, отчёт триажа —
|
||||
[review/report.md](../../openspec/changes/archive/2026-08-12-oidc-login/review/report.md),
|
||||
пункт срезанного потолком под номером 7.
|
||||
|
||||
Сегодня адрес согласия собирается своим кодом: состав запрашиваемых сведений,
|
||||
способ проверочного кода и признак ответа записаны у нас, а обмен кода берёт
|
||||
настройки провайдера из коллекции хранилища. Библиотека умеет собирать этот
|
||||
адрес сама — она делает это своим обработчиком способов входа.
|
||||
|
||||
Цена расхождения отложенная: адреса провайдера и идентификатор клиента получают
|
||||
второго потребителя мимо единственного места, где настройки живут, а правка
|
||||
провайдера в панели на начало входа не влияет вовсе. Обновление библиотеки,
|
||||
тронувшее форму запроса согласия, доедет до половины протокола и разойдётся
|
||||
молча — отказом на живой выкладке, которого нечем воспроизвести.
|
||||
|
||||
## Затрагивает
|
||||
|
||||
- эндпоинт `GET /auth/login`, где сегодня адрес согласия собирается вручную;
|
||||
- поля `auth_url` и `client_id` в секции `[auth]` конфига и их проброс —
|
||||
часть из них перестаёт быть нужной приложению;
|
||||
- дельта-спека `access`, требование «Вход через внешнего провайдера» — состав
|
||||
запрашиваемых сведений и способ проверочного кода перестают быть нашими.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
- Адрес согласия строится из настроек коллекции: правка провайдера в панели
|
||||
меняет адрес, куда уводит вход. Оракул — тест: сменить настройки провайдера в
|
||||
хранилище и убедиться, что адрес перенаправления изменился.
|
||||
- Проверочный код и состав запрашиваемых сведений берутся у библиотеки, а не
|
||||
записаны у нас. Оракул — чтение кода: своих литералов состава больше нет.
|
||||
- Вход по-прежнему проходит целиком. Оракул — существующий тест входа через
|
||||
подставного провайдера остаётся зелёным.
|
||||
@@ -1,44 +0,0 @@
|
||||
# 🐞 Убрать код провайдера из журнала запросов хранилища
|
||||
|
||||
- **Тип:** fix
|
||||
- **Категория:** Очередь — Три задачи входа собраны подряд: все правят обработчики входа и одно требование спеки access — три захода в один файл дороже одного.
|
||||
- **Зачем:** Строка запроса с кодом входа целиком уезжает в таблицу _logs и лежит там пять суток, хотя спека access требует, чтобы код в журнал не попадал.
|
||||
|
||||
Найдено ревью задачи `oidc-login` 2026-08-12, отчёт триажа —
|
||||
[review/report.md](../../openspec/changes/archive/2026-08-12-oidc-login/review/report.md),
|
||||
пункт срезанного потолком под номером 2.
|
||||
|
||||
Наш собственный журнал чист — код туда не пишет ни одна строка приложения.
|
||||
Пишет его слой хранилища: он логирует всякий запрос вместе со строкой запроса,
|
||||
а адрес возврата несёт код параметром. Тест на отсутствие значений в журнале
|
||||
этого не видит, потому что смотрит только в наш логгер.
|
||||
|
||||
Код провайдера одноразовый и живёт минуты, поэтому это не захват сессии, а
|
||||
расхождение написанного со сделанным: комментарий в коде и норма спеки
|
||||
утверждают, что код в журнал не идёт.
|
||||
|
||||
## Воспроизведение
|
||||
|
||||
1. Поднять сервис с настроенным провайдером.
|
||||
2. Пройти вход и вернуться на адрес возврата.
|
||||
3. Открыть журнал запросов хранилища — панель, `GET /api/logs` либо файл базы.
|
||||
4. В строке запроса и в поле `url` виден код провайдера целиком.
|
||||
|
||||
## Затрагивает
|
||||
|
||||
- адрес возврата `GET /auth/callback` и слой журналирования запросов хранилища;
|
||||
- настройка срока хранения журнала запросов (сегодня умолчание, пять суток);
|
||||
- дельта-спека `access`, требование «Значение, дающее доступ, не печатается» —
|
||||
либо норма выполняется, либо изъятие называется поимённо;
|
||||
- `docs/security.md`, перечень мест, где оседает чувствительное.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
- После входа код провайдера не встречается в журнале запросов хранилища.
|
||||
Оракул — тест: пройти вход подставным провайдером, затем отобрать записи
|
||||
журнала и убедиться, что значения кода в них нет.
|
||||
- Строка о запросе к адресу возврата в журнале остаётся: пропажа самого следа
|
||||
не годится, прослеживаемость входа нужна. Оракул — тот же тест: запись о
|
||||
запросе есть, кода в ней нет.
|
||||
- Норма и код сошлись: либо спека выполняется буквально, либо в ней названо
|
||||
изъятие с ценой. Оракул — чтение требования против исхода первого теста.
|
||||
@@ -1,53 +0,0 @@
|
||||
# 🐞 Починить срок сессии, который ставит откат шага входа
|
||||
|
||||
- **Тип:** fix
|
||||
- **Категория:** Очередь — Оба про откат шага схемы: соседняя строка называет, что откат не отменяет применённое, эта чинит константу, которую он ставит. Порознь их правят дважды в одном файле.
|
||||
- **Зачем:** Константа defaultAuthTokenDuration в шаге 202608120001 названа умолчанием библиотеки, но 1209600 — это 14 суток, а умолчание PocketBase 432000, пять суток: откат объявляет возврат к умолчанию и ставит срок вдвое больше выбранных владельцем семи.
|
||||
|
||||
Найдено ревью пачки задач о гейте 2026-08-12, проход разбора кода. Дефект
|
||||
пришёл из задачи `oidc-login` и её правкой не был замечен; переезд шагов схемы в
|
||||
свой каталог развёл противоречащие комментарии по разным файлам, где раньше они
|
||||
стояли в трёх строках друг от друга: `provider.go` пишет «умолчание библиотеки в
|
||||
пять суток», шаг — «умолчание библиотеки» о числе в 14 суток.
|
||||
|
||||
Оракул сегодняшнего состояния:
|
||||
`grep -n "Duration: 432000" ~/go/pkg/mod/github.com/pocketbase/pocketbase@v0.39.10/core/collection_model_auth_options.go`
|
||||
отдаёт строку `Duration: 432000, // 5days`. Числа `1209600` в модуле нет ни разу
|
||||
как длительности токена.
|
||||
|
||||
**Развилка, которую решает человек:** правка меняет поведение **применённого**
|
||||
шага схемы, а такое спрашивается всегда. Либо константа приводится к 432000
|
||||
внутри существующего шага (откат ещё не исполнялся ни разу, и переписывание
|
||||
трогает только будущие откаты), либо 14 суток объявляются выбранным числом — и
|
||||
тогда меняется имя константы и её комментарий, а не значение.
|
||||
|
||||
## Воспроизведение
|
||||
|
||||
1. Подключить откаты (`migratecmd`) — сегодня их не подключает ничто.
|
||||
2. Откатить шаг `202608120001_oidc_login.go`.
|
||||
3. Прочитать `AuthToken.Duration` коллекции `users`: там 1209600 — вдвое больше
|
||||
семи суток, выбранных владельцем, и в 2.8 раза больше умолчания библиотеки,
|
||||
к которому откат обещал вернуть.
|
||||
|
||||
## Затрагивает
|
||||
|
||||
- `internal/adapter/repo/pocketbase/migrations/202608120001_oidc_login.go`,
|
||||
константа `defaultAuthTokenDuration` и комментарий `down202608120001`;
|
||||
- `internal/adapter/repo/pocketbase/provider.go`, комментарий к
|
||||
`SessionDuration` — он называет умолчание пятью сутками;
|
||||
- поведение откатов, если их подключат.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
- Число в откате и число, названное умолчанием библиотеки, совпадают. Оракул —
|
||||
чтение константы против `core/collection_model_auth_options.go` версии
|
||||
PocketBase из `go.mod`.
|
||||
- Комментарии шага и `provider.go` говорят об умолчании одно и то же. Оракул —
|
||||
чтение обоих мест подряд.
|
||||
- Гейт зелёный целиком. Оракул — `task gate`.
|
||||
|
||||
## Рамки
|
||||
|
||||
Правка применённого шага схемы — необратимое: решение принимает человек. Новым
|
||||
шагом это не лечится: новый шаг накатывается вперёд, а исправить нужно ветку
|
||||
отката прежнего.
|
||||
@@ -1,54 +0,0 @@
|
||||
# 🐞 Вести учёт употреблённых состояний входа на сервере
|
||||
|
||||
- **Тип:** fix
|
||||
- **Категория:** Очередь — Тот же файл и та же спека, что у строки выше.
|
||||
- **Зачем:** Одноразовость возврата держится на уборке куки, то есть на браузере: сервер не помнит, какие состояния уже потрачены.
|
||||
|
||||
Найдено ревью задачи `oidc-login` 2026-08-12, отчёт триажа —
|
||||
[review/report.md](../../openspec/changes/archive/2026-08-12-oidc-login/review/report.md),
|
||||
остаток пункта 4.
|
||||
|
||||
Носитель состояния здесь — кука, которую сервис ставит на время входа: в ней
|
||||
лежат выданное состояние и проверочный код, и по ней сверяется возврат.
|
||||
|
||||
Спека требует, чтобы состояние было одноразовым: возврат с уже употреблённым
|
||||
отвергается наравне с невыданным. Сегодня это выполняется тем, что носитель
|
||||
состояния убирается у браузера на возврате — и для обычного человека этого
|
||||
достаточно: второй раз тот же адрес возврата сверку не пройдёт.
|
||||
|
||||
Чего это не закрывает: тот, кто носитель контролирует, поставит его себе заново
|
||||
и повторит возврат. Отказ тогда наступит только потому, что код у провайдера
|
||||
одноразовый, — то есть гарантия перенесена на внешнюю систему, чего норма не
|
||||
допускает.
|
||||
|
||||
Цена сегодняшнего состояния невелика, поэтому задача и отложена: код живёт
|
||||
минуты, а вход у провайдера всё равно нужен. Цена решения — своё хранение
|
||||
состояний со сроком жизни и его чистка.
|
||||
|
||||
## Воспроизведение
|
||||
|
||||
1. Пройти вход до конца: получить сессию по возврату от провайдера.
|
||||
2. Поставить носитель состояния заново — тем же значением, которое сервис выдавал
|
||||
на первом шаге.
|
||||
3. Повторить тот же запрос возврата.
|
||||
4. Сверка состояния проходит, и запрос уходит в обмен. Отказ наступает только
|
||||
потому, что код у провайдера одноразовый, — то есть одноразовость держит
|
||||
внешняя система, а не сервис.
|
||||
|
||||
## Затрагивает
|
||||
|
||||
- обработчики начала входа и возврата;
|
||||
- место хранения употреблённых состояний: своя коллекция хранилища либо память
|
||||
процесса — выбор входит в задачу;
|
||||
- дельта-спека `access`, требование «Вход через внешнего провайдера» — сценарий
|
||||
«Возврат нельзя переиграть» получает настоящий оракул.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
- Повторный возврат с тем же состоянием отвергается, даже если носитель
|
||||
восстановлен вручную. Оракул — тест: пройти вход, затем повторить тот же
|
||||
возврат с заново поставленным носителем; сессия не открывается.
|
||||
- Состояния не копятся без предела. Оракул — тест либо чтение кода: у записи
|
||||
состояния есть срок жизни, и просроченные убираются.
|
||||
- Вход по-прежнему проходит целиком. Оракул — существующий тест входа через
|
||||
подставного провайдера остаётся зелёным.
|
||||
@@ -0,0 +1,72 @@
|
||||
# ✨ Пускать по доверенным заголовкам Authelia вместо входа OIDC
|
||||
|
||||
- **Тип:** feature
|
||||
- **Категория:** Очередь — Вход переезжает на заголовки прокси: пять задач про механику OIDC этим закрываются, а всё, что трогает вход и локальный прогон, ставится на него
|
||||
- **Зачем:** Вход собран своими руками — состояние, PKCE, обмен кода внутрипроцессным запросом к роутеру хранилища, — а обратный прокси уже отдаёт трём соседним сервисам заголовки Remote-* от Authelia; заодно секрет клиента лежит в базе, а панель обходится подменой знака в пути.
|
||||
|
||||
Кто пришёл, сервис узнаёт из заголовка, который поставил обратный прокси, сходив
|
||||
к Authelia. Своего входа у сервиса не остаётся вовсе: ни адреса, уводящего к
|
||||
провайдеру, ни возврата, ни куки сессии, ни выхода.
|
||||
|
||||
Контур к этому готов: `files/caddyproxy/Caddyfile.template` в
|
||||
`pet-project-server` уже отдаёт `Remote-User`, `Remote-Groups`, `Remote-Email` и
|
||||
`Remote-Name` панели, netdata и remembos, а правила для этого сервиса там нет
|
||||
вовсе — он не выложен. Контейнер портов наружу не публикует.
|
||||
|
||||
Три следствия, ради которых это и делается. Отзыв доступа перестаёт ждать
|
||||
семи суток: Authelia судит каждый запрос, а не только вход. Секрет клиента
|
||||
уходит из конфига и из базы — вместе с ним снимается изъятие из инварианта
|
||||
«Секрет не покидает конфиг». Панель закрывается доменом, а не правилом на литерал
|
||||
пути, и обход `/%5f/` перестаёт существовать.
|
||||
|
||||
## Затрагивает
|
||||
|
||||
- адреса `GET /auth/login`, `GET /auth/callback`, `POST /auth/logout` — исчезают
|
||||
целиком вместе с корнем `/auth`;
|
||||
- куки `transcriber_session` и `transcriber_login`, слои `SessionFromCookie` и
|
||||
`BlockSessionRefresh`;
|
||||
- заголовки `Remote-User`, `Remote-Email`, `Remote-Name` — новый недоверенный
|
||||
вход, и адрес источника запроса как условие доверия к ним;
|
||||
- секция `[auth]` конфига и `config.example.toml`: имена ключей — необратимое;
|
||||
- настройки провайдера у коллекции `users` (`ApplyProviderSettings`) и новый шаг
|
||||
схемы; применённый `202608120001_oidc_login` не переписывается;
|
||||
- собственные адреса входа хранилища под `/api/collections/users/`: обмена кода,
|
||||
входа по паролю и запроса подтверждения почты больше не предъявляет никто;
|
||||
- `cmd/oidcstub` и подставной провайдер в тестах входа;
|
||||
- способ представиться на машине без прокси: сегодня им служит заглушка
|
||||
провайдера, и замену ей называет эта задача — на неё опирается `dev-run-task`;
|
||||
- спека `access`; `docs/security.md` — периметр, недоверенный вход, «Четвёртый
|
||||
сдвиг»; `CLAUDE.md` — изъятие из инварианта о секрете; `docs/architecture.md`;
|
||||
- правило прокси и правило Authelia для домена сервиса — они живут в
|
||||
`pet-project-server`, вне этого репозитория.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
- Обращение к адресу приложения с заголовком от доверенного источника идёт от
|
||||
имени учётной записи, заведённой при первом таком обращении, а повторное с тем
|
||||
же значением попадает в ту же запись. Оракул — тест обработчика: два запроса
|
||||
подряд, в хранилище одна запись пользователя.
|
||||
- Тот же заголовок с недоверенного адреса даёт `401`, а не вход под названным
|
||||
именем. Оракул — тест: запрос с адресом источника вне перечня доверенных.
|
||||
- Собственные адреса входа хранилища сессии не выдают и учётную запись не
|
||||
меняют. Оракул — тест по перечню адресов под `/api/collections/users/`: каждый
|
||||
отвечает отказом.
|
||||
- Механики OIDC в дереве не осталось: корня `/auth`, кук входа,
|
||||
`ApplyProviderSettings`, `cmd/oidcstub` и секрета клиента в конфиге. Оракул —
|
||||
поиск по этим именам плюс зелёный `task gate`.
|
||||
- Разграничение записей по владельцу работает как прежде: чужая запись
|
||||
неотличима от несуществующей. Оракул — существующие тесты владельца остаются
|
||||
зелёными.
|
||||
|
||||
## Рамки
|
||||
|
||||
Ключ учётной записи — `Remote-User`: переименование пользователя в Authelia
|
||||
заведёт новую запись, и прежние записи останутся у прежней. Это принятая цена,
|
||||
и она записывается в спеку, а не обходится.
|
||||
|
||||
Второй уровень доступа по `Remote-Groups` здесь не заводится: его потребителя —
|
||||
страницы расхода — ещё нет.
|
||||
|
||||
Половина работы живёт в `pet-project-server` и этим репозиторием не проверяется
|
||||
ничем: задача обязана назвать требование к контуру в `docs/security.md`, а
|
||||
выкладку запускает человек.
|
||||
Reference in New Issue
Block a user