Documentation
¶
Overview ¶
Package clienttokenhttp — токен-эндпоинт платформы (задача #898, приёмка F2 §9.1 п. 1).
Клиент предъявляет подписанное утверждение, мы сверяем подпись его открытым ключом из своей же таблицы и выдаём токен доступа по виду выдачи «учётные данные клиента». Форма запроса и форма ответа — стандартные (RFC 6749 §4.4, RFC 7523 §2.2): предъявитель — чужая библиотека, и ответ обязан быть тем, который она умеет прочитать, иначе отказ выглядит для неё сбоем сети.
Единый тон наружу и различимость внутрь ¶
Всякий отказ, наступивший ПОСЛЕ того, как в запросе назван клиент — включая «такого клиента нет», — отдаёт побайтово ОДНО И ТО ЖЕ. Различимый отказ есть оракул: по нему устанавливают, существует ли клиент, жив ли он, какой у него алгоритм и какие идентификаторы однократности уже заняты. Каждый ответ сам по себе безобиден, а вместе они дают карту.
Различимыми остаются ровно ПЯТЬ отказов, и все пять решаются ДО того, как запрос назвал хоть какого-нибудь клиента: метод, потолок тела, неразбираемая форма, вид выдачи вне перечня и повторённый параметр утверждения. Они не сообщают о клиенте ничего, потому что клиента на этом шаге ещё нет, и стандартные коды у них обязаны быть свои — иначе чужая библиотека прочтёт «слишком большое тело» как «неверный клиент» и будет чинить не то.
Различимость для НАС живёт с другой стороны провода: у каждого исхода свой счётчик и своя запись в журнале. Без счётчика мёртвый контроль невидим — проверка, не отказавшая ни разу за всё время жизни, неотличима от проверки, которая работает и просто не встречала нарушителя.
Index ¶
Constants ¶
const TokenPath = "/iam/v1/token"
TokenPath — объявленный путь эндпоинта.
#nosec G101 -- это АДРЕС поверхности, а не учётные данные: строка попадает в маршрут и в документацию клиента, её знает всякий, кто обращается к сервису. Слово в адресе называет предмет выдачи, а не хранимый секрет.
Variables ¶
This section is empty.
Functions ¶
func DeclaredOutcomes ¶ added in v0.2.0
func DeclaredOutcomes() []string
DeclaredOutcomes — закрытый словарь исходов этой полосы строками.
Отдаётся наружу ради читателя величин: набор рядов витрины обязан совпадать с набором клеток переписи by construction. Выведен из того же clientassertion.Outcomes, которым засеяна перепись, поэтому второй копией словаря не является.
Types ¶
type Config ¶
type Config struct {
// BodyCeiling — потолок тела запроса в байтах. ОБЯЗАТЕЛЕН.
//
// Умолчания здесь нет намеренно. Величина, которую построение подставляет
// молча, не может быть предметом стража старта: страж, требующий её
// задания, зелен при любом входе, потому что незаданной она не бывает. Тело
// этого запроса — форма с одним подписанным утверждением, и его потолок
// объявляет тот, кто поднимает сервис.
BodyCeiling int64
Logger *slog.Logger
}
Config — настройка эндпоинта.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler — токен-эндпоинт.
func NewHandler ¶
NewHandler строит эндпоинт. Неполная провязка — отказ построения: эндпоинт без проверяющего принимал бы кого угодно, без выдачи — не выдавал бы никому, и оба состояния обнаружились бы на первом запросе, а не на старте.
type Issuer ¶
type Issuer interface {
Issue(ctx context.Context, in client_token.Input) (client_token.Output, clientassertion.Outcome, error)
}
Issuer — порт выдачи.
type Verifier ¶
type Verifier interface {
// Verify — полоса аутентификации клиента (RFC 7523 §2.2): утверждение
// доказывает личность клиента, ключ берётся из строки реестра.
Verify(ctx context.Context, assertionType, raw string) (clientassertion.Result, error)
// VerifyFederated — федеративная полоса (RFC 7523 §2.1): утверждение
// подписал внешний издатель, ключ берётся из нашего перечня доверенных
// издателей.
VerifyFederated(ctx context.Context, raw string) (clientassertion.Result, error)
}
Verifier — порт проверяющего утверждение, ОБЕ полосы.
Один порт на две полосы, а не два: эндпоинт обязан выбирать полосу сам, по объявленному виду выдачи. Разнеси их по двум портам — и появилась бы посадка, где провязана одна, а вторая молча отвергает всё.