From 0da721a9abac9a7f4b82b239a63766d7a74559d4 Mon Sep 17 00:00:00 2001 From: Darrin Husselmann Date: Mon, 22 Feb 2021 08:50:55 +0200 Subject: [PATCH 01/10] Added recursive fetch of domains for listUsageRecords API call --- .../api/command/admin/usage/ListUsageRecordsCmd.java | 8 ++++++++ .../main/java/com/cloud/usage/UsageServiceImpl.java | 12 +++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java index 748b9d7b8bb7..6d61306996b2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java @@ -85,6 +85,10 @@ public class ListUsageRecordsCmd extends BaseListCmd { @Parameter(name = ApiConstants.OLD_FORMAT, type = CommandType.BOOLEAN, description = "Flag to enable description rendered in old format which uses internal database IDs instead of UUIDs. False by default.") private Boolean oldFormat; + @Parameter(name = ApiConstants.IS_RECURSIVE, type = CommandType.BOOLEAN, + description = "Specify if usage records should be fetched recursively per domain.") + private Boolean recursive = false; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -153,6 +157,10 @@ public boolean getOldFormat() { return oldFormat != null && oldFormat; } + public Boolean isRecursive() { + return recursive; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java index 2d8d9370b9ff..c8432683fee6 100644 --- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java +++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java @@ -248,7 +248,17 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd sc.addAnd("domainId", SearchCriteria.Op.IN, domainIds.toArray()); } - if (domainId != null) { + if (cmd.isRecursive() && domainId != null){ + SearchCriteria sdc = _domainDao.createSearchCriteria(); + sdc.addOr("path", SearchCriteria.Op.LIKE, _domainDao.findById(domainId).getPath() + "%"); + List domains = _domainDao.search(sdc, null); + List domainIds = new ArrayList(); + for (DomainVO domain : domains) + domainIds.add(domain.getId()); + sc.addAnd("domainId", SearchCriteria.Op.IN, domainIds.toArray()); + } + + if (!cmd.isRecursive() && domainId != null) { sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); } From e66d92b67b7168b14470dc3ca145062f046cc0f0 Mon Sep 17 00:00:00 2001 From: Darrin Husselmann Date: Mon, 22 Feb 2021 15:40:37 +0200 Subject: [PATCH 02/10] Added security check for domain admin --- .../com/cloud/usage/UsageServiceImpl.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java index c8432683fee6..dcb0c7992b05 100644 --- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java +++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java @@ -216,6 +216,31 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd s_logger.debug("Account details not available. Using userContext accountId: " + accountId); } + // Check if a domain admin is allowed to access the requested account info. + if (_accountService.isDomainAdmin(caller.getId()) && accountId != null){ + long accountDomainId = _accountDao.getDomainIdForGivenAccountId(accountId); + long callerDomainId = caller.getDomainId(); + boolean matchFound = false; + + if (callerDomainId == accountDomainId) { + matchFound = true; + } else { + // Check if the account is in a child domain of this domain admin. + List childDomains = _domainDao.findAllChildren(_domainDao.findById(caller.getDomainId()).getPath(), caller.getDomainId()); + + for (DomainVO domainVO: childDomains) { + if (accountDomainId == domainVO.getId()) { + matchFound = true; + break; + } + } + } + + if (!matchFound){ + throw new PermissionDeniedException("Domain admins may only retrieve usage records for accounts in their own domain."); + } + } + Date startDate = cmd.getStartDate(); Date endDate = cmd.getEndDate(); if (startDate.after(endDate)) { @@ -238,7 +263,7 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); } - if (isDomainAdmin) { + if (isDomainAdmin && !cmd.isRecursive()) { SearchCriteria sdc = _domainDao.createSearchCriteria(); sdc.addOr("path", SearchCriteria.Op.LIKE, _domainDao.findById(caller.getDomainId()).getPath() + "%"); List domains = _domainDao.search(sdc, null); From 7a7023096ab0cd7f676e8e82f80f01b3c9b2e784 Mon Sep 17 00:00:00 2001 From: Darrin Husselmann Date: Fri, 26 Feb 2021 14:05:04 +0200 Subject: [PATCH 03/10] Review changes --- .../admin/usage/ListUsageRecordsCmd.java | 3 +- .../com/cloud/usage/UsageServiceImpl.java | 91 ++++++++++--------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java index 6d61306996b2..5e40644117ea 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java @@ -86,7 +86,8 @@ public class ListUsageRecordsCmd extends BaseListCmd { private Boolean oldFormat; @Parameter(name = ApiConstants.IS_RECURSIVE, type = CommandType.BOOLEAN, - description = "Specify if usage records should be fetched recursively per domain.") + description = "Specify if usage records should be fetched recursively per domain.", + since = "4.15") private Boolean recursive = false; ///////////////////////////////////////////////////// diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java index dcb0c7992b05..3fba3091e83d 100644 --- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java +++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java @@ -26,6 +26,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.domain.Domain; import org.apache.cloudstack.api.command.admin.usage.GenerateUsageRecordsCmd; import org.apache.cloudstack.api.command.admin.usage.ListUsageRecordsCmd; import org.apache.cloudstack.api.command.admin.usage.RemoveRawUsageRecordsCmd; @@ -201,7 +202,8 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd } boolean isAdmin = false; - boolean isDomainAdmin = false; + boolean isDomainAdmin = _accountService.isDomainAdmin(caller.getId()); + boolean isNormalUser = _accountService.isNormalUser(caller.getId()); //If accountId couldn't be found using accountName and domainId, get it from userContext if (accountId == null) { @@ -210,34 +212,42 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd //If account_id or account_name is explicitly mentioned, list records for the specified account only even if the caller is of type admin if (_accountService.isRootAdmin(caller.getId())) { isAdmin = true; - } else if (_accountService.isDomainAdmin(caller.getId())) { - isDomainAdmin = true; } s_logger.debug("Account details not available. Using userContext accountId: " + accountId); } - // Check if a domain admin is allowed to access the requested account info. - if (_accountService.isDomainAdmin(caller.getId()) && accountId != null){ - long accountDomainId = _accountDao.getDomainIdForGivenAccountId(accountId); - long callerDomainId = caller.getDomainId(); - boolean matchFound = false; - - if (callerDomainId == accountDomainId) { - matchFound = true; + // Check if a domain admin is allowed to access the requested domain id + if (isDomainAdmin) { + if (domainId != null) { + Account callerAccount = _accountService.getAccount(caller.getId()); + Domain domain = _domainDao.findById(domainId); + _accountService.checkAccess(callerAccount, domain); } else { - // Check if the account is in a child domain of this domain admin. - List childDomains = _domainDao.findAllChildren(_domainDao.findById(caller.getDomainId()).getPath(), caller.getDomainId()); - - for (DomainVO domainVO: childDomains) { - if (accountDomainId == domainVO.getId()) { - matchFound = true; - break; - } - } + // Domain admins can only access their own domain's usage records. + // Set the domain if not specified. + domainId = caller.getDomainId(); } - if (!matchFound){ - throw new PermissionDeniedException("Domain admins may only retrieve usage records for accounts in their own domain."); + // Check if a domain admin is allowed to access the requested account info. + Account account = _accountService.getAccount(accountId); + Domain domain = _domainDao.findById(caller.getDomainId()); + _accountService.checkAccess(account, domain); + } + + // By default users do not have access to this API. + // Adding checks here in case someone changes the default access. + if (isNormalUser) { + // A user can only access their own account records + if (caller.getId() != accountId) { + throw new PermissionDeniedException("Users are only allowed to list usage records for their own account."); + } + // Users cannot get recursive records + if (cmd.isRecursive()) { + throw new PermissionDeniedException("Users are not allowed to list usage records recursively."); + } + // Users cannot get domain records + if (cmd.getDomainId() != null) { + throw new PermissionDeniedException("Users are not allowed to list usage records for a domain"); } } @@ -259,32 +269,23 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd SearchCriteria sc = _usageDao.createSearchCriteria(); - if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !isAdmin && !isDomainAdmin) { + if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !isAdmin && !cmd.isRecursive()) { sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); } - if (isDomainAdmin && !cmd.isRecursive()) { - SearchCriteria sdc = _domainDao.createSearchCriteria(); - sdc.addOr("path", SearchCriteria.Op.LIKE, _domainDao.findById(caller.getDomainId()).getPath() + "%"); - List domains = _domainDao.search(sdc, null); - List domainIds = new ArrayList(); - for (DomainVO domain : domains) - domainIds.add(domain.getId()); - sc.addAnd("domainId", SearchCriteria.Op.IN, domainIds.toArray()); - } - - if (cmd.isRecursive() && domainId != null){ - SearchCriteria sdc = _domainDao.createSearchCriteria(); - sdc.addOr("path", SearchCriteria.Op.LIKE, _domainDao.findById(domainId).getPath() + "%"); - List domains = _domainDao.search(sdc, null); - List domainIds = new ArrayList(); - for (DomainVO domain : domains) - domainIds.add(domain.getId()); - sc.addAnd("domainId", SearchCriteria.Op.IN, domainIds.toArray()); - } - - if (!cmd.isRecursive() && domainId != null) { - sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + if (domainId != null) { + if (cmd.isRecursive()) { + SearchCriteria sdc = _domainDao.createSearchCriteria(); + sdc.addOr("path", SearchCriteria.Op.LIKE, _domainDao.findById(domainId).getPath() + "%"); + List domains = _domainDao.search(sdc, null); + List domainIds = new ArrayList(); + for (DomainVO domain : domains) { + domainIds.add(domain.getId()); + } + sc.addAnd("domainId", SearchCriteria.Op.IN, domainIds.toArray()); + } else { + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + } } if (usageType != null) { From 9270df4384157611665d13fab3ed775362328790 Mon Sep 17 00:00:00 2001 From: Darrin Husselmann Date: Mon, 1 Mar 2021 10:36:25 +0200 Subject: [PATCH 04/10] Changed account check --- .../com/cloud/usage/UsageServiceImpl.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java index 3fba3091e83d..8589fdfa4907 100644 --- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java +++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java @@ -231,7 +231,25 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd // Check if a domain admin is allowed to access the requested account info. Account account = _accountService.getAccount(accountId); Domain domain = _domainDao.findById(caller.getDomainId()); - _accountService.checkAccess(account, domain); + boolean matchFound = false; + + if (account.getDomainId() == domainId) { + matchFound = true; + } else { + + // Check if the account is in a child domain of this domain admin. + List childDomains = _domainDao.findAllChildren(_domainDao.findById(domainId).getPath(), domainId); + + for (DomainVO domainVO : childDomains) { + if (account.getDomainId() == domainVO.getId()) { + matchFound = true; + break; + } + } + } + if (!matchFound) { + throw new PermissionDeniedException("Domain admins may only retrieve usage records for accounts in their own domain and child domains."); + } } // By default users do not have access to this API. @@ -269,7 +287,7 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd SearchCriteria sc = _usageDao.createSearchCriteria(); - if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !isAdmin && !cmd.isRecursive()) { + if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !isAdmin) { sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); } From 5d43c1ccc2e77140df455127a7dd4068824d2a17 Mon Sep 17 00:00:00 2001 From: Darrin Husselmann Date: Mon, 1 Mar 2021 10:38:45 +0200 Subject: [PATCH 05/10] Removed unused var --- server/src/main/java/com/cloud/usage/UsageServiceImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java index 8589fdfa4907..9fe4451b6d5f 100644 --- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java +++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java @@ -230,7 +230,6 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd // Check if a domain admin is allowed to access the requested account info. Account account = _accountService.getAccount(accountId); - Domain domain = _domainDao.findById(caller.getDomainId()); boolean matchFound = false; if (account.getDomainId() == domainId) { From 71c7c716977c1ebd07aeaf779bac8db5c1e110b9 Mon Sep 17 00:00:00 2001 From: Darrin Husselmann Date: Mon, 1 Mar 2021 13:17:28 +0200 Subject: [PATCH 06/10] Adding recursive check back --- server/src/main/java/com/cloud/usage/UsageServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java index 9fe4451b6d5f..86e8c69924fd 100644 --- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java +++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java @@ -286,7 +286,7 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd SearchCriteria sc = _usageDao.createSearchCriteria(); - if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !isAdmin) { + if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !isAdmin && !cmd.isRecursive()) { sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); } From 19fd61288ef3184e5cccfab2d5d75f8e5d432092 Mon Sep 17 00:00:00 2001 From: Darrin Husselmann Date: Mon, 1 Mar 2021 15:02:21 +0200 Subject: [PATCH 07/10] Changed logic around setting the account id --- .../src/main/java/com/cloud/usage/UsageServiceImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java index 86e8c69924fd..849fa7513ead 100644 --- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java +++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java @@ -286,8 +286,12 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd SearchCriteria sc = _usageDao.createSearchCriteria(); - if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !isAdmin && !cmd.isRecursive()) { - sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !isAdmin) { + // account exists and either domain on user role + // If not recursive and the account belongs to the user/domain admin, or the account was passed in, filter + if ((accountId == caller.getId() && !cmd.isRecursive()) || cmd.getAccountId() != null){ + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + } } if (domainId != null) { From a45fcee722ece23807701be2916251d48e0b3af8 Mon Sep 17 00:00:00 2001 From: Darrin Husselmann Date: Tue, 16 Mar 2021 17:00:08 +0200 Subject: [PATCH 08/10] Fixed null account issue --- .../com/cloud/usage/UsageServiceImpl.java | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java index 849fa7513ead..0635dd22d545 100644 --- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java +++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java @@ -228,26 +228,29 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd domainId = caller.getDomainId(); } - // Check if a domain admin is allowed to access the requested account info. - Account account = _accountService.getAccount(accountId); - boolean matchFound = false; + if (cmd.getAccountId() != null) { - if (account.getDomainId() == domainId) { - matchFound = true; - } else { + // Check if a domain admin is allowed to access the requested account info. + Account account = _accountService.getAccount(accountId); + boolean matchFound = false; + + if (account.getDomainId() == domainId) { + matchFound = true; + } else { - // Check if the account is in a child domain of this domain admin. - List childDomains = _domainDao.findAllChildren(_domainDao.findById(domainId).getPath(), domainId); + // Check if the account is in a child domain of this domain admin. + List childDomains = _domainDao.findAllChildren(_domainDao.findById(domainId).getPath(), domainId); - for (DomainVO domainVO : childDomains) { - if (account.getDomainId() == domainVO.getId()) { - matchFound = true; - break; + for (DomainVO domainVO : childDomains) { + if (account.getDomainId() == domainVO.getId()) { + matchFound = true; + break; + } } } - } - if (!matchFound) { + if (!matchFound) { throw new PermissionDeniedException("Domain admins may only retrieve usage records for accounts in their own domain and child domains."); + } } } From 83c9b0adfbfaa8c9c43f7cfa969f01c684550941 Mon Sep 17 00:00:00 2001 From: Darrin Husselmann Date: Wed, 17 Mar 2021 12:47:46 +0200 Subject: [PATCH 09/10] Refactored code --- .../com/cloud/usage/UsageServiceImpl.java | 85 ++++++++++--------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java index 0635dd22d545..253daadb10cf 100644 --- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java +++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java @@ -201,7 +201,7 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd } } - boolean isAdmin = false; + boolean ignoreAccountId = false; boolean isDomainAdmin = _accountService.isDomainAdmin(caller.getId()); boolean isNormalUser = _accountService.isNormalUser(caller.getId()); @@ -210,9 +210,7 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd accountId = caller.getId(); //List records for all the accounts if the caller account is of type admin. //If account_id or account_name is explicitly mentioned, list records for the specified account only even if the caller is of type admin - if (_accountService.isRootAdmin(caller.getId())) { - isAdmin = true; - } + ignoreAccountId = _accountService.isRootAdmin(caller.getId()); s_logger.debug("Account details not available. Using userContext accountId: " + accountId); } @@ -229,47 +227,14 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd } if (cmd.getAccountId() != null) { - // Check if a domain admin is allowed to access the requested account info. - Account account = _accountService.getAccount(accountId); - boolean matchFound = false; - - if (account.getDomainId() == domainId) { - matchFound = true; - } else { - - // Check if the account is in a child domain of this domain admin. - List childDomains = _domainDao.findAllChildren(_domainDao.findById(domainId).getPath(), domainId); - - for (DomainVO domainVO : childDomains) { - if (account.getDomainId() == domainVO.getId()) { - matchFound = true; - break; - } - } - } - if (!matchFound) { - throw new PermissionDeniedException("Domain admins may only retrieve usage records for accounts in their own domain and child domains."); - } + checkDomainAdminAccountAccess(accountId, domainId); } } // By default users do not have access to this API. // Adding checks here in case someone changes the default access. - if (isNormalUser) { - // A user can only access their own account records - if (caller.getId() != accountId) { - throw new PermissionDeniedException("Users are only allowed to list usage records for their own account."); - } - // Users cannot get recursive records - if (cmd.isRecursive()) { - throw new PermissionDeniedException("Users are not allowed to list usage records recursively."); - } - // Users cannot get domain records - if (cmd.getDomainId() != null) { - throw new PermissionDeniedException("Users are not allowed to list usage records for a domain"); - } - } + checkUserAccess(cmd, accountId, caller, isNormalUser); Date startDate = cmd.getStartDate(); Date endDate = cmd.getEndDate(); @@ -289,7 +254,7 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd SearchCriteria sc = _usageDao.createSearchCriteria(); - if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !isAdmin) { + if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !ignoreAccountId) { // account exists and either domain on user role // If not recursive and the account belongs to the user/domain admin, or the account was passed in, filter if ((accountId == caller.getId() && !cmd.isRecursive()) || cmd.getAccountId() != null){ @@ -432,6 +397,46 @@ public Pair, Integer> getUsageRecords(ListUsageRecordsCmd return new Pair, Integer>(usageRecords.first(), usageRecords.second()); } + private void checkUserAccess(ListUsageRecordsCmd cmd, Long accountId, Account caller, boolean isNormalUser) { + if (isNormalUser) { + // A user can only access their own account records + if (caller.getId() != accountId) { + throw new PermissionDeniedException("Users are only allowed to list usage records for their own account."); + } + // Users cannot get recursive records + if (cmd.isRecursive()) { + throw new PermissionDeniedException("Users are not allowed to list usage records recursively."); + } + // Users cannot get domain records + if (cmd.getDomainId() != null) { + throw new PermissionDeniedException("Users are not allowed to list usage records for a domain"); + } + } + } + + private void checkDomainAdminAccountAccess(Long accountId, Long domainId) { + Account account = _accountService.getAccount(accountId); + boolean matchFound = false; + + if (account.getDomainId() == domainId) { + matchFound = true; + } else { + + // Check if the account is in a child domain of this domain admin. + List childDomains = _domainDao.findAllChildren(_domainDao.findById(domainId).getPath(), domainId); + + for (DomainVO domainVO : childDomains) { + if (account.getDomainId() == domainVO.getId()) { + matchFound = true; + break; + } + } + } + if (!matchFound) { + throw new PermissionDeniedException("Domain admins may only retrieve usage records for accounts in their own domain and child domains."); + } + } + @Override public TimeZone getUsageTimezone() { return _usageTimezone; From 80860ee4af9177c8bcb5e6362fe046cfb85a9747 Mon Sep 17 00:00:00 2001 From: Darrin Husselmann Date: Wed, 17 Mar 2021 14:24:13 +0200 Subject: [PATCH 10/10] Added message regarding account id --- .../cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java index 5e40644117ea..91a38b0021cf 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java @@ -86,7 +86,7 @@ public class ListUsageRecordsCmd extends BaseListCmd { private Boolean oldFormat; @Parameter(name = ApiConstants.IS_RECURSIVE, type = CommandType.BOOLEAN, - description = "Specify if usage records should be fetched recursively per domain.", + description = "Specify if usage records should be fetched recursively per domain. If an account id is passed, records will be limited to that account.", since = "4.15") private Boolean recursive = false;