Zum Hauptinhalt springen

Nginx CAS Authentication and SSO: Schützen Sie jede App hinter Nginx mit Casdoor

· 11 Minuten Lektüre
Yang Luo
Casdoor Maintainer

Open-Source-nginx hat kein CAS-Modul, daher bedeutet "nginx CAS authentication" in der Praxis eines von zwei Setups. Entweder fragt nginx jeden Request über sein auth_request-Modul bei einem Authentifizierungsdienst ab, und Casdoor antwortet (direkt unter /api/forward-auth, oder über casdoor-forward-auth oder OAuth2 Proxy), oder die App hinter nginx ist selbst ein CAS-Client und kommuniziert mit den CAS-Server-Endpunkten von Casdoor. Wenn Sie nginx neu kompilieren können, führt das Casdoor-nginx-Modul den Login innerhalb von nginx aus, und wenn Sie nginx gar nicht betreiben möchten, kann der Site-Proxy von Casdoor vor der App sitzen. In jedem Fall ist die Login-Seite die von Casdoor, sodass eine SSO-Sitzung, ein Satz Berechtigungen und eine MFA-Richtlinie alle Apps abdecken.

Die Optionen auf einen Blick​

OptionLogin-Logik läuft inWas nginx benötigtProtokoll zu CasdoorWer erhält ZugriffWählen Sie es, wenn
Casdoor forward authCasdoor, /api/forward-authauth_requestCasdoor-Sitzungscookie auf der Domain der AppAnwendungs-Berechtigungen, mindestens einmal pro Minute erneut überprüftnginx steht bereits davor und Sie möchten keinen zusätzlichen Dienst
casdoor-forward-authEin kleiner Go-Dienstauth_requestOIDC Authorization CodeCasdoor-Rollen oder -Gruppen, pro LocationEin Sitzungscookie, das von vielen Subdomains geteilt wird
OAuth2 ProxyOAuth2 Proxyauth_requestOIDCallowed_groups, E-Mail-DomainsSie betreiben bereits OAuth2 Proxy
casdoor-nginx-modulenginx selbstEin kompiliertes ModulOIDC mit PKCE, Tokens lokal verifiziertJeder angemeldete Benutzer der AppKein zusätzlicher Prozess, plus Bearer-Tokens für APIs
CAS-Client in der AppDie AppNichts, sie proxyt nurCAS 1.0, 2.0, 3.0Was auch immer die App mit den Attributen machtDie App unterstützt bereits CAS
Casdoor site proxyCasdoor auf Ports 80 und 443Kein nginxCasdoor-SitzungAnwendungs-BerechtigungenNichts anderes steht vor der App

Die ersten drei unterscheiden sich nur darin, wer die Subrequest von nginx beantwortet.

Warum es kein "nginx CAS module" gibt​

CAS ist eine Unterhaltung zwischen einer Anwendung und dem CAS-Server: Die App leitet den Browser zum /login des Servers mit einer service-URL weiter, erhält ein Service-Ticket auf dieser URL zurück und validiert das Ticket mit einem Server-zu-Server-Aufruf. Apache httpd hat Apereos mod_auth_cas, um dies am Webserver durchzuführen, aber nginx hat kein CAS-Modul unter seinen offiziellen Modulen. Für nginx ist der Standard-Baustein ngx_http_auth_request_module: Bevor nginx einen Request bedient, sendet es eine Subrequest an eine von Ihnen gewählte URL. Eine 2xx-Antwort lässt den Request durch, 401 oder 403 verweigern ihn mit diesem Code, und jeder andere Code ist ein Fehler.

Für den Benutzer sehen ein CAS-Login und ein OIDC-Login gleich aus: eine Weiterleitung zur Casdoor-Login-Seite und zurück. Daher ist die praktische Antwort für eine App ohne CAS-Unterstützung OIDC auf der nginx-Ebene. Hintergrund zum Protokoll: What is CAS.

