diff --git a/api/src/org/apache/cloudstack/acl/AclService.java b/api/src/org/apache/cloudstack/acl/AclService.java index 749fc155845..dbdcf0bdce5 100644 --- a/api/src/org/apache/cloudstack/acl/AclService.java +++ b/api/src/org/apache/cloudstack/acl/AclService.java @@ -20,8 +20,8 @@ import java.util.List; import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import com.cloud.utils.Pair; import com.cloud.user.Account; +import com.cloud.utils.Pair; public interface AclService { @@ -89,4 +89,10 @@ public interface AclService { List getEffectiveRoles(Account caller, ControlledEntity entity); + List getGrantedDomains(long accountId, AclEntityType entityType, String action); + + List getGrantedAccounts(long accountId, AclEntityType entityType, String action); + + List getGrantedResources(long accountId, AclEntityType entityType, String action); + } diff --git a/api/src/org/apache/cloudstack/acl/QueryChecker.java b/api/src/org/apache/cloudstack/acl/QueryChecker.java index bbe9a2e3f07..e8e9cf3aa08 100644 --- a/api/src/org/apache/cloudstack/acl/QueryChecker.java +++ b/api/src/org/apache/cloudstack/acl/QueryChecker.java @@ -35,15 +35,6 @@ public interface QueryChecker extends Adapter { */ List getAuthorizedDomains(Account caller, AclEntityType entityType); - /** - * List denied domains for the caller, given a specific entity type. - * - * @param caller account to check against. - * @param entityType entity type - * @return list of domain Ids granted to the caller account. - */ - List getDeniedDomains(Account caller, AclEntityType entityType); - /** * List granted accounts for the caller, given a specific entity type. * @@ -53,14 +44,6 @@ public interface QueryChecker extends Adapter { */ List getAuthorizedAccounts(Account caller, AclEntityType entityType); - /** - * List denied accounts for the caller, given a specific entity type. - * - * @param caller account to check against. - * @param entityType entity type - * @return list of domain Ids granted to the caller account. - */ - List getDeniedAccounts(Account caller, AclEntityType entityType); /** * List granted resources for the caller, given a specific entity type. @@ -71,13 +54,5 @@ public interface QueryChecker extends Adapter { */ List getAuthorizedResources(Account caller, AclEntityType entityType); - /** - * List denied resources for the caller, given a specific entity type. - * - * @param caller account to check against. - * @param entityType entity type - * @return list of domain Ids granted to the caller account. - */ - List getDeniedResources(Account caller, AclEntityType entityType); } diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java index 1b018f9a8d4..23a0413e384 100644 --- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java +++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java @@ -397,6 +397,22 @@ public class MockAccountManager extends ManagerBase implements AccountManager { // TODO Auto-generated method stub return false; } + + @Override + public void buildACLSearchParameters(Account caller, Long id, String accountName, Long projectId, List permittedDomains, List permittedAccounts, + List permittedResources, Ternary domainIdRecursiveListProject, boolean listAll, boolean forProjectInvitation, + String action) { + // TODO Auto-generated method stub + + } + + @Override + public void buildACLViewSearchCriteria(SearchCriteria sc, SearchCriteria aclSc, boolean isRecursive, + List permittedDomains, List permittedAccounts, List permittedResources, ListProjectResourcesCriteria listProjectResourcesCriteria) { + // TODO Auto-generated method stub + + } + } diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index f55fcd8dee1..37f46325ec8 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -29,12 +29,10 @@ import javax.inject.Inject; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.acl.AclEntityType; import org.apache.cloudstack.acl.AclGroup; import org.apache.cloudstack.acl.AclRole; import org.apache.cloudstack.acl.AclService; import org.apache.cloudstack.acl.ControlledEntity.ACLType; -import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.acl.dao.AclGroupDao; import org.apache.cloudstack.acl.dao.AclRoleDao; import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO; @@ -749,20 +747,17 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { private Pair, Integer> searchForUserVMsInternal(ListVMsCmd cmd) { Account caller = CallContext.current().getCallingAccount(); + List permittedDomains = new ArrayList(); List permittedAccounts = new ArrayList(); - - // get granted or denied entity instance permissions - Pair, List> idPair = _aclService.getAclEntityPermission(caller.getId(), AclEntityType.VM.toString(), AccessType.ListEntry); - List grantedIds = idPair.first(); - List revokedIds = idPair.second(); + List permittedResources = new ArrayList(); boolean listAll = cmd.listAll(); Long id = cmd.getId(); Ternary domainIdRecursiveListProject = new Ternary( cmd.getDomainId(), cmd.isRecursive(), null); - _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, - domainIdRecursiveListProject, listAll, false); - Long domainId = domainIdRecursiveListProject.first(); + _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedDomains, permittedAccounts, permittedResources, + domainIdRecursiveListProject, listAll, false, "listVirtualMachines"); + //Long domainId = domainIdRecursiveListProject.first(); Boolean isRecursive = domainIdRecursiveListProject.second(); ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); @@ -773,10 +768,6 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { SearchBuilder sb = _userVmJoinDao.createSearchBuilder(); sb.select(null, Func.DISTINCT, sb.entity().getId()); // select distinct ids - // build acl search builder condition - _accountMgr.buildACLViewSearchBuilder(sb, domainId, isRecursive, permittedAccounts, - listProjectResourcesCriteria, grantedIds, revokedIds); - Map tags = cmd.getTags(); String hypervisor = cmd.getHypervisor(); Object name = cmd.getName(); @@ -854,10 +845,10 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { // populate the search criteria with the values passed in SearchCriteria sc = sb.create(); + SearchCriteria aclSc = _userVmJoinDao.createSearchCriteria(); // building ACL search criteria - _accountMgr.buildACLViewSearchCriteria(sc, domainId, isRecursive, permittedAccounts, - listProjectResourcesCriteria, grantedIds, revokedIds); + _accountMgr.buildACLViewSearchCriteria(sc, aclSc, isRecursive, permittedDomains, permittedAccounts, permittedResources, listProjectResourcesCriteria); if (tags != null && !tags.isEmpty()) { SearchCriteria tagSc = _userVmJoinDao.createSearchCriteria(); diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java index 24bf6487d3d..ed5ff1736b0 100755 --- a/server/src/com/cloud/user/AccountManager.java +++ b/server/src/com/cloud/user/AccountManager.java @@ -107,6 +107,15 @@ public interface AccountManager extends AccountService { void buildACLSearchParameters(Account caller, Long id, String accountName, Long projectId, List permittedAccounts, Ternary domainIdRecursiveListProject, boolean listAll, boolean forProjectInvitation); + // new ACL model routine for query api based on db views + void buildACLSearchParameters(Account caller, Long id, + String accountName, Long projectId, List permittedDomains, List permittedAccounts, List permittedResources, + Ternary domainIdRecursiveListProject, boolean listAll, boolean forProjectInvitation, String action); + + void buildACLViewSearchCriteria(SearchCriteria sc, SearchCriteria aclSc, boolean isRecursive, + List permittedDomains, List permittedAccounts, + List permittedResources, ListProjectResourcesCriteria listProjectResourcesCriteria); + /** * Deletes a user by userId * diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 6a5b29c62d7..1e32aefec30 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -2537,4 +2537,132 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M return _userAccountDao.getUserByApiKey(apiKey); } + @Override + public void buildACLSearchParameters(Account caller, Long id, String accountName, Long projectId, List permittedDomains, List permittedAccounts, + List permittedResources, Ternary domainIdRecursiveListProject, boolean listAll, boolean forProjectInvitation, + String action) { + Long domainId = domainIdRecursiveListProject.first(); + if (domainId != null) { + // look for entity in the given domain + Domain domain = _domainDao.findById(domainId); + if (domain == null) { + throw new InvalidParameterValueException("Unable to find domain by id " + domainId); + } + // check permissions + checkAccess(caller, domain); + } + + if (id != null) { + // look for an individual entity, no other permission criteria are needed + permittedResources.add(id); + return; + } + + if (accountName != null) { + if (projectId != null) { + throw new InvalidParameterValueException("Account and projectId can't be specified together"); + } + + Account userAccount = null; + Domain domain = null; + if (domainId != null) { + userAccount = _accountDao.findActiveAccount(accountName, domainId); + domain = _domainDao.findById(domainId); + } else { + userAccount = _accountDao.findActiveAccount(accountName, caller.getDomainId()); + domain = _domainDao.findById(caller.getDomainId()); + } + + if (userAccount != null) { + //check permissions + checkAccess(caller, null, false, userAccount); + permittedAccounts.add(userAccount.getId()); + } else { + throw new InvalidParameterValueException("could not find account " + accountName + " in domain " + domain.getUuid()); + } + } + + // set project information + if (projectId != null) { + if (!forProjectInvitation) { + if (projectId.longValue() == -1) { + if (isNormalUser(caller.getId())) { + permittedAccounts.addAll(_projectMgr.listPermittedProjectAccounts(caller.getId())); + } else { + domainIdRecursiveListProject.third(Project.ListProjectResourcesCriteria.ListProjectResourcesOnly); + } + } else { + Project project = _projectMgr.getProject(projectId); + if (project == null) { + throw new InvalidParameterValueException("Unable to find project by id " + projectId); + } + if (!_projectMgr.canAccessProjectAccount(caller, project.getProjectAccountId())) { + throw new PermissionDeniedException("Account " + caller + " can't access project id=" + projectId); + } + permittedAccounts.add(project.getProjectAccountId()); + } + } + } else { + domainIdRecursiveListProject.third(Project.ListProjectResourcesCriteria.SkipProjectResources); + + // search for policy permissions associated with caller to get all his authorized domains, accounts, and resources + // Assumption: if a domain is in grantedDomains, then all the accounts under this domain will not be returned in "grantedAccounts". Similarly, if an account + // is in grantedAccounts, then all the resources owned by this account will not be returned in "grantedResources". + List grantedDomains = _aclService.getGrantedDomains(caller.getId(), AclEntityType.VM, action); + List grantedAccounts = _aclService.getGrantedAccounts(caller.getId(), AclEntityType.VM, action); + List grantedResources = _aclService.getGrantedResources(caller.getId(), AclEntityType.VM, action); + + if (domainId != null) { + // specific domain is specified + if (grantedDomains.contains(domainId)) { + permittedDomains.add(domainId); + } else { + for (Long acctId : grantedAccounts) { + Account acct = _accountDao.findById(acctId); + if (acct != null && acct.getDomainId() == domainId) { + permittedAccounts.add(acctId); + } + } + permittedResources.addAll(grantedResources); + } + } else if (permittedAccounts.isEmpty()) { + // neither domain nor account is not specified + permittedDomains.addAll(grantedDomains); + permittedAccounts.addAll(grantedAccounts); + permittedResources.addAll(grantedResources); + } + } + + } + + @Override + public void buildACLViewSearchCriteria(SearchCriteria sc, SearchCriteria aclSc, boolean isRecursive, + List permittedDomains, + List permittedAccounts, List permittedResources, ListProjectResourcesCriteria listProjectResourcesCriteria) { + + if (listProjectResourcesCriteria != null) { + sc.addAnd("accountType", SearchCriteria.Op.EQ, Account.ACCOUNT_TYPE_PROJECT); + } + + // Note that this may have limitations on number of permitted domains, accounts, or resource ids are allowed due to sql package size limitation + if (!permittedDomains.isEmpty()) { + if (isRecursive) { + for (int i = 0; i < permittedDomains.size(); i++) { + Domain domain = _domainDao.findById(permittedDomains.get(i)); + aclSc.addOr("domainPath" + i, SearchCriteria.Op.LIKE, domain.getPath() + "%"); + } + } else { + aclSc.addOr("domainIdIN", SearchCriteria.Op.IN, permittedDomains.toArray()); + } + } + if (!permittedAccounts.isEmpty()) { + aclSc.addOr("accountIdIN", SearchCriteria.Op.IN, permittedAccounts.toArray()); + } + if (!permittedResources.isEmpty()) { + aclSc.addOr("idIn", SearchCriteria.Op.IN, permittedResources.toArray()); + } + + sc.addAnd("accountIdIn", SearchCriteria.Op.SC, aclSc); + } + } diff --git a/server/src/org/apache/cloudstack/acl/AclServiceImpl.java b/server/src/org/apache/cloudstack/acl/AclServiceImpl.java index c7badd0cb18..320b5422cf4 100644 --- a/server/src/org/apache/cloudstack/acl/AclServiceImpl.java +++ b/server/src/org/apache/cloudstack/acl/AclServiceImpl.java @@ -689,4 +689,22 @@ public class AclServiceImpl extends ManagerBase implements AclService, Manager { return roles; } + @Override + public List getGrantedDomains(long accountId, AclEntityType entityType, String action) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getGrantedAccounts(long accountId, AclEntityType entityType, String action) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getGrantedResources(long accountId, AclEntityType entityType, String action) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/user/MockAccountManagerImpl.java b/server/test/com/cloud/user/MockAccountManagerImpl.java index 085670c7f42..cf3bc6a76f2 100644 --- a/server/test/com/cloud/user/MockAccountManagerImpl.java +++ b/server/test/com/cloud/user/MockAccountManagerImpl.java @@ -362,4 +362,20 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco return false; } + @Override + public void buildACLSearchParameters(Account caller, Long id, String accountName, Long projectId, List permittedDomains, List permittedAccounts, + List permittedResources, Ternary domainIdRecursiveListProject, boolean listAll, boolean forProjectInvitation, + String action) { + // TODO Auto-generated method stub + + } + + @Override + public void buildACLViewSearchCriteria(SearchCriteria sc, SearchCriteria aclSc, boolean isRecursive, + List permittedDomains, List permittedAccounts, List permittedResources, ListProjectResourcesCriteria listProjectResourcesCriteria) { + // TODO Auto-generated method stub + + } + + }