From 9220ffc36873da6369b77dc55b1b27b192425de0 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Mon, 23 Feb 2026 18:35:47 +0530 Subject: [PATCH 1/2] test_accounts.py failure fix - fallback using the camelCase parameter name "domainId" (as earlier) --- .../oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java | 4 ++++ .../com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java index 88e678bcc267..090586cdd332 100644 --- a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java +++ b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java @@ -177,6 +177,10 @@ private String doOauthAuthentication(HttpSession session, Long domainId, String protected Long getDomainIdFromParams(Map params, StringBuilder auditTrailSb, String responseType) { String[] domainIdArr = (String[])params.get(ApiConstants.DOMAIN_ID); + if (domainIdArr == null) { + // Fallback to support clients using the camelCase parameter name "domainId" + domainIdArr = (String[])params.get(ApiConstants.DOMAIN__ID); + } Long domainId = null; if (domainIdArr != null && domainIdArr.length > 0) { try { diff --git a/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java b/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java index 86f2a63a6a58..c5fd0e52997f 100644 --- a/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java +++ b/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java @@ -110,7 +110,11 @@ public String authenticate(String command, Map params, HttpSes // FIXME: ported from ApiServlet, refactor and cleanup final String[] username = (String[])params.get(ApiConstants.USERNAME); final String[] password = (String[])params.get(ApiConstants.PASSWORD); - final String[] domainIdArr = (String[])params.get(ApiConstants.DOMAIN_ID); + String[] domainIdArr = (String[])params.get(ApiConstants.DOMAIN_ID); + if (domainIdArr == null) { + // Fallback to support clients using the camelCase parameter name "domainId" + domainIdArr = (String[])params.get(ApiConstants.DOMAIN__ID); + } Long domainId = null; if (domainIdArr != null && domainIdArr.length > 0) { try { From de60cd142aa6ac0eebff156ba488260397dfd167 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Mon, 23 Feb 2026 19:20:06 +0530 Subject: [PATCH 2/2] refactor and unit test --- .../cloudstack/api/ApiServerService.java | 2 ++ .../OauthLoginAPIAuthenticatorCmd.java | 12 ++++------- .../OauthLoginAPIAuthenticatorCmdTest.java | 19 ++++++++++++++++++ .../main/java/com/cloud/api/ApiServer.java | 20 +++++++++++++++++++ .../auth/DefaultLoginAPIAuthenticatorCmd.java | 13 +++++------- 5 files changed, 50 insertions(+), 16 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiServerService.java b/api/src/main/java/org/apache/cloudstack/api/ApiServerService.java index cbbcdc3bda42..a422129ad213 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiServerService.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiServerService.java @@ -48,4 +48,6 @@ public ResponseObject loginUser(HttpSession session, String username, String pas boolean forgotPassword(UserAccount userAccount, Domain domain); boolean resetPassword(UserAccount userAccount, String token, String password); + + String getDomainId(Map params); } diff --git a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java index 090586cdd332..e273358e83ef 100644 --- a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java +++ b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java @@ -176,18 +176,14 @@ private String doOauthAuthentication(HttpSession session, Long domainId, String } protected Long getDomainIdFromParams(Map params, StringBuilder auditTrailSb, String responseType) { - String[] domainIdArr = (String[])params.get(ApiConstants.DOMAIN_ID); - if (domainIdArr == null) { - // Fallback to support clients using the camelCase parameter name "domainId" - domainIdArr = (String[])params.get(ApiConstants.DOMAIN__ID); - } + String domainIdStr = _apiServer.getDomainId(params); Long domainId = null; - if (domainIdArr != null && domainIdArr.length > 0) { + if (StringUtils.isNotEmpty(domainIdStr)) { try { //check if UUID is passed in for domain - domainId = _apiServer.fetchDomainId(domainIdArr[0]); + domainId = _apiServer.fetchDomainId(domainIdStr); if (domainId == null) { - domainId = Long.parseLong(domainIdArr[0]); + domainId = Long.parseLong(domainIdStr); } auditTrailSb.append(" domainid=" + domainId);// building the params for POST call } catch (final NumberFormatException e) { diff --git a/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmdTest.java b/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmdTest.java index ccbb53cfc80d..962ffefd5ce3 100644 --- a/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmdTest.java +++ b/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmdTest.java @@ -85,10 +85,29 @@ public void testGetDomainIdFromParams() { ApiServer apiServer = mock(ApiServer.class); cmd._apiServer = apiServer; when(apiServer.fetchDomainId("1234")).thenReturn(5678L); + when(apiServer.getDomainId(params)).thenCallRealMethod(); Long domainId = cmd.getDomainIdFromParams(params, auditTrailSb, responseType); assertEquals(Long.valueOf(5678), domainId); assertEquals(" domainid=5678", auditTrailSb.toString()); } + + @Test + public void testGetDomainIdFromCamelCaseParam() { + StringBuilder auditTrailSb = new StringBuilder(); + String responseType = "json"; + Map params = new HashMap<>(); + params.put(ApiConstants.DOMAIN_ID, null); + params.put(ApiConstants.DOMAIN__ID, new String[]{"5678"}); + ApiServer apiServer = mock(ApiServer.class); + cmd._apiServer = apiServer; + when(apiServer.fetchDomainId("5678")).thenReturn(1234L); + when(apiServer.getDomainId(params)).thenCallRealMethod(); + + Long domainId = cmd.getDomainIdFromParams(params, auditTrailSb, responseType); + + assertEquals(Long.valueOf(1234), domainId); + assertEquals(" domainid=1234", auditTrailSb.toString()); + } } diff --git a/server/src/main/java/com/cloud/api/ApiServer.java b/server/src/main/java/com/cloud/api/ApiServer.java index 85d58ec0d53d..3a89c7bde230 100644 --- a/server/src/main/java/com/cloud/api/ApiServer.java +++ b/server/src/main/java/com/cloud/api/ApiServer.java @@ -115,6 +115,7 @@ import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.user.UserPasswordResetManager; import org.apache.commons.codec.binary.Base64; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.EnumUtils; import org.apache.http.ConnectionClosedException; import org.apache.http.HttpException; @@ -1354,6 +1355,25 @@ public boolean resetPassword(UserAccount userAccount, String token, String passw return userPasswordResetManager.validateAndResetPassword(userAccount, token, password); } + @Override + public String getDomainId(Map params) { + if (MapUtils.isEmpty(params)) { + return null; + } + + String[] domainIdArr = (String[])params.get(ApiConstants.DOMAIN_ID); + if (domainIdArr == null) { + // Fallback to support clients using the camelCase parameter name "domainId" + domainIdArr = (String[])params.get(ApiConstants.DOMAIN__ID); + } + + if (domainIdArr == null || domainIdArr.length == 0) { + return null; + } + + return domainIdArr[0]; + } + private void checkCommandAvailable(final User user, final String commandName, final InetAddress remoteAddress) throws PermissionDeniedException { if (user == null) { throw new PermissionDeniedException("User is null for role based API access check for command" + commandName); diff --git a/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java b/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java index c5fd0e52997f..41174c37be2e 100644 --- a/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java +++ b/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java @@ -20,6 +20,7 @@ import com.cloud.domain.Domain; import com.cloud.user.User; import com.cloud.user.UserAccount; +import com.cloud.utils.StringUtils; import org.apache.cloudstack.api.ApiServerService; import com.cloud.api.response.ApiResponseSerializer; import com.cloud.exception.CloudAuthenticationException; @@ -110,18 +111,14 @@ public String authenticate(String command, Map params, HttpSes // FIXME: ported from ApiServlet, refactor and cleanup final String[] username = (String[])params.get(ApiConstants.USERNAME); final String[] password = (String[])params.get(ApiConstants.PASSWORD); - String[] domainIdArr = (String[])params.get(ApiConstants.DOMAIN_ID); - if (domainIdArr == null) { - // Fallback to support clients using the camelCase parameter name "domainId" - domainIdArr = (String[])params.get(ApiConstants.DOMAIN__ID); - } + String domainIdStr = _apiServer.getDomainId(params); Long domainId = null; - if (domainIdArr != null && domainIdArr.length > 0) { + if (StringUtils.isNotEmpty(domainIdStr)) { try { //check if UUID is passed in for domain - domainId = _apiServer.fetchDomainId(domainIdArr[0]); + domainId = _apiServer.fetchDomainId(domainIdStr); if (domainId == null) { - domainId = Long.parseLong(domainIdArr[0]); + domainId = Long.parseLong(domainIdStr); } auditTrailSb.append(" domainid=" + domainId);// building the params for POST call } catch (final NumberFormatException e) {