Das auth_request-Modul ist standardmäßig nicht eingebaut: Fügen Sie --with-http_auth_request_module beim Kompilieren hinzu, oder prüfen Sie nginx -V bei einem gepackten nginx.

Option 1: Casdoors eigenes Forward Auth​

Casdoor kann die Subrequest von nginx selbst beantworten. Sie fügen eine Site in Casdoor hinzu, deren Domain die Domain der App ist und deren Casdoor app die Anwendung ist, in die sich Benutzer einloggen, und fügen https://app.example.com/caswaf-handler zu den Redirect URLs dieser Anwendung hinzu. Host und Port können leer bleiben, da der Traffic nicht durch Casdoor geht.

Da auth_request keine Weiterleitungen folgen kann, antwortet Casdoor auf eine unauthentifizierte Subrequest mit 401 und setzt die Login-URL in Location. nginx wandelt dies in einen 302 um:

server {
server_name app.example.com;

proxy_buffer_size 16k;
proxy_buffers 8 16k;

location = /caswaf-handler {
proxy_pass http://casdoor:8000/api/forward-auth;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri $request_uri;
}

location = /casdoor-auth {
internal;
proxy_pass http://casdoor:8000/api/forward-auth;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Forwarded-Method $request_method;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location / {
auth_request /casdoor-auth;
auth_request_set $casdoor_redirect $upstream_http_location;
auth_request_set $casdoor_user $upstream_http_x_forwarded_user;
auth_request_set $casdoor_email $upstream_http_x_forwarded_email;
auth_request_set $casdoor_groups $upstream_http_x_forwarded_groups;
error_page 401 =302 $casdoor_redirect;

proxy_set_header X-Forwarded-User $casdoor_user;
proxy_set_header X-Forwarded-Email $casdoor_email;
proxy_set_header X-Forwarded-Groups $casdoor_groups;
proxy_pass http://app:3000;
}
}

Das Backend empfängt den Benutzer in X-Forwarded-User, X-Forwarded-Email und X-Forwarded-Groups. Der Zugriff folgt einer permission auf der Anwendung, die mindestens einmal pro Minute erneut überprüft wird, sodass ein deaktivierter Benutzer schnell den Zugriff verliert. Die Public paths der Site (Webhooks, Health Checks) werden ohne Login passiert.

Siehe Verwenden Ihres eigenen Reverse Proxys für die Referenz und Login zu einer App hinzufügen ohne OIDC für eine Grafana-Anleitung. Die App darf nur über nginx erreichbar sein, da sonst jeder X-Forwarded-User selbst senden kann.

Option 2: casdoor-forward-auth oder OAuth2 Proxy​

Wenn Sie nicht für jede App eine Casdoor-Site erstellen möchten, führen Sie einen kleinen Dienst aus, der den OIDC-Flow gegen Casdoor durchführt und die Unteranfrage beantwortet.

casdoor-forward-auth ist Casdoors eigenständiger Dienst dafür (er hat traefik-casdoor-auth ersetzt). Er speichert den Benutzer in einem signierten Cookie ohne Server-State. Für nginx stellt es /verify bereit, das Identitäts-Header mit 200 oder 401 beantwortet, und nginx leitet bei 401 auf sein /login um:

