Documentation
¶
Overview ¶
Package presentedcred — читатель удостоверения, ПРЕДЪЯВЛЕННОГО самим вызывающим, на публичном слушателе (задача продукта #2077, приёмка KAN-AUTHN-1).
Зачем он существует ¶
Личность на публичном слушателе производилась ровно двумя способами, и оба предполагают НАШУ инфраструктуру рядом: клиентский сертификат проверенного пира и личность, переданная разрешённым отправителем. В чужом облаке нет ни нашего края, чтобы передать, ни модульного сертификата у человека — арендатору нечем назваться. Этот читатель и есть третий способ: арендатор приходит обычным клиентом и предъявляет то, что мы сами ему выдали.
Внешней зависимости у проверки нет ПО ПОСТРОЕНИЮ ¶
Подпись проверяется собственным реестром ключей: служба сама издатель. Для установки в чужом облаке это не удобство, а условие исполнимости — иначе решение о доступе зависело бы от достижимости чего-то, чего у арендатора нет.
Отзыв читается НА ПРЕДЪЯВЛЕНИИ ¶
Контроль, действующий на выдаче и не действующий на предъявлении, отзывом не является: он лишь не выдаёт нового, а предъявленное продолжает проходить до истечения срока. Это состояние НЕ СХОДИТСЯ САМО, и окно отзыва равнялось бы сроку токена, а не сроку, который мы выбрали. Здесь окно задаёт срок кеша положительного вердикта — величина ОПЕРАТОРА, объявленная им и видимая ему.
Отрицательный вердикт не кешируется: восстановленный доступ не ждёт истечения записи.
Отказ ОДИН ¶
Все отказы аутентификации побайтово одинаковы, включая приложенные к ответу подробности. Различимый отказ здесь есть ОРАКУЛ: он сообщает предъявителю, какая половина предъявленного неверна. Поэтому производитель отказа в пакете ровно один — тринадцать вызовов `status.Error` по месту разошлись бы на первой же правке текста, и разошлись бы молча.
Подробность — какая именно проверка не сошлась — уходит ОПЕРАТОРУ, в журнал и измерители его установки, и никогда предъявителю.
Index ¶
- Constants
- Variables
- func Presented(ctx context.Context) bool
- type Config
- type KeySetSource
- type Reader
- func (r *Reader) DeclaredChecks() []tokenpolicy.Check
- func (r *Reader) DeclaredDeviations() []tokenpolicy.Deviation
- func (r *Reader) Stats() Stats
- func (r *Reader) StreamOver(pair []grpc.StreamServerInterceptor) grpc.StreamServerInterceptor
- func (r *Reader) UnaryOver(pair []grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor
- type RevocationReader
- type Stats
Constants ¶
const MetadataKey = "authorization"
MetadataKey — ключ метаданных, которым удостоверение предъявляется.
Стандартная форма выбрана не из вкуса: иной формы у арендатора нет — он приходит обычным клиентом, и всякая своя означала бы, что пользоваться службой можно только нашим клиентом.
const RefusalMessage = "credential is not accepted"
RefusalMessage — ЕДИНСТВЕННЫЙ текст отказа аутентификации.
Он не называет ни причины, ни поля, ни значения: предъявитель не обязан узнать, какая половина предъявленного неверна. Текст — часть контракта, и экспортирован затем, чтобы проба утверждала ЕГО, а не свою копию.
Variables ¶
var ( // ErrIssuerRequired — незаданный издатель означает «любой», то есть токен // любого происхождения принимался бы как наш. ErrIssuerRequired = errors.New("presentedcred: the issuer we accept as our own is not declared") // ErrAudienceRequired — незаданный адресат означает «любой»: токен, годный // для другой поверхности, проходил бы здесь. ErrAudienceRequired = errors.New("presentedcred: the audience of this listener is not declared") // ErrAlgorithmsRequired — пустой перечень означает «принимаем любую // подпись», и на этом перечне держится сверка заголовка с ключом. ErrAlgorithmsRequired = errors.New("presentedcred: the list of accepted signatures has no elements") // ErrAlgorithmUnknown — алгоритм вне закрытого словаря платформы. ErrAlgorithmUnknown = errors.New("presentedcred: accepted signature list names an algorithm outside the platform dictionary") // ErrKeysRequired — без собственного реестра ключей проверять подпись нечем. ErrKeysRequired = errors.New("presentedcred: no key registry is wired") // ErrRevocationsRequired — без авторитета отзыва контроль действовал бы // только на выдаче. ErrRevocationsRequired = errors.New("presentedcred: no revocation authority is wired") // ErrCacheTTLRequired — срок кеша И ЕСТЬ окно отзыва. Величина, которую // построение подставляет молча, предметом стража быть не может. ErrCacheTTLRequired = errors.New("presentedcred: the revocation cache lifetime is not declared") )
Отказы ПОСТРОЕНИЯ. Каждый отдельный: неполная настройка означает читателя, который либо принимает лишнее, либо не принимает ничего, — и узналось бы это на первом запросе.
Functions ¶
func Presented ¶
Presented отвечает, приложил ли вызывающий удостоверение к ЭТОМУ запросу.
Зачем это спрашивают снаружи ¶
Звено, решающее ЧТО ОТВЕТИТЬ не назвавшемуся, обязано отличать «не предъявлял вовсе» от «предъявил, и не сошлось»: первому отвечают «назовись», второму — единственным побайтово равным отказом. Различие есть свойство ЗАПРОСА, и узнаётся оно ровно здесь.
Почему предикат, а не вторая копия разбора у вызывающего ¶
Ключ метаданных и объявленная схема предъявления живут в этом пакете. Второй разбор той же строки разошёлся бы с первым молча — и разошёлся бы именно там, где расхождение не видно: на входе, который оба считают годным.
Неоднозначность (два предъявления разом) считается предъявлением: вызывающий приложил удостоверение, а то, что их два, — уже вопрос годности, и отвечает на него отказ читателя, а не этот предикат.
Types ¶
type Config ¶
type Config struct {
// Issuer — издатель, которым установка объявила СЕБЯ.
Issuer string
// Audience — адресат ЭТОЙ поверхности. Токен, выданный для другой,
// здесь не годится: тип и адресат — свойства поверхности предъявления.
Audience string
// AllowedAlgorithms — перечень принимаемых подписей, ОБЪЯВЛЕННЫЙ
// установкой. Решение принимается по нему, а не по тому, что заявлено в
// самом токене.
AllowedAlgorithms []string
// Keys — собственный реестр ключей.
Keys KeySetSource
// Revocations — авторитет отзыва.
Revocations RevocationReader
// RevocationCacheTTL — срок кеша ПОЛОЖИТЕЛЬНОГО вердикта, он же
// объявленное окно отзыва.
RevocationCacheTTL time.Duration
// Clock — источник времени. Передаётся, а не берётся из окружения: без
// этого обе половины окна отзыва наблюдаются выжиданием, а не
// детерминированно.
Clock func() time.Time
// Logger — журнал ОПЕРАТОРА: сюда уходит причина отказа, которой нет в
// ответе предъявителю.
Logger *slog.Logger
// TrustDomain — домен доверия установки: по нему опознаётся личность модуля
// из сертификата пира. Приезжает величиной, а не берётся из сборки: пока он
// был скомпилирован, установка меняла его только пересборкой, и правка
// величины профиля давала сертификаты, которых эта сторона не признавала.
//
// Необъявленный домен — не отказ построения: читатель предъявленного
// удостоверения работает и там, где личности модуля нет вовсе (внешний
// клиент). Он лишь не опознаёт НИКОГО, и это фейл-клоуз. Отказ старта —
// предмет стражи посадки, а не этого конструктора.
TrustDomain grpcsrv.TrustDomain
}
Config — настройка читателя. Каждое поле ОБЯЗАТЕЛЬНО: незаданное здесь означает «не сужаем», а не «взять разумное».
type KeySetSource ¶
type KeySetSource interface {
PublishedSet(ctx context.Context) ([]domain.PublishedKey, error)
}
KeySetSource — источник публикуемого набора.
Тем же набором, что отдаётся потребителям, проверяется и подпись здесь: один источник, а не второй, — иначе читатель судил бы по другим ключам, чем публикует издатель.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader — читатель предъявленного удостоверения.
func New ¶
New строит читателя. Неполная настройка — ОТКАЗ ПОСТРОЕНИЯ, а не умолчание.
Асимметрия цены, из которой это выведено: слишком строгая настройка даёт отказ В СТАРТЕ — видимый сразу, с именем настройки в тексте; слишком слабая даёт принимаемый чужой токен, не видимый никогда.
func (*Reader) DeclaredChecks ¶
func (r *Reader) DeclaredChecks() []tokenpolicy.Check
DeclaredChecks — состав проверок ЭТОГО проверяющего.
Объявление существует затем, чтобы его можно было СВЕРИТЬ с единым перечнем, а не читать реализацию глазами. Запись, которой проверяющий не исполняет, отсюда нельзя: тогда объявление станет вторым местом об одном предмете, и разойдётся оно молча.
func (*Reader) DeclaredDeviations ¶
func (r *Reader) DeclaredDeviations() []tokenpolicy.Deviation
DeclaredDeviations — обязательные проверки, которых читатель НЕ исполняет.
Перечень ПУСТ, и пуст осознанно: адресат и тип объявлены отступлением у авторитета отзыва, потому что он судит о состоянии токена У ИЗДАТЕЛЯ. Здесь поверхность предъявления и есть та, чьими свойствами адресат и тип являются, — отступления быть не может.
func (*Reader) StreamOver ¶
func (r *Reader) StreamOver(pair []grpc.StreamServerInterceptor) grpc.StreamServerInterceptor
StreamOver — то же на второй полосе.
Стримовых RPC у службы сегодня ноль, и полоса провязывается не ради них: полоса без читателя при полосе с читателем — различие, которого никто не принимал, и обнаружилось бы оно первым же стримовым RPC.
func (*Reader) UnaryOver ¶
func (r *Reader) UnaryOver(pair []grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor
UnaryOver ставит читателя НАД парой извлечения личности, а не после неё.
Почему НАД, а не после — это не стиль, а единственная работающая форма ¶
Пара извлечения на двух ветках из трёх снимает носитель личности явным снятием, и снятие имеет ПРИОРИТЕТ над любым последующим назначением: так устроен носитель платформы, и устроен намеренно — подделанная личность от непроверенного пира не должна просачиваться никаким «а потом мы её вернём». Читатель, поставленный ПОСЛЕ пары, назначил бы вызывающего, и назначение молча не доехало бы до обработчика: отказа нет, личности нет, а дальше отсечка анонима отвергает мутацию — по причине, которой в запросе не было.
Поэтому читатель прогоняет пару САМ и решает по её вердикту: полосы взаимно исключают друг друга (ось 8 решения), и решение о том, КТО звонит, принимается в одном месте, а не складывается из двух назначений.
Прежний путь при этом не тронут ¶
Запроса БЕЗ предъявленного удостоверения читатель не касается вовсе: пара исполняется как исполнялась, и её ветки — доверенный отправитель, непроверенный пир, проверенный без переданной личности — работают ровно как прежде.
type RevocationReader ¶
type RevocationReader = tokenrevocation.Reader
RevocationReader — хранилище отсечек отзыва.
type Stats ¶
Stats — величины по каждому исходу.
Отдаются СНИМКОМ, а не через порт наблюдателя: измерители читают их сами, и все три ряда печатаются всегда, включая нулевые. Ряд, появляющийся только вместе с первым событием, делает ноль невыразимым — отсутствующий ряд и нулевой выглядят одинаково у того, кто смотрит на график.