Saltar al contenido principal

Nginx CAS Authentication and SSO: Protecting Any App Behind Nginx with Casdoor

· 12 min de lectura
Yang Luo
Casdoor Maintainer

nginx de código abierto no tiene un módulo CAS, por lo que "nginx CAS authentication" en la práctica significa uno de dos tipos de configuración. O bien nginx pregunta a un servicio de autenticación sobre cada solicitud a través de su módulo auth_request, y Casdoor responde (directamente en /api/forward-auth, o mediante casdoor-forward-auth u OAuth2 Proxy), o la aplicación detrás de nginx es en sí misma un cliente CAS y se comunica con los endpoints del servidor CAS de Casdoor. Si puedes recompilar nginx, el módulo Casdoor nginx ejecuta el inicio de sesión dentro de nginx, y si prefieres no ejecutar nginx en absoluto, el proxy de sitio de Casdoor puede situarse delante de la aplicación. En todos los casos, la página de inicio de sesión es la de Casdoor, por lo que una sola sesión SSO, un conjunto de permisos y una política de MFA cubren todas las aplicaciones.

Las opciones de un vistazo​

OptionLogin logic runs inWhat nginx needsProtocol to CasdoorWho gets inPick it when
Casdoor forward authCasdoor, /api/forward-authauth_requestCookie de sesión de Casdoor en el dominio de la appPermisos de aplicación, comprobados al menos una vez por minutonginx ya está delante y no quieres servicios adicionales
casdoor-forward-authUn pequeño servicio Goauth_requestCódigo de autorización OIDCRoles o grupos de Casdoor, por ubicaciónUna cookie de sesión compartida por muchos subdominios
OAuth2 ProxyOAuth2 Proxyauth_requestOIDCallowed_groups, dominios de correoYa ejecutas OAuth2 Proxy
casdoor-nginx-modulenginx itselfA compiled moduleOIDC with PKCE, tokens verified locallyAny signed-in user of the appNo extra process, plus bearer tokens for APIs
CAS client in the appThe appNothing, it only proxiesCAS 1.0, 2.0, 3.0Whatever the app does with the attributesLa aplicación ya soporta CAS
Casdoor site proxyCasdoor on ports 80 and 443No nginxCasdoor sessionApplication permissionsNada más está delante de la aplicación

Las tres primeras opciones difieren solo en quién responde a la subpetición de nginx.

Por qué no existe un "módulo CAS para nginx"​

CAS es una conversación entre una aplicación y el servidor CAS: la aplicación envía el navegador al /login del servidor con una URL service, recibe un ticket de servicio en esa URL y valida el ticket con una llamada de servidor a servidor. Apache httpd tiene mod_auth_cas de Apereo para hacer esto en el servidor web, pero nginx no tiene ningún módulo CAS entre sus módulos oficiales. Para nginx, el bloque de construcción estándar es ngx_http_auth_request_module: antes de servir una solicitud, nginx envía una subpetición a una URL que tú eliges. Una respuesta 2xx permite pasar la solicitud, 401 o 403 la deniega con ese código, y cualquier otro código es un error.

Para el usuario, un inicio de sesión CAS y uno OIDC parecen iguales: una redirección a la página de inicio de sesión de Casdoor y vuelta. Así que para una aplicación sin soporte CAS, la respuesta práctica es OIDC en la capa de nginx. Información general sobre el protocolo: What is CAS.

El módulo auth_request no se compila por defecto: añade --with-http_auth_request_module al compilar, o comprueba nginx -V en un nginx empaquetado.

Opción 1: Forward auth propio de Casdoor​

Casdoor puede responder él mismo a la subpetición de nginx. Añades un Site en Casdoor cuyo Domain sea el dominio de la aplicación y cuyo Casdoor app sea la aplicación en la que inician sesión los usuarios, y añades https://app.example.com/caswaf-handler a los Redirect URLs de esa aplicación. El host y el puerto pueden permanecer vacíos, ya que el tráfico no pasa a través de Casdoor.

Dado que auth_request no puede seguir una redirección, Casdoor responde a una subpetición no autenticada con 401 y pone la URL de inicio de sesión en Location. nginx convierte eso en un 302:

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;
}
}

El backend recibe al usuario en X-Forwarded-User, X-Forwarded-Email y X-Forwarded-Groups. El acceso sigue un permission en la aplicación, comprobado de nuevo al menos una vez por minuto, por lo que un usuario deshabilitado pierde el acceso rápidamente. Las Public paths del sitio (webhooks, comprobaciones de estado) pasan sin necesidad de inicio de sesión.

Consulte Usar su propio proxy inverso para la referencia y Agregar inicio de sesión a una aplicación sin OIDC para una guía paso a paso con Grafana. La aplicación solo debe ser accesible a través de nginx, o cualquiera puede enviar X-Forwarded-User por sí mismo.

Opción 2: casdoor-forward-auth u OAuth2 Proxy​

Si prefiere no crear un sitio de Casdoor para cada aplicación, ejecute un pequeño servicio que realice el flujo OIDC contra Casdoor y responda a la sub-solicitud.

casdoor-forward-auth es el servicio independiente de Casdoor para esto (reemplazó a traefik-casdoor-auth). Mantiene al usuario en una cookie firmada sin estado en el servidor. Para nginx expone /verify, que responde con 200 y encabezados de identidad o 401, y nginx redirige a su /login ante un 401:

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;
}
}

Los parámetros de consulta roles y groups en la URL de verificación restringen cada aplicación a los titulares de un rol de Casdoor o miembros de un grupo; los usuarios conectados sin ellos reciben 403. Los roles y grupos se leen en el inicio de sesión y se mantienen durante la sesión, por lo que los cambios se aplican después de que el usuario vuelva a iniciar sesión. Establecer COOKIE_DOMAIN=example.com permite que un solo inicio de sesión cubra todos los subdominios. La guía de Traefik cubre el mismo servicio para Traefik.

OAuth2 Proxy funciona de la misma manera con provider = "oidc" y oidc_issuer_url configurado con la URL de su Casdoor. Su endpoint /oauth2/auth devuelve 202 o 401, los encabezados de usuario y correo electrónico necesitan --set-xauthrequest, y el manejo de encabezados reenviados en su ejemplo de nginx requiere --reverse-proxy. Dos configuraciones de Casdoor son importantes: use el formato de token JWT-Standard, o los usuarios con un correo electrónico no verificado serán rechazados, y mantenga el scope profile para que se devuelvan los grupos y roles. Consulte OAuth2 Proxy con Casdoor y la guía de la edición comunitaria de nginx.

Opción 3: el módulo de nginx de Casdoor​

casdoor-nginx-module realiza el inicio de sesión dentro de nginx, sin un proceso separado. Los navegadores sin sesión van a la página de inicio de sesión de Casdoor; el módulo intercambia el código con PKCE, verifica la firma del token de acceso, exp, aud y tipo contra el certificado de Casdoor, y mantiene al usuario en una cookie firmada. Los clientes API pueden enviar Authorization: Bearer con un token de acceso de Casdoor, verificado localmente sin llamar a Casdoor.

Requiere nginx 1.22 o superior y OpenSSL 1.1.1 o superior. Puede compilarlo como un módulo dinámico contra el nginx que ya ejecuta:

./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;
}
}
}

Reemplace los marcadores de posición con los valores de la aplicación. La sesión no se vuelve a verificar con Casdoor hasta que expire, por lo que deshabilitar a un usuario surte efecto cuando termina la sesión; casdoor_session_timeout acorta ese periodo. El módulo no tiene comprobaciones de roles o grupos. En NGINX Plus, consulte la guía de NGINX Plus en su lugar.

Opción 4: la aplicación es un cliente CAS​

Si la aplicación ya habla CAS, como una aplicación Java con el cliente Apereo CAS, nginx solo actúa como proxy y Casdoor es el servidor CAS. Cada aplicación de Casdoor tiene endpoints CAS bajo /cas/<organization>/<application>: /login y /logout, /validate para CAS 1.0, /serviceValidate, /proxyValidate y /proxy para 2.0, /p3/serviceValidate y /p3/proxyValidate para 3.0, y /samlValidate para validación SAML 1.1.

La aplicación envía el navegador a /login?service=..., Casdoor redirige de vuelta con ticket=ST-..., y la aplicación lo valida:

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

Una respuesta exitosa es un cas:serviceResponse con cas:user y atributos como correo electrónico, nombre para mostrar y memberOf; agregue format=json para JSON. Cosas que suelen confundir:

  • Cada URL service debe estar listada en los Redirect URLs de la aplicación, y el service en la validación debe coincidir exactamente con aquel para el que se emitió el ticket.
  • Los tickets funcionan una sola vez y caducan después de 5 minutos.
  • Los tickets se guardan en memoria, por lo que con varias réplicas de Casdoor, la validación debe llegar a la réplica que emitió el ticket (sesiones adherentes).
  • Detrás de nginx, pase Host y X-Forwarded-Proto para que la aplicación construya la misma URL service que vio el navegador.

La configuración, incluidos los filtros del cliente Java para cada versión de CAS, está en Conectar un cliente CAS.

Opción 5: dejar que Casdoor sea el proxy inverso​

Cuando nada más está delante de la aplicación, Casdoor puede servirla directamente: su proxy de sitio escucha en gatewayHttpPort y gatewayHttpsPort (80 y 443 por defecto) una vez que existe un sitio. Configure el Host del sitio con el backend, elija un certificado, establezca Casdoor app, y apunte el DNS a Casdoor. El inicio de sesión, los permisos y los encabezados se comportan como en la opción 1. Consulte Sitios.

Agregar MFA​

MFA no necesita ningún cambio en nginx ni en la aplicación. Casdoor solicita el segundo factor en su propia página de inicio de sesión antes de emitir un código de autorización OAuth o un ticket de servicio CAS, por lo que todas las opciones anteriores lo obtienen. Los usuarios pueden usar una aplicación TOTP, SMS, correo electrónico o RADIUS, con códigos de recuperación, y los administradores pueden requerir MFA para una organización con Elementos de MFA. Esto también responde a "CAS 2FA": con Casdoor como servidor CAS, el segundo factor es parte del inicio de sesión CAS.

MFA se aplica en el inicio de sesión, no por solicitud: una sesión que nginx o un servicio forward-auth ya mantiene dura hasta que expira, y el Tiempo de recordatorio de MFA de la organización permite a los usuarios omitir el segundo factor en un dispositivo confiable durante un tiempo. Consulte la guía de MFA y Qué es MFA.

Una vez conectado a Casdoor, los usuarios acceden a otras aplicaciones que los envían a Casdoor sin una nueva solicitud de contraseña; con Auto signin, Casdoor también omite el selector de cuenta. Consulte inicio de sesión único y Cierre de sesión único.

Cuál elegir​

  • Sin inicio de sesión en la aplicación y nginx ya delante: autenticación hacia adelante de Casdoor.
  • Un inicio de sesión en varios subdominios, o comprobaciones de roles por ubicación: casdoor-forward-auth (o OAuth2 Proxy si ya lo ejecuta).
  • Usted compila nginx usted mismo y también protege las API con tokens bearer: casdoor-nginx-module.
  • La aplicación admite CAS: endpoints CAS de Casdoor, nginx como proxy simple.
  • Aún no hay proxy: proxy de sitio de Casdoor.

Referencias​