openidc: OpenID Connect Relying Party und OAuth 2.0 Resource Server Implementierung in Lua für NGINX / nginx-module-lua
Installation
Wenn Sie noch kein RPM-Repository-Abonnement eingerichtet haben, melden Sie sich an. Dann können Sie mit den folgenden Schritten fortfahren.
CentOS/RHEL 7 oder 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
Um diese Lua-Bibliothek mit NGINX zu verwenden, stellen Sie sicher, dass nginx-module-lua installiert ist.
Dieses Dokument beschreibt lua-resty-openidc v1.9.0, veröffentlicht am 01. Juli 2026.
lua-resty-openidc
lua-resty-openidc ist eine Bibliothek für NGINX, die die Funktionalität des OpenID Connect Relying Party (RP) und/oder des OAuth 2.0 Resource Server (RS) implementiert.
Wenn es als OpenID Connect Relying Party verwendet wird, authentifiziert es Benutzer gegen einen OpenID Connect Provider unter Verwendung von OpenID Connect Discovery und dem Basic Client Profile (d.h. dem Authorization Code Flow). Wenn es als OAuth 2.0 Resource Server verwendet wird, kann es OAuth 2.0 Bearer Access Tokens gegen einen Authorization Server validieren oder, falls ein JSON Web Token für ein Access Token verwendet wird, kann die Überprüfung gegen ein vorkonfiguriertes Geheimnis/Schlüssel erfolgen.
Es verwaltet Sitzungen für authentifizierte Benutzer, indem es lua-resty-session nutzt, und bietet somit eine konfigurierbare Wahl zwischen der Speicherung des Sitzungsstatus in einem clientseitigen Browser-Cookie oder der Verwendung eines der serverseitigen Speichermechanismen shared-memory|memcache|redis.
Es unterstützt serverweites Caching von aufgelösten Discovery-Dokumenten und validierten Access Tokens.
Es kann als Reverse-Proxy verwendet werden, der OAuth/OpenID Connect vor einem Origin-Server terminiert, sodass der Origin-Server/Dienste mit den relevanten Standards geschützt werden können, ohne diese auf dem Server selbst implementieren zu müssen.
Beispielkonfiguration für Google+ Sign-In
Beispielkonfiguration nginx.conf zur Authentifizierung von Benutzern gegen Google+ Sign-In, zum Schutz eines umgekehrten Proxy-Pfades.
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;
# Cache für Discovery-Metadaten-Dokumente
lua_shared_dict discovery 1m;
# Cache für JWKs
lua_shared_dict jwks 1m;
server {
listen 8080;
location / {
access_by_lua_block {
local opts = {
-- Die vollständige Redirect-URI muss durch dieses Skript geschützt werden
-- Wenn die URI mit einem / beginnt, wird die vollständige Redirect-URI
-- ngx.var.scheme.."://"..ngx.var.http_host..opts.redirect_uri
-- es sei denn, das Schema wurde durch opts.redirect_uri_scheme oder einen X-Forwarded-Proto-Header in der eingehenden Anfrage überschrieben
redirect_uri = "https://MY_HOST_NAME/redirect_uri",
-- Bis zur Version 1.6.1 hätten Sie angeben müssen
-- redirect_uri_path = "/redirect_uri",
-- und konnten den Hostnamen nicht festlegen
-- Der Discovery-Endpunkt des OP. Aktivieren Sie, um die URI aller Endpunkte (Token, Introspektion, Logout...) zu erhalten
discovery = "https://accounts.google.com/.well-known/openid-configuration",
-- Der Zugriff auf den OP-Token-Endpunkt erfordert eine Authentifizierung. Mehrere Authentifizierungsmethoden werden unterstützt:
--token_endpoint_auth_method = ["client_secret_basic"|"client_secret_post"|"private_key_jwt"|"client_secret_jwt"],
-- o Wenn token_endpoint_auth_method auf "client_secret_basic", "client_secret_post" oder "client_secret_jwt" gesetzt ist, erfolgt die Authentifizierung zum Token-Endpunkt unter Verwendung von client_id und client_secret
-- Für nicht konforme OPs zu OAuth 2.0 RFC 6749 für die Client-Authentifizierung (vgl. https://tools.ietf.org/html/rfc6749#section-2.3.1)
-- client_id und client_secret MÜSSEN invariant sein, wenn sie URL-kodiert sind
client_id = "<client_id>",
client_secret = "<client_secret>",
-- o Wenn token_endpoint_auth_method auf "private_key_jwt" gesetzt ist, erfolgt die Authentifizierung zum Token-Endpunkt unter Verwendung von client_id, client_rsa_private_key und client_rsa_private_key_id zur Berechnung eines signierten JWT
-- client_rsa_private_key ist der RSA-Private-Key, der verwendet werden soll, um das von lua-resty-openidc generierte JWT zur Authentifizierung beim OP zu signieren
-- client_rsa_private_key_id (optional) ist die Schlüssel-ID, die im JWT-Header festgelegt wird, um zu identifizieren, welchen öffentlichen Schlüssel der OP verwenden soll, um die JWT-Signatur zu überprüfen
--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",
-- Signaturalgorithmus für das Client-Assertion-JWT. Standardmäßig RS256 für private_key_jwt und HS256 für client_secret_jwt.
-- Wenn token_endpoint_auth_signing_alg_values_supported in der Discovery beworben wird, muss der konfigurierte Wert vom OP unterstützt werden.
--client_jwt_assertion_alg = "PS256",
-- Audience für das Client-Assertion-JWT. Standardmäßig die aufgerufene Endpunkt-URL.
-- Setzen Sie dies, wenn der Endpunkt über eine interne URL erreicht wird, der OP jedoch seine externe Token-Endpunkt-URL als Audience erwartet.
--client_jwt_assertion_audience = "https://op.example.com/token",
-- Lebensdauer, ausgedrückt in Sekunden, des signierten JWT, das von lua-resty-openidc zur Authentifizierung beim OP generiert wurde.
-- (wird verwendet, wenn token_endpoint_auth_method auf "private_key_jwt" oder "client_secret_jwt" Authentifizierung gesetzt ist). Standard ist 60 Sekunden.
--client_jwt_assertion_expires_in = 60,
-- Wenn Sie https zu einem beliebigen OP-Endpunkt verwenden, kann die Durchsetzung der SSL-Zertifikatsprüfung vorgeschrieben ("ja") oder nicht ("nein") sein.
--ssl_verify = "no",
-- Die Verbindung zum OP kann aktiviert ("ja") oder deaktiviert ("nein") werden.
--keepalive = "no",
--response_mode=form_post kann verwendet werden, um lua-resty-openidc den [OAuth 2.0 Form Post Response Mode](https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html) verwenden zu lassen. *Hinweis*: Für moderne Browser müssen Sie [`$session_cookie_samesite`](https://github.com/bungle/lua-resty-session#string-sessioncookiesamesite) auf `None` mit form_post setzen, es sei denn, Ihr OpenID Connect Provider und Relying Party teilen sich dieselbe Domain.
--authorization_params = { hd="zmartzone.eu" },
-- Wenn use_par auf true gesetzt ist, verwendet lua-resty-openidc OAuth 2.0 Pushed Authorization Requests (PAR, RFC 9126).
-- Die Autorisierungsanfrageparameter werden an den pushed_authorization_request_endpoint aus der Discovery gesendet,
-- und der Browser wird mit der zurückgegebenen request_uri an den Autorisierungsendpunkt umgeleitet.
--use_par = false,
-- Überschreiben Sie den PAR-Endpunkt aus der Discovery, wenn nötig.
--pushed_authorization_request_endpoint = "https://MY_OP/pushed_authorization_request",
-- Überschreiben Sie die Client-Authentifizierungsmethode für den PAR-Endpunkt. Standardmäßig token_endpoint_auth_method.
--pushed_authorization_request_endpoint_auth_method = "client_secret_basic",
-- Wenn use_dpop auf true gesetzt ist, sendet lua-resty-openidc OAuth 2.0 DPoP (RFC 9449)
-- Proof-JWTs an den Token-Endpunkt und verwendet DPoP-gebundene Access Tokens für die Benutzerinformationen.
-- Die ursprüngliche DPoP-Implementierung unterstützt ES256, RS256 und PS256 Nachweise und wiederholt Token-/Benutzerinfo-Aufrufe
-- einmal, wenn der OP eine DPoP-Nonce-Herausforderung zurückgibt.
-- Autorisierungsanfragen enthalten dpop_jkt, um den Autorisierungscode an den konfigurierten DPoP-öffentlichen Schlüssel zu binden.
-- Token-Antworten werden erwartet, token_type=DPoP zurückzugeben.
-- Wenn der OP DPoP-Nonce bei einer erfolgreichen Token-Antwort bereitstellt, wird sie für nachfolgende Token-Anfragen wiederverwendet.
--use_dpop = false,
--dpop_signing_alg = "ES256",
--dpop_private_key = "PEM-kodierter privater Schlüssel, der mit dpop_signing_alg übereinstimmt",
--dpop_public_jwk = {
-- kty = "EC",
-- crv = "P-256",
-- x = "...",
-- y = "..."
--},
--scope = "openid email profile",
-- Aktualisieren Sie das id_token des Benutzers nach 900 Sekunden, ohne eine erneute Authentifizierung zu verlangen
--refresh_session_interval = 900,
--iat_slack = 600,
--redirect_uri_scheme = "https",
--logout_path = "/logout",
--redirect_after_logout_uri = "/",
-- Wohin soll der Benutzer nach dem Logout von der RP umgeleitet werden? Diese Option überschreibt jeden end_session_endpoint, den der OP möglicherweise in der Discovery-Antwort bereitgestellt hat.
--redirect_after_logout_with_id_token_hint = true,
-- Ob die Umleitung nach dem Logout das id_token als Hinweis (sofern verfügbar) enthalten soll. Diese Option wird nur verwendet, wenn redirect_after_logout_uri gesetzt ist.
--redirect_after_logout_with_client_id = true,
-- Ob die Umleitung nach dem Logout die Client-ID enthalten soll, wenn kein id_token_hint gesendet wird (sofern verfügbar).
--post_logout_redirect_uri = "https://www.zmartzone.eu/logoutSuccessful",
-- Wo fordert die RP an, dass der OP den Benutzer nach dem Logout umleitet? Wenn diese Option auf eine relative URI gesetzt ist, wird sie relativ zum Logout-Endpunkt des OPs sein, nicht zum der RP.
--accept_none_alg = false
-- wenn Ihr OpenID Connect Provider seine id Tokens nicht signiert
-- (verwendet den "none" Signaturalgorithmus), setzen Sie dies auf true.
--accept_unsupported_alg = true
-- wenn Sie Tokens ablehnen möchten, die mit einem Algorithmus signiert sind,
-- der von lua-resty-jwt nicht unterstützt wird, setzen Sie dies auf false. Wenn
-- Sie es ungesetzt lassen oder auf true setzen, wird die Token-Signatur nicht
-- überprüft, wenn ein nicht unterstützter Algorithmus verwendet wird.
--renew_access_token_on_expiry = true
-- ob dieses Plugin versuchen soll, das Access Token stillschweigend zu erneuern, sobald es abgelaufen ist, wenn ein Refresh-Token verfügbar ist.
-- Wenn es nicht gelingt, das Token zu erneuern, wird der Benutzer zum Autorisierungsendpunkt umgeleitet.
--access_token_expires_in = 3600
-- Standardlebensdauer in Sekunden des access_token, wenn kein expires_in-Attribut in der Antwort des Token-Endpunkts vorhanden ist.
--access_token_expires_leeway = 0
-- Ablaufspielraum für die Erneuerung des access_token. Wenn dies gesetzt ist, erfolgt die Erneuerung access_token_expires_leeway Sekunden vor dem Ablauf des Tokens. Dies vermeidet Fehler, falls das access_token gerade abläuft, wenn es beim OAuth Resource Server ankommt.
--force_reauthorize = false
-- Wenn force_reauthorize auf true gesetzt ist, wird der Autorisierungsfluss ausgeführt, auch wenn ein Token bereits zwischengespeichert wurde
--session_contents = {id_token=true}
-- Whitelist des aktivierten Sitzungsinhalts. Dies kann verwendet werden, um die Sitzungsgröße zu reduzieren.
-- Wenn nicht gesetzt, wird alles in der Sitzung enthalten sein.
-- Verfügbar sind:
-- id_token, enc_id_token, user, access_token (einschließlich Refresh-Token)
-- Sie können Timeouts für connect/send/read als einzelne Zahl (alle Timeouts festlegen) oder als Tabelle angeben. Werte sind in Millisekunden
-- timeout = 1000
-- timeout = { connect = 500, send = 1000, read = 1000 }
--use_nonce = false
-- Standardmäßig enthält die Autorisierungsanfrage den
-- nonce-Parameter. Sie können diese Option verwenden, um ihn zu deaktivieren,
-- was notwendig sein kann, wenn Sie mit einem fehlerhaften OpenID
-- Connect-Provider sprechen, der den Parameter ignoriert, da das
-- id_token andernfalls abgelehnt wird.
--authorization_state_expires_in = 300
-- Maximales Alter in Sekunden für den ausstehenden Autorisierungsstatus, der
-- in der Sitzung gespeichert ist. Abgelaufene Autorisierungsstatus werden entfernt, wenn
-- eine neue Autorisierungsanfrage erstellt wird.
--authorization_state_max_number = 10
-- Maximale Anzahl ausstehender Autorisierungsstatus, die in der
-- Sitzung gespeichert sind. Wenn dies überschritten wird, werden die ältesten Autorisierungsstatus
-- entfernt, wenn eine neue Autorisierungsanfrage erstellt wird.
--revoke_tokens_on_logout = false
-- Wenn revoke_tokens_on_logout auf true gesetzt ist, benachrichtigt ein Logout den Autorisierungsserver, dass zuvor erhaltene Refresh- und Access-Tokens nicht mehr benötigt werden. Dies erfordert, dass der revocation_endpoint auffindbar ist.
-- Wenn kein Widerrufs-Endpunkt bereitgestellt wird oder wenn es beim Widerruf Fehler gibt, wird der Benutzer nicht benachrichtigt und der Logout-Prozess wird normal fortgesetzt.
-- Optional: Verwenden Sie einen ausgehenden Proxy zu den Endpunkten des OpenID Connect-Providers mit der proxy_opts-Tabelle:
-- dies erfordert lua-resty-http >= 0.12
-- proxy_opts = {
-- http_proxy = "http://<proxy_host>:<proxy_port>/",
-- https_proxy = "http://<proxy_host>:<proxy_port>/"
-- }
-- Lifecycle Hooks
--
-- lifecycle = {
-- on_created = handle_created,
-- on_authenticated = handle_authenticated,
-- on_regenerated = handle_regenerated
-- on_logout = handle_logout
-- }
--
-- wobei `handle_created`, `handle_authenticated`, `handle_regenerated` und `handle_logout` aufrufbare Funktionen sind,
-- die das Argument `session` akzeptieren. `handle_created` akzeptiert auch das zweite Argument `params`, das eine Tabelle ist,
-- die die Abfrageparameter der Autorisierungsanfrage enthält, die verwendet wird, um den Benutzer zum OpenID
-- Connect-Provider-Endpunkt umzuleiten.
--
-- -- Der `on_created` Hook wird *nach* der Erstellung einer Sitzung in
-- `openidc_authorize` unmittelbar vor dem Speichern der Sitzung aufgerufen
-- -- Der `on_authenticated` Hook wird *nach* dem Erhalt der Autorisierungsantwort in
-- `openidc_authorization_response` unmittelbar vor dem Speichern der Sitzung aufgerufen
-- Ab Version lua-resty-openidc 1.7.5 erhält dieser das decodierte id_token als zweites und die Antwort des Token-Endpunkts als drittes Argument
-- -- Der `on_regenerated` Hook wird unmittelbar nach dem
-- Erhalt eines neuen Access Tokens über das Token
-- Refresh aufgerufen und wird mit der regenerierten Sitzungstabelle aufgerufen
-- -- Der `on_logout` Hook wird *vor* der Zerstörung einer Sitzung in
-- `openidc_logout` aufgerufen
--
-- Jeder, alle oder keiner der Hooks kann verwendet werden. Ein leeres `lifecycle` tut nichts.
-- Ein Hook, der einen wahrheitsgemäßen Wert zurückgibt, führt dazu, dass die Lifecycle-Aktion, an der sie teilnehmen, fehlschlägt.
-- Optional: Fügen Sie einen Dekorator für HTTP-Anfragen hinzu, der
-- angewendet wird, wenn lua-resty-openidc direkt mit dem OpenID Connect
-- Provider kommuniziert. Kann verwendet werden, um zusätzliche HTTP-Header bereitzustellen
-- oder ähnliches Verhalten hinzuzufügen.
-- http_request_decorator = function(req)
-- local h = req.headers or {}
-- h[EXTRA_HEADER] = 'mein zusätzlicher Header'
-- req.headers = h
-- return req
-- end,
-- use_pkce = false,
-- wenn auf true gesetzt, wird der "Proof Key for Code Exchange" verwendet,
-- wie in RFC 7636 definiert. Die Code-Challenge-Methode wird immer S256 sein
}
-- Konfigurieren Sie lua-resty-session
-- Die vollständige Liste der Konfigurationsoptionen ist im GitHub-Repository von lua-resty-session dokumentiert: https://github.com/bungle/lua-resty-session?tab=readme-ov-file#session-configuration
local session_opts = {
-- Wenn Sie Cookies zur Speicherung von Sitzungen verwenden, setzen Sie ein gemeinsames Geheimnis zur Verschlüsselung des Sitzungscookies. Dies ermöglicht es, dass Sitzungen nach einem Neustart von nginx gültig bleiben.
-- Es ermöglicht auch ein "zustandsloses" Sitzungsmanagement, sodass mehrere Instanzen von nginx Anfragen ohne die Notwendigkeit für "sticky" Lastenausgleichstechniken bearbeiten können.
-- secret = "xxxxxxxxxxxxxxxxxxx",
-- Optional können Sie das Cookie-Präfix festlegen, um ein versehentliches Überschreiben des Sitzungscookies zu verhindern
-- cookie_prefix = "__Host-",
-- Login-Sitzungscookies sollten HTTP-Only sein
cookie_http_only = true,
-- Login-Sitzungscookies sollten als "Sicher" markiert sein
cookie_secure = true,
-- Setzen Sie die Same-Site-Cookie-Richtlinie
cookie_same_site = "Lax",
-- Setzen Sie dies auf true, wenn Sie möchten, dass Login-Sitzungscookies einen Neustart des Browsers überstehen
remember = true
}
-- Rufen Sie authenticate für die OpenID Connect-Benutzerauthentifizierung auf
local res, err = require("resty.openidc").authenticate(opts, nil, nil, session_opts)
if err then
ngx.status = 500
ngx.say(err)
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
-- An diesem Punkt ist res eine Lua-Tabelle mit 3 Schlüsseln:
-- id_token : eine Lua-Tabelle mit den Ansprüchen aus dem id_token (erforderlich)
-- access_token: das Access Token (optional)
-- user : eine Lua-Tabelle mit den Ansprüchen, die vom Benutzerinfo-Endpunkt zurückgegeben werden (optional)
--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
-- Setzen Sie Header mit Benutzerinformationen: dies überschreibt alle vorhandenen Header
-- löscht sie aber auch (!), falls kein Wert im Token bereitgestellt wird
ngx.req.set_header("X-USER", res.id_token.sub)
}
proxy_pass http://localhost:80;
}
}
}
Über redirect_uri
Die sogenannte redirect_uri ist eine URI, die Teil des OpenID
Connect-Protokolls ist. Die Redirect-URI wird bei Ihrem OpenID
Connect-Provider registriert und ist die URI, zu der Ihr Provider die Benutzer
nach erfolgreichem Login umleitet. Diese URI wird dann von
lua-resty-openidc verarbeitet, wo sie Tokens erhält und einige Überprüfungen durchführt, und erst danach wird der Browser dorthin umgeleitet, wo Ihr Benutzer ursprünglich hin wollte.
Die redirect_uri wird von Ihrem Anwendungscode überhaupt nicht erwartet.
Es muss eine URI sein, für die lua-resty-openidc verantwortlich ist,
also muss sie in einem location sein, das durch lua-resty-openidc geschützt ist.
Sie konfigurieren die redirect_uri auf der lua-resty-openidc-Seite über den
Parameter opts.redirect_uri (der standardmäßig auf /redirect_uri gesetzt ist). Wenn
sie mit einem / beginnt, wird lua-resty-openidc das Protokoll
und den aktuellen Hostnamen voranstellen, wenn es die URI an den OpenID Connect
Provider sendet (unter Berücksichtigung der Forwarded und X-Forwarded-* HTTP-Header). Aber Sie können auch eine absolute URI angeben, die Host und
Protokoll selbst enthält.
Vor Version 1.6.1 war opts.redirect_uri_path der Weg, um die
redirect_uri zu konfigurieren, ohne eine Möglichkeit zu haben, die Protokoll- und Hostteile zu steuern.
Wann immer lua-resty-openidc einen lokalen Pfad sieht, der mit dem Pfad von
opts.redirect_uri (oder opts.redirect_uri_path) übereinstimmt, wird es
die Anfrage abfangen und selbst verarbeiten.
Dies funktioniert in den meisten Fällen, aber manchmal hat die extern sichtbare
redirect_uri einen anderen Pfad als der, der lokal für
den Server sichtbar ist. Dies kann passieren, wenn ein Reverse-Proxy vor Ihrem Server
URIs umschreibt, bevor er die Anfragen weiterleitet. Daher wurde in Version 1.7.6
eine neue Option opts.local_redirect_uri_path eingeführt. Wenn sie gesetzt ist,
wird lua-resty-openidc Anfragen an diesen Pfad abfangen, anstatt an den Pfad von opts.redirect_uri.
Überprüfen Sie nur die Authentifizierung
-- Überprüfen Sie die Sitzung, aber leiten Sie nicht zur Authentifizierung um, wenn nicht bereits eingeloggt
local res, err = require("resty.openidc").authenticate(opts, nil, "pass")
Überprüfen Sie nur die Authentifizierung und verweigern Sie nicht authentifizierten Zugriff
-- Überprüfen Sie die Sitzung, leiten Sie nicht zur Authentifizierung um, wenn nicht bereits eingeloggt, sondern geben Sie stattdessen einen Fehler zurück
local res, err = require("resty.openidc").authenticate(opts, nil, "deny")
Sitzungen und Sperren
Die Funktion authenticate gibt das aktuelle Sitzungsobjekt als vierten Rückgabewert zurück. Wenn Sie lua-resty-session so konfiguriert haben, dass es ein serverseitiges Speicher-Backend verwendet, das Sperrmechanismen verwendet, kann die Sitzung möglicherweise noch gesperrt sein, wenn sie zurückgegeben wird. In diesem Fall möchten Sie sie möglicherweise explizit schließen.
local res, err, target, session = require("resty.openidc").authenticate(opts)
session:close()
Caching
lua-resty-openidc kann Shared Memory Caches für verschiedene Dinge verwenden. Wenn Sie möchten, dass es die Caches verwendet, müssen Sie lua_shared_dict in Ihrer nginx.conf-Datei verwenden.
Derzeit werden bis zu vier Caches verwendet:
- Der Cache mit dem Namen
discoveryspeichert die OpenID Connect Discovery-Metadaten Ihres OpenID Connect Providers. Cache-Elemente laufen nach 24 Stunden ab, es sei denn, sie werden durchopts.discovery_expires_in(ein in Sekunden angegebener Wert) überschrieben. Dieser Cache speichert ein Element pro Issuer-URI, und Sie können das Discovery-Dokument selbst nachschlagen, um eine Schätzung für die benötigte Größe zu erhalten - normalerweise einige kB pro OpenID Connect Provider. - Der Cache mit dem Namen
jwksspeichert das Schlüsselmaterial Ihres OpenID Connect Providers, wenn es über den JWKS-Endpunkt bereitgestellt wird. Cache-Elemente laufen nach 24 Stunden ab, es sei denn, sie werden durchopts.jwks_expires_inüberschrieben. Dieser Cache speichert ein Element pro JWKS-URI, und Sie können die jwks selbst nachschlagen, um eine Schätzung für die benötigte Größe zu erhalten - normalerweise einige kB pro OpenID Connect Provider. - Der Cache mit dem Namen
introspectionspeichert das Ergebnis der OAuth2-Token-Introspektion. Cache-Elemente laufen ab, wenn das entsprechende Token abläuft. Tokens mit unbekanntem Ablauf werden überhaupt nicht zwischengespeichert. Dieser Cache enthält einen Eintrag pro introspektiertem Access Token - normalerweise sind das einige kB pro Token. - Der Cache mit dem Namen
jwt_verificationspeichert das Ergebnis der JWT-Überprüfung. Cache-Elemente laufen ab, wenn das entsprechende Token abläuft. Tokens mit unbekanntem Ablauf werden zwei Minuten lang nicht zwischengespeichert. Dieser Cache enthält einen Eintrag pro verifiziertem JWT - normalerweise sind das einige kB pro Token.
Caching von Introspektions- und JWT-Überprüfungsergebnissen
Beachten Sie, dass die Caches jwt_verification und introspection zwischen allen konfigurierten Locations geteilt werden. Wenn Sie Locations mit unterschiedlichen opts-Konfigurationen verwenden, kann der gemeinsame Cache es ermöglichen, dass ein Token, das nur für eine Location gültig ist, von einer anderen akzeptiert wird, wenn es aus dem Cache gelesen wird. Um Cache-Verwirrung zu vermeiden, wird empfohlen, opts.cache_segment auf eindeutige Zeichenfolgen für jede Gruppe verwandter Locations zu setzen.
Caching negativer Introspektionsantworten
Standardmäßig speichert der introspection-Cache keine negativen Antworten.
Das bedeutet, dass ein böswilliger Akteur potenziell versuchen kann, den Introspektions-Endpunkt zu erschöpfen, indem er den Dienst mit vielen Anfragen mit einem ungültigen Token überflutet.
Um diese Situation zu verhindern, kann opts.introspection_enable_negative_cache auf true gesetzt werden. Dadurch wird der introspection-Cache aktiviert, um negative Antworten für die im exp-Feld definierte Zeit zu speichern.
Das Caching negativer Introspektionsantworten wird den Verkehr vom Introspektions-Endpunkt entlasten, kann jedoch auch NGINX für Angriffe auf die Ressourcenerschöpfung anfällig machen, da das Speichern negativer Introspektionsantworten zusätzlichen Cache-Speicher benötigt.
Tokens widerrufen
Die Funktion revoke_tokens(opts, session) widerruft das aktuelle Refresh- und Access-Token. Im Gegensatz zu einem vollständigen Logout wird das Sitzungscookie nicht zerstört und der Endsession-Endpunkt wird nicht aufgerufen. Die Funktion gibt true zurück, wenn beide Tokens erfolgreich widerrufen wurden. Diese Funktion kann in Szenarien hilfreich sein, in denen Sie eine Sitzung vom Server aus zerstören/entfernen möchten.
Mit revoke_token(opts, token_type_hint, token) ist es auch möglich, ein bestimmtes Token zu widerrufen. token_type_hint kann normalerweise refresh_token oder access_token sein.
Beispielkonfiguration zur Validierung von OAuth 2.0 JWT-Token
Beispielkonfiguration nginx.conf zur Überprüfung von Bearer JWT Access Tokens gegen ein vorkonfiguriertes Geheimnis/Schlüssel.
Sobald erfolgreich verifiziert, kann der NGINX-Server als Reverse-Proxy zu einem internen Origin-Server fungieren.
events {
worker_connections 128;
}
http {
resolver 8.8.8.8;
# Cache für JWT-Überprüfungsergebnisse
lua_shared_dict jwt_verification 10m;
server {
listen 8080;
location /api {
access_by_lua '
local opts = {
-- 1. Beispiel für ein gemeinsames Geheimnis zur Überprüfung der HS???-Signatur
--symmetric_key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
-- In Versionen bis 1.6.1 wäre der Schlüssel dieser Option secret gewesen
-- anstelle von symmetric_key
-- 2. Ein weiteres Beispiel für ein öffentliches Zertifikat zur Überprüfung der RS???-Signatur
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-----]],
-- In Versionen bis 1.6.1 wäre der Schlüssel dieser Option secret gewesen
-- anstelle von public_key
-- 3. Alternativ kann man auf ein sogenanntes Discovery-Dokument verweisen, das
-- einen "jwks_uri"-Eintrag enthält; der jwks-Endpunkt muss entweder einen "x5c"-Eintrag
-- oder sowohl die "n"-Modulus- als auch die "e"-Exponenteinträge für die RSA-Signaturüberprüfung bereitstellen
-- discovery = "https://accounts.google.com/.well-known/openid-configuration",
-- Der Signaturalgorithmus, von dem Sie erwarten, dass er verwendet wurde;
-- kann eine einzelne Zeichenfolge oder eine Tabelle sein.
-- Sie sollten dies aus Sicherheitsgründen festlegen, um zu
-- vermeiden, dass ein Token akzeptiert wird, das mit HMAC signiert zu sein behauptet,
-- unter Verwendung eines öffentlichen RSA-Schlüssels.
--token_signing_alg_values_expected = { "RS256" }
-- Wenn Sie unsignierte Tokens akzeptieren möchten (unter Verwendung des
-- "none"-Signaturalgorithmus), setzen Sie dies auf true.
--accept_none_alg = false
-- Wenn Sie Tokens ablehnen möchten, die mit einem Algorithmus signiert sind,
-- der von lua-resty-jwt nicht unterstützt wird, setzen Sie dies auf false. Wenn
-- Sie es ungesetzt lassen, wird die Token-Signatur nicht
-- überprüft.
--accept_unsupported_alg = true
-- Die Ablaufzeit in Sekunden für den jwk-Cache, standardmäßig 1 Tag.
--jwk_expires_in = 24 * 60 * 60
-- Es kann notwendig sein, die Überprüfung für ein Bearer-Token zu erzwingen und die vorhandenen zwischengespeicherten
-- Überprüfungsergebnisse zu ignorieren. Wenn ja, müssen Sie die Option jwt_verification_cache_ignore auf true setzen.
-- jwt_verification_cache_ignore = true
-- optionaler Name eines Cache-Segments, wenn Sie separate
-- Caches für unterschiedlich konfigurierte Locations benötigen
-- cache_segment = 'api'
}
-- Rufen Sie bearer_jwt_verify für die OAuth 2.0 JWT-Validierung auf
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 "kein access_token bereitgestellt")
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- An diesem Punkt ist res eine Lua-Tabelle, die die (validierte) JSON
-- Nutzlast im JWT-Token darstellt; jetzt möchten wir typischerweise nicht einfach irgendein
-- Token zulassen, das vom Autorisierungsserver ausgegeben wurde, sondern wir möchten
-- einige Zugriffsrestriktionen über Client-IDs oder Scopes anwenden
--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;
}
}
}
Beispielkonfiguration für PingFederate OAuth 2.0
Beispielkonfiguration nginx.conf zur Validierung von Bearer Access Tokens gegen einen PingFederate OAuth 2.0 Authorization Server.
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;
# Cache für Validierungsergebnisse
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",
-- Standardmäßig auf "exp" - Steuert die TTL des Introspektions-Caches
-- https://tools.ietf.org/html/rfc7662#section-2.2
-- introspection_expiry_claim = "exp"
-- optionaler Name eines Cache-Segments, wenn Sie separate
-- Caches für unterschiedlich konfigurierte Locations benötigen
-- cache_segment = 'api'
}
-- Rufen Sie introspect für die OAuth 2.0 Bearer Access Token-Validierung auf
local res, err = require("resty.openidc").introspect(opts)
if err then
ngx.status = 403
ngx.say(err)
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- An diesem Punkt ist res eine Lua-Tabelle, die das JSON
-- Objekt darstellt, das vom Introspektions-/Validierungsendpunkt zurückgegeben wird
--if res.scope ~= "edit" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
--if res.client_id ~= "ro_client" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
';
}
}
}
Beispielkonfiguration für das Übergeben von Bearer OAuth 2.0 Access Tokens als Cookie
Beispielkonfiguration nginx.conf zur Validierung von Bearer Access Tokens, die als Cookie gegen einen ORY/Hydra Authorization Server übergeben werden.
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;
# Cache für Validierungsergebnisse
lua_shared_dict introspection 10m;
server {
listen 8080;
location /api {
access_by_lua '
local opts = {
-- Setzt die URI des Introspektionsendpunkts
introspection_endpoint="https://localhost:9031/oauth2/introspect",
-- Alternativ, wenn Ihr OAuth2-Provider ein Discovery-Dokument bereitstellt, das den
-- introspection_endpoint-Anspruch enthält, können Sie die Option introspection_endpoint
-- ungesetzt lassen und stattdessen verwenden
-- discovery = "https://my-oauth2-provider/.well-known/oauth-authorization-server",
client_id="admin",
client_secret="demo-password",
ssl_verify = "no",
-- Definiert das Intervall in Sekunden, nach dem ein zwischengespeichertes und introspektiertes Access Token
-- erneut durch Introspektion (und Validierung) gegen den Autorisierungsserver aktualisiert werden muss.
-- Wenn nicht definiert, ist der Wert 0, was bedeutet, dass es nur nach dem `exp` (oder alternativ,
-- siehe introspection_expiry_claim) Hinweis abläuft, wie vom Autorisierungsserver zurückgegeben
-- introspection_interval = 60,
-- Definiert die Art und Weise, wie Bearer OAuth 2.0 Access Tokens an diesen Resource Server übergeben werden können.
-- "cookie" als Cookie-Header namens "PA.global" oder unter Verwendung des nach ":" angegebenen Namens
-- "header" "Authorization: bearer" Header
-- Wenn nicht definiert, wird der Standard-Header "Authorization: bearer" verwendet
-- auth_accept_token_as = "cookie:PA",
-- Wenn der Header verwendet wird, ist das Header-Feld Authorization
-- auth_accept_token_as_header_name = "cf-Access-Jwt-Assertion"
-- Authentifizierungsmethode für den OAuth 2.0 Authorization Server Introspektionsendpunkt,
-- Wird verwendet, um den Client beim Introspektionsendpunkt mit einer client_id/client_secret zu authentifizieren
-- Standardmäßig auf "client_secret_post"
-- introspection_endpoint_auth_method = "client_secret_basic",
-- Geben Sie die Namen der Cookies an, die durch Leerzeichen getrennt vom Browser abgerufen und bei Backchannel
-- Aufrufen an die OP- und AS-Endpunkte gesendet werden sollen.
-- Wenn nicht definiert, werden keine solchen Cookies gesendet.
-- pass_cookies = "JSESSION"
-- Standardmäßig auf "exp" - Steuert die TTL des Introspektions-Caches
-- https://tools.ietf.org/html/rfc7662#section-2.2
-- introspection_expiry_claim = "exp"
-- Es kann notwendig sein, einen Introspektionsaufruf für ein access_token zu erzwingen und die vorhandenen zwischengespeicherten
-- Introspektionsresultate zu ignorieren. Wenn ja, müssen Sie die Option introspection_cache_ignore auf true setzen.
-- introspection_cache_ignore = true
-- optionaler Name eines Cache-Segments, wenn Sie separate
-- Caches für unterschiedlich konfigurierte Locations benötigen
-- cache_segment = 'api'
}
-- Rufen Sie introspect für die OAuth 2.0 Bearer Access Token-Validierung auf
local res, err = require("resty.openidc").introspect(opts)
if err then
ngx.status = 403
ngx.say(err)
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- An diesem Punkt ist res eine Lua-Tabelle, die das JSON
-- Objekt darstellt, das vom Introspektions-/Validierungsendpunkt zurückgegeben wird
--if res.scope ~= "edit" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
--if res.client_id ~= "ro_client" then
-- ngx.exit(ngx.HTTP_FORBIDDEN)
--end
';
}
}
}
Protokollierung
Die Protokollierung kann angepasst werden, einschließlich der Verwendung eines benutzerdefinierten Protokollierers und der Neuzuordnung der Standardprotokollstufen von OpenIDC, z.B.:
local openidc = require("resty.openidc")
openidc.set_logging(nil, { DEBUG = ngx.INFO })
Tests ausführen
Wir haben ein dockerisiertes Setup für den Test erstellt, um die Installation von Abhängigkeiten zu vereinfachen.
Um die Tests auszuführen, führen Sie aus:
$ docker build -f tests/Dockerfile . -t lua-resty-openidc/test
$ docker run -it --rm lua-resty-openidc/test:latest
Wenn Sie während des Tests eine luacov-Abdeckung erstellen möchten, verwenden Sie
$ docker run -it --rm -e coverage=t lua-resty-openidc/test:latest
als zweiten Befehl.
Unterstützung
Für allgemeine Fragen siehe die Wiki-Seiten mit häufig gestellten Fragen unter:
https://github.com/zmartzone/lua-resty-openidc/wiki
Alle Fragen/Probleme sollten an die GitHub-Diskussionen oder den Issues-Tracker gerichtet werden.
Haftungsausschluss
Diese Software ist von ZmartZone IAM Open Source, wird jedoch nicht kommerziell unterstützt. Alle Fragen/Probleme sollten an die GitHub-Diskussionen oder den Issues-Tracker gerichtet werden. Siehe auch die DISCLAIMER-Datei in diesem Verzeichnis.
GitHub
Sie finden möglicherweise zusätzliche Konfigurationstipps und Dokumentation für dieses Modul im GitHub-Repository für nginx-module-openidc.
