Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

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

未关闭 适合新手
#13,172 4 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
78/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
java

调研方向

从 ApiServlet.java 第 512 行开始,检查 skip2FAcheckForUser 如何读取 2FAuthenticated 会话属性。然后跟踪 SAML2LoginAPIAuthenticatorCmd,将会话设置与本地登录流程进行比较。在启用 SAML2 且禁用两个 2FA 设置的情况下复现;当后续 API 请求在没有 NullPointerException 的情况下成功,并且用户进入控制面板时,即表示完成。

由索引模型根据 Issue 内容生成。

描述

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.
主要语言
Java
星标
3.1k
派生
1.4k
平均合并
6 天 20 小时
30 天内合并 PR
27

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

apache/cloudstack 的其他 Issue

查看 apache/cloudstack 的全部 Issue

相似的 Issue

更多 Java Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。