server {
server_name app.example.com;

location = /_casdoor_verify {
internal;
proxy_pass http://casdoor-forward-auth:9999/verify?groups=built-in/dev;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}

location @casdoor_login {
return 302 https://auth.example.com/login?rd=$scheme://$http_host$request_uri;
}

location / {
auth_request /_casdoor_verify;
error_page 401 = @casdoor_login;

auth_request_set $casdoor_user $upstream_http_x_forwarded_user;
auth_request_set $casdoor_roles $upstream_http_x_forwarded_roles;
proxy_set_header X-Forwarded-User $casdoor_user;
proxy_set_header X-Forwarded-Roles $casdoor_roles;
proxy_pass http://app:8080;
}
}

Die Query-Parameter roles und groups in der Verify-URL beschränken jede App auf Inhaber einer Casdoor-Rolle oder Mitglieder einer Gruppe; angemeldete Benutzer ohne diese erhalten 403. Rollen und Gruppen werden beim Login gelesen und für die Sitzung beibehalten, sodass Änderungen erst nach erneuter Anmeldung wirksam werden. Das Setzen von COOKIE_DOMAIN=example.com ermöglicht es, dass ein Login alle Subdomains abdeckt. Der Traefik-Leitfaden behandelt denselben Dienst für Traefik.

OAuth2 Proxy funktioniert auf dieselbe Weise mit provider = "oidc" und oidc_issuer_url, das auf Ihre Casdoor-URL gesetzt ist. Sein Endpunkt /oauth2/auth gibt 202 oder 401 zurück, User- und Email-Header benötigen --set-xauthrequest, und die Behandlung von Forwarded-Headers im Nginx-Beispiel erfordert --reverse-proxy. Zwei Casdoor-Einstellungen sind wichtig: Verwenden Sie das Token-Format JWT-Standard, andernfalls werden Benutzer mit unverifizierter E-Mail abgelehnt, und behalten Sie den Scope profile bei, damit Gruppen und Rollen zurückgegeben werden. Siehe OAuth2 Proxy mit Casdoor und den Nginx Community Edition Leitfaden.

Option 3: Das Casdoor nginx-Modul​

casdoor-nginx-module führt den Login innerhalb von nginx durch, ohne separaten Prozess. Browser ohne Sitzung gehen zur Casdoor-Login-Seite; das Modul tauscht den Code mit PKCE aus, verifiziert die Signatur des Access Tokens, exp, aud und Typ gegen das Casdoor-Zertifikat und speichert den Benutzer in einem signierten Cookie. API-Clients können Authorization: Bearer mit einem Casdoor Access Token senden, das lokal ohne Aufruf an Casdoor verifiziert wird.

Es benötigt nginx 1.22 oder neuer und OpenSSL 1.1.1 oder neuer. Sie können es als dynamisches Modul gegen das bereits ausgeführte nginx bauen:

./configure --with-compat --with-http_ssl_module --add-dynamic-module=/path/to/casdoor-nginx-module
make modules
cp objs/ngx_http_casdoor_module.so /etc/nginx/modules/
load_module modules/ngx_http_casdoor_module.so;

events {}

http {
server {
listen 443 ssl;
server_name app.example.com;
ssl_certificate /etc/nginx/app.crt;
ssl_certificate_key /etc/nginx/app.key;

casdoor_endpoint https://door.example.com;
casdoor_client_id <client-id>;
casdoor_client_secret <client-secret>;
casdoor_certificate /etc/nginx/casdoor.pem;
casdoor_redirect_uri https://app.example.com/casdoor/callback;
casdoor_token_location /_casdoor/token;

location = /_casdoor/token {
internal;
proxy_pass https://door.example.com/api/login/oauth/access_token;
proxy_ssl_server_name on;
}

location = /casdoor/callback {
casdoor_callback;
}

location / {
casdoor on;
proxy_set_header X-User $casdoor_user;
proxy_pass http://127.0.0.1:3000;
}
}
}

Ersetzen Sie die Platzhalter durch die Werte der Anwendung. Die Sitzung wird nicht erneut mit Casdoor überprüft, bis sie abläuft, daher wirkt sich das Deaktivieren eines Benutzers erst aus, wenn die Sitzung endet; casdoor_session_timeout verkürzt dieses Zeitfenster. Das Modul hat keine Rollen- oder Gruppenüberprüfungen. Bei NGINX Plus siehe stattdessen den NGINX Plus Leitfaden.

Option 4: Die App ist ein CAS-Client​

Wenn die App bereits CAS spricht, z. B. eine Java-App mit dem Apereo CAS Client, proxyt nginx nur und Casdoor ist der CAS-Server. Jede Casdoor-Anwendung hat CAS-Endpunkte unter /cas/<organization>/<application>: /login und /logout, /validate für CAS 1.0, /serviceValidate, /proxyValidate und /proxy für 2.0, /p3/serviceValidate und /p3/proxyValidate für 3.0 sowie /samlValidate für SAML 1.1 Validierung.

Die App sendet den Browser an /login?service=..., Casdoor leitet mit ticket=ST-... zurück, und die App validiert es:

curl "https://door.example.com/cas/my-org/my-app/p3/serviceValidate?ticket=ST-1234567890&service=https%3A%2F%2Fapp.example.com%2F"

Eine erfolgreiche Antwort ist ein cas:serviceResponse mit cas:user und Attributen wie E-Mail, Anzeigename und memberOf; fügen Sie format=json für JSON hinzu. Häufige Fehlerquellen:

  • Jede service URL muss in den Redirect URLs der Anwendung aufgeführt sein, und der service bei der Validierung muss exakt mit dem übereinstimmen, für den das Ticket ausgestellt wurde.
  • Tickets funktionieren einmal und laufen nach 5 Minuten ab.
  • Tickets werden im Speicher gehalten, daher muss die Validierung bei mehreren Casdoor-Replikas die Replika erreichen, die das Ticket ausgestellt hat (Sticky Sessions).
  • Hinter nginx geben Sie Host und X-Forwarded-Proto weiter, damit die App dieselbe service URL aufbaut, die der Browser gesehen hat.

Das Setup, einschließlich der Filter des Java-Clients für jede CAS-Version, finden Sie unter Einen CAS-Client verbinden.

Option 5: Lassen Sie Casdoor den Reverse Proxy übernehmen​

Wenn nichts anderes vor der App sitzt, kann Casdoor sie direkt bedienen: Sein Site-Proxy lauscht auf gatewayHttpPort und gatewayHttpsPort (standardmäßig 80 und 443), sobald eine Site existiert. Setzen Sie den Host der Site auf das Backend, wählen Sie ein Zertifikat, setzen Sie Casdoor app und leiten Sie DNS auf Casdoor. Login, Berechtigungen und Header verhalten sich wie in Option 1. Siehe Sites.

MFA hinzufügen​

MFA erfordert keine Änderung in nginx oder in der App. Casdoor fragt den zweiten Faktor auf seiner eigenen Login-Seite ab, bevor es einen OAuth-Autorisierungscode oder ein CAS Service Ticket ausstellt, daher erhält jede oben genannte Option dies. Benutzer können eine TOTP-App, SMS, E-Mail oder RADIUS verwenden, mit Wiederherstellungscodes, und Administratoren können MFA für eine Organisation mit MFA items erzwingen. Dies beantwortet auch "CAS 2FA": Mit Casdoor als CAS-Server ist der zweite Faktor Teil des CAS-Logins.

MFA wird beim Login erzwungen, nicht pro Anfrage: Eine Sitzung, die nginx oder ein Forward-Auth-Dienst bereits hält, bleibt gültig, bis sie abläuft, und die MFA remember time der Organisation erlaubt es Benutzern, den zweiten Faktor auf einem vertrauenswürdigen Gerät für eine Weile zu überspringen. Siehe den MFA Leitfaden und Was ist MFA.

Sobald Benutzer bei Casdoor angemeldet sind, erreichen sie andere Apps, die sie an Casdoor senden, ohne neue Passwortabfrage; mit Auto signin überspringt Casdoor auch die Kontoauswahl. Siehe Single Sign-On und Single Logout.

Welche Option wählen?​

  • Kein Login in der App und nginx bereits davor: Casdoors Forward Auth.
  • Ein Login über viele Subdomains oder Rollenprüfungen pro Standort: casdoor-forward-auth (oder OAuth2 Proxy, falls Sie diesen bereits betreiben).
  • Sie bauen nginx selbst und schützen APIs zusätzlich mit Bearer-Tokens: casdoor-nginx-module.
  • Die App unterstützt CAS: Casdoors CAS-Endpunkte, nginx als einfacher Proxy.
  • Noch kein Proxy vorhanden: Casdoors Site-Proxy.

Referenzen​