diff --git a/services/iam/plugin/src/org/apache/cloudstack/acl/api/AclApiService.java b/services/iam/plugin/src/org/apache/cloudstack/acl/api/AclApiService.java index eb08de5b6f9..8b964955d7a 100644 --- a/services/iam/plugin/src/org/apache/cloudstack/acl/api/AclApiService.java +++ b/services/iam/plugin/src/org/apache/cloudstack/acl/api/AclApiService.java @@ -19,6 +19,7 @@ package org.apache.cloudstack.acl.api; import java.util.List; import org.apache.cloudstack.acl.PermissionScope; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.acl.api.response.AclGroupResponse; import org.apache.cloudstack.acl.api.response.AclPolicyResponse; import org.apache.cloudstack.api.response.ListResponse; @@ -64,6 +65,9 @@ public interface AclApiService extends PluggableService { AclPolicyPermission getAclPolicyPermission(long accountId, String entityType, String action); + /* Utility routine to grant invidivual resource to list of accounts */ + void grantEntityPermissioinToAccounts(String entityType, Long entityId, AccessType accessType, String action, List accountIds); + /* Response Generation */ AclPolicyResponse createAclPolicyResponse(AclPolicy policy); diff --git a/services/iam/plugin/src/org/apache/cloudstack/acl/api/AclApiServiceImpl.java b/services/iam/plugin/src/org/apache/cloudstack/acl/api/AclApiServiceImpl.java index c3c9caaeda1..ee33620cc86 100644 --- a/services/iam/plugin/src/org/apache/cloudstack/acl/api/AclApiServiceImpl.java +++ b/services/iam/plugin/src/org/apache/cloudstack/acl/api/AclApiServiceImpl.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.acl.api; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -47,6 +48,7 @@ import org.apache.cloudstack.acl.api.command.RemoveAclPolicyFromAclGroupCmd; import org.apache.cloudstack.acl.api.response.AclGroupResponse; import org.apache.cloudstack.acl.api.response.AclPermissionResponse; import org.apache.cloudstack.acl.api.response.AclPolicyResponse; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.context.CallContext; @@ -179,6 +181,22 @@ public class AclApiServiceImpl extends ManagerBase implements AclApiService, Man } }); + _messageBus.subscribe(EntityManager.MESSAGE_GRANT_ENTITY_EVENT, new MessageSubscriber() { + @Override + public void onPublishMessage(String senderAddress, String subject, Object obj) { + Map permit = (Map)obj; + if (permit != null) { + String entityType = (String)permit.get(ApiConstants.ENTITY_TYPE); + Long entityId = (Long)permit.get(ApiConstants.ENTITY_ID); + AccessType accessType = (AccessType)permit.get(ApiConstants.ACCESS_TYPE); + String action = (String)permit.get(ApiConstants.ACL_ACTION); + List acctIds = (List)permit.get(ApiConstants.ACCOUNTS); + s_logger.debug("MessageBus message: grant permission to an entity: (" + entityType + "," + entityId + ")"); + grantEntityPermissioinToAccounts(entityType, entityId, accessType, action, acctIds); + } + } + }); + return super.configure(name, params); } @@ -469,6 +487,38 @@ public class AclApiServiceImpl extends ManagerBase implements AclApiService, Man return response; } + @Override + public void grantEntityPermissioinToAccounts(String entityType, Long entityId, AccessType accessType, String action, List accountIds) { + // check if there is already a policy with only this permission added to it + AclPolicy policy = _iamSrv.getResourceGrantPolicy(entityType, entityId, accessType.toString(), action); + if (policy == null) { + // not found, just create a policy with resource grant permission + Account caller = CallContext.current().getCallingAccount(); + String aclPolicyName = "policyGrant" + entityType + entityId; + String description = "Policy to grant permission to " + entityType + entityId; + policy = createAclPolicy(caller, aclPolicyName, description, null); + // add permission to this policy + addAclPermissionToAclPolicy(policy.getId(), entityType, PermissionScope.RESOURCE, entityId, action, Permission.Allow); + } + // attach this policy to list of accounts if not attached already + Long policyId = policy.getId(); + for (Long acctId : accountIds) { + if (!isPolicyAttachedToAccount(policyId, acctId)) { + attachAclPolicyToAccounts(policyId, Collections.singletonList(acctId)); + } + } + } + + private boolean isPolicyAttachedToAccount(Long policyId, Long accountId) { + List pList = listAclPolicies(accountId); + for (AclPolicy p : pList) { + if (p.getId() == policyId.longValue()) { + return true; + } + } + return false; + } + @Override public List> getCommands() { List> cmdList = new ArrayList>(); 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 98aec5d91fb..76fab055efe 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,6 +66,8 @@ public interface IAMService { void removeAclPermissionForEntity(final String entityType, final Long entityId); + AclPolicy getResourceGrantPolicy(String entityType, Long entityId, String accessType, String action); + AclPolicy getResourceOwnerPolicy(); List listPolicyPermissions(long policyId); 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 d2b173ede6b..11116b0be61 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 @@ -24,6 +24,7 @@ import javax.inject.Inject; import org.apache.log4j.Logger; +import org.apache.cloudstack.acl.PermissionScope; import org.apache.cloudstack.iam.api.AclGroup; import org.apache.cloudstack.iam.api.AclPolicy; import org.apache.cloudstack.iam.api.AclPolicyPermission; @@ -387,6 +388,7 @@ public class IAMServiceImpl extends ManagerBase implements IAMService, Manager { return policies; } + @SuppressWarnings("unchecked") @Override public Pair, Integer> listAclPolicies(Long aclPolicyId, String aclPolicyName, String path, Long startIndex, Long pageSize) { @@ -706,4 +708,25 @@ public class IAMServiceImpl extends ManagerBase implements IAMService, Manager { return _aclPolicyDao.findByName("RESOURCE_OWNER"); } + // search for policy with only one resource grant permission + @Override + public AclPolicy getResourceGrantPolicy(String entityType, Long entityId, String accessType, String action) { + List policyList = _aclPolicyDao.listAll(); + for (AclPolicyVO policy : policyList){ + List pp = listPolicyPermissions(policy.getId()); + if ( pp != null && pp.size() == 1){ + // resource grant policy should only have one ACL permission assigned + AclPolicyPermission permit = pp.get(0); + if ( permit.getEntityType().equals(entityType) && permit.getScope().equals(PermissionScope.RESOURCE.toString()) && permit.getScopeId().longValue() == entityId.longValue()){ + if (accessType != null && permit.getAccessType().equals(accessType)){ + return policy; + } else if (action != null && permit.getAction().equals(action)) { + return policy; + } + } + } + } + return null; + } + } diff --git a/utils/src/com/cloud/utils/db/EntityManager.java b/utils/src/com/cloud/utils/db/EntityManager.java index aed5bcbc312..3226e908c39 100644 --- a/utils/src/com/cloud/utils/db/EntityManager.java +++ b/utils/src/com/cloud/utils/db/EntityManager.java @@ -72,4 +72,5 @@ public interface EntityManager { public void remove(Class entityType, K id); public static final String MESSAGE_REMOVE_ENTITY_EVENT = "Message.RemoveEntity.Event"; + public static final String MESSAGE_GRANT_ENTITY_EVENT = "Message.GrantEntity.Event"; }