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.8.0, das am 13. September 2024 veröffentlicht wurde.
lua-resty-openidc
lua-resty-openidc ist eine Bibliothek für NGINX, die die OpenID Connect Relying Party (RP) und/oder die OAuth 2.0 Resource Server (RS) Funktionalität implementiert.
Wenn sie als OpenID Connect Relying Party verwendet wird, authentifiziert sie Benutzer gegenüber einem OpenID Connect Provider unter Verwendung von OpenID Connect Discovery und dem Basic Client Profile (d.h. dem Authorization Code Flow). Wenn sie als OAuth 2.0 Resource Server verwendet wird, kann sie OAuth 2.0 Bearer Access Tokens gegenüber einem 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.
Sie verwaltet Sitzungen für authentifizierte Benutzer, indem sie 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/die 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 über 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;
# NB: Wenn Sie "lua_code_cache off;" haben, verwenden Sie:
# set $session_secret xxxxxxxxxxxxxxxxxxx;
# siehe: https://github.com/bungle/lua-resty-session#notes-about-turning-lua-code-cache-off
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 zu
-- 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 Version 1.6.1 hätten Sie angeben müssen
-- redirect_uri_path = "/redirect_uri",
-- und konnten den Hostnamen nicht setzen
-- 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 Authentifizierungsmodi 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 mit 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 mit 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 wird, 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 gesetzt wird, um anzugeben, 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",
-- Lebensdauer in Sekunden des signierten JWT, das von lua-resty-openidc zur Authentifizierung beim OP generiert wurde.
-- (verwendet, wenn token_endpoint_auth_method auf "private_key_jwt" oder "client_secret_jwt" gesetzt ist). Standard ist 60 Sekunden.
--client_jwt_assertion_expires_in = 60,
-- Bei der Verwendung von https zu einem OP-Endpunkt kann die Durchsetzung der SSL-Zertifikatsprüfung vorgeschrieben ("ja") oder nicht ("nein") werden.
--ssl_verify = "no",
-- Die Verbindungshaltung mit dem 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 die Relying Party teilen sich dieselbe Domain.
--authorization_params = { hd="zmartzone.eu" },
--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 sollte 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.
--post_logout_redirect_uri = "https://www.zmartzone.eu/logoutSuccessful",
-- Wohin 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 nicht setzen 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 zur Autorisierungsstelle 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 bereits ein Token im Cache ist
--session_contents = {id_token=true}
-- Whitelist von Sitzungselementen, die aktiviert werden sollen. 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 Zeitüberschreitungen für connect/send/read als einzelne Zahl (alle Zeitüberschreitungen 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 erforderlich sein kann, wenn Sie mit einem fehlerhaften OpenID
-- Connect-Anbieter sprechen, der den Parameter ignoriert, da das
-- id_token andernfalls abgelehnt wird.
--revoke_tokens_on_logout = false
-- Wenn revoke_tokens_on_logout auf true gesetzt ist, informiert 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 Widerrufsendpunkt bereitgestellt wird oder wenn es Fehler beim Widerruf gibt, wird der Benutzer nicht informiert und der Logout-Prozess wird normal fortgesetzt.
-- Optional: Verwenden Sie einen ausgehenden Proxy zu den OpenID Connect-Anbieterendpunkten 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 wurde, um den Benutzer zum OpenID
-- Connect-Anbieterendpunkt weiterzuleiten.
--
-- -- 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 dekodierte id_token als zweiten und die Antwort des Token-Endpunkts als dritten Argument
-- -- Der `on_regenerated` wird unmittelbar nach dem
einem neuen Access Token, das über das Token
Refresh erhalten wurde, 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
-- Anbieter 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" wie
-- in RFC 7636 definiert verwendet. Die Code-Challenge-Methode wird immer S256 sein.
}
-- rufen Sie authenticate für die OpenID Connect-Benutzerauthentifizierung auf
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
-- 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 vorhandene Header
-- entfernt 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 ist bei Ihrem OpenID
Connect-Anbieter registriert und ist die URI, zu der Ihr Anbieter 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 nicht erwartet. Sie muss eine URI sein, für die lua-resty-openidc verantwortlich ist, sodass sie sich in einem location befinden muss, 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, fügt lua-resty-openidc das Protokoll
und den aktuellen Hostnamen hinzu, wenn die URI an den OpenID Connect
Provider gesendet wird (unter Berücksichtigung der Forwarded und X-Forwarded-* HTTP-Header). Sie können jedoch auch eine absolute URI angeben, die Host und Protokoll enthält.
Vor Version 1.6.1 war opts.redirect_uri_path der Weg, um die redirect_uri zu konfigurieren, ohne die Möglichkeit, 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 die Anfrage abgefangen und selbst verarbeitet.
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.
Nur Authentifizierung überprüfen
-- Überprüfen Sie die Sitzung, leiten Sie jedoch nicht zur Authentifizierung um, wenn nicht bereits angemeldet
local res, err = require("resty.openidc").authenticate(opts, nil, "pass")
Nur Authentifizierung überprüfen und nicht authentifizierten Zugriff verweigern
-- Überprüfen Sie die Sitzung, leiten Sie nicht zur Authentifizierung um, wenn nicht bereits angemeldet, 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 sie ein serverseitiges Speicher-Backend verwendet, das Sperrmechanismen nutzt, 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 sie 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-Anbieters. Cache-Elemente laufen nach 24 Stunden ab, es sei denn, sie werden vonopts.discovery_expires_in(einem Wert in Sekunden) ü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-Anbieter. - Der Cache mit dem Namen
jwksspeichert das Schlüsselmaterial Ihres OpenID Connect-Anbieters, wenn es über den JWKS-Endpunkt bereitgestellt wird. Cache-Elemente laufen nach 24 Stunden ab, es sei denn, sie werden vonopts.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-Anbieter. - Der Cache mit dem Namen
introspectionspeichert das Ergebnis der OAuth2-Token-Introspektion. Cache-Elemente laufen ab, wenn das entsprechende Token abläuft. Tokens mit unbekannter Ablaufzeit werden überhaupt nicht im Cache gespeichert. Dieser Cache enthält einen Eintrag pro introspektiertem Access Token - normalerweise sind dies 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 unbekannter Ablaufzeit werden zwei Minuten lang nicht im Cache gespeichert. Dieser Cache enthält einen Eintrag pro verifiziertem JWT - normalerweise sind dies einige kB pro Token.
Caching von Introspektions- und JWT-Überprüfungsergebnissen
Beachten Sie, dass die Caches jwt_verification und introspection zwischen allen konfigurierten Standorten geteilt werden. Wenn Sie Standorte mit unterschiedlichen opts-Konfigurationen verwenden, kann der gemeinsame Cache es ermöglichen, dass ein Token, das nur für einen Standort gültig ist, von einem 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 Standorte zu setzen.
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 von der Serverseite löschen/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 überprüft, 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 eines gemeinsamen Geheimnisses für die HS??? Signaturüberprüfung
--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 eines öffentlichen Zertifikats für die RS??? Signaturüberprüfung
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 auf ein sogenanntes Discovery-Dokument verwiesen werden, 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 vorgibt, mit HMAC
-- unter Verwendung eines öffentlichen RSA-Schlüssels signiert zu sein.
--token_signing_alg_values_expected = { "RS256" }
-- Wenn Sie nicht signierte Tokens (mit dem
-- "none"-Signaturalgorithmus) akzeptieren möchten, 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 nicht setzen, wird die Token-Signatur nicht
-- überprüft.
--accept_unsupported_alg = true
-- Die Ablaufzeit in Sekunden für den jwk-Cache, Standard ist 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 Standorte benötigen
-- cache_segment = 'api'
}
-- rufen Sie bearer_jwt_verify zur Validierung von OAuth 2.0 JWT 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 (validierten) JSON
-- Nutzdaten im JWT-Token darstellt; jetzt möchten wir typischerweise nicht einfach irgendein
-- Token zulassen, das vom Autorisierungsserver ausgestellt wurde, sondern wir möchten
-- einige Zugriffsbeschränkungen ü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 Standorte benötigen
-- cache_segment = 'api'
}
-- rufen Sie introspect zur Validierung des OAuth 2.0 Bearer Access Tokens 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 zum Ü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-Anbieter 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, beträgt 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, 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 Namens, der nach ":" angegeben ist
-- "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 mit einer client_id/client_secret beim Introspektionsendpunkt 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 sind, um sie aus dem Browser abzurufen und bei Backchannel-Anrufen an die OP- und AS-Endpunkte zu senden.
-- 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 Standorte benötigen
-- cache_segment = 'api'
}
-- rufen Sie introspect zur Validierung des OAuth 2.0 Bearer Access Tokens 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 Standard-Protokollebene 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 die Tests erstellt, um die Installation von Abhängigkeiten zu vereinfachen.
Um die Tests auszuführen, führen Sie Folgendes 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 wird von ZmartZone IAM Open Source bereitgestellt, 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 zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-openidc.
