diff --git a/api/src/com/cloud/user/AccountService.java b/api/src/com/cloud/user/AccountService.java index 2afaa64021f..37f61055f3d 100755 --- a/api/src/com/cloud/user/AccountService.java +++ b/api/src/com/cloud/user/AccountService.java @@ -108,6 +108,9 @@ public interface AccountService { void checkAccess(Account account, AccessType accessType, boolean sameOwner, ControlledEntity... entities) throws PermissionDeniedException; + void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName, + ControlledEntity... entities) throws PermissionDeniedException; + //TO be implemented, to check accessibility for an entity owned by domain void checkAccess(Account account, AccessType accessType, boolean sameOwner, PartOf... entities) throws PermissionDeniedException; } diff --git a/api/src/org/apache/cloudstack/acl/SecurityChecker.java b/api/src/org/apache/cloudstack/acl/SecurityChecker.java index 80fc14b1ad8..3fdcfedb5ca 100644 --- a/api/src/org/apache/cloudstack/acl/SecurityChecker.java +++ b/api/src/org/apache/cloudstack/acl/SecurityChecker.java @@ -36,7 +36,8 @@ public interface SecurityChecker extends Adapter { ModifyProject, UseNetwork, DeleteEntry, - OperateEntry + OperateEntry, + UseEntry } /** diff --git a/server/src/com/cloud/api/ApiDispatcher.java b/server/src/com/cloud/api/ApiDispatcher.java index 9f4f766fc45..751706db005 100755 --- a/server/src/com/cloud/api/ApiDispatcher.java +++ b/server/src/com/cloud/api/ApiDispatcher.java @@ -40,6 +40,7 @@ import org.apache.cloudstack.acl.InfrastructureEntity; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.ACL; +import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; @@ -107,19 +108,14 @@ public class ApiDispatcher { private void doAccessChecks(BaseCmd cmd, Map entitiesToAccess) { Account caller = CallContext.current().getCallingAccount(); - Account owner = _accountMgr.getActiveAccountById(cmd.getEntityOwnerId()); - if (cmd instanceof BaseAsyncCreateCmd) { - //check that caller can access the owner account. - _accountMgr.checkAccess(caller, null, true, owner); - } + APICommand commandAnnotation = cmd.getClass().getAnnotation(APICommand.class); + String apiName = commandAnnotation != null ? commandAnnotation.name() : null; if (!entitiesToAccess.isEmpty()) { - //check that caller can access the owner account. - _accountMgr.checkAccess(caller, null, true, owner); for (Object entity : entitiesToAccess.keySet()) { if (entity instanceof ControlledEntity) { - _accountMgr.checkAccess(caller, entitiesToAccess.get(entity), true, (ControlledEntity)entity); + _accountMgr.checkAccess(caller, entitiesToAccess.get(entity), false, apiName, (ControlledEntity) entity); } else if (entity instanceof InfrastructureEntity) { //FIXME: Move this code in adapter, remove code from Account manager } diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index f89e629ac3d..2771859e4e2 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -447,6 +447,11 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Override public void checkAccess(Account caller, AccessType accessType, boolean sameOwner, ControlledEntity... entities) { + checkAccess(caller, accessType, sameOwner, null, entities); + } + + @Override + public void checkAccess(Account caller, AccessType accessType, boolean sameOwner, String apiName, ControlledEntity... entities) { //check for the same owner Long ownerId = null; ControlledEntity prevEntity = null; @@ -492,7 +497,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } boolean granted = false; for (SecurityChecker checker : _securityCheckers) { - if (checker.checkAccess(caller, entity, accessType)) { + if (checker.checkAccess(caller, entity, accessType, apiName)) { if (s_logger.isDebugEnabled()) { s_logger.debug("Access to " + entity + " granted to " + caller + " by " + checker.getName()); } diff --git a/services/iam/plugin/src/org/apache/cloudstack/acl/RoleBasedAPIAccessChecker.java b/services/iam/plugin/src/org/apache/cloudstack/acl/RoleBasedAPIAccessChecker.java index acd14578ee2..fc39e102613 100644 --- a/services/iam/plugin/src/org/apache/cloudstack/acl/RoleBasedAPIAccessChecker.java +++ b/services/iam/plugin/src/org/apache/cloudstack/acl/RoleBasedAPIAccessChecker.java @@ -30,9 +30,11 @@ import org.apache.log4j.Logger; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.iam.api.AclPolicy; +import org.apache.cloudstack.iam.api.AclPolicyPermission; import org.apache.cloudstack.iam.api.AclPolicyPermission.Permission; import org.apache.cloudstack.iam.api.IAMService; @@ -205,7 +207,9 @@ public class RoleBasedAPIAccessChecker extends AdapterBase implements APIChecker try { cmdObj = (BaseCmd) cmdClass.newInstance(); if (cmdObj instanceof BaseListCmd) { - accessType = AccessType.ListEntry; + accessType = AccessType.UseEntry; + } else if (!(cmdObj instanceof BaseAsyncCreateCmd)) { + accessType = AccessType.OperateEntry; } } catch (Exception e) { throw new CloudRuntimeException(String.format( @@ -238,11 +242,11 @@ public class RoleBasedAPIAccessChecker extends AdapterBase implements APIChecker if (entityTypes == null || entityTypes.length == 0) { - _iamSrv.addAclPermissionToAclPolicy(policyId, null, permissionScope.toString(), new Long(-1), + _iamSrv.addAclPermissionToAclPolicy(policyId, null, permissionScope.toString(), new Long(AclPolicyPermission.PERMISSION_SCOPE_ID_CURRENT_CALLER), apiName, (accessType == null) ? null : accessType.toString(), Permission.Allow); } else { for (AclEntityType entityType : entityTypes) { - _iamSrv.addAclPermissionToAclPolicy(policyId, entityType.toString(), permissionScope.toString(), new Long(-1), + _iamSrv.addAclPermissionToAclPolicy(policyId, entityType.toString(), permissionScope.toString(), new Long(AclPolicyPermission.PERMISSION_SCOPE_ID_CURRENT_CALLER), apiName, (accessType == null) ? null : accessType.toString(), Permission.Allow); } } diff --git a/services/iam/plugin/src/org/apache/cloudstack/acl/RoleBasedEntityAccessChecker.java b/services/iam/plugin/src/org/apache/cloudstack/acl/RoleBasedEntityAccessChecker.java index e2b149bcdee..4802456560d 100644 --- a/services/iam/plugin/src/org/apache/cloudstack/acl/RoleBasedEntityAccessChecker.java +++ b/services/iam/plugin/src/org/apache/cloudstack/acl/RoleBasedEntityAccessChecker.java @@ -24,6 +24,7 @@ import javax.inject.Inject; import org.apache.log4j.Logger; +import org.apache.cloudstack.api.InternalIdentity; import org.apache.cloudstack.iam.api.AclPolicy; import org.apache.cloudstack.iam.api.AclPolicyPermission; import org.apache.cloudstack.iam.api.IAMService; @@ -71,7 +72,7 @@ public class RoleBasedEntityAccessChecker extends DomainChecker implements Secur String entityType = entity.getEntityType().toString(); if (accessType == null) { - accessType = AccessType.ListEntry; + accessType = AccessType.UseEntry; } // get all Policies of this caller w.r.t the entity @@ -82,13 +83,21 @@ public class RoleBasedEntityAccessChecker extends DomainChecker implements Secur List permissions = new ArrayList(); if (action != null) { - permissions = _iamSrv.listPolicyPermissionByEntityType(policy.getId(), action, entityType); + permissions = _iamSrv.listPolicyPermissionByActionAndEntity(policy.getId(), action, entityType); + if (permissions.isEmpty()) { + if (accessType != null) { + permissions.addAll(_iamSrv.listPolicyPermissionByAccessAndEntity(policy.getId(), + accessType.toString(), entityType)); + } + } } else { - permissions = _iamSrv.listPolicyPermissionByAccessType(policy.getId(), accessType.toString(), - entityType, action); + if (accessType != null) { + permissions.addAll(_iamSrv.listPolicyPermissionByAccessAndEntity(policy.getId(), + accessType.toString(), entityType)); + } } for (AclPolicyPermission permission : permissions) { - if (checkPermissionScope(caller, permission.getScope(), entity)) { + if (checkPermissionScope(caller, permission.getScope(), permission.getScopeId(), entity)) { if (permission.getEntityType().equals(entityType)) { policyPermissionMap.put(policy, permission.getPermission().isGranted()); break; @@ -114,18 +123,38 @@ public class RoleBasedEntityAccessChecker extends DomainChecker implements Secur return false; } - private boolean checkPermissionScope(Account caller, String scope, ControlledEntity entity) { + private boolean checkPermissionScope(Account caller, String scope, Long scopeId, ControlledEntity entity) { - if (scope.equals(PermissionScope.ACCOUNT.name())) { - if(caller.getAccountId() == entity.getAccountId()){ - return true; + if(scopeId != null && !scopeId.equals(new Long(AclPolicyPermission.PERMISSION_SCOPE_ID_CURRENT_CALLER))){ + //scopeId is set + if (scope.equals(PermissionScope.ACCOUNT.name())) { + if(scopeId == entity.getAccountId()){ + return true; + } + } else if (scope.equals(PermissionScope.DOMAIN.name())) { + if (_domainDao.isChildDomain(scopeId, entity.getDomainId())) { + return true; + } + } else if (scope.equals(PermissionScope.RESOURCE.name())) { + if (entity instanceof InternalIdentity) { + InternalIdentity entityWithId = (InternalIdentity) entity; + if(scopeId.equals(entityWithId.getId())){ + return true; + } + } } - } else if (scope.equals(PermissionScope.DOMAIN.name())) { - if (_domainDao.isChildDomain(caller.getDomainId(), entity.getDomainId())) { - return true; + } else if (scopeId == null || scopeId.equals(new Long(AclPolicyPermission.PERMISSION_SCOPE_ID_CURRENT_CALLER))) { + if (scope.equals(PermissionScope.ACCOUNT.name())) { + if(caller.getAccountId() == entity.getAccountId()){ + return true; + } + } else if (scope.equals(PermissionScope.DOMAIN.name())) { + if (_domainDao.isChildDomain(caller.getDomainId(), entity.getDomainId())) { + return true; + } } } - + return false; } diff --git a/services/iam/server/src/org/apache/cloudstack/iam/api/AclPolicyPermission.java b/services/iam/server/src/org/apache/cloudstack/iam/api/AclPolicyPermission.java index 38e5d05eb1f..f0352bcf959 100644 --- a/services/iam/server/src/org/apache/cloudstack/iam/api/AclPolicyPermission.java +++ b/services/iam/server/src/org/apache/cloudstack/iam/api/AclPolicyPermission.java @@ -49,4 +49,5 @@ public interface AclPolicyPermission { long getId(); + public static final long PERMISSION_SCOPE_ID_CURRENT_CALLER = -1; } diff --git a/services/iam/server/src/org/apache/cloudstack/iam/api/IAMService.java b/services/iam/server/src/org/apache/cloudstack/iam/api/IAMService.java index 2d303d1493c..90dbb57d48d 100644 --- a/services/iam/server/src/org/apache/cloudstack/iam/api/IAMService.java +++ b/services/iam/server/src/org/apache/cloudstack/iam/api/IAMService.java @@ -66,7 +66,7 @@ public interface IAMService { List listPolicyPermissionsByScope(long policyId, String action, String scope); - List listPolicyPermissionByEntityType(long policyId, String action, String entityType); + List listPolicyPermissionByActionAndEntity(long policyId, String action, String entityType); boolean isActionAllowedForPolicies(String action, List policies); @@ -74,6 +74,7 @@ public interface IAMService { AclPolicy resetAclPolicy(long aclPolicyId); - List listPolicyPermissionByAccessType(long policyId, String accessType, String entityType, String action); + List listPolicyPermissionByAccessAndEntity(long policyId, String accessType, + String entityType); } diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/IAMServiceImpl.java b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMServiceImpl.java index 6eb3223ed18..8a070dd928d 100644 --- a/services/iam/server/src/org/apache/cloudstack/iam/server/IAMServiceImpl.java +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMServiceImpl.java @@ -670,7 +670,8 @@ public class IAMServiceImpl extends ManagerBase implements IAMService, Manager { @SuppressWarnings("unchecked") @Override - public List listPolicyPermissionByEntityType(long policyId, String action, String entityType) { + public List listPolicyPermissionByActionAndEntity(long policyId, String action, + String entityType) { @SuppressWarnings("rawtypes") List pp = _policyPermissionDao.listByPolicyActionAndEntity(policyId, action, entityType); return pp; @@ -678,9 +679,10 @@ public class IAMServiceImpl extends ManagerBase implements IAMService, Manager { @SuppressWarnings("unchecked") @Override - public List listPolicyPermissionByAccessType(long policyId, String accessType, String entityType, String action) { + public List listPolicyPermissionByAccessAndEntity(long policyId, String accessType, + String entityType) { @SuppressWarnings("rawtypes") - List pp = _policyPermissionDao.listByPolicyAccessAndEntity(policyId, accessType, entityType, action); + List pp = _policyPermissionDao.listByPolicyAccessAndEntity(policyId, accessType, entityType); return pp; } diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/AclPolicyPermissionDao.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/AclPolicyPermissionDao.java index 5abadf948e8..53c89837ecd 100644 --- a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/AclPolicyPermissionDao.java +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/AclPolicyPermissionDao.java @@ -33,6 +33,6 @@ public interface AclPolicyPermissionDao extends GenericDao listByPolicyActionAndEntity(long policyId, String action, String entityType); - List listByPolicyAccessAndEntity(long id, String accessType, String entityType, String action); + List listByPolicyAccessAndEntity(long policyId, String accessType, String entityType); } diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/AclPolicyPermissionDaoImpl.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/AclPolicyPermissionDaoImpl.java index b014cb494fd..d738e007e48 100644 --- a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/AclPolicyPermissionDaoImpl.java +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/AclPolicyPermissionDaoImpl.java @@ -104,12 +104,11 @@ public class AclPolicyPermissionDaoImpl extends GenericDaoBase listByPolicyAccessAndEntity(long policyId, String accessType, - String entityType, String action) { + String entityType) { SearchCriteria sc = fullSearch.create(); sc.setParameters("policyId", policyId); sc.setParameters("entityType", entityType); sc.setParameters("accessType", accessType); - sc.setParameters("action", action); return listBy(sc); }