31.20. Поддержка OAuth#
31.20. Поддержка OAuth #
libpq реализует поддержку клиентского потока авторизации устройства OAuth v2, задокументированного в RFC 8628, в качестве дополнительного модуля
Когда поддержка включена и установлен дополнительный модуль, libpq будет использовать встроенный поток по умолчанию, если сервер запрашивает токен-носитель во время аутентификации. Этот поток может быть использован даже если система, на которой работает клиентское приложение, не имеет доступного веб-браузера, например, при запуске клиента через SSH.
Встроенный поток по умолчанию выведет URL для посещения и код пользователя для ввода:
$ psql 'dbname=postgres oauth_issuer=https://example.com oauth_client_id=...' Visit https://example.com/device and enter the code: ABCD-EFGH
(Этот запрос может быть настроен.) Затем пользователь войдет в свою учетную запись OAuth, которая спросит, разрешить ли libpq и серверу выполнять действия от их имени. Всегда полезно внимательно проверять отображаемый URL и разрешения, чтобы убедиться, что они соответствуют ожиданиям, прежде чем продолжить. Разрешения не должны предоставляться ненадежным третьим сторонам.
Клиентские приложения могут реализовывать собственные потоки для настройки взаимодействия и интеграции с приложениями. См. Раздел 31.20.1 для получения дополнительной информации о том, как добавить пользовательский поток в libpq.
Чтобы поток клиента OAuth был пригоден для использования, строка подключения должна как минимум содержать oauth_issuer и oauth_client_id. (Эти настройки определяются поставщиком OAuth вашей организации.) Встроенный поток дополнительно требует, чтобы сервер авторизации OAuth публиковал конечную точку авторизации устройства.
Примечание
Пользовательские потоки клиентов все еще могут быть реализованы.
31.20.1. Хуки Authdata #
Поведение потока OAuth может быть изменено или заменено клиентом с использованием следующего API-хука:
PQsetAuthDataHook
#Устанавливает
PGauthDataHook
, переопределяя обработку libpq одного или нескольких аспектов его клиентского потока OAuth.void PQsetAuthDataHook(PQauthDataHook_type hook);
Если
hook
равенNULL
, будет переустановлен обработчик по умолчанию. В противном случае приложение передает указатель на функцию обратного вызова с сигнатурой:int hook_fn(PGauthData type, PGconn *conn, void *data);
который libpq вызовет, когда от приложения требуется действие.
type
описывает запрашиваемое действие,conn
— это дескриптор соединения, который проходит аутентификацию, аdata
указывает на метаданные, специфичные для запроса. Содержимое этого указателя определяетсяtype
; см. Раздел 31.20.1.1 для поддерживаемого списка.Хуки могут быть объединены в цепочку, чтобы обеспечить кооперативное и/или резервное поведение. В общем случае, реализация хука должна проверять входящий
type
(и, возможно, метаданные запроса и/или настройки для конкретногоconn
в использовании), чтобы решить, обрабатывать ли конкретный фрагмент authdata. Если нет, она должна делегировать предыдущему хуку в цепочке (доступному черезPQgetAuthDataHook
).Успех обозначается возвращением целого числа, большего нуля. Возвращение отрицательного целого числа сигнализирует об ошибке и прекращает попытку подключения. (Значение ноль зарезервировано для реализации по умолчанию.)
PQgetAuthDataHook
#Извлекает текущее значение
PGauthDataHook
.PQauthDataHook_type PQgetAuthDataHook(void);
Во время инициализации (до первого вызова
PQsetAuthDataHook
), эта функция вернетPQdefaultAuthDataHook
.
31.20.1.1. Типы хуков #
Следующие типы PGauthData
и их соответствующие
структуры data
определены:
-
PQAUTHDATA_PROMPT_OAUTH_DEVICE
# Заменяет приглашение пользователя по умолчанию во время встроенного клиентского потока авторизации устройства.
data
указывает на экземплярPGpromptOAuthDevice
:typedef struct _PGpromptOAuthDevice { const char *verification_uri; /* verification URI to visit */ const char *user_code; /* user code to enter */ const char *verification_uri_complete; /* optional combination of URI and * code, or NULL */ int expires_in; /* seconds until user code expires */ } PGpromptOAuthDevice;
Подсказка по умолчанию просто выводит
verification_uri
иuser_code
в стандартный поток ошибок. Альтернативные реализации могут отображать эту информацию любым предпочтительным способом, например, с помощью графического интерфейса.Этот обратный вызов вызывается только во время встроенного процесса авторизации устройства. Если приложение устанавливает пользовательский процесс OAuth , или libpq не был собран с поддержкой встроенного процесса, этот тип authdata не будет использоваться.
Если предоставлено ненулевое значение
verification_uri_complete
, оно может быть использовано для нетекстовой верификации (например, путем отображения QR-кода). В этом случае URL и код пользователя все равно должны быть отображены конечному пользователю, поскольку код будет вручную подтвержден провайдером, а URL позволяет пользователям продолжать, даже если они не могут использовать нетекстовый метод. Для получения дополнительной информации см. раздел 3.3.1 в RFC 8628.-
PQAUTHDATA_OAUTH_BEARER_TOKEN
# Хук должен либо напрямую возвращать токен Bearer для текущей комбинации пользователь/издатель/область, если он доступен без блокировки, либо настроить асинхронный обратный вызов для его получения.
data
указывает на экземплярPGoauthBearerRequest
, который должен быть заполнен реализацией:typedef struct PGoauthBearerRequest { /* Hook inputs (constant across all calls) */ const char *openid_configuration; /* OIDC discovery URL */ const char *scope; /* required scope(s), or NULL */ /* Hook outputs */ /* Callback implementing a custom asynchronous OAuth flow. */ PostgresPollingStatusType (*async) (PGconn *conn, struct PGoauthBearerRequest *request, SOCKTYPE *altsock); /* Callback to clean up custom allocations. */ void (*cleanup) (PGconn *conn, struct PGoauthBearerRequest *request); char *token; /* acquired Bearer token */ void *user; /* hook-defined allocated data */ } PGoauthBearerRequest;
Два фрагмента информации предоставляются хуку libpq:
openid_configuration
содержит URL документа обнаружения OAuth, описывающего поддерживаемые потоки сервера авторизации, аscope
содержит (возможно, пустой) список разделенных пробелами областей OAuth, которые необходимы для доступа к серверу. Любой из них или оба могут бытьNULL
, чтобы указать, что информация не была обнаружена. (В этом случае реализации могут быть в состоянии установить требования, используя какую-либо другую предварительно настроенную информацию, или они могут выбрать отказ.)Окончательный вывод хука — это
token
, который должен указывать на действительный токен Bearer для использования при подключении. (Этот токен должен быть выдан oauth_issuer и содержать запрашиваемые области, иначе подключение будет отклонено модулем проверки сервера.) Выделенная строка токена должна оставаться действительной до тех пор, пока libpq не завершит подключение; хук должен установить обратный вызовcleanup
, который будет вызван, когда libpq больше не будет его требовать.Если реализация не может сразу создать
token
во время первоначального вызова хука, она должна установитьasync
обратный вызов для обработки неблокирующей связи с сервером авторизации. [16] Это будет вызвано для немедленного начала потока после возврата из хука. Когда обратный вызов не может продолжать выполнение без блокировки, он должен вернуть либоPGRES_POLLING_READING
, либоPGRES_POLLING_WRITING
после установки*pgsocket
в файловый дескриптор, который будет помечен готовым для чтения/записи, когда выполнение может быть продолжено. (Этот дескриптор затем предоставляется в цикл опроса верхнего уровня черезPQsocket()
.) ВернитеPGRES_POLLING_OK
после установкиtoken
, когда поток завершен, илиPGRES_POLLING_FAILED
для указания на неудачу.Реализации могут захотеть хранить дополнительные данные для учета между вызовами
async
иcleanup
обратных вызовов. Указательuser
предоставляется для этой цели; libpq не будет изменять его содержимое, и приложение может использовать его по своему усмотрению. (Не забудьте освободить любые выделенные ресурсы во время очистки токена.)
31.20.2. Отладка и настройки разработчика #
A "опасный режим отладки" может быть включен путем установки переменной
окружения PGOAUTHDEBUG=UNSAFE
. Эта функциональность предоставляется
только для удобства локальной разработки и тестирования. Она выполняет несколько действий,
которые вы не захотите, чтобы производственная система выполняла:
разрешает использование незашифрованного HTTP во время обмена с провайдером OAuth
позволяет полностью заменить список доверенных УЦ системы, используя переменную окружения
PGOAUTHCAFILE
выводит HTTP-трафик (содержащий несколько критических секретов) на стандартный поток ошибок во время OAuth-потока
разрешает использование интервалов повторной попытки с нулевой секундой, что может привести к зацикливанию клиента и бесполезному потреблению процессора
Предупреждение
Не передавайте данные трафика OAuth третьим сторонам. Они содержат секреты, которые могут быть использованы для атаки на ваших клиентов и серверы.
[16]
Выполнение блокирующих операций во время
PQAUTHDATA_OAUTH_BEARER_TOKEN
обратного вызова хука будет
мешать неблокирующим API подключения, таким как
PQconnectPoll
, и предотвращать прогресс параллельных подключений.
Приложения, которые используют только синхронные примитивы подключения, такие как
PQconnectdb
, могут синхронно получать токен
во время хука вместо реализации
асинхронного
обратного вызова, но они будут ограничены
только одним подключением за раз.