diff --git a/api/src/com/cloud/acl/SecurityChecker.java b/api/src/com/cloud/acl/SecurityChecker.java index d39e9841c2a..e835d9d2241 100644 --- a/api/src/com/cloud/acl/SecurityChecker.java +++ b/api/src/com/cloud/acl/SecurityChecker.java @@ -3,6 +3,7 @@ */ package com.cloud.acl; +import com.cloud.dc.DataCenter; import com.cloud.domain.Domain; import com.cloud.exception.PermissionDeniedException; import com.cloud.user.Account; @@ -53,6 +54,8 @@ public interface SecurityChecker extends Adapter { * @throws PermissionDeniedException if this adapter is suppose to authenticate ownership and the check failed. */ boolean checkAccess(User user, ControlledEntity entity) throws PermissionDeniedException; + + boolean checkAccess(Account account, DataCenter zone) throws PermissionDeniedException; // We should be able to use this method to check against commands. For example, we can // annotate the command with access annotations and this method can use it to extract diff --git a/api/src/com/cloud/dc/DataCenter.java b/api/src/com/cloud/dc/DataCenter.java index 8b2e976c6bf..f1013b1e880 100644 --- a/api/src/com/cloud/dc/DataCenter.java +++ b/api/src/com/cloud/dc/DataCenter.java @@ -13,4 +13,5 @@ public interface DataCenter extends Grouping { String getDns1(); String getDns2(); String getGuestNetworkCidr(); + Long getDomainId(); } diff --git a/server/src/com/cloud/acl/DomainChecker.java b/server/src/com/cloud/acl/DomainChecker.java index 7a5eceaa966..95dca17171b 100644 --- a/server/src/com/cloud/acl/DomainChecker.java +++ b/server/src/com/cloud/acl/DomainChecker.java @@ -20,7 +20,9 @@ package com.cloud.acl; import javax.ejb.Local; import com.cloud.api.BaseCmd; +import com.cloud.dc.DataCenter; import com.cloud.domain.Domain; +import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.exception.PermissionDeniedException; import com.cloud.storage.LaunchPermissionVO; @@ -97,4 +99,71 @@ public class DomainChecker extends AdapterBase implements SecurityChecker { Account account = _accountDao.findById(user.getAccountId()); return checkAccess(account, entity); } + + @Override + public boolean checkAccess(Account account, DataCenter zone) throws PermissionDeniedException { + if(account == null || zone.getDomainId() == null){//public zone + return true; + }else{ + //admin has all permissions + if(account.getType() == Account.ACCOUNT_TYPE_ADMIN){ + return true; + } + //if account is normal user + //check if account's domain is a child of zone's domain + else if(account.getType() == Account.ACCOUNT_TYPE_NORMAL){ + if(account.getDomainId() == zone.getDomainId()){ + return true; //zone and account at exact node + }else{ + DomainVO domainRecord = _domainDao.findById(account.getDomainId()); + if(domainRecord != null) + { + while(true){ + if(domainRecord.getId() == zone.getDomainId()){ + //found as a child + return true; + } + if(domainRecord.getParent() != null) + domainRecord = _domainDao.findById(domainRecord.getParent()); + else + break; + } + } + } + //not found + return false; + } + //if account is domain admin + //check if the account's domain is either child of zone's domain, or if zone's domain is child of account's domain + else if(account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN){ + if(account.getDomainId() == zone.getDomainId()){ + return true; //zone and account at exact node + }else{ + DomainVO zoneDomainRecord = _domainDao.findById(zone.getDomainId()); + DomainVO accountDomainRecord = _domainDao.findById(account.getDomainId()); + if(accountDomainRecord != null) + { + DomainVO localRecord = accountDomainRecord; + while(true){ + if(localRecord.getId() == zone.getDomainId()){ + //found as a child + return true; + } + if(localRecord.getParent() != null) + localRecord = _domainDao.findById(localRecord.getParent()); + else + break; + } + } + //didn't find in upper tree + if(zoneDomainRecord.getPath().contains(accountDomainRecord.getPath())){ + return true; + } + } + //not found + return false; + } + } + return false; + } } diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 74a3ad387e5..de38aaadba5 100644 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -19,12 +19,15 @@ package com.cloud.configuration; import java.util.List; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.PermissionDeniedException; import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.DiskOfferingVO; +import com.cloud.user.Account; import com.cloud.utils.component.Manager; /** @@ -144,5 +147,8 @@ public interface ConfigurationManager extends Manager { * @return String containing a comma separated list of tags */ String listToCsvTags(List tags); + + void checkAccess(Account caller, DataCenter zone) + throws PermissionDeniedException; } diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 4b97a5886b5..07ad08574a8 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -29,6 +29,7 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; +import com.cloud.acl.SecurityChecker; import com.cloud.api.BaseCmd; import com.cloud.api.ServerApiException; import com.cloud.api.commands.CreateCfgCmd; @@ -56,8 +57,8 @@ import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; import com.cloud.dc.PodVlanMapVO; import com.cloud.dc.Vlan; -import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; +import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.dao.AccountVlanMapDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterIpAddressDao; @@ -80,8 +81,8 @@ import com.cloud.network.NetworkManager; import com.cloud.network.dao.IPAddressDao; import com.cloud.offering.DiskOffering; import com.cloud.offering.NetworkOffering; -import com.cloud.offering.NetworkOffering.GuestIpType; import com.cloud.offering.ServiceOffering; +import com.cloud.offering.NetworkOffering.GuestIpType; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DiskOfferingVO; @@ -95,6 +96,7 @@ import com.cloud.user.UserVO; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.utils.NumbersUtil; +import com.cloud.utils.component.Adapters; import com.cloud.utils.component.Inject; import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; @@ -136,6 +138,8 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura @Inject SecondaryStorageVmDao _secStorageDao; @Inject AccountManager _accountMgr; @Inject NetworkManager _networkMgr; + @Inject(adapter=SecurityChecker.class) + Adapters _secChecker; private int _maxVolumeSizeInGb; @@ -1363,7 +1367,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura String vlanGateway = cmd.getGateway(); String vlanNetmask = cmd.getNetmask(); - //check for hypervisor type to be xenserver + //check for hypervisor type to be xenserver String hypervisorType = _configDao.getValue("hypervisor.type"); if(hypervisorType.equalsIgnoreCase("xenserver")) { @@ -1393,11 +1397,13 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura throw new InvalidParameterValueException("Please specify a valid zone."); } - //check if the account's domain is a child of the zone's domain, for adding vlan ip ranges - if(domainId != null && !_domainDao.isChildDomain(zone.getDomainId(), domainId)){ - //this is for account specific case, as domainId != null - throw new PermissionDeniedException("The account associated with specific domain id:"+domainId+" doesn't have permissions to add vlan ip ranges for the zone:"+zone.getId()); - } +// //check if the account's domain is a child of the zone's domain, for adding vlan ip ranges +// if(domainId != null && !_domainDao.isChildDomain(zone.getDomainId(), domainId)){ +// //this is for account specific case, as domainId != null +// throw new PermissionDeniedException("The account associated with specific domain id:"+domainId+" doesn't have permissions to add vlan ip ranges for the zone:"+zone.getId()); +// } + //ACL check + checkAccess(account, zone); boolean associateIpRangeToAccount = false; if (vlanType.equals(VlanType.VirtualNetwork)) { @@ -2215,4 +2221,21 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura return deleteVlanAndPublicIpRange(userId, vlanDbId); } + + @Override + public void checkAccess(Account caller, DataCenter zone) throws PermissionDeniedException { + for (SecurityChecker checker : _secChecker) { + if (checker.checkAccess(caller, zone)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Access granted to " + caller + " to zone:" + zone.getId() + " by " + checker.getName()); + } + return; + }else{ + throw new PermissionDeniedException("Access denied to "+caller+" by "+checker.getName()); + } + } + + assert false : "How can all of the security checkers pass on checking this caller?"; + throw new PermissionDeniedException("There's no way to confirm " + caller + " has access to zone:" + zone.getId()); + } } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 16c08cec59a..ae86023e978 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -60,6 +60,8 @@ import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; +import com.cloud.acl.DomainChecker; +import com.cloud.acl.SecurityChecker; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.GetVncPortAnswer; @@ -150,6 +152,7 @@ import com.cloud.configuration.dao.ResourceLimitDao; import com.cloud.consoleproxy.ConsoleProxyManager; import com.cloud.dc.AccountVlanMapVO; import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterIpAddressVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; @@ -163,6 +166,7 @@ import com.cloud.dc.dao.DataCenterIpAddressDaoImpl; import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.PodVlanMapDao; import com.cloud.dc.dao.VlanDao; +import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.EventState; @@ -272,6 +276,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.PasswordGenerator; import com.cloud.utils.component.Adapters; import com.cloud.utils.component.ComponentLocator; +import com.cloud.utils.component.Inject; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; @@ -393,7 +398,7 @@ public class ManagementServerImpl implements ManagementServer { private boolean _networkGroupsEnabled = false; private boolean _isHypervisorSnapshotCapable = false; - + protected ManagementServerImpl() { ComponentLocator locator = ComponentLocator.getLocator(Name); _lunDao = locator.getDao(PreallocatedLunDao.class); @@ -461,7 +466,7 @@ public class ManagementServerImpl implements ManagementServer { _snapMgr = locator.getManager(SnapshotManager.class); _networkGroupMgr = locator.getManager(NetworkGroupManager.class); _uploadMonitor = locator.getManager(UploadMonitor.class); - + _userAuthenticators = locator.getAdapters(UserAuthenticator.class); if (_userAuthenticators == null || !_userAuthenticators.isSet()) { s_logger.error("Unable to find an user authenticator."); @@ -1116,7 +1121,8 @@ public class ManagementServerImpl implements ManagementServer { String[] networkGroups = null; Long sizeObj = cmd.getSize(); long size = (sizeObj == null) ? 0 : sizeObj; - + Account userAccount = null; + DataCenterVO dc = _dcDao.findById(dataCenterId); if (dc == null) { throw new InvalidParameterValueException("Unable to find zone: " + dataCenterId); @@ -1128,7 +1134,7 @@ public class ManagementServerImpl implements ManagementServer { throw new PermissionDeniedException("Failed to deploy VM, invalid domain id (" + domainId + ") given."); } if (accountName != null) { - Account userAccount = _accountDao.findActiveAccount(accountName, domainId); + userAccount = _accountDao.findActiveAccount(accountName, domainId); if (userAccount == null) { throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId); } @@ -1147,25 +1153,18 @@ public class ManagementServerImpl implements ManagementServer { if(domainId == null){ domainId = dc.getDomainId(); //get the domain id from zone - - if(domainId == null){ - //do nothing (public zone case) - } - else{ - //check if this account has the permission to deploy a vm in this domain - if(ctxAccount != null){ - if((ctxAccount.getType() == Account.ACCOUNT_TYPE_NORMAL) || ctxAccount.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN){ - if(domainId == ctxAccount.getDomainId()){ - //user in same domain as dedicated zone - } - else if ((!_domainDao.isChildDomain(domainId,ctxAccount.getDomainId()))){ - //may need to revisit domain admin case for leaves - throw new PermissionDeniedException("Failed to deploy VM, user does not have permission to deploy a vm within this dedicated private zone under domain id:"+domainId); - } - } - } - } } + + if(domainId == null){ + //do nothing (public zone case) + } + else{ + if(userAccount != null){ + _configMgr.checkAccess(userAccount, dc);//user deploying his own vm + }else{ + _configMgr.checkAccess(ctxAccount, dc); + } + } List netGrpList = cmd.getNetworkGroupList(); if ((netGrpList != null) && !netGrpList.isEmpty()) {