Help us shape the future of Go! Take the 2026 Go Developer Survey

tokenpolicy

package
v1.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 1 Imported by: 1

Documentation

Overview

Package tokenpolicy — ОДНО объявленное место для политики токенов платформы: закрытый словарь алгоритмов подписи, перечень обязательных проверок и числа, из которых вычисляется отсрочка снятия подписного ключа.

Почему перечень проверок объявляется, а не описывается словами

Приём нашего токена исполняют РАЗНЫЕ реализации на разных поверхностях. Пока состав обязательных проверок живёт у каждой свой, различие между ними не является ничьей находкой: оно НЕ ВЫРАЖЕНО, и потому не может покраснеть. Перечень здесь — предмет, на который может смотреть гейт по дереву.

Реализация проверок остаётся у поверхности: они разные по существу (одна разбирает токен библиотекой, другая — своим кодом над crypto/*). Общей делается ПОЛИТИКА, а не функция.

Почему числа здесь, а не у того, кто их применяет

Отсрочка снятия ключа ВЫЧИСЛЯЕТСЯ из двух слагаемых: максимального срока выпускаемого токена и потолка кэша ключей у самого «медленного» потребителя. Пока слагаемые объявлены по своим сервисам, арифметика невыразима — её нечем проверить, и она угадывается. Здесь она проверяется гейтом, и смена любого слагаемого без пересмотра отсрочки роняет проверку, называя оба числа.

Index

Constants

View Source
const (
	AlgRS256 = "RS256"
	AlgES256 = "ES256"
	AlgEdDSA = "EdDSA"
)

Алгоритмы подписи, которые платформа выпускает и принимает.

View Source
const (
	// MaxTokenTTL — потолок срока выпускаемого токена. Первое слагаемое
	// арифметики отсрочки: ключ нельзя снять раньше, чем истечёт последний
	// подписанный им токен.
	MaxTokenTTL = 30 * time.Minute

	// ConsumerKeySetCacheCeiling — потолок срока, на который ПОТРЕБИТЕЛЬ
	// вправе удерживать снимок набора ключей. Второе слагаемое: снятый ключ
	// ещё какое-то время отвечает «да» из чужого кэша, и всё выглядит
	// исправным. Потолок обязан быть объявлен числом на КАЖДОЙ поверхности —
	// без него слагаемое неизвестно, и отсрочка не вычисляется, а угадывается.
	ConsumerKeySetCacheCeiling = time.Hour

	// RemovalSlack — запас. Он невелик намеренно: запас, покрывающий
	// произвольную величину, скрыл бы ошибку в слагаемых.
	RemovalSlack = 15 * time.Minute

	// KeyRemovalGrace — отсрочка снятия ключа из набора после вывода его из
	// подписи. ВЫЧИСЛЯЕТСЯ, а не выбирается: смена любого слагаемого без
	// пересмотра этого числа роняет гейт и называет оба.
	KeyRemovalGrace = MaxTokenTTL + ConsumerKeySetCacheCeiling + RemovalSlack

	// ClockSkew — допуск на расхождение часов при приёме токена. Объявлен
	// числом, потому что проба допуска обязана утверждать обе стороны: за
	// пределом — отказ, внутри — проход.
	ClockSkew = 60 * time.Second

	// UnknownKeyIDRefetchInterval — собственный минимальный интервал
	// вынужденного перезапроса набора. Без него неизвестный идентификатор
	// ключа становится усилителем нагрузки: поток запросов с выдуманными
	// идентификаторами превращается в поток обращений к публикатору.
	UnknownKeyIDRefetchInterval = 30 * time.Second

	// KeySetBodyCeiling — потолок тела ответа источника набора. Чтение
	// прекращается на нём, а не «после разбора».
	KeySetBodyCeiling = 1 << 20

	// KeyIDMaxLen — потолок длины идентификатора ключа.
	//
	// Идентификатор приходит ОТ ПРЕДЪЯВИТЕЛЯ и потому ограничивается по форме
	// ДО того, как попадёт в поиск по снимку, в журнал и в повод вынужденного
	// перезапроса. Число объявлено здесь, а не у каждого, кто его применяет: у
	// формы идентификатора три места исполнения — чеканка и две конфигурации
	// приёма, — и разойтись им можно только молча.
	KeyIDMaxLen = 128
)
View Source
const (
	// TokenTypeAccess — объявленный тип токена доступа, выпускаемого
	// платформой (RFC 9068).
	TokenTypeAccess = "at+jwt"

	// TokenTypeClientAssertion — объявленный тип утверждения, которым клиент
	// себя аутентифицирует.
	//
	// Значение ИНОЕ, чем у токена доступа, и это первый из трёх независимых
	// признаков, разделяющих два вида (приёмка F2 §2.6). Единственным его
	// назначать нельзя: клиент, тип не проставивший, снял бы его целиком —
	// поэтому рядом стоят ещё два (адресат и чей ключ подписал), и требование
	// выполняется КАЖДЫМ по отдельности.
	TokenTypeClientAssertion = "client-authentication+jwt"

	// TokenTypeLegacy — тип, которым помечает свои токены ПРЕЖНИЙ издатель.
	//
	// Значение объявлено здесь по той же причине, что и два выше: пока оно жило
	// копиями в конфигурациях двух поверхностей, их различие не было находкой —
	// оно не выражено и потому не может покраснеть. А разойтись им было чем:
	// полоса прежнего издателя ТЕРПИТ отсутствие типа, но несовпадение
	// отвергает, поэтому расхождение значений даёт отказ на КАЖДОМ запросе этой
	// полосы у одной поверхности и ни одного — у другой. Обе при этом зелены на
	// своих пробах: их фикстуры чеканят тип сами.
	//
	// ПРЕДИКАТ СНЯТИЯ: значение уходит вместе с самой полосой прежнего издателя
	// (Ф4 эпика отказа от внешнего сервера выдачи). Пока полоса существует, у
	// значения есть предмет; когда её снимут — эта константа обязана исчезнуть
	// в том же изменении, а не пережить его.
	TokenTypeLegacy = "JWT"

	// ClientAssertionType — объявленный стандартом вид предъявления
	// (RFC 7523 §2.2). Сравнивается ТОЧНО, без нормализации: отличие регистром
	// либо хвостовым пробелом — тоже отказ.
	ClientAssertionType = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"

	// GrantTypeClientCredentials — выдача по учётным данным клиента, чья
	// личность доказана подписанным утверждением (RFC 7523 §2.2).
	GrantTypeClientCredentials = "client_credentials"

	// GrantTypeJWTBearer — ФЕДЕРАТИВНАЯ выдача: основанием служит утверждение
	// ВНЕШНЕГО издателя, которому мы доверяем поимённо (RFC 7523 §2.1,
	// задача #1124).
	//
	// Отличается от вида предъявления выше не только строкой, но и предметом:
	// там утверждение доказывает личность клиента, здесь оно И ЕСТЬ основание
	// выдачи, а клиента, который себя аутентифицирует, нет вовсе. Поэтому
	// параметры у них разные, и смешивать их формы нельзя: иначе предъявитель
	// выбирал бы, какой проверкой его проверят.
	//
	// #nosec G101 -- это ОБЪЯВЛЕННОЕ СТАНДАРТОМ имя вида выдачи, а не учётные
	// данные: строка приезжает в теле запроса от клиента и сверяется с ней же.
	// Её знает всякий, кто читал RFC 7523; секретом она быть не может by
	// construction, потому что клиент обязан её ПРИСЛАТЬ.
	GrantTypeJWTBearer = "urn:ietf:params:oauth:grant-type:jwt-bearer"
)
View Source
const ExpiredCredentialReclaimGrace = 24 * time.Hour

ExpiredCredentialReclaimGrace — верхняя отсрочка снятия истёкшего удостоверения.

Это ПРОДУКТОВОЕ решение, а не арифметика, и сказано это прямо: арифметика даёт нижнюю границу (MinExpiredCredentialReclaimDelay, около двадцати минут), а сутки выбраны НАБЛЮДАЕМОСТЬЮ. Человек, у которого доступ перестал работать ночью, приходит утром и обязан увидеть ПРИЧИНУ — истёкшую строку в перечне, — а не пустоту. Сутки покрывают цикл дежурства; меньшая величина отдаёт разбор в журнал аудита, большая ничего не добавляет, потому что след снятия в журнале остаётся навсегда.

View Source
const MaxAssertionLifetime = 5 * time.Minute

MaxAssertionLifetime — потолок разницы «срок − момент выпуска» у утверждения клиента.

Объявлен числом РОВНО ОДИН РАЗ и участвует в двух расчётах сразу: он ограничивает длительность самого утверждения и он же задаёт верхнюю границу жизни строки погашения. Два объявления об одном предмете разошлись бы молча — и разошлись бы там, где расхождение не видно, потому что обе величины по отдельности выглядят разумными.

Почему потолок вообще нужен

Запись погашения обязана жить до истечения утверждения: снять её раньше значит сделать повтор законным. Значит длительность утверждения И ЕСТЬ срок жизни строки, а выбирает эту длительность ПРЕДЪЯВИТЕЛЬ. Без потолка утверждение со сроком в годы занимает свой ключ на годы, то есть хранилище, ограниченное сроком, перестаёт быть ограниченным, а отказ в обслуживании становится дешёвым.

Почему отсчёт от момента выпуска, а не от «сейчас»

«Сейчас» — у нас, момент выпуска — у клиента. Отсчёт от «сейчас» дал бы разный потолок при одном и том же утверждении в зависимости от задержки доставки, то есть величину, которую нельзя ни объяснить клиенту, ни воспроизвести в пробе. Разница `exp − iat` — свойство самого утверждения.

View Source
const MaxAuthorizationCodeTTL = 60 * time.Second

MaxAuthorizationCodeTTL — потолок срока кода авторизации.

Почему потолок вообще есть

Код едет ПЕРЕДНИМ каналом — адресом перенаправления в браузере, то есть через строку адреса, историю и журналы посредников. Срок кода и есть окно, в которое перехваченный код ещё годен к обмену. Без потолка это окно выбирает посадка, и час ничем не отличим от минуты.

Чего этот срок НЕ ограничивает

Жизни записи кода. Погашенный код, предъявленный повторно, отзывает семейство гранта (RFC 6749 §4.1.2) и узнаётся как повтор по записи, а не по сроку, — в том числе после срока самого кода. Поэтому запись погашенного кода хранится, пока может жить семейство, и порог её уборки считается от MaxRefreshTokenFamilyTTL (замысел LINE-A-1 §4.4а), а не от этой константы. Обязанность и её довод записаны в контракте выборки (oauthceremony.AuthorizationCodeVault.FetchAuthorizationCode); держит её проба TestConsumedCodeRecordOutlivesTheCodeLifespan.

Почему 60 секунд

Решение продукта о политике окна (замысел LINE-A-1): законная жизнь кода — одно перенаправление и один обмен, то есть секунды. Код выпускается ПОСЛЕ того, как человек опознан и согласие получено, поэтому время человека в срок кода не входит, и узкая величина берётся намеренно. RFC 6749 §4.1.2 называет десять минут НАИБОЛЬШИМ рекомендуемым сроком — это верх рекомендации стандарта, под которым решение лежит, а не само решение. Держит величину проба TestCeremonyLifespanCeilingsStayWithinTheProductDecision.

View Source
const MaxFederatedAssertionLifetime = time.Hour

MaxFederatedAssertionLifetime — потолок той же разницы у утверждения, которое подписал ВНЕШНИЙ издатель (задача #1124).

Почему потолок здесь ДРУГОЙ, а не тот же

Потолок выше выбран из того, что утверждение полосы клиента выписывается СПЕЦИАЛЬНО для нас: подписант — наш же клиент, он знает адресата и вправе дать документу минуты. Внешний издатель выпускает своей нагрузке токен со своим сроком и о нашем потолке не знает вовсе. Приложи мы к нему пятиминутную величину — федеративная полоса отвергала бы КАЖДОЕ утверждение обычного издателя, и выглядело бы это как исправная строгая проверка.

Почему час, а не «сколько дадут»

Час покрывает наблюдаемые сроки: проецируемый токен Kubernetes по умолчанию живёт час, полосы сборочных конвейеров — минуты. Всё, что дольше, есть предъявительский документ с окном в сутки и более: однократность гасит повтор, но окно ДО первого предъявления перехвативший получает целиком.

Величина связана с тем же расчётом, что и потолок выше: длительность утверждения есть срок жизни строки погашения, и час означает час, а не месяц.

View Source
const MaxRefreshTokenFamilyTTL = 168 * time.Hour

MaxRefreshTokenFamilyTTL — потолок срока СЕМЕЙСТВА токенов обновления, отсчитанного от первой выдачи: ни один токен семейства, в том числе выпущенный оборотом, не вправе быть годным позже первой выдачи плюс этот срок.

Кто этот потолок держит

Сборка церемонии (`oauthceremony.New`) судит по нему срок ОДНОГО токена (Config.RefreshTokenLifespan): срок токена длиннее предела его семейства не исполнялся бы ни на одном выпуске, и настройка лгала бы молча. Предела семейству New НЕ ставит: движок назначает каждому токену оборота срок «сейчас + срок из настроек», и оборот сдвигает срок семейства вперёд. Держат предел двое. Граница гранта — AuthorizationGrant.ExpiresAt по виду токена обновления, которую служба называет при выдаче и которую церемония не даёт перешагнуть ни одному обороту. И база службы, хранящей семейство: она обязана не вставлять при обороте токен со сроком позже момента создания семейства плюс этот потолок. Сама константа предела не создаёт — его создаёт тот, кто её применяет.

Почему потолок вообще есть

Токен обновления — предъявительский документ: к ключу он не привязан, и публичный клиент на обмене не предъявляет ничего, кроме самого значения. Оборот с отзывом семейства на повторе ловит перехват лишь тогда, когда владелец сам предъявит уже обёрнутый токен (RFC 9700 §4.14.2). Семейство, которое оборачивают без перерыва, окно простоя не ограничивает вовсе; ограничивает только срок от первой выдачи.

Почему 168 часов

Решение продукта о политике окна (замысел LINE-A-1): семь суток — верхняя граница окна, которое оператор способен пережить без глагола досрочного завершения семейства. Держит величину проба TestCeremonyLifespanCeilingsStayWithinTheProductDecision.

Сверху решение ограничено потолком срока секрета (SecretCredentialTTLCeiling): срок секрета владелец называет сам, явным запросом, а семейство токенов обновления выпускается по ходу входа, и его срока владелец не выбирает. Документ, срок которого не выбирал никто из владельцев, не вправе жить дольше того, чей срок назван явно. Соотношение держит проба TestRefreshTokenFamilyCeilingStaysWithinTheSecretCredentialCeiling.

View Source
const MinRSAModulusBits = 2048

MinRSAModulusBits — минимальный допустимый размер модуля RSA.

Короткий модуль факторизуется, а значит подпись подделывается: ключ меньшего размера не должен попадать в снимок вовсе. Величина объявлена ЗДЕСЬ, потому что её обязаны знать все, кто принимает ключи, а второй словарь разошёлся бы молча — и разошёлся бы в сторону «принимаем меньше», потому что смягчать проще, чем ужесточать.

View Source
const SecretCredentialTTLCeiling = 90 * 24 * time.Hour

SecretCredentialTTLCeiling — потолок срока удостоверения вида SECRET.

Почему потолок вообще есть

Секрет ПРЕДЪЯВИТЕЛЬСКИЙ: доказать владение при предъявлении он не может ни на одной поверхности, где принимается (докерная полоса шлёт `Basic`, сборочный конвейер кладёт строку в переменную). Значит перехвативший строку получает ровно то же, что владелец, и окно этого равенства закрывает СРОК — больше ничего. Отзыв закрывает окно только там, где владелец заметил утечку.

Почему 90 суток, а не «сколько попросят»

Девяносто суток — квартал: срок, который переживает отпуск и релизный цикл, но не переживает смену состава команды. Больше означало бы удостоверение, живущее дольше, чем помнят о его существовании.

Срок СВЕРХ потолка отвергается, а НЕ урезается молча: урезание даёт вызывающему успех при неприменённом параметре — «принято-и-проигнорировано».

View Source
const SecretCredentialTTLDefault = 30 * 24 * time.Hour

SecretCredentialTTLDefault — срок, применяемый когда вызывающий его не назвал.

Почему умолчание, а не отказ

Требование срока было бы ломающим изменением у существующего глагола: клиент, сегодня законно не шлющий срока, начал бы получать отказ. Умолчание сохраняет вход и при этом НЕ заводит бессрочного секрета.

Коллизия нуля разрешена ИЗЪЯТИЕМ значения, а не вторым его написанием

У видов KEYPAIR и FEDERATED `ttl_seconds = 0` означает «бессрочно». У вида SECRET бессрочного НЕ СУЩЕСТВУЕТ НИ В КАКОМ НАПИСАНИИ, поэтому ноль означает «срок не назван» и разрешается этим умолчанием. Из области значений убрано одно из двух значений — не введён второй способ написать его.

Цена названа честно: один и тот же ноль означает у двух видов разное. Смягчение — в том, что неоднозначность живёт ТОЛЬКО ВО ВХОДЕ и снимается на границе: строка удостоверения и ответ выдачи всегда несут ЗАПОЛНЕННЫЙ срок, поэтому ниже по потоку двусмысленности нет ни у одного читателя.

Variables

This section is empty.

Functions

func AlgorithmAllowed

func AlgorithmAllowed(alg string) bool

AlgorithmAllowed отвечает, входит ли алгоритм в словарь.

Пустое значение НЕ входит: «алгоритм не назван» означало бы «любой», а именно этого класса мы и избегаем.

func Algorithms

func Algorithms() []string

Algorithms возвращает закрытый словарь целиком.

Всякий, кому нужен перечень, ВЫВОДИТ его отсюда: страж старта, текст отказа, сверка алгоритма с ключом. Вторая копия словаря разошлась бы молча — и разошлась бы в сторону «принимаем больше», потому что расширять проще.

func CriticalHeadersUnderstood

func CriticalHeadersUnderstood(crit []string) (bool, string)

CriticalHeadersUnderstood отвечает, можем ли мы принять токен с этим `crit`.

Второй ответ — имя первого непонятого параметра — нужен тексту отказа: без него оператор видит «токен отвергнут» и не знает, чем именно он негоден.

Пустой и отсутствующий `crit` — законный вход: требование касается только того, что отправитель ЯВНО пометил обязательным.

func ExpiredCredentialGraceFor

func ExpiredCredentialGraceFor(lifetime, ceiling, minDelay time.Duration) time.Duration

ExpiredCredentialGraceFor — отсрочка ОДНОЙ строки: она связана со сроком самой строки, а не одинакова для всех.

Правило одной фразой: окно памяти о вещи не должно быть дольше жизни самой вещи. Никто не ищет часовое удостоверение сутки спустя, и никто не приходит за девяностосуточным чаще раза в сутки.

grace = min( ceiling , max( minDelay , lifetime ) )

Зачем связывать. Минимального срока у секрета нет — законно и часовое удостоверение, — поэтому плоская отсрочка держала бы его труп в двадцать четыре раза дольше, чем жила сама вещь. Тогда ОТСРОЧКА САМА становилась бы тем, что упирается в потолок, то есть работа частично воспроизводила бы предмет, который чинит.

Ниже minDelay результат не опускается никогда: там ещё живут отчеканенные токены. Следствие названо прямо — при сроке короче пола строка лежит дольше, чем жила; это свойство пола, а не дефект уборки.

func GraceCoversLiveTokens

func GraceCoversLiveTokens() bool

GraceCoversLiveTokens отвечает, покрывает ли объявленная отсрочка оба слагаемых. Предикат, а не комментарий: его зовёт гейт.

func GrantTypes

func GrantTypes() []string

GrantTypes возвращает ЗАКРЫТЫЙ перечень видов выдачи, принимаемых нашим токен-эндпоинтом.

Перечень объявлен один раз и функцией, а не выписан по месту употребления: место, узнавшее про один вид и не узнавшее про второй, выглядит полным, а «прочее» корзиной приёма не является ни в одном из них.

func KeySourceHeaderMember

func KeySourceHeaderMember(name string) bool

KeySourceHeaderMember отвечает, является ли член заголовка источником ключа.

func KeySourceHeaderMembers

func KeySourceHeaderMembers() []string

KeySourceHeaderMembers — члены заголовка, из которых ключ проверки выбираться НЕ МОЖЕТ.

Перечень объявлен в ОДНОМ месте, а не выписан по месту употребления: место, закрывшее один член и забывшее второй, выглядит закрытым, и разница видна только тому, кто держит перечень в голове.

Почему это запрет, а не осторожность

Доверять ключу, приехавшему ВМЕСТЕ С ПОДПИСЬЮ, значит принимать любую подпись: предъявитель приложит тот ключ, которым подписал. Ключ выбирается ТОЛЬКО из нашего реестра.

Где то же доверие ЗАКОННО — названо, чтобы запрет не расползся

В доказательстве владения ключом (RFC 9449) ключ приходит В САМОМ доказательстве, и проверяющий связывает его с токеном по отпечатку: там встроенный ключ не уязвимость, а ПРЕДМЕТ. Такое место обязано включать выбор из предъявленного материала ЯВНО и по своему решению — умолчание «как получится» перенесло бы доверие туда, где оно недопустимо, и перенесло бы ТИХО: положительный путь при этом работает.

func KnownCriticalHeaders

func KnownCriticalHeaders() []string

KnownCriticalHeaders — параметры заголовка, которые мы УМЕЕМ исполнять и потому вправе принять помеченными обязательными.

Перечень ПУСТ, и это факт, а не заготовка: ни одна поверхность приёма не исполняет ни одного расширения заголовка. Пустой перечень означает «любой помеченный обязательным параметр отвергается» — то, что и требуется, пока расширений нет.

func MinExpiredCredentialReclaimDelay

func MinExpiredCredentialReclaimDelay(registryTokenTTL time.Duration) time.Duration

MinExpiredCredentialReclaimDelay — техническая НИЖНЯЯ граница отсрочки.

Раньше неё снимать нельзя ни при какой настройке: до этого момента ещё живут токены, отчеканенные снимаемой строкой.

	ClockSkew + registryTokenTTL + RemovalSlack

  - ClockSkew — часы предъявителя и наши расходятся; строка, истёкшая по нашим
    часам, у него ещё жива;
  - registryTokenTTL — на полосе секрета срок докерного токена НЕ урезается
    остатком срока строки (он чеканится фиксированным), поэтому токен,
    отчеканенный перед самым истечением, живёт ещё столько;
  - RemovalSlack — запас, невелик намеренно.

MaxTokenTTL в сумму НЕ входит, и это решение, а не пропуск. У KeyRemovalGrace это слагаемое есть потому, что там ключ снимают из набора ПРИ ЖИВЫХ токенах. На полосе ключевой пары такого состояния не бывает: срок токена урезается до остатка срока клиента, и запас взят самим урезанием. Внести MaxTokenTTL сюда значило бы заплатить дважды за одно свойство; полоса, где урезания нет, учтена СВОИМ слагаемым — сроком докерного токена.

Срок докерного токена приходит АРГУМЕНТОМ, а не константой: он конфигурируем (`api-server.registry-token.ttl`), и страж старта обязан считать границу по ДЕЙСТВУЮЩЕМУ значению. Иначе поднятый срок молча вывел бы отсрочку из-под её же основания.

func ReclaimGraceCoversLiveTokens

func ReclaimGraceCoversLiveTokens(grace, registryTokenTTL time.Duration) bool

ReclaimGraceCoversLiveTokens — предикат, а не комментарий: его зовёт гейт.

Он существует затем, чтобы следующий, кто захочет снимать «сразу», упёрся в часы, а не в чужое мнение: смена любого слагаемого без пересмотра отсрочки роняет пробу и называет оба числа.

func ResolveSecretCredentialTTL

func ResolveSecretCredentialTTL(requested time.Duration) (ttl time.Duration, ok bool)

ResolveSecretCredentialTTL — единственное место, где ноль превращается в срок, а превышение потолка — в отказ. Второй копии этого разрешения не заводится: копия разошлась бы молча и разошлась бы в сторону «принимаем больше».

ok=false означает «сверх потолка»; вызывающий обязан отвергнуть запрос с именем поля, а не урезать величину.

func SignedMaterialTypes

func SignedMaterialTypes() []string

SignedMaterialTypes возвращает объявленные типы обоих видов подписанного.

Перечень читается гейтом, требующим попарной различности: два вида, у которых совпал объявленный тип, — это один вид, и разделение между ними держалось бы оставшимися двумя признаками, ни один из которых не назначен единственным.

Types

type Check

type Check string

Check — обязательная проверка предъявленного токена.

const (
	// CheckSignature — подпись сходится с ключом, найденным по kid.
	CheckSignature Check = "signature"
	// CheckAlgorithmAllowed — алгоритм заголовка входит в закрытый словарь;
	// «без подписи» отвергается ДО разрешения ключа.
	CheckAlgorithmAllowed Check = "algorithm-allowed"
	// CheckKeyBoundAlgorithm — алгоритм заголовка равен алгоритму,
	// ЗАКРЕПЛЁННОМУ за найденным ключом. Заголовок алгоритм не выбирает.
	CheckKeyBoundAlgorithm Check = "key-bound-algorithm"
	// CheckIssuer — издатель токена имеет объявленную запись источника
	// ключей; издателя без записи не бывает.
	CheckIssuer Check = "issuer"
	// CheckAudience — адресат токена равен адресату поверхности. Незаданный
	// адресат означает «любой», поэтому он обязателен в настройке.
	CheckAudience Check = "audience"
	// CheckTokenType — тип объявлен и равен ожидаемому.
	CheckTokenType Check = "token-type"
	// CheckExpiry — срок ПРИСУТСТВУЕТ и не истёк. Обязательность включается
	// ЯВНЫМ параметром: разбор, не встретив срока, не возразит сам.
	CheckExpiry Check = "expiry"
	// CheckNotBefore — токен не выпущен «из будущего» за пределом допуска.
	CheckNotBefore Check = "not-before"
	// CheckKeyID — идентификатор ключа присутствует, его форма ограничена ДО
	// использования, и он резолвится в ключ объявленной записи.
	CheckKeyID Check = "key-id"
	// CheckCriticalHeaders — параметр, помеченный отправителем обязательным к
	// пониманию (`crit`, RFC 7515 §4.1.11), либо исполняется, либо токен
	// отвергается целиком. Обратная сторона того же требования — НЕ помеченное
	// неизвестное игнорируется (RFC 7519, EID 8060): ужесточение первого без
	// второго ломает совместимость.
	CheckCriticalHeaders Check = "critical-headers"
	// CheckRevocation — отзыв читается НА ПРЕДЪЯВЛЕНИИ. Контроль, действующий
	// только на выдаче, отзывом не является: он лишь не выдаёт нового.
	CheckRevocation Check = "revocation"
)

Обязательные проверки. Перечень ЗАКРЫТ: поверхность, объявляющая свою проверку сверх него, обязана объявить и ПРИЧИНУ — молчаливое расхождение является находкой.

func MandatoryChecks

func MandatoryChecks() []Check

MandatoryChecks возвращает перечень обязательных проверок.

Это и есть тот «один объявленный перечень», которым пользуются все реализации приёма. Реализация объявляет, какие проверки она исполняет, и гейт сверяет её объявление с этим перечнем.

func MissingChecks

func MissingChecks(declared []Check) []Check

MissingChecks возвращает обязательные проверки, которых нет в объявлении реализации. Пустой ответ означает согласие с перечнем.

func MissingChecksExcept

func MissingChecksExcept(declared []Check, deviations []Deviation) []Check

MissingChecksExcept возвращает обязательные проверки, которых нет ни в объявлении реализации, ни в перечне её объявленных отступлений.

Пустой ответ означает: всякая обязательная проверка либо исполняется, либо её неисполнение НАЗВАНО с причиной. Отступление с пустой причиной не засчитывается — иначе поле стало бы способом снять требование молча.

type Deviation

type Deviation struct {
	Check  Check
	Reason string
}

Deviation — обязательная проверка, которую поверхность НЕ исполняет, вместе с причиной.

Причина обязательна и не бывает «пока»: отступление без причины неотличимо от пропуска, а «сделаем потом» — тот самый отложенный долг, за который никто не отвечает. Причина обязана называть, ЧТО делает эту проверку неприменимой здесь, а не то, когда её собираются добавить.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL