NPE in ApiServlet.skip2FAcheckForUser on SAML login when 2FA is disabled (4.22.0.0)

Abierto Apto para principiantes
#13,172 4 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
78/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
java

Línea de trabajo

Comienza en ApiServlet.java, en la línea 512, e inspecciona cómo skip2FAcheckForUser lee el atributo de sesión 2FAuthenticated. Luego sigue SAML2LoginAPIAuthenticatorCmd para comparar la configuración de la sesión con el flujo de inicio de sesión local. Reproduce el problema con SAML2 habilitado y ambas configuraciones de 2FA deshabilitadas; se considera terminado cuando la solicitud API posterior se realiza correctamente sin la NullPointerException y el usuario llega al panel.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

component:saml type:bug
problem
COMPONENT NAME

API, SAML

SUMMARY

Every API request issued after a successful samlSso callback throws a NullPointerException in ApiServlet.skip2FAcheckForUser, because session.getAttribute("2FAuthenticated") returns null and is unboxed directly to boolean. The SAML login flow does not set this session attribute, and the 2FA-disabled global settings are not consulted before the unboxing.

Local username/password login is unaffected — only the SAML path triggers the NPE.

STEPS TO REPRODUCE
  1. Enable SAML2 plugin and configure an IdP (Keycloak in our case).
  2. Ensure enable.user.2fa=false and mandate.user.2fa=false.
  3. Authorize a CloudStack user for SAML via authorizeSamlSso.
  4. Click "Login with SSO" → authenticate at IdP → redirected back to /client/api?command=samlSso.
  5. Browser immediately fires follow-up API call (e.g. listIdps, login, etc.).
EXPECTED RESULTS

The follow-up API request completes; user lands on the dashboard. A null value for the 2FAuthenticated session attribute should be treated as "2FA not required / not completed" rather than dereferenced as a boolean.

ACTUAL RESULTS

Use cannot login via SAML:

2026-05-17 10:22:39,650 ERROR [c.c.a.ApiServlet] (qtp1047478056-364:[ctx-50e47dca]) (logid:59e6408b) unknown exception writing api response java.lang.NullPointerException: Cannot invoke "java.lang.Boolean.booleanValue()" because the return value of "javax.servlet.http.HttpSession.getAttribute(String)" is null
        at com.cloud.api.ApiServlet.skip2FAcheckForUser(ApiServlet.java:512)
        at com.cloud.api.ApiServlet.processRequestInContext(ApiServlet.java:361)
        at com.cloud.api.ApiServlet$1.run(ApiServlet.java:193)
        at org.apache.cloudstack.managed.context.impl.DefaultManagedContext$1.call(DefaultManagedContext.java:56)
        at org.apache.cloudstack.managed.context.impl.DefaultManagedContext.callWithContext(DefaultManagedContext.java:103)
        at org.apache.cloudstack.managed.context.impl.DefaultManagedContext.runWithContext(DefaultManagedContext.java:53)
        at com.cloud.api.ApiServlet.processRequest(ApiServlet.java:190)
        at com.cloud.api.ApiServlet.doPost(ApiServlet.java:149)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:665)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)
        ... (Jetty frames truncated)

Client receives the auth failure / error response, lands back on the login screen.

This is my first ticket here, so be gentle please!

versions

4.22.0 on Debian 13.4 via shapeblue

i cloudstack-common 4.22.0.0-shapeblue0 all A common package which contains files which are shared by several CloudStack packages
ii cloudstack-management 4.22.0.0-shapeblue0 all CloudStack server library
ii cloudstack-usage 4.22.0.0-shapeblue0 all CloudStack usage monitor

And just auto installed java 21 (I know the docs says 17, but I haven't been able to downgrade).

ii default-jdk-headless 2:1.21-76 amd64 Standard Java or Java compatible Development Kit (headless)
ii openjdk-21-jdk-headless:amd64 21.0.11+10-1deb13u2 amd64 OpenJDK Development Kit (JDK) (headless)
ii openjdk-21-jre-headless:amd64 21.0.11+10-1
deb13u2 amd64 OpenJDK Java runtime, using Hotspot JIT (headless)

CONFIGURATION
  • SAML2 plugin enabled (saml2.enabled=true)
  • IdP: Keycloak 26.x, realm lluw, SAML client with dedicated uid mapper (User Property: email)
  • 2FA disabled globally: enable.user.2fa=false, mandate.user.2fa=false
  • Single management server, MySQL backend
The steps to reproduce the bug
  1. Enable SAML2 plugin and configure an IdP (Keycloak in our case).
  2. Ensure enable.user.2fa=false and mandate.user.2fa=false.
  3. Authorize a CloudStack user for SAML via authorizeSamlSso.
  4. Click "Login with SSO" → authenticate at IdP → redirected back to /client/api?command=samlSso.

5 browser response:

<loginresponse>
<errorcode>531</errorcode>
<errortext>
Your authenticated user is not authorized for SAML Single Sign-On, please contact your administrator
</errortext>
</loginresponse>
LOG response
2026-05-17 10:22:39,650 ERROR [c.c.a.ApiServlet] (qtp1047478056-364:[ctx-50e47dca]) (logid:59e6408b) unknown exception writing api response java.lang.NullPointerException: Cannot invoke "java.lang.Boolean.booleanValue()" because the return value of "javax.servlet.http.HttpSession.getAttribute(String)" is null
        at com.cloud.api.ApiServlet.skip2FAcheckForUser(ApiServlet.java:512)
        at com.cloud.api.ApiServlet.processRequestInContext(ApiServlet.java:361)
        at com.cloud.api.ApiServlet$1.run(ApiServlet.java:193)
        at org.apache.cloudstack.managed.context.impl.DefaultManagedContext$1.call(DefaultManagedContext.java:56)
        at org.apache.cloudstack.managed.context.impl.DefaultManagedContext.callWithContext(DefaultManagedContext.java:103)
        at org.apache.cloudstack.managed.context.impl.DefaultManagedContext.runWithContext(DefaultManagedContext.java:53)
        at com.cloud.api.ApiServlet.processRequest(ApiServlet.java:190)
        at com.cloud.api.ApiServlet.doPost(ApiServlet.java:149)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:665)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)
        ... (Jetty frames truncated)
What to do about it?
Expected result

The follow-up API request completes; user lands on the dashboard. A null value for the 2FAuthenticated session attribute should be treated as "2FA not required / not completed" rather than dereferenced as a boolean.

  • ApiServlet.java:512 reads the 2FAuthenticated attribute and unboxes without a null check.
  • The SAML auth command (SAML2LoginAPIAuthenticatorCmd) creates the session but does not set 2FAuthenticated.
  • Suggested fix: replace direct unboxing with Boolean.TRUE.equals(session.getAttribute("2FAuthenticated")), or short-circuit when both enable.user.2fa and mandate.user.2fa are false.
Lenguaje dominante
Java
Estrellas
3.1k
Forks
1.4k
Merge medio
7 d 5 h
PR fusionados (30 d)
28

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de apache/cloudstack

Todos los issues de apache/cloudstack

Issues similares

Más issues de Java

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.