openidc: Реализация OpenID Connect Relying Party и OAuth 2.0 Resource Server на Lua для NGINX / nginx-module-lua
Установка
Если вы еще не подписались на репозиторий RPM, зарегистрируйтесь. После этого вы можете продолжить с следующими шагами.
CentOS/RHEL 7 или Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-openidc
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-openidc
Чтобы использовать эту библиотеку Lua с NGINX, убедитесь, что nginx-module-lua установлен.
Этот документ описывает lua-resty-openidc v1.8.0, выпущенную 13 сентября 2024 года.
lua-resty-openidc
lua-resty-openidc — это библиотека для NGINX, реализующая функциональность Relying Party (RP) для OpenID Connect и/или Resource Server (RS) для OAuth 2.0.
При использовании в качестве Relying Party OpenID Connect она аутентифицирует пользователей с помощью провайдера OpenID Connect, используя OpenID Connect Discovery и базовый клиентский профиль (т.е. поток авторизации с кодом). При использовании в качестве Resource Server OAuth 2.0 она может проверять токены доступа Bearer OAuth 2.0 на авторизационном сервере или, если используется JSON Web Token для токена доступа, проверка может происходить по заранее настроенному секрету/ключу.
Она поддерживает сессии для аутентифицированных пользователей, используя lua-resty-session, предлагая настраиваемый выбор между хранением состояния сессии в cookie браузера на стороне клиента или использованием серверных механизмов хранения shared-memory|memcache|redis.
Она поддерживает кэширование документов Discovery и проверенных токенов доступа на уровне сервера.
Ее можно использовать в качестве обратного прокси, завершающего OAuth/OpenID Connect перед исходным сервером, чтобы защитить исходный сервер/сервисы с помощью соответствующих стандартов без реализации этих стандартов на самом сервере.
Пример конфигурации для Google+ Signin
Пример конфигурации nginx.conf для аутентификации пользователей через Google+ Signin, защищая путь обратного прокси.
events {
worker_connections 128;
}
http {
resolver 8.8.8.8;
lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
lua_ssl_verify_depth 5;
# кэш для документов метаданных discovery
lua_shared_dict discovery 1m;
# кэш для JWK
lua_shared_dict jwks 1m;
# NB: если у вас "lua_code_cache off;", используйте:
# set $session_secret xxxxxxxxxxxxxxxxxxx;
# см. https://github.com/bungle/lua-resty-session#notes-about-turning-lua-code-cache-off
server {
listen 8080;
location / {
access_by_lua_block {
local opts = {
-- полный URI перенаправления должен быть защищен этим скриптом
-- если URI начинается с / полный URI перенаправления становится
-- ngx.var.scheme.."://"..ngx.var.http_host..opts.redirect_uri
-- если схема не была переопределена с помощью opts.redirect_uri_scheme или заголовка X-Forwarded-Proto в входящем запросе
redirect_uri = "https://MY_HOST_NAME/redirect_uri",
-- до версии 1.6.1 вы указывали
-- redirect_uri_path = "/redirect_uri",
-- и не могли установить имя хоста
-- Конечная точка discovery OP. Включите, чтобы получить URI всех конечных точек (Token, introspection, logout...)
discovery = "https://accounts.google.com/.well-known/openid-configuration",
-- Доступ к конечной точке Token OP требует аутентификации. Поддерживаются несколько режимов аутентификации:
--token_endpoint_auth_method = ["client_secret_basic"|"client_secret_post"|"private_key_jwt"|"client_secret_jwt"],
-- o Если token_endpoint_auth_method установлен на "client_secret_basic", "client_secret_post" или "client_secret_jwt", аутентификация к конечной точке Token осуществляется с использованием client_id и client_secret
-- Для несовместимых OP с RFC 6749 OAuth 2.0 для аутентификации клиента (см. https://tools.ietf.org/html/rfc6749#section-2.3.1)
-- client_id и client_secret ДОЛЖНЫ оставаться неизменными при кодировании URL
client_id = "<client_id>",
client_secret = "<client_secret>",
-- o Если token_endpoint_auth_method установлен на "private_key_jwt", аутентификация к конечной точке Token осуществляется с использованием client_id, client_rsa_private_key и client_rsa_private_key_id для вычисления подписанного JWT
-- client_rsa_private_key — это RSA закрытый ключ, который будет использоваться для подписи JWT, сгенерированного lua-resty-openidc для аутентификации к OP
-- client_rsa_private_key_id (необязательно) — это идентификатор ключа, который будет установлен в заголовке JWT для идентификации, какой открытый ключ OP должен использовать для проверки подписи JWT
--client_id = "<client_id>",
--client_rsa_private_key=[[-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAiThmpvXBYdur716D2q7fYKirKxzZIU5QrkBGDvUOwg5izcTv
[...]
h2JHukolz9xf6qN61QMLSd83+kwoBr2drp6xg3eGDLIkQCQLrkY=
-----END RSA PRIVATE KEY-----]],
--client_rsa_private_key_id="key id#1",
-- Срок действия в секундах подписанного JWT, сгенерированного lua-resty-openidc для аутентификации к OP.
-- (используется, когда token_endpoint_auth_method установлен на "private_key_jwt" или "client_secret_jwt"). По умолчанию 60 секунд.
--client_jwt_assertion_expires_in = 60,
-- При использовании https для любых конечных точек OP, проверка SSL сертификата может быть обязательной ("yes") или нет ("no").
--ssl_verify = "no",
-- Подключение keepalive с OP может быть включено ("yes") или отключено ("no").
--keepalive = "no",
--response_mode=form_post может быть использован, чтобы заставить lua-resty-openidc использовать [OAuth 2.0 Form Post Response Mode](https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html). *Примечание* для современных браузеров вам нужно будет установить [`$session_cookie_samesite`](https://github.com/bungle/lua-resty-session#string-sessioncookiesamesite) в `None` с form_post, если ваш провайдер OpenID Connect и Relying Party не делят один и тот же домен.
--authorization_params = { hd="zmartzone.eu" },
--scope = "openid email profile",
-- Обновить id_token пользователя через 900 секунд без необходимости повторной аутентификации
--refresh_session_interval = 900,
--iat_slack = 600,
--redirect_uri_scheme = "https",
--logout_path = "/logout",
--redirect_after_logout_uri = "/",
-- Куда пользователь должен быть перенаправлен после выхода из RP. Эта опция переопределяет любой end_session_endpoint, который OP мог предоставить в ответе discovery.
--redirect_after_logout_with_id_token_hint = true,
-- Должно ли перенаправление после выхода включать id токен как подсказку (если доступно). Эта опция используется только если redirect_after_logout_uri установлено.
--post_logout_redirect_uri = "https://www.zmartzone.eu/logoutSuccessful",
-- Куда RP запрашивает, чтобы OP перенаправил пользователя после выхода. Если эта опция установлена на относительный URI, она будет относительной к конечной точке выхода OP, а не к RP.
--accept_none_alg = false
-- если ваш провайдер OpenID Connect не подписывает свои id токены
-- (использует алгоритм подписи "none"), то установите это значение в true.
--accept_unsupported_alg = true
-- если вы хотите отклонить токены, подписанные с использованием алгоритма,
-- не поддерживаемого lua-resty-jwt, установите это значение в false. Если
-- вы оставите его не установленным или установите в true, подпись токена не будет
-- проверена, если используется неподдерживаемый алгоритм.
--renew_access_token_on_expiry = true
-- должен ли этот плагин пытаться безшумно обновить токен доступа, как только он истечет, если доступен токен обновления.
-- если обновление токена не удастся, пользователь будет перенаправлен на конечную точку авторизации.
--access_token_expires_in = 3600
-- Срок действия в секундах токена доступа по умолчанию, если в ответе конечной точки токена отсутствует атрибут expires_in.
--access_token_expires_leeway = 0
-- Допуск истечения срока для обновления access_token. Если это установлено, обновление произойдет за access_token_expires_leeway секунд до истечения срока токена. Это избегает ошибок в случае, если access_token только истекает при поступлении на сервер ресурсов OAuth.
--force_reauthorize = false
-- Когда force_reauthorize установлен в true, процесс авторизации будет выполнен, даже если токен уже был кэширован
--session_contents = {id_token=true}
-- Белый список содержимого сессии для включения. Это можно использовать для уменьшения размера сессии.
-- Когда не установлено, все будет включено в сессию.
-- Доступные:
-- id_token, enc_id_token, user, access_token (включает токен обновления)
-- Вы можете указать таймауты для connect/send/read как одно число (устанавливая все таймауты) или как таблицу. Значения в миллисекундах
-- timeout = 1000
-- timeout = { connect = 500, send = 1000, read = 1000 }
--use_nonce = false
-- По умолчанию запрос авторизации включает параметр
-- nonce. Вы можете использовать эту опцию, чтобы отключить его,
-- что может быть необходимо при взаимодействии с неисправным провайдером OpenID,
-- который игнорирует параметр, так как
-- id_token будет отклонен в противном случае.
--revoke_tokens_on_logout = false
-- Когда revoke_tokens_on_logout установлен в true, выход уведомляет авторизационный сервер о том, что ранее полученные токены обновления и доступа больше не нужны. Это требует, чтобы revocation_endpoint был доступен.
-- Если не предоставлена конечная точка отзыва или если возникают ошибки при отзыве, пользователь не будет уведомлен, и процесс выхода продолжится нормально.
-- Опционально: используйте исходящий прокси для конечных точек провайдера OpenID Connect с таблицей proxy_opts:
-- это требует lua-resty-http >= 0.12
-- proxy_opts = {
-- http_proxy = "http://<proxy_host>:<proxy_port>/",
-- https_proxy = "http://<proxy_host>:<proxy_port>/"
-- }
-- Жизненные циклы
--
-- lifecycle = {
-- on_created = handle_created,
-- on_authenticated = handle_authenticated,
-- on_regenerated = handle_regenerated
-- on_logout = handle_logout
-- }
--
-- где `handle_created`, `handle_authenticated`, `handle_regenerated` и `handle_logout` являются вызываемыми
-- принимающими аргумент `session`. `handle_created` также принимает второй аргумент `params`, который является таблицей
-- содержащей параметры запроса авторизации, используемые для перенаправления пользователя на конечную точку провайдера OpenID
-- Connect.
--
-- -- Хук `on_created` вызывается *после* создания сессии в
-- `openidc_authorize` сразу перед сохранением сессии
-- -- Хук `on_authenticated` вызывается *после* получения ответа авторизации в
-- `openidc_authorization_response` сразу перед сохранением сессии
-- Начиная с lua-resty-openidc 1.7.5, он получает декодированный id_token в качестве второго и ответ конечной точки токена в качестве третьего аргумента
-- -- `on_regenerated` вызывается сразу после
получения нового токена доступа через обновление токена
и вызывается с таблицей сессии, которая была регенерирована
-- -- Хук `on_logout` вызывается *перед* уничтожением сессии в
-- `openidc_logout`
--
-- Любой, все или ни один из хуков могут быть использованы. Пустой `lifecycle` ничего не делает.
-- Хук, который возвращает истинное значение, вызывает сбой действия жизненного цикла, частью которого они являются.
-- Опционально: добавьте декоратор для HTTP-запроса, который
-- применяется, когда lua-resty-openidc общается с провайдером OpenID Connect
-- напрямую. Может быть использован для предоставления дополнительных HTTP-заголовков
-- или добавления другого подобного поведения.
-- http_request_decorator = function(req)
-- local h = req.headers or {}
-- h[EXTRA_HEADER] = 'my extra header'
-- req.headers = h
-- return req
-- end,
-- use_pkce = false,
-- когда установлено в true, будет использован "Proof Key for Code Exchange", как
-- определено в RFC 7636. Метод проверки кода всегда будет S256
}
-- вызов authenticate для аутентификации пользователя OpenID Connect
local res, err = require("resty.openidc").authenticate(opts)
if err then
ngx.status = 500
ngx.say(err)
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
-- на этом этапе res — это таблица Lua с 3 ключами:
-- id_token : таблица Lua с утверждениями из id_token (обязательно)
-- access_token: токен доступа (необязательно)
-- user : таблица Lua с утверждениями, возвращенными из конечной точки информации о пользователе (необязательно)
--if res.id_token.hd ~= "zmartzone.eu" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
--if res.user.email ~= "[email protected]" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
-- установить заголовки с информацией о пользователе: это перезапишет любые существующие заголовки
-- но также очистит(!) их в случае, если в токене не предоставлено значение
ngx.req.set_header("X-USER", res.id_token.sub)
}
proxy_pass http://localhost:80;
}
}
}
О redirect_uri
Так называемый redirect_uri — это URI, который является частью протокола OpenID Connect. URI перенаправления регистрируется у вашего провайдера OpenID Connect и является URI, на который ваш провайдер перенаправит пользователей после успешного входа. Этот URI затем обрабатывается lua-resty-openidc, где он получает токены и выполняет некоторые проверки, и только после этого браузер перенаправляется туда, куда ваш пользователь хотел изначально.
redirect_uri не должен обрабатываться вашим кодом приложения. Это должен быть URI, за который отвечает lua-resty-openidc, поэтому он должен находиться в location, защищенном lua-resty-openidc.
Вы настраиваете redirect_uri на стороне lua-resty-openidc через параметр opts.redirect_uri (по умолчанию /redirect_uri). Если он начинается с /, то lua-resty-openidc добавит протокол и текущее имя хоста к нему при отправке URI провайдеру OpenID Connect (принимая во внимание HTTP-заголовки Forwarded и X-Forwarded-*). Но вы также можете указать абсолютный URI, содержащий хост и протокол самостоятельно.
До версии 1.6.1 opts.redirect_uri_path был способом настроить redirect_uri без возможности контролировать части протокола и хоста.
Когда lua-resty-openidc "видит" локальный путь, который совпадает с путем opts.redirect_uri (или opts.redirect_uri_path), он перехватывает запрос и обрабатывает его самостоятельно.
Это работает в большинстве случаев, но иногда внешний видимый redirect_uri имеет другой путь, чем тот, который локально виден серверу. Это может произойти, если обратный прокси перед вашим сервером переписывает URI перед пересылкой запросов. Поэтому версия 1.7.6 ввела новую опцию opts.local_redirect_uri_path. Если она установлена, lua-resty-openidc будет перехватывать запросы к этому пути, а не к пути opts.redirect_uri.
Проверка аутентификации только
-- проверьте сессию, но не перенаправляйте на аутентификацию, если еще не вошли в систему
local res, err = require("resty.openidc").authenticate(opts, nil, "pass")
Проверка аутентификации только и отказ в неаутентифицированном доступе
-- проверьте сессию, не перенаправляйте на аутентификацию, если еще не вошли в систему, но вместо этого верните ошибку
local res, err = require("resty.openidc").authenticate(opts, nil, "deny")
Сессии и блокировка
Функция authenticate возвращает текущий объект сессии в качестве своего четвертого возвращаемого аргумента. Если вы настроили lua-resty-session для использования серверного хранилища, которое использует блокировку, сессия может быть все еще заблокирована, когда она возвращается. В этом случае вы можете захотеть закрыть ее явно.
local res, err, target, session = require("resty.openidc").authenticate(opts)
session:close()
Кэширование
lua-resty-openidc может использовать кэши общей памяти для нескольких вещей. Если вы хотите, чтобы он использовал кэши, вы должны использовать lua_shared_dict в вашем файле nginx.conf.
В настоящее время используется до четырех кэшей:
- кэш с именем
discoveryхранит метаданные Discovery OpenID Connect вашего провайдера OpenID Connect. Элементы кэша истекают через 24 часа, если не переопределеныopts.discovery_expires_in(значение, указанное в секундах). Этот кэш будет хранить один элемент на URI эмитента, и вы можете самостоятельно просмотреть документ discovery, чтобы получить оценку необходимого размера — обычно несколько кБ на провайдера OpenID Connect. - кэш с именем
jwksхранит ключевые материалы вашего провайдера OpenID Connect, если они предоставляются через конечную точку JWKS. Элементы кэша истекают через 24 часа, если не переопределеныopts.jwks_expires_in. Этот кэш будет хранить один элемент на URI JWKS, и вы можете самостоятельно просмотреть jwks, чтобы получить оценку необходимого размера — обычно несколько кБ на провайдера OpenID Connect. - кэш с именем
introspectionхранит результат интроспекции токена OAuth2. Элементы кэша истекают, когда соответствующий токен истекает. Токены с неизвестным сроком действия вообще не кэшируются. Этот кэш будет содержать одну запись на интроспектированный токен доступа — обычно это будет несколько кБ на токен. - кэш с именем
jwt_verificationхранит результат проверки JWT. Элементы кэша истекают, когда соответствующий токен истекает. Токены с неизвестным сроком действия не кэшируются в течение двух минут. Этот кэш будет содержать одну запись на проверенный JWT — обычно это будет несколько кБ на токен.
Кэширование результатов интроспекции и проверки JWT
Обратите внимание, что кэши jwt_verification и introspection разделяются между всеми настроенными местоположениями. Если вы используете местоположения с различной конфигурацией opts, общий кэш может позволить токену, который действителен только для одного местоположения, быть принят другим, если он читается из кэша. Чтобы избежать путаницы с кэшом, рекомендуется установить opts.cache_segment на уникальные строки для каждого набора связанных местоположений.
Отзыв токенов
Функция revoke_tokens(opts, session) отзывает текущий токен обновления и токен доступа. В отличие от полного выхода, cookie сессии не будет уничтожен, и конечная точка завершения сессии не будет вызвана. Функция возвращает true, если оба токена были успешно отозваны. Эта функция может быть полезна в сценариях, когда вы хотите уничтожить/удалить сессию со стороны сервера.
С помощью revoke_token(opts, token_type_hint, token) также можно отозвать конкретный токен. token_type_hint обычно может быть refresh_token или access_token.
Пример конфигурации для проверки токенов доступа Bearer JWT OAuth 2.0
Пример конфигурации nginx.conf для проверки токенов доступа Bearer JWT на основе заранее настроенного секрета/ключа. После успешной проверки сервер NGINX может функционировать как обратный прокси к внутреннему исходному серверу.
events {
worker_connections 128;
}
http {
resolver 8.8.8.8;
# кэш для результатов проверки JWT
lua_shared_dict jwt_verification 10m;
server {
listen 8080;
location /api {
access_by_lua '
local opts = {
-- 1. пример общего секрета для проверки подписи HS???
--symmetric_key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
-- в версиях до 1.6.1 ключ этой опции назывался secret
-- вместо symmetric_key
-- 2. другой пример публичного сертификата для проверки подписи RS???
public_key = [[-----BEGIN CERTIFICATE-----
MIIC0DCCAbigAwIBAgIGAVSbMZs1MA0GCSqGSIb3DQEBCwUAMCkxCzAJBgNVBAYTAlVTMQwwCgYD
VQQKEwNibGExDDAKBgNVBAMTA2JsYTAeFw0xNjA1MTAxNTAzMjBaFw0yNjA1MDgxNTAzMjBaMCkx
CzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNibGExDDAKBgNVBAMTA2JsYTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAIcLtHjX2GFxYv1033dvfohyCU6nsuR1qoDXfHTG3Mf/Yj4BfLHtMjJr
nR3sgHItH3B6qZPnfErfsN0LP4uZ10/74CrWVqT5dy6ecXMqYtz/KNJ8rG0vY8vltc417AU4fie8
gyeWv/Z6wHWUCf3NHRV8GfFgfuvywgUpHo8ujpUPFr+zrPr8butrzJPq1h3+r0f5P45tfWOdpjCT
gsTzK6urUG0k3WkwdDYapL3wRCAw597nYfgKzzXuh9N0ZL3Uj+eJ6BgCzUZDLXABpMBZfk6hmmzp
cAFV4nTf1AaAs/EOwVE0YgZBJiBrueMcteAIxKrKjEHgThU2Zs9gN9cSFicCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAQLU1A58TrSwrEccCIy0wxiGdCwQbaNMohzirc41zRMCXleJXbtsn1vv85J6A
RmejeH5f/JbDqRRRArGMdLooGbqjWG/lwZT456Q6DXqF2plkBvh37kp/GjthGyR8ODJn5ekZwxuB
OcTuruRhqYOIJjiYZSgK/P0zUw1cjLwUJ9ig/O6ozYmof83974fygA/wK3SgFNEoFlTkTpOvZhVW
9kLfCVA/CRBfJNKnz5PWBBxd/3XSEuP/fcWqKGTy7zZso4MTB0NKgWO4duGTgMyZbM4onJPyA0CY
lAc5Csj0o5Q+oEhPUAVBIF07m4rd0OvAVPOCQ2NJhQSL1oWASbf+fg==
-----END CERTIFICATE-----]],
-- в версиях до 1.6.1 ключ этой опции назывался secret
-- вместо public_key
-- 3. в качестве альтернативы можно указать так называемый документ Discovery, который
-- содержит запись "jwks_uri"; конечная точка jwks должна предоставлять либо запись "x5c",
-- либо обе записи "n" и "e" для проверки подписи RSA
-- discovery = "https://accounts.google.com/.well-known/openid-configuration",
-- алгоритм подписи, который вы ожидаете, что был использован;
-- может быть одной строкой или таблицей.
-- Вы должны установить это по соображениям безопасности, чтобы
-- избежать принятия токена, утверждающего, что он подписан HMAC
-- с использованием открытого RSA ключа.
--token_signing_alg_values_expected = { "RS256" }
-- если вы хотите принимать неподписанные токены (используя
-- алгоритм подписи "none"), установите это значение в true.
--accept_none_alg = false
-- если вы хотите отклонить токены, подписанные с использованием алгоритма,
-- не поддерживаемого lua-resty-jwt, установите это значение в false. Если
-- вы оставите его не установленным, подпись токена не будет
-- проверена вообще.
--accept_unsupported_alg = true
-- время истечения в секундах для кэша jwk, по умолчанию 1 день.
--jwk_expires_in = 24 * 60 * 60
-- Возможно, потребуется принудительно проверить токен Bearer и игнорировать существующие кэшированные
-- результаты проверки. Если это так, вам нужно установить опцию jwt_verification_cache_ignore в true.
-- jwt_verification_cache_ignore = true
-- опциональное имя сегмента кэша, если вам нужны отдельные
-- кэши для по-разному настроенных местоположений
-- cache_segment = 'api'
}
-- вызов bearer_jwt_verify для проверки JWT OAuth 2.0
local res, err = require("resty.openidc").bearer_jwt_verify(opts)
if err or not res then
ngx.status = 403
ngx.say(err and err or "no access_token provided")
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- на этом этапе res — это таблица Lua, представляющая (проверенный) JSON
-- полезную нагрузку в токене JWT; теперь мы обычно не хотим разрешать просто любой
-- токен, выданный авторизационным сервером, но хотим применить
-- некоторые ограничения доступа через идентификаторы клиентов или области
--if res.scope ~= "edit" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
--if res.client_id ~= "ro_client" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
';
proxy_pass http://localhost:80;
}
}
}
Пример конфигурации для PingFederate OAuth 2.0
Пример конфигурации nginx.conf для проверки токенов доступа Bearer против сервера авторизации PingFederate OAuth 2.0.
events {
worker_connections 128;
}
http {
resolver 8.8.8.8;
lua_ssl_trusted_certificate /opt/local/etc/openssl/cert.pem;
lua_ssl_verify_depth 5;
# кэш для результатов проверки
lua_shared_dict introspection 10m;
server {
listen 8080;
location /api {
access_by_lua '
local opts = {
introspection_endpoint="https://localhost:9031/as/introspect.oauth2",
client_id="rs_client",
client_secret="2Federate",
ssl_verify = "no",
-- По умолчанию "exp" - Управляет TTL кэша интроспекции
-- https://tools.ietf.org/html/rfc7662#section-2.2
-- introspection_expiry_claim = "exp"
-- опциональное имя сегмента кэша, если вам нужны отдельные
-- кэши для по-разному настроенных местоположений
-- cache_segment = 'api'
}
-- вызов introspect для проверки токена доступа Bearer OAuth 2.0
local res, err = require("resty.openidc").introspect(opts)
if err then
ngx.status = 403
ngx.say(err)
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- на этом этапе res — это таблица Lua, представляющая JSON
-- объект, возвращенный из конечной точки интроспекции/проверки
--if res.scope ~= "edit" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
--if res.client_id ~= "ro_client" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
';
}
}
}
Пример конфигурации для передачи токенов доступа Bearer OAuth 2.0 в виде cookie
Пример конфигурации nginx.conf для проверки токенов доступа Bearer, переданных в виде cookie, против сервера авторизации ORY/Hydra.
events {
worker_connections 128;
}
http {
resolver 8.8.8.8;
lua_ssl_trusted_certificate /opt/local/etc/openssl/cert.pem;
lua_ssl_verify_depth 5;
# кэш для результатов проверки
lua_shared_dict introspection 10m;
server {
listen 8080;
location /api {
access_by_lua '
local opts = {
-- устанавливает URI конечной точки интроспекции
introspection_endpoint="https://localhost:9031/oauth2/introspect",
-- в качестве альтернативы, если ваш провайдер OAuth2 предоставляет документ discovery, который содержит
-- утверждение introspection_endpoint, вы можете оставить опцию introspection_endpoint
-- не установленной и вместо этого использовать
-- discovery = "https://my-oauth2-provider/.well-known/oauth-authorization-server",
client_id="admin",
client_secret="demo-password",
ssl_verify = "no",
-- Определяет интервал в секундах, после которого кэшированный и интроспектированный токен доступа должен
-- быть обновлен путем повторной интроспекции (и проверки) его против сервера авторизации.
-- Когда не определено, значение равно 0, что означает, что он истекает только после `exp` (или альтернативного,
-- см. introspection_expiry_claim) подсказки, как возвращается сервером авторизации
-- introspection_interval = 60,
-- Определяет способ, которым токены доступа Bearer OAuth 2.0 могут быть переданы этому серверу ресурсов.
-- "cookie" как заголовок cookie, называемый "PA.global" или с использованием имени, указанного после ":"
-- "header" заголовок "Authorization: bearer"
-- Когда не определено, используется заголовок по умолчанию "Authorization: bearer"
-- auth_accept_token_as = "cookie:PA",
-- Если используется заголовок, поле заголовка — Authorization
-- auth_accept_token_as_header_name = "cf-Access-Jwt-Assertion"
-- Метод аутентификации для конечной точки интроспекции сервера авторизации OAuth 2.0,
-- Используется для аутентификации клиента к конечной точке интроспекции с client_id/client_secret
-- По умолчанию "client_secret_post"
-- introspection_endpoint_auth_method = "client_secret_basic",
-- Укажите имена cookie, разделенные пробелами, чтобы забрать из браузера и отправить вместе с
-- обратными вызовами к конечным точкам OP и AS.
-- Когда не определено, такие cookie не отправляются.
-- pass_cookies = "JSESSION"
-- По умолчанию "exp" - Управляет TTL кэша интроспекции
-- https://tools.ietf.org/html/rfc7662#section-2.2
-- introspection_expiry_claim = "exp"
-- Возможно, потребуется принудительно вызвать интроспекцию для access_token и игнорировать существующие кэшированные
-- результаты интроспекции. Если это так, вам нужно установить опцию introspection_cache_ignore в true.
-- introspection_cache_ignore = true
-- опциональное имя сегмента кэша, если вам нужны отдельные
-- кэши для по-разному настроенных местоположений
-- cache_segment = 'api'
}
-- вызов introspect для проверки токена доступа Bearer OAuth 2.0
local res, err = require("resty.openidc").introspect(opts)
if err then
ngx.status = 403
ngx.say(err)
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- на этом этапе res — это таблица Lua, представляющая JSON
-- объект, возвращенный из конечной точки интроспекции/проверки
--if res.scope ~= "edit" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
--if res.client_id ~= "ro_client" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
';
}
}
}
Логирование
Логирование можно настроить, включая использование пользовательского логгера и переназначение уровней логирования OpenIDC по умолчанию, например:
local openidc = require("resty.openidc")
openidc.set_logging(nil, { DEBUG = ngx.INFO })
Запуск тестов
Мы создали контейнеризированную настройку для тестов, чтобы упростить установку зависимостей.
Чтобы запустить тесты, выполните
$ docker build -f tests/Dockerfile . -t lua-resty-openidc/test
$ docker run -it --rm lua-resty-openidc/test:latest
если вы хотите создать luacov покрытие во время тестирования, используйте
$ docker run -it --rm -e coverage=t lua-resty-openidc/test:latest
в качестве второй команды.
Поддержка
По общим вопросам смотрите страницы вики с часто задаваемыми вопросами на: https://github.com/zmartzone/lua-resty-openidc/wiki Все вопросы/проблемы следует направлять в обсуждения или трекер проблем GitHub.
Отказ от ответственности
Это программное обеспечение открыто предоставлено ZmartZone IAM, но не поддерживается коммерчески как таковое. Все вопросы/проблемы следует направлять в обсуждения или трекер проблем GitHub. См. также файл DISCLAIMER в этом каталоге.
GitHub
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-openidc.
