From 334dc485f9776ccaf9b50b8ded6a4d386ed4288b Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Thu, 6 Aug 2026 13:40:06 +0200 Subject: [PATCH 01/13] CertService: Fix account requirement by using caller account fallback --- .../network/ssl/CertServiceImpl.java | 19 ++++++------- .../network/ssl/CertServiceTest.java | 27 +++++++++++++++++++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index d101ab989caa..90f2b994a30f 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -199,16 +199,12 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) final Account caller = ctx.getCallingAccount(); final Long certId = listSslCertCmd.getCertId(); - final Long accountId = listSslCertCmd.getAccountId(); + final Long accountId = listSslCertCmd.getAccountId() != null ? listSslCertCmd.getAccountId() : caller.getAccountId(); final Long lbRuleId = listSslCertCmd.getLbId(); final Long projectId = listSslCertCmd.getProjectId(); final List certResponseList = new ArrayList(); - if (certId == null && accountId == null && lbRuleId == null && projectId == null) { - throw new InvalidParameterValueException("Invalid parameters either certificate ID or Account ID or Loadbalancer ID or Project ID required"); - } - List certLbMap = null; SslCertVO certVO = null; @@ -241,7 +237,7 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) lbCertMapRule = _lbCertDao.findByLbRuleId(lbRuleId); if (lbCertMapRule == null) { - logger.debug("No certificate bound to loadbalancer id: " + lbRuleId); + logger.debug("No certificate bound to loadbalancer id: {}", lbRuleId); return certResponseList; } @@ -273,7 +269,7 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) return certResponseList; } - //reached here look by accountId + // Reached here: list by explicit accountId or the caller account if accountId was not provided. final List certVOList = _sslCertDao.listByAccountId(accountId); if (certVOList == null || certVOList.isEmpty()) { return certResponseList; @@ -374,7 +370,7 @@ private void validateKeys(final PublicKey pubKey, final PrivateKey privKey) { } // No encryption for DSA - if (pubKey.getAlgorithm() != "RSA") { + if (!pubKey.getAlgorithm().equals("RSA")) { return; } @@ -492,7 +488,12 @@ public Certificate parseCertificate(final String cert) { } catch (final CertificateException | IOException e) { throw new InvalidParameterValueException("Invalid Certificate format. Expected X509 certificate. Failed due to " + e.getMessage()); } finally { - IOUtils.closeQuietly(certPem); + // Try to close quietly + try { + IOUtils.close(certPem); + } catch (IOException e) { + logger.debug("Failed to close pem reader", e); + } } } diff --git a/server/src/test/java/org/apache/cloudstack/network/ssl/CertServiceTest.java b/server/src/test/java/org/apache/cloudstack/network/ssl/CertServiceTest.java index 0685167c2a42..759383136792 100644 --- a/server/src/test/java/org/apache/cloudstack/network/ssl/CertServiceTest.java +++ b/server/src/test/java/org/apache/cloudstack/network/ssl/CertServiceTest.java @@ -32,6 +32,7 @@ import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.TransactionLegacy; import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListSslCertsCmd; import org.apache.cloudstack.api.command.user.loadbalancer.UploadSslCertCmd; import org.apache.cloudstack.context.CallContext; import org.bouncycastle.openssl.PKCS8Generator; @@ -819,6 +820,25 @@ public void runDeleteSslCertInvalidId() throws NoSuchFieldException, IllegalAcce } + @Test + public void runListSslCertsUsesCallerAccountWhenNoFilters() { + final long callerAccountId = 42L; + final CertServiceImpl certService = new CertServiceImpl(); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.listByAccountId(anyLong())).thenReturn(new ArrayList<>()); + + final AccountVO callerAccount = new AccountVO("testaccount", 1, "networkdomain", Account.Type.NORMAL, UUID.randomUUID().toString()); + callerAccount.setId(callerAccountId); + final UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN); + CallContext.unregister(); + CallContext.register(user, callerAccount); + + certService.listSslCerts(new ListSslCertsCmdExtn()); + + Mockito.verify(certService._sslCertDao).listByAccountId(callerAccountId); + } + public class UploadSslCertCmdExtn extends UploadSslCertCmd { @Override public long getEntityOwnerId() { @@ -833,6 +853,13 @@ public long getEntityOwnerId() { } } + public class ListSslCertsCmdExtn extends ListSslCertsCmd { + @Override + public long getEntityOwnerId() { + return 1; + } + } + private String generateEncryptedPrivateKey(String password) throws NoSuchAlgorithmException, OperatorCreationException, IOException { // Generate RSA key pair KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); From a9dc8bfe297e14e4f30d40f9cf4c9e7f04b18393 Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Thu, 6 Aug 2026 14:36:50 +0200 Subject: [PATCH 02/13] revert to deprecated closeQuietly --- .../org/apache/cloudstack/network/ssl/CertServiceImpl.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index 90f2b994a30f..7036e4a386d3 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -488,12 +488,7 @@ public Certificate parseCertificate(final String cert) { } catch (final CertificateException | IOException e) { throw new InvalidParameterValueException("Invalid Certificate format. Expected X509 certificate. Failed due to " + e.getMessage()); } finally { - // Try to close quietly - try { - IOUtils.close(certPem); - } catch (IOException e) { - logger.debug("Failed to close pem reader", e); - } + IOUtils.closeQuietly(certPem); } } From 8a3871f3b608650b6d91b13bfe8fa7cd1428c59c Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Fri, 7 Aug 2026 09:07:47 +0200 Subject: [PATCH 03/13] sslcert: add account and domainid to api streamline ssl cert list api, deprecate accountid --- .../user/loadbalancer/ListSslCertsCmd.java | 18 +++++++++++++++++- .../network/ssl/CertServiceImpl.java | 9 ++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java index 1bc300fdc69f..b23c702522ad 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.response.AccountResponse; +import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.FirewallRuleResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ProjectResponse; @@ -50,9 +51,15 @@ public class ListSslCertsCmd extends BaseCmd { @Parameter(name = ApiConstants.CERTIFICATE_ID, type = CommandType.UUID, entityType = SslCertResponse.class, required = false, description = "ID of SSL certificate") private Long certId; - @Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, required = false, description = "Account ID") + @Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, required = false, description = "Account ID, deprecated: use " + ApiConstants.ACCOUNT + " and " + ApiConstants.DOMAIN_ID + " instead") private Long accountId; + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, since = "4.24", description = "Account owning the SSL certificate") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, since = "4.24", entityType = DomainResponse.class, description = "Domain ID of the account owning the SSL certificate") + private Long domainId; + @Parameter(name = ApiConstants.LBID, type = CommandType.UUID, entityType = FirewallRuleResponse.class, required = false, description = "Load balancer rule ID") private Long lbId; @@ -67,6 +74,7 @@ public Long getCertId() { return certId; } + @Deprecated public Long getAccountId() { return accountId; } @@ -79,6 +87,14 @@ public Long getProjectId() { return projectId; } + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index 7036e4a386d3..2f698591ee72 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -198,8 +198,15 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) final CallContext ctx = CallContext.current(); final Account caller = ctx.getCallingAccount(); + Account owner = null; + if (StringUtils.isNotEmpty(listSslCertCmd.getAccountName()) && listSslCertCmd.getDomainId() != null || listSslCertCmd.getProjectId() != null) { + owner = _accountMgr.finalizeOwner(caller, listSslCertCmd.getAccountName(), listSslCertCmd.getDomainId(), listSslCertCmd.getProjectId()); + } else { + owner = caller; + } + final Long certId = listSslCertCmd.getCertId(); - final Long accountId = listSslCertCmd.getAccountId() != null ? listSslCertCmd.getAccountId() : caller.getAccountId(); + final Long accountId = listSslCertCmd.getAccountId() != null ? listSslCertCmd.getAccountId() : owner.getId(); final Long lbRuleId = listSslCertCmd.getLbId(); final Long projectId = listSslCertCmd.getProjectId(); From bddcf1e2f9e6180d638e20aa7fe1e4b7f08684bf Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Mon, 10 Aug 2026 15:20:29 +0200 Subject: [PATCH 04/13] undeprecate account id add a note about mutually exclusive with account --- .../api/command/user/loadbalancer/ListSslCertsCmd.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java index b23c702522ad..d9af78314129 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java @@ -51,7 +51,7 @@ public class ListSslCertsCmd extends BaseCmd { @Parameter(name = ApiConstants.CERTIFICATE_ID, type = CommandType.UUID, entityType = SslCertResponse.class, required = false, description = "ID of SSL certificate") private Long certId; - @Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, required = false, description = "Account ID, deprecated: use " + ApiConstants.ACCOUNT + " and " + ApiConstants.DOMAIN_ID + " instead") + @Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, required = false, description = "Account ID and " + ApiConstants.ACCOUNT + " are mutually exclusive.") private Long accountId; @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, since = "4.24", description = "Account owning the SSL certificate") @@ -74,7 +74,6 @@ public Long getCertId() { return certId; } - @Deprecated public Long getAccountId() { return accountId; } From 57636129717817d54aa371229e6ce507141ad27f Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Mon, 10 Aug 2026 15:25:56 +0200 Subject: [PATCH 05/13] verify accountid / account are mutually exclusive --- .../network/ssl/CertServiceImpl.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index 2f698591ee72..7ed8c008d2b7 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -198,18 +198,26 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) final CallContext ctx = CallContext.current(); final Account caller = ctx.getCallingAccount(); + final Long certId = listSslCertCmd.getCertId(); + final Long lbRuleId = listSslCertCmd.getLbId(); + final Long projectId = listSslCertCmd.getProjectId(); + final Long accountId = listSslCertCmd.getAccountId(); + final String accountName = listSslCertCmd.getAccountName(); + final Long domainId = listSslCertCmd.getDomainId(); + + if (accountId != null && (accountName != null || domainId != null)) { + throw new InvalidParameterValueException("The accountid and account/domainid are mutually exclusive"); + } + Account owner = null; if (StringUtils.isNotEmpty(listSslCertCmd.getAccountName()) && listSslCertCmd.getDomainId() != null || listSslCertCmd.getProjectId() != null) { owner = _accountMgr.finalizeOwner(caller, listSslCertCmd.getAccountName(), listSslCertCmd.getDomainId(), listSslCertCmd.getProjectId()); + } else if (accountId != null) { + owner = _accountMgr.getAccount(accountId); } else { owner = caller; } - final Long certId = listSslCertCmd.getCertId(); - final Long accountId = listSslCertCmd.getAccountId() != null ? listSslCertCmd.getAccountId() : owner.getId(); - final Long lbRuleId = listSslCertCmd.getLbId(); - final Long projectId = listSslCertCmd.getProjectId(); - final List certResponseList = new ArrayList(); List certLbMap = null; @@ -276,8 +284,7 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) return certResponseList; } - // Reached here: list by explicit accountId or the caller account if accountId was not provided. - final List certVOList = _sslCertDao.listByAccountId(accountId); + final List certVOList = _sslCertDao.listByAccountId(owner.getId()); if (certVOList == null || certVOList.isEmpty()) { return certResponseList; } From c23976d210fcfce6c3510b78b2a263513cde9bb0 Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Mon, 10 Aug 2026 15:26:50 +0200 Subject: [PATCH 06/13] finalizeOwner add additional common checks e.g. domainId with account --- .../org/apache/cloudstack/network/ssl/CertServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index 7ed8c008d2b7..08f6640ad089 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -210,8 +210,8 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) } Account owner = null; - if (StringUtils.isNotEmpty(listSslCertCmd.getAccountName()) && listSslCertCmd.getDomainId() != null || listSslCertCmd.getProjectId() != null) { - owner = _accountMgr.finalizeOwner(caller, listSslCertCmd.getAccountName(), listSslCertCmd.getDomainId(), listSslCertCmd.getProjectId()); + if (StringUtils.isNotEmpty(accountName)) { + owner = _accountMgr.finalizeOwner(caller, accountName, domainId, projectId); } else if (accountId != null) { owner = _accountMgr.getAccount(accountId); } else { From 0aed4d035b8b49ec368d79903f5407f9b7502de8 Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Mon, 10 Aug 2026 15:28:59 +0200 Subject: [PATCH 07/13] verify only one or zero of the params are given not a common verify in cloudstack but in terms of unexpected results, it should be verified. --- .../cloudstack/network/ssl/CertServiceImpl.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index 08f6640ad089..177506dcfb18 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -209,6 +209,23 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) throw new InvalidParameterValueException("The accountid and account/domainid are mutually exclusive"); } + // Validate that only one of certid, lbid, projectid, or accountid/account can be specified + ArrayList params = new ArrayList<>(); + params.add(certId); + params.add(accountId != null ? accountId : accountName); + params.add(lbRuleId); + params.add(projectId); + + int nonNullIds = 0; + for (Object param : params) { + if (param != null) { + nonNullIds++; + } + } + if (nonNullIds > 1) { + throw new InvalidParameterValueException("Only one of certid, lbid, projectid, or accountid/account can be specified"); + } + Account owner = null; if (StringUtils.isNotEmpty(accountName)) { owner = _accountMgr.finalizeOwner(caller, accountName, domainId, projectId); From db72cc6e2ab0eb5de5213a4088189baa6def265d Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Mon, 10 Aug 2026 15:56:48 +0200 Subject: [PATCH 08/13] address copilot review concerns --- .../api/command/user/loadbalancer/ListSslCertsCmd.java | 2 +- .../org/apache/cloudstack/network/ssl/CertServiceImpl.java | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java index d9af78314129..123339702750 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java @@ -86,7 +86,7 @@ public Long getProjectId() { return projectId; } - public String getAccountName() { + public String getAccountName() { return accountName; } diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index 177506dcfb18..79e6b7b43687 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -205,7 +205,7 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) final String accountName = listSslCertCmd.getAccountName(); final Long domainId = listSslCertCmd.getDomainId(); - if (accountId != null && (accountName != null || domainId != null)) { + if (accountId != null && (StringUtils.isNotBlank(accountName) || domainId != null)) { throw new InvalidParameterValueException("The accountid and account/domainid are mutually exclusive"); } @@ -229,8 +229,6 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) Account owner = null; if (StringUtils.isNotEmpty(accountName)) { owner = _accountMgr.finalizeOwner(caller, accountName, domainId, projectId); - } else if (accountId != null) { - owner = _accountMgr.getAccount(accountId); } else { owner = caller; } @@ -301,7 +299,7 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) return certResponseList; } - final List certVOList = _sslCertDao.listByAccountId(owner.getId()); + final List certVOList = _sslCertDao.listByAccountId(accountId != null ? accountId : owner.getId()); if (certVOList == null || certVOList.isEmpty()) { return certResponseList; } From 574b250f6ac2fe540484e76b06077f4278fe139d Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Mon, 10 Aug 2026 16:28:10 +0200 Subject: [PATCH 09/13] upload cert: ensure checks in finalizeOwner are executed Unlike in `listSslCerts`, where we have to make a distinction because of the additional `accountId`, we use `finalizeOwner` early on so that the checks it contains are called. `caller` is returned as a last resort by `finalzieOwner`. --- .../cloudstack/network/ssl/CertServiceImpl.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index 79e6b7b43687..b57497ddc3ae 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -128,6 +128,9 @@ public CertServiceImpl() { public SslCertResponse uploadSslCert(final UploadSslCertCmd certCmd) { Preconditions.checkNotNull(certCmd); + final Account caller = CallContext.current().getCallingAccount(); + final Account owner = _accountMgr.finalizeOwner(caller, certCmd.getAccountName(), certCmd.getDomainId(), certCmd.getProjectId()); + final String cert = certCmd.getCert(); final String key = certCmd.getKey(); final String password = certCmd.getPassword(); @@ -138,17 +141,6 @@ public SslCertResponse uploadSslCert(final UploadSslCertCmd certCmd) { logger.debug("Certificate Validation succeeded"); final String fingerPrint = CertificateHelper.generateFingerPrint(parseCertificate(cert)); - - final CallContext ctx = CallContext.current(); - final Account caller = ctx.getCallingAccount(); - - Account owner = null; - if (StringUtils.isNotEmpty(certCmd.getAccountName()) && certCmd.getDomainId() != null || certCmd.getProjectId() != null) { - owner = _accountMgr.finalizeOwner(caller, certCmd.getAccountName(), certCmd.getDomainId(), certCmd.getProjectId()); - } else { - owner = caller; - } - final Long accountId = owner.getId(); final Long domainId = owner.getDomainId(); From c731613ac080d998f9558696568ccd38f68efa8f Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Tue, 11 Aug 2026 14:14:55 +0200 Subject: [PATCH 10/13] fix NPE, finalizeOwner is nullable --- .../cloudstack/network/ssl/CertServiceImpl.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index b57497ddc3ae..bb7acbb49cbd 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -128,8 +128,15 @@ public CertServiceImpl() { public SslCertResponse uploadSslCert(final UploadSslCertCmd certCmd) { Preconditions.checkNotNull(certCmd); - final Account caller = CallContext.current().getCallingAccount(); - final Account owner = _accountMgr.finalizeOwner(caller, certCmd.getAccountName(), certCmd.getDomainId(), certCmd.getProjectId()); + final CallContext ctx = CallContext.current(); + final Account caller = ctx.getCallingAccount(); + + Account owner = null; + if (StringUtils.isNotBlank(certCmd.getAccountName())) { + owner = _accountMgr.finalizeOwner(caller, certCmd.getAccountName(), certCmd.getDomainId(), certCmd.getProjectId()); + } else { + owner = caller; + } final String cert = certCmd.getCert(); final String key = certCmd.getKey(); From 321fe2fd34b75b6fdce6f4fbf7b894bed40e6bf0 Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Tue, 11 Aug 2026 14:21:47 +0200 Subject: [PATCH 11/13] ensure owner not null --- .../org/apache/cloudstack/network/ssl/CertServiceImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index bb7acbb49cbd..14e5129f8c62 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -138,6 +138,8 @@ public SslCertResponse uploadSslCert(final UploadSslCertCmd certCmd) { owner = caller; } + Preconditions.checkNotNull(owner); + final String cert = certCmd.getCert(); final String key = certCmd.getKey(); final String password = certCmd.getPassword(); @@ -226,12 +228,14 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) } Account owner = null; - if (StringUtils.isNotEmpty(accountName)) { + if (StringUtils.isNotBlank(accountName)) { owner = _accountMgr.finalizeOwner(caller, accountName, domainId, projectId); } else { owner = caller; } + Preconditions.checkNotNull(owner); + final List certResponseList = new ArrayList(); List certLbMap = null; From d08de80d3d633bd45305a38ee5d629b9736af62b Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Tue, 11 Aug 2026 14:48:29 +0200 Subject: [PATCH 12/13] check for nullable projectId --- .../apache/cloudstack/network/ssl/CertServiceImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index 14e5129f8c62..cb46f6e24f24 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -131,8 +131,8 @@ public SslCertResponse uploadSslCert(final UploadSslCertCmd certCmd) { final CallContext ctx = CallContext.current(); final Account caller = ctx.getCallingAccount(); - Account owner = null; - if (StringUtils.isNotBlank(certCmd.getAccountName())) { + Account owner; + if (StringUtils.isNotBlank(certCmd.getAccountName()) || certCmd.getProjectId() != null) { owner = _accountMgr.finalizeOwner(caller, certCmd.getAccountName(), certCmd.getDomainId(), certCmd.getProjectId()); } else { owner = caller; @@ -227,8 +227,8 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) throw new InvalidParameterValueException("Only one of certid, lbid, projectid, or accountid/account can be specified"); } - Account owner = null; - if (StringUtils.isNotBlank(accountName)) { + Account owner; + if (StringUtils.isNotBlank(accountName) || projectId != null) { owner = _accountMgr.finalizeOwner(caller, accountName, domainId, projectId); } else { owner = caller; From 247b5345d50fde48a1729ad7e8846511904158be Mon Sep 17 00:00:00 2001 From: Rene Moser Date: Tue, 11 Aug 2026 15:16:24 +0200 Subject: [PATCH 13/13] also take domainId into account --- .../org/apache/cloudstack/network/ssl/CertServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java index cb46f6e24f24..a607bb5a68e2 100644 --- a/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/ssl/CertServiceImpl.java @@ -132,7 +132,7 @@ public SslCertResponse uploadSslCert(final UploadSslCertCmd certCmd) { final Account caller = ctx.getCallingAccount(); Account owner; - if (StringUtils.isNotBlank(certCmd.getAccountName()) || certCmd.getProjectId() != null) { + if ((StringUtils.isNotBlank(certCmd.getAccountName()) && certCmd.getDomainId() != null) || certCmd.getProjectId() != null) { owner = _accountMgr.finalizeOwner(caller, certCmd.getAccountName(), certCmd.getDomainId(), certCmd.getProjectId()); } else { owner = caller; @@ -228,7 +228,7 @@ public List listSslCerts(final ListSslCertsCmd listSslCertCmd) } Account owner; - if (StringUtils.isNotBlank(accountName) || projectId != null) { + if ((StringUtils.isNotBlank(accountName) && domainId != null) || projectId != null) { owner = _accountMgr.finalizeOwner(caller, accountName, domainId, projectId); } else { owner = caller;