joltcan opened a new issue, #13172:
URL: https://github.com/apache/cloudstack/issues/13172

   ### 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:
   
   ```java
   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
   
   
   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-1~deb13u2                 
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:
   ```xml
   <loginresponse>
   <errorcode>531</errorcode>
   <errortext>
   Your authenticated user is not authorized for SAML Single Sign-On, please 
contact your administrator
   </errortext>
   </loginresponse>
   ```
   
   ##### LOG response
   
   ```java
   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.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to