You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mc...@apache.org on 2014/03/14 00:54:59 UTC
[06/50] [abbrv] Renaming plugin packages to 'iam' instead if 'acl'
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b2ba6c05/services/iam/plugin/src/org/apache/cloudstack/iam/AclApiServiceImpl.java
----------------------------------------------------------------------
diff --git a/services/iam/plugin/src/org/apache/cloudstack/iam/AclApiServiceImpl.java b/services/iam/plugin/src/org/apache/cloudstack/iam/AclApiServiceImpl.java
new file mode 100644
index 0000000..996f8d4
--- /dev/null
+++ b/services/iam/plugin/src/org/apache/cloudstack/iam/AclApiServiceImpl.java
@@ -0,0 +1,690 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.iam;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.IAMEntityType;
+import org.apache.cloudstack.acl.PermissionScope;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.command.iam.AddAccountToAclGroupCmd;
+import org.apache.cloudstack.api.command.iam.AddAclPermissionToAclPolicyCmd;
+import org.apache.cloudstack.api.command.iam.AttachAclPolicyToAccountCmd;
+import org.apache.cloudstack.api.command.iam.AttachAclPolicyToAclGroupCmd;
+import org.apache.cloudstack.api.command.iam.CreateAclGroupCmd;
+import org.apache.cloudstack.api.command.iam.CreateAclPolicyCmd;
+import org.apache.cloudstack.api.command.iam.DeleteAclGroupCmd;
+import org.apache.cloudstack.api.command.iam.DeleteAclPolicyCmd;
+import org.apache.cloudstack.api.command.iam.ListAclGroupsCmd;
+import org.apache.cloudstack.api.command.iam.ListAclPoliciesCmd;
+import org.apache.cloudstack.api.command.iam.RemoveAccountFromAclGroupCmd;
+import org.apache.cloudstack.api.command.iam.RemoveAclPermissionFromAclPolicyCmd;
+import org.apache.cloudstack.api.command.iam.RemoveAclPolicyFromAccountCmd;
+import org.apache.cloudstack.api.command.iam.RemoveAclPolicyFromAclGroupCmd;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.iam.AclGroupResponse;
+import org.apache.cloudstack.api.response.iam.AclPermissionResponse;
+import org.apache.cloudstack.api.response.iam.AclPolicyResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.messagebus.MessageBus;
+import org.apache.cloudstack.framework.messagebus.MessageSubscriber;
+import org.apache.cloudstack.iam.api.AclGroup;
+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;
+
+import com.cloud.api.ApiServerService;
+import com.cloud.domain.Domain;
+import com.cloud.domain.DomainVO;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.event.ActionEvent;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.template.TemplateManager;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.DomainManager;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.Manager;
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.EntityManager;
+
+@Local(value = {AclApiService.class})
+public class AclApiServiceImpl extends ManagerBase implements AclApiService, Manager {
+
+ public static final Logger s_logger = Logger.getLogger(AclApiServiceImpl.class);
+ private String _name;
+
+ @Inject
+ ApiServerService _apiServer;
+
+ @Inject
+ IAMService _iamSrv;
+
+ @Inject
+ DomainDao _domainDao;
+
+ @Inject
+ AccountDao _accountDao;
+
+ @Inject
+ AccountManager _accountMgr;
+
+ @Inject
+ MessageBus _messageBus;
+
+ @Override
+ public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
+ _messageBus.subscribe(AccountManager.MESSAGE_ADD_ACCOUNT_EVENT, new MessageSubscriber() {
+ @Override
+ public void onPublishMessage(String senderAddress, String subject, Object obj) {
+ HashMap<Long, Long> acctGroupMap = (HashMap<Long, Long>) obj;
+ for (Long accountId : acctGroupMap.keySet()) {
+ Long groupId = acctGroupMap.get(accountId);
+ s_logger.debug("MessageBus message: new Account Added: " + accountId + ", adding it to groupId :"
+ + groupId);
+ addAccountToAclGroup(accountId, groupId);
+ // add it to domain group too
+ AccountVO account = _accountDao.findById(accountId);
+ Domain domain = _domainDao.findById(account.getDomainId());
+ if (domain != null) {
+ List<AclGroup> domainGroups = listDomainGroup(domain);
+
+ if (domainGroups != null) {
+ for (AclGroup group : domainGroups) {
+ addAccountToAclGroup(accountId, new Long(group.getId()));
+ }
+ }
+ }
+ }
+ }
+ });
+
+ _messageBus.subscribe(AccountManager.MESSAGE_REMOVE_ACCOUNT_EVENT, new MessageSubscriber() {
+ @Override
+ public void onPublishMessage(String senderAddress, String subject, Object obj) {
+ Long accountId = ((Long) obj);
+ if (accountId != null) {
+ s_logger.debug("MessageBus message: Account removed: " + accountId
+ + ", releasing the group associations");
+ removeAccountFromAclGroups(accountId);
+ }
+ }
+ });
+
+ _messageBus.subscribe(DomainManager.MESSAGE_ADD_DOMAIN_EVENT, new MessageSubscriber() {
+ @Override
+ public void onPublishMessage(String senderAddress, String subject, Object obj) {
+ Long domainId = ((Long) obj);
+ if (domainId != null) {
+ s_logger.debug("MessageBus message: new Domain created: " + domainId + ", creating a new group");
+ Domain domain = _domainDao.findById(domainId);
+ _iamSrv.createAclGroup("DomainGrp-" + domain.getUuid(), "Domain group", domain.getPath());
+ }
+ }
+ });
+
+ _messageBus.subscribe(DomainManager.MESSAGE_REMOVE_DOMAIN_EVENT, new MessageSubscriber() {
+ @Override
+ public void onPublishMessage(String senderAddress, String subject, Object obj) {
+ Long domainId = ((Long) obj);
+ if (domainId != null) {
+ s_logger.debug("MessageBus message: Domain removed: " + domainId + ", removing the domain group");
+ Domain domain = _domainDao.findById(domainId);
+ List<AclGroup> groups = listDomainGroup(domain);
+ for (AclGroup group : groups) {
+ _iamSrv.deleteAclGroup(group.getId());
+ }
+ }
+ }
+ });
+
+ _messageBus.subscribe(TemplateManager.MESSAGE_REGISTER_PUBLIC_TEMPLATE_EVENT, new MessageSubscriber() {
+ @Override
+ public void onPublishMessage(String senderAddress, String subject, Object obj) {
+ Long templateId = (Long)obj;
+ if (templateId != null) {
+ s_logger.debug("MessageBus message: new public template registered: " + templateId + ", grant permission to domain admin and normal user policies");
+ _iamSrv.addAclPermissionToAclPolicy(new Long(Account.ACCOUNT_TYPE_DOMAIN_ADMIN + 1), IAMEntityType.VirtualMachineTemplate.toString(),
+ PermissionScope.RESOURCE.toString(), templateId, "listTemplates", AccessType.UseEntry.toString(), Permission.Allow, false);
+ _iamSrv.addAclPermissionToAclPolicy(new Long(Account.ACCOUNT_TYPE_NORMAL + 1), IAMEntityType.VirtualMachineTemplate.toString(),
+ PermissionScope.RESOURCE.toString(), templateId, "listTemplates", AccessType.UseEntry.toString(), Permission.Allow, false);
+ }
+ }
+ });
+
+ _messageBus.subscribe(TemplateManager.MESSAGE_RESET_TEMPLATE_PERMISSION_EVENT, new MessageSubscriber() {
+ @Override
+ public void onPublishMessage(String senderAddress, String subject, Object obj) {
+ Long templateId = (Long)obj;
+ if (templateId != null) {
+ s_logger.debug("MessageBus message: reset template permission: " + templateId);
+ resetTemplatePermission(templateId);
+ }
+ }
+ });
+
+ _messageBus.subscribe(EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, new MessageSubscriber() {
+ @Override
+ public void onPublishMessage(String senderAddress, String subject, Object obj) {
+ Pair<IAMEntityType, Long> entity = (Pair<IAMEntityType, Long>)obj;
+ if (entity != null) {
+ String entityType = entity.first().toString();
+ Long entityId = entity.second();
+ s_logger.debug("MessageBus message: delete an entity: (" + entityType + "," + entityId + "), remove its related permission");
+ _iamSrv.removeAclPermissionForEntity(entityType, entityId);
+ }
+ }
+ });
+
+
+ _messageBus.subscribe(EntityManager.MESSAGE_GRANT_ENTITY_EVENT, new MessageSubscriber() {
+ @Override
+ public void onPublishMessage(String senderAddress, String subject, Object obj) {
+ Map<String, Object> permit = (Map<String, Object>)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<Long> acctIds = (List<Long>)permit.get(ApiConstants.ACCOUNTS);
+ s_logger.debug("MessageBus message: grant accounts permission to an entity: (" + entityType + "," + entityId + ")");
+ grantEntityPermissioinToAccounts(entityType, entityId, accessType, action, acctIds);
+ }
+ }
+ });
+
+ _messageBus.subscribe(EntityManager.MESSAGE_REVOKE_ENTITY_EVENT, new MessageSubscriber() {
+ @Override
+ public void onPublishMessage(String senderAddress, String subject, Object obj) {
+ Map<String, Object> permit = (Map<String, Object>)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<Long> acctIds = (List<Long>)permit.get(ApiConstants.ACCOUNTS);
+ s_logger.debug("MessageBus message: revoke from accounts permission to an entity: (" + entityType + "," + entityId + ")");
+ revokeEntityPermissioinFromAccounts(entityType, entityId, accessType, action, acctIds);
+ }
+ }
+ });
+
+ _messageBus.subscribe(EntityManager.MESSAGE_ADD_DOMAIN_WIDE_ENTITY_EVENT, new MessageSubscriber() {
+ @Override
+ public void onPublishMessage(String senderAddress, String subject, Object obj) {
+ Map<String, Object> params = (Map<String, Object>) obj;
+ if (params != null) {
+ addDomainWideResourceAccess(params);
+ }
+ }
+ });
+
+ return super.configure(name, params);
+ }
+
+ private void addDomainWideResourceAccess(Map<String, Object> params) {
+
+ IAMEntityType entityType = (IAMEntityType)params.get(ApiConstants.ENTITY_TYPE);
+ Long entityId = (Long) params.get(ApiConstants.ENTITY_ID);
+ Long domainId = (Long) params.get(ApiConstants.DOMAIN_ID);
+ Boolean isRecursive = (Boolean) params.get(ApiConstants.SUBDOMAIN_ACCESS);
+
+ if (entityType == IAMEntityType.Network) {
+ createPolicyAndAddToDomainGroup("DomainWideNetwork-" + entityId, "domain wide network", entityType.toString(),
+ entityId, "listNetworks", AccessType.UseEntry, domainId, isRecursive);
+ } else if (entityType == IAMEntityType.AffinityGroup) {
+ createPolicyAndAddToDomainGroup("DomainWideNetwork-" + entityId, "domain wide affinityGroup", entityType.toString(),
+ entityId, "listAffinityGroups", AccessType.UseEntry, domainId, isRecursive);
+ }
+
+ }
+
+ private void createPolicyAndAddToDomainGroup(String policyName, String description, String entityType,
+ Long entityId, String action, AccessType accessType, Long domainId, Boolean recursive) {
+
+ Domain domain = _domainDao.findById(domainId);
+ if (domain != null) {
+ AclPolicy policy = _iamSrv.createAclPolicy(policyName, description, null, domain.getPath());
+ _iamSrv.addAclPermissionToAclPolicy(policy.getId(), entityType, PermissionScope.RESOURCE.toString(),
+ entityId, action, accessType.toString(), Permission.Allow, recursive);
+ List<Long> policyList = new ArrayList<Long>();
+ policyList.add(new Long(policy.getId()));
+
+ List<AclGroup> domainGroups = listDomainGroup(domain);
+ if (domainGroups != null) {
+ for (AclGroup group : domainGroups) {
+ _iamSrv.attachAclPoliciesToGroup(policyList, group.getId());
+ }
+ }
+ }
+ }
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_GROUP_CREATE, eventDescription = "Creating Acl Group", create = true)
+ public AclGroup createAclGroup(Account caller, String aclGroupName, String description) {
+ Long domainId = caller.getDomainId();
+ Domain callerDomain = _domainDao.findById(domainId);
+ if (callerDomain == null) {
+ throw new InvalidParameterValueException("Caller does not have a domain");
+ }
+ return _iamSrv.createAclGroup(aclGroupName, description, callerDomain.getPath());
+ }
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_GROUP_DELETE, eventDescription = "Deleting Acl Group")
+ public boolean deleteAclGroup(final Long aclGroupId) {
+ return _iamSrv.deleteAclGroup(aclGroupId);
+ }
+
+ @Override
+ public List<AclGroup> listAclGroups(long accountId) {
+ return _iamSrv.listAclGroups(accountId);
+ }
+
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_GROUP_UPDATE, eventDescription = "Adding accounts to acl group")
+ public AclGroup addAccountsToGroup(final List<Long> acctIds, final Long groupId) {
+ return _iamSrv.addAccountsToGroup(acctIds, groupId);
+ }
+
+
+ private void removeAccountFromAclGroups(long accountId) {
+ List<AclGroup> groups = listAclGroups(accountId);
+ List<Long> accts = new ArrayList<Long>();
+ accts.add(accountId);
+ if (groups != null) {
+ for (AclGroup grp : groups) {
+ removeAccountsFromGroup(accts, grp.getId());
+ }
+ }
+ }
+
+ private void addAccountToAclGroup(long accountId, long groupId) {
+ List<Long> accts = new ArrayList<Long>();
+ accts.add(accountId);
+ addAccountsToGroup(accts, groupId);
+ }
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_GROUP_UPDATE, eventDescription = "Removing accounts from acl group")
+ public AclGroup removeAccountsFromGroup(final List<Long> acctIds, final Long groupId) {
+ return _iamSrv.removeAccountsFromGroup(acctIds, groupId);
+ }
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_POLICY_CREATE, eventDescription = "Creating Acl Policy", create = true)
+ public AclPolicy createAclPolicy(Account caller, final String aclPolicyName, final String description, final Long parentPolicyId) {
+ Long domainId = caller.getDomainId();
+ Domain callerDomain = _domainDao.findById(domainId);
+ if (callerDomain == null) {
+ throw new InvalidParameterValueException("Caller does not have a domain");
+ }
+ return _iamSrv.createAclPolicy(aclPolicyName, description, parentPolicyId, callerDomain.getPath());
+ }
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_POLICY_DELETE, eventDescription = "Deleting Acl Policy")
+ public boolean deleteAclPolicy(final long aclPolicyId) {
+ return _iamSrv.deleteAclPolicy(aclPolicyId);
+ }
+
+
+ @Override
+ public List<AclPolicy> listAclPolicies(long accountId) {
+ return _iamSrv.listAclPolicies(accountId);
+ }
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_GROUP_UPDATE, eventDescription = "Attaching policy to acl group")
+ public AclGroup attachAclPoliciesToGroup(final List<Long> policyIds, final Long groupId) {
+ return _iamSrv.attachAclPoliciesToGroup(policyIds, groupId);
+ }
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_GROUP_UPDATE, eventDescription = "Removing policies from acl group")
+ public AclGroup removeAclPoliciesFromGroup(final List<Long> policyIds, final Long groupId) {
+ return _iamSrv.removeAclPoliciesFromGroup(policyIds, groupId);
+ }
+
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_ACCOUNT_POLICY_UPDATE, eventDescription = "Attaching policy to accounts")
+ public void attachAclPolicyToAccounts(final Long policyId, final List<Long> accountIds) {
+ _iamSrv.attachAclPolicyToAccounts(policyId, accountIds);
+ }
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_ACCOUNT_POLICY_UPDATE, eventDescription = "Removing policy from accounts")
+ public void removeAclPolicyFromAccounts(final Long policyId, final List<Long> accountIds) {
+ _iamSrv.removeAclPolicyFromAccounts(policyId, accountIds);
+ }
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_POLICY_GRANT, eventDescription = "Granting acl permission to Acl Policy")
+ public AclPolicy addAclPermissionToAclPolicy(long aclPolicyId, String entityType, PermissionScope scope,
+ Long scopeId, String action, Permission perm, Boolean recursive) {
+ Class<?> cmdClass = _apiServer.getCmdClass(action);
+ AccessType accessType = null;
+ if (BaseListCmd.class.isAssignableFrom(cmdClass)) {
+ accessType = AccessType.UseEntry;
+ }
+ return _iamSrv.addAclPermissionToAclPolicy(aclPolicyId, entityType, scope.toString(), scopeId, action,
+ accessType.toString(), perm, recursive);
+ }
+
+ @DB
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_ACL_POLICY_REVOKE, eventDescription = "Revoking acl permission from Acl Policy")
+ public AclPolicy removeAclPermissionFromAclPolicy(long aclPolicyId, String entityType, PermissionScope scope, Long scopeId, String action) {
+ return _iamSrv.removeAclPermissionFromAclPolicy(aclPolicyId, entityType, scope.toString(), scopeId, action);
+ }
+
+ @Override
+ public AclPolicyPermission getAclPolicyPermission(long accountId, String entityType, String action) {
+ List<AclPolicy> policies = _iamSrv.listAclPolicies(accountId);
+ AclPolicyPermission curPerm = null;
+ for (AclPolicy policy : policies) {
+ List<AclPolicyPermission> perms = _iamSrv.listPolicyPermissionByActionAndEntity(policy.getId(), action,
+ entityType);
+ if (perms == null || perms.size() == 0)
+ continue;
+ AclPolicyPermission perm = perms.get(0); // just pick one
+ if (curPerm == null) {
+ curPerm = perm;
+ } else if (PermissionScope.valueOf(perm.getScope()).greaterThan(PermissionScope.valueOf(curPerm.getScope()))) {
+ // pick the more relaxed allowed permission
+ curPerm = perm;
+ }
+ }
+
+ return curPerm;
+ }
+
+
+ @Override
+ public AclPolicyResponse createAclPolicyResponse(AclPolicy policy) {
+ AclPolicyResponse response = new AclPolicyResponse();
+ response.setId(policy.getUuid());
+ response.setName(policy.getName());
+ response.setDescription(policy.getDescription());
+ String domainPath = policy.getPath();
+ if (domainPath != null) {
+ DomainVO domain = _domainDao.findDomainByPath(domainPath);
+ if (domain != null) {
+ response.setDomainId(domain.getUuid());
+ response.setDomainName(domain.getName());
+ }
+ }
+ long accountId = policy.getAccountId();
+ AccountVO owner = _accountDao.findById(accountId);
+ if (owner != null) {
+ response.setAccountName(owner.getAccountName());
+ }
+ // find permissions associated with this policy
+ List<AclPolicyPermission> permissions = _iamSrv.listPolicyPermissions(policy.getId());
+ if (permissions != null && permissions.size() > 0) {
+ for (AclPolicyPermission permission : permissions) {
+ AclPermissionResponse perm = new AclPermissionResponse();
+ perm.setAction(permission.getAction());
+ if (permission.getEntityType() != null) {
+ perm.setEntityType(IAMEntityType.valueOf(permission.getEntityType()));
+ }
+ if (permission.getScope() != null) {
+ perm.setScope(PermissionScope.valueOf(permission.getScope()));
+ }
+ perm.setScopeId(permission.getScopeId());
+ perm.setPermission(permission.getPermission());
+ response.addPermission(perm);
+ }
+ }
+ response.setObjectName("aclpolicy");
+ return response;
+ }
+
+ @Override
+ public AclGroupResponse createAclGroupResponse(AclGroup group) {
+ AclGroupResponse response = new AclGroupResponse();
+ response.setId(group.getUuid());
+ response.setName(group.getName());
+ response.setDescription(group.getDescription());
+ String domainPath = group.getPath();
+ if (domainPath != null) {
+ DomainVO domain = _domainDao.findDomainByPath(domainPath);
+ if (domain != null) {
+ response.setDomainId(domain.getUuid());
+ response.setDomainName(domain.getName());
+ }
+ }
+ long accountId = group.getAccountId();
+ AccountVO owner = _accountDao.findById(accountId);
+ if (owner != null) {
+ response.setAccountName(owner.getAccountName());
+ }
+ // find all the members in this group
+ List<Long> members = _iamSrv.listAccountsByGroup(group.getId());
+ if (members != null && members.size() > 0) {
+ for (Long member : members) {
+ AccountVO mem = _accountDao.findById(member);
+ if (mem != null) {
+ response.addMemberAccount(mem.getAccountName());
+ }
+ }
+ }
+
+ // find all the policies attached to this group
+ List<AclPolicy> policies = _iamSrv.listAclPoliciesByGroup(group.getId());
+ if (policies != null && policies.size() > 0) {
+ for (AclPolicy policy : policies) {
+ response.addPolicy(policy.getName());
+ }
+ }
+
+ response.setObjectName("aclgroup");
+ return response;
+
+ }
+
+ public List<AclGroup> listDomainGroup(Domain domain) {
+
+ if (domain != null) {
+ String domainPath = domain.getPath();
+ // search for groups
+ Pair<List<AclGroup>, Integer> result = _iamSrv.listAclGroups(null, "DomainGrp-" + domain.getUuid(),
+ domainPath, null, null);
+ return result.first();
+ }
+ return new ArrayList<AclGroup>();
+
+ }
+
+ @Override
+ public ListResponse<AclGroupResponse> listAclGroups(Long aclGroupId, String aclGroupName, Long domainId, Long startIndex, Long pageSize) {
+ // acl check
+ Account caller = CallContext.current().getCallingAccount();
+
+ Domain domain = null;
+ if (domainId != null) {
+ domain = _domainDao.findById(domainId);
+ if (domain == null) {
+ throw new InvalidParameterValueException("Domain id=" + domainId + " doesn't exist");
+ }
+
+ _accountMgr.checkAccess(caller, domain);
+ } else {
+ domain = _domainDao.findById(caller.getDomainId());
+ }
+ String domainPath = domain.getPath();
+ // search for groups
+ Pair<List<AclGroup>, Integer> result = _iamSrv.listAclGroups(aclGroupId, aclGroupName, domainPath, startIndex, pageSize);
+ // generate group response
+ ListResponse<AclGroupResponse> response = new ListResponse<AclGroupResponse>();
+ List<AclGroupResponse> groupResponses = new ArrayList<AclGroupResponse>();
+ for (AclGroup group : result.first()) {
+ AclGroupResponse resp = createAclGroupResponse(group);
+ groupResponses.add(resp);
+ }
+ response.setResponses(groupResponses, result.second());
+ return response;
+ }
+
+ @Override
+ public ListResponse<AclPolicyResponse> listAclPolicies(Long aclPolicyId, String aclPolicyName, Long domainId, Long startIndex,
+ Long pageSize) {
+ // acl check
+ Account caller = CallContext.current().getCallingAccount();
+
+ Domain domain = null;
+ if (domainId != null) {
+ domain = _domainDao.findById(domainId);
+ if (domain == null) {
+ throw new InvalidParameterValueException("Domain id=" + domainId + " doesn't exist");
+ }
+
+ _accountMgr.checkAccess(caller, domain);
+ } else {
+ domain = _domainDao.findById(caller.getDomainId());
+ }
+ String domainPath = domain.getPath();
+ // search for policies
+ Pair<List<AclPolicy>, Integer> result = _iamSrv.listAclPolicies(aclPolicyId, aclPolicyName, domainPath, startIndex, pageSize);
+ // generate policy response
+ ListResponse<AclPolicyResponse> response = new ListResponse<AclPolicyResponse>();
+ List<AclPolicyResponse> policyResponses = new ArrayList<AclPolicyResponse>();
+ for (AclPolicy policy : result.first()) {
+ AclPolicyResponse resp = createAclPolicyResponse(policy);
+ policyResponses.add(resp);
+ }
+ response.setResponses(policyResponses, result.second());
+ return response;
+ }
+
+ @Override
+ public void grantEntityPermissioinToAccounts(String entityType, Long entityId, AccessType accessType, String action, List<Long> 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, false);
+ }
+ // 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));
+ }
+ }
+ }
+
+ @Override
+ public void revokeEntityPermissioinFromAccounts(String entityType, Long entityId, AccessType accessType, String action, List<Long> accountIds) {
+ // there should already a policy with only this permission added to it, this call is mainly used
+ AclPolicy policy = _iamSrv.getResourceGrantPolicy(entityType, entityId, accessType.toString(), action);
+ if (policy == null) {
+ s_logger.warn("Cannot find a policy associated with this entity permissioin to be revoked, just return");
+ return;
+ }
+ // detach this policy from list of accounts if not detached already
+ Long policyId = policy.getId();
+ for (Long acctId : accountIds) {
+ if (isPolicyAttachedToAccount(policyId, acctId)) {
+ removeAclPolicyFromAccounts(policyId, Collections.singletonList(acctId));
+ }
+ }
+
+ }
+
+ private boolean isPolicyAttachedToAccount(Long policyId, Long accountId) {
+ List<AclPolicy> pList = listAclPolicies(accountId);
+ for (AclPolicy p : pList) {
+ if (p.getId() == policyId.longValue()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void resetTemplatePermission(Long templateId){
+ // reset template will change template to private, so we need to remove its permission for domain admin and normal user group
+ _iamSrv.removeAclPermissionFromAclPolicy(new Long(Account.ACCOUNT_TYPE_DOMAIN_ADMIN + 1), IAMEntityType.VirtualMachineTemplate.toString(),
+ PermissionScope.RESOURCE.toString(), templateId, "listTemplates");
+ _iamSrv.removeAclPermissionFromAclPolicy(new Long(Account.ACCOUNT_TYPE_NORMAL + 1), IAMEntityType.VirtualMachineTemplate.toString(),
+ PermissionScope.RESOURCE.toString(), templateId, "listTemplates");
+ // check if there is a policy with only UseEntry permission for this template added
+ AclPolicy policy = _iamSrv.getResourceGrantPolicy(IAMEntityType.VirtualMachineTemplate.toString(), templateId, AccessType.UseEntry.toString(), "listTemplates");
+ if ( policy == null ){
+ s_logger.info("No policy found for this template grant: " + templateId + ", no detach to be done");
+ return;
+ }
+ // delete the policy, which should detach it from groups and accounts
+ _iamSrv.deleteAclPolicy(policy.getId());
+
+ }
+
+ @Override
+ public List<Class<?>> getCommands() {
+ List<Class<?>> cmdList = new ArrayList<Class<?>>();
+ cmdList.add(CreateAclPolicyCmd.class);
+ cmdList.add(DeleteAclPolicyCmd.class);
+ cmdList.add(ListAclPoliciesCmd.class);
+ cmdList.add(AddAclPermissionToAclPolicyCmd.class);
+ cmdList.add(RemoveAclPermissionFromAclPolicyCmd.class);
+ cmdList.add(AttachAclPolicyToAclGroupCmd.class);
+ cmdList.add(RemoveAclPolicyFromAclGroupCmd.class);
+ cmdList.add(CreateAclGroupCmd.class);
+ cmdList.add(DeleteAclGroupCmd.class);
+ cmdList.add(ListAclGroupsCmd.class);
+ cmdList.add(AddAccountToAclGroupCmd.class);
+ cmdList.add(RemoveAccountFromAclGroupCmd.class);
+ cmdList.add(AttachAclPolicyToAccountCmd.class);
+ cmdList.add(RemoveAclPolicyFromAccountCmd.class);
+ return cmdList;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b2ba6c05/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java
----------------------------------------------------------------------
diff --git a/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java
new file mode 100644
index 0000000..448e45f
--- /dev/null
+++ b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java
@@ -0,0 +1,273 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.iam;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.APIChecker;
+import org.apache.cloudstack.acl.IAMEntityType;
+import org.apache.cloudstack.acl.PermissionScope;
+import org.apache.cloudstack.acl.RoleType;
+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;
+
+import com.cloud.api.ApiServerService;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountService;
+import com.cloud.user.User;
+import com.cloud.utils.PropertiesUtil;
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.utils.component.PluggableService;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+//This is the Role Based API access checker that grab's the account's roles
+//based on the set of roles, access is granted if any of the role has access to the api
+@Local(value=APIChecker.class)
+public class RoleBasedAPIAccessChecker extends AdapterBase implements APIChecker {
+
+ protected static final Logger s_logger = Logger.getLogger(RoleBasedAPIAccessChecker.class);
+
+ @Inject
+ AccountService _accountService;
+ @Inject
+ ApiServerService _apiServer;
+ @Inject
+ IAMService _iamSrv;
+ @Inject
+ VMTemplateDao _templateDao;
+
+ Set<String> commandsPropertiesOverrides = new HashSet<String>();
+ Map<RoleType, Set<String>> commandsPropertiesRoleBasedApisMap = new HashMap<RoleType, Set<String>>();
+
+ List<PluggableService> _services;
+
+ protected RoleBasedAPIAccessChecker() {
+ super();
+ for (RoleType roleType : RoleType.values()) {
+ commandsPropertiesRoleBasedApisMap.put(roleType, new HashSet<String>());
+ }
+ }
+
+ @Override
+ public boolean checkAccess(User user, String commandName) throws PermissionDeniedException {
+ Account account = _accountService.getAccount(user.getAccountId());
+ if (account == null) {
+ throw new PermissionDeniedException("The account id=" + user.getAccountId() + "for user id=" + user.getId()
+ + "is null");
+ }
+
+ List<AclPolicy> policies = _iamSrv.listAclPolicies(account.getAccountId());
+
+ boolean isAllowed = _iamSrv.isActionAllowedForPolicies(commandName, policies);
+ if (!isAllowed) {
+ throw new PermissionDeniedException("The API does not exist or is blacklisted. api: " + commandName);
+ }
+ return isAllowed;
+ }
+
+ @Override
+ public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+ super.configure(name, params);
+
+ processMapping(PropertiesUtil.processConfigFile(new String[] { "commands.properties" }));
+ return true;
+ }
+
+ @Override
+ public boolean start() {
+
+ // drop all default policy api permissions - we reload them every time
+ // to include any changes done to the @APICommand or
+ // commands.properties.
+
+ for (RoleType role : RoleType.values()) {
+ Long policyId = getDefaultPolicyId(role);
+ if (policyId != null) {
+ _iamSrv.resetAclPolicy(policyId);
+ }
+ }
+
+ // add the system-domain capability
+
+ _iamSrv.addAclPermissionToAclPolicy(new Long(Account.ACCOUNT_TYPE_ADMIN + 1), null, null, null,
+ "SystemCapability", null, Permission.Allow, false);
+ _iamSrv.addAclPermissionToAclPolicy(new Long(Account.ACCOUNT_TYPE_DOMAIN_ADMIN + 1), null, null, null,
+ "DomainCapability", null, Permission.Allow, false);
+ _iamSrv.addAclPermissionToAclPolicy(new Long(Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN + 1), null, null, null,
+ "DomainResourceCapability", null, Permission.Allow, false);
+
+ // add permissions for public templates
+ List<VMTemplateVO> pTmplts = _templateDao.listByPublic();
+ for (VMTemplateVO tmpl : pTmplts){
+ _iamSrv.addAclPermissionToAclPolicy(new Long(Account.ACCOUNT_TYPE_DOMAIN_ADMIN + 1), IAMEntityType.VirtualMachineTemplate.toString(),
+ PermissionScope.RESOURCE.toString(), tmpl.getId(), "listTemplates", AccessType.UseEntry.toString(), Permission.Allow, false);
+ _iamSrv.addAclPermissionToAclPolicy(new Long(Account.ACCOUNT_TYPE_NORMAL + 1), IAMEntityType.VirtualMachineTemplate.toString(),
+ PermissionScope.RESOURCE.toString(), tmpl.getId(), "listTemplates", AccessType.UseEntry.toString(), Permission.Allow, false);
+ }
+
+ for (PluggableService service : _services) {
+ for (Class<?> cmdClass : service.getCommands()) {
+ APICommand command = cmdClass.getAnnotation(APICommand.class);
+ if (!commandsPropertiesOverrides.contains(command.name())) {
+ for (RoleType role : command.authorized()) {
+ addDefaultAclPolicyPermission(command.name(), cmdClass, role);
+ }
+ }
+ }
+ }
+
+ // read commands.properties and load api acl permissions -
+ // commands.properties overrides any @APICommand authorization
+
+ for (String apiName : commandsPropertiesOverrides) {
+ Class<?> cmdClass = _apiServer.getCmdClass(apiName);
+ for (RoleType role : RoleType.values()) {
+ if (commandsPropertiesRoleBasedApisMap.get(role).contains(apiName)) {
+ // insert permission for this role for this api
+ addDefaultAclPolicyPermission(apiName, cmdClass, role);
+ }
+ }
+ }
+
+ return super.start();
+ }
+
+ private Long getDefaultPolicyId(RoleType role) {
+ Long policyId = null;
+ switch (role) {
+ case User:
+ policyId = new Long(Account.ACCOUNT_TYPE_NORMAL + 1);
+ break;
+
+ case Admin:
+ policyId = new Long(Account.ACCOUNT_TYPE_ADMIN + 1);
+ break;
+
+ case DomainAdmin:
+ policyId = new Long(Account.ACCOUNT_TYPE_DOMAIN_ADMIN + 1);
+ break;
+
+ case ResourceAdmin:
+ policyId = new Long(Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN + 1);
+ break;
+ }
+
+ return policyId;
+ }
+
+ private void processMapping(Map<String, String> configMap) {
+ for (Map.Entry<String, String> entry : configMap.entrySet()) {
+ String apiName = entry.getKey();
+ String roleMask = entry.getValue();
+ commandsPropertiesOverrides.add(apiName);
+ try {
+ short cmdPermissions = Short.parseShort(roleMask);
+ for (RoleType roleType : RoleType.values()) {
+ if ((cmdPermissions & roleType.getValue()) != 0)
+ commandsPropertiesRoleBasedApisMap.get(roleType).add(apiName);
+ }
+ } catch (NumberFormatException nfe) {
+ s_logger.info("Malformed key=value pair for entry: " + entry.toString());
+ }
+ }
+ }
+
+ public List<PluggableService> getServices() {
+ return _services;
+ }
+
+ @Inject
+ public void setServices(List<PluggableService> services) {
+ _services = services;
+ }
+
+ private void addDefaultAclPolicyPermission(String apiName, Class<?> cmdClass, RoleType role) {
+
+ AccessType accessType = null;
+ IAMEntityType[] entityTypes = null;
+ if (cmdClass != null) {
+ BaseCmd cmdObj;
+ try {
+ cmdObj = (BaseCmd) cmdClass.newInstance();
+ if (cmdObj instanceof BaseListCmd) {
+ accessType = AccessType.UseEntry;
+ } else if (!(cmdObj instanceof BaseAsyncCreateCmd)) {
+ accessType = AccessType.OperateEntry;
+ }
+ } catch (Exception e) {
+ throw new CloudRuntimeException(String.format(
+ "%s is claimed as an API command, but it cannot be instantiated", cmdClass.getName()));
+ }
+
+ APICommand at = cmdClass.getAnnotation(APICommand.class);
+ entityTypes = at.entityType();
+ }
+
+ PermissionScope permissionScope = PermissionScope.ACCOUNT;
+ Long policyId = getDefaultPolicyId(role);
+ switch (role) {
+ case User:
+ permissionScope = PermissionScope.ACCOUNT;
+ break;
+
+ case Admin:
+ permissionScope = PermissionScope.ALL;
+ break;
+
+ case DomainAdmin:
+ permissionScope = PermissionScope.DOMAIN;
+ break;
+
+ case ResourceAdmin:
+ permissionScope = PermissionScope.DOMAIN;
+ break;
+ }
+
+
+ if (entityTypes == null || entityTypes.length == 0) {
+ _iamSrv.addAclPermissionToAclPolicy(policyId, null, permissionScope.toString(), new Long(AclPolicyPermission.PERMISSION_SCOPE_ID_CURRENT_CALLER),
+ apiName, (accessType == null) ? null : accessType.toString(), Permission.Allow, false);
+ } else {
+ for (IAMEntityType entityType : entityTypes) {
+ _iamSrv.addAclPermissionToAclPolicy(policyId, entityType.toString(), permissionScope.toString(), new Long(AclPolicyPermission.PERMISSION_SCOPE_ID_CURRENT_CALLER),
+ apiName, (accessType == null) ? null : accessType.toString(), Permission.Allow, false);
+ }
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b2ba6c05/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedEntityAccessChecker.java
----------------------------------------------------------------------
diff --git a/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedEntityAccessChecker.java b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedEntityAccessChecker.java
new file mode 100644
index 0000000..5420f84
--- /dev/null
+++ b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedEntityAccessChecker.java
@@ -0,0 +1,186 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.iam;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.acl.PermissionScope;
+import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.api.InternalIdentity;
+import org.apache.cloudstack.iam.api.AclGroup;
+import org.apache.cloudstack.iam.api.AclPolicy;
+import org.apache.cloudstack.iam.api.AclPolicyPermission;
+import org.apache.cloudstack.iam.api.IAMService;
+
+import com.cloud.acl.DomainChecker;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.user.Account;
+import com.cloud.user.AccountService;
+
+public class RoleBasedEntityAccessChecker extends DomainChecker implements SecurityChecker {
+
+ private static final Logger s_logger = Logger.getLogger(RoleBasedEntityAccessChecker.class.getName());
+
+ @Inject
+ AccountService _accountService;
+
+ @Inject DomainDao _domainDao;
+
+ @Inject
+ IAMService _iamSrv;
+
+
+ @Override
+ public boolean checkAccess(Account caller, ControlledEntity entity, AccessType accessType)
+ throws PermissionDeniedException {
+ return checkAccess(caller, entity, accessType, null);
+ }
+
+ @Override
+ public boolean checkAccess(Account caller, ControlledEntity entity, AccessType accessType, String action)
+ throws PermissionDeniedException {
+
+ if (entity == null && action != null) {
+ // check if caller can do this action
+ List<AclPolicy> policies = _iamSrv.listAclPolicies(caller.getAccountId());
+
+ boolean isAllowed = _iamSrv.isActionAllowedForPolicies(action, policies);
+ if (!isAllowed) {
+ throw new PermissionDeniedException("The action '" + action + "' not allowed for account " + caller);
+ }
+ return true;
+ }
+
+ String entityType = entity.getEntityType().toString();
+
+ if (accessType == null) {
+ accessType = AccessType.UseEntry;
+ }
+
+ // get all Policies of this caller w.r.t the entity
+ List<AclPolicy> policies = getEffectivePolicies(caller, entity);
+ HashMap<AclPolicy, Boolean> policyPermissionMap = new HashMap<AclPolicy, Boolean>();
+
+ for (AclPolicy policy : policies) {
+ List<AclPolicyPermission> permissions = new ArrayList<AclPolicyPermission>();
+
+ if (action != null) {
+ permissions = _iamSrv.listPolicyPermissionByActionAndEntity(policy.getId(), action, entityType);
+ if (permissions.isEmpty()) {
+ if (accessType != null) {
+ permissions.addAll(_iamSrv.listPolicyPermissionByAccessAndEntity(policy.getId(),
+ accessType.toString(), entityType));
+ }
+ }
+ } else {
+ if (accessType != null) {
+ permissions.addAll(_iamSrv.listPolicyPermissionByAccessAndEntity(policy.getId(),
+ accessType.toString(), entityType));
+ }
+ }
+ for (AclPolicyPermission permission : permissions) {
+ if (checkPermissionScope(caller, permission.getScope(), permission.getScopeId(), entity)) {
+ if (permission.getEntityType().equals(entityType)) {
+ policyPermissionMap.put(policy, permission.getPermission().isGranted());
+ break;
+ } else if (permission.getEntityType().equals("*")) {
+ policyPermissionMap.put(policy, permission.getPermission().isGranted());
+ }
+ }
+ }
+ if (policyPermissionMap.containsKey(policy) && policyPermissionMap.get(policy)) {
+ return true;
+ }
+ }
+
+ if (!policies.isEmpty()) { // Since we reach this point, none of the
+ // roles granted access
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Account " + caller + " does not have permission to access resource " + entity
+ + " for access type: " + accessType);
+ }
+ throw new PermissionDeniedException(caller + " does not have permission to access resource " + entity);
+ }
+
+ return false;
+ }
+
+ private boolean checkPermissionScope(Account caller, String scope, Long scopeId, ControlledEntity entity) {
+
+ 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 (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;
+ }
+
+ private List<AclPolicy> getEffectivePolicies(Account caller, ControlledEntity entity) {
+
+ // Get the static Policies of the Caller
+ List<AclPolicy> policies = _iamSrv.listAclPolicies(caller.getId());
+
+ // add any dynamic policies w.r.t the entity
+ if (caller.getId() == entity.getAccountId()) {
+ // The caller owns the entity
+ policies.add(_iamSrv.getResourceOwnerPolicy());
+ }
+
+ List<AclGroup> groups = _iamSrv.listAclGroups(caller.getId());
+ for (AclGroup group : groups) {
+ // for each group find the grand parent groups.
+ List<AclGroup> parentGroups = _iamSrv.listParentAclGroups(group.getId());
+ for (AclGroup parentGroup : parentGroups) {
+ policies.addAll(_iamSrv.listRecursiveAclPoliciesByGroup(parentGroup.getId()));
+ }
+ }
+
+ return policies;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b2ba6c05/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedEntityQuerySelector.java
----------------------------------------------------------------------
diff --git a/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedEntityQuerySelector.java b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedEntityQuerySelector.java
new file mode 100644
index 0000000..4cec0d9
--- /dev/null
+++ b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedEntityQuerySelector.java
@@ -0,0 +1,147 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.iam;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.PermissionScope;
+import org.apache.cloudstack.acl.QuerySelector;
+import org.apache.cloudstack.iam.api.AclGroup;
+import org.apache.cloudstack.iam.api.AclPolicy;
+import org.apache.cloudstack.iam.api.AclPolicyPermission;
+import org.apache.cloudstack.iam.api.IAMService;
+
+import com.cloud.user.Account;
+import com.cloud.utils.component.AdapterBase;
+
+public class RoleBasedEntityQuerySelector extends AdapterBase implements QuerySelector {
+
+ private static final Logger s_logger = Logger.getLogger(RoleBasedEntityQuerySelector.class.getName());
+
+ @Inject
+ IAMService _iamService;
+
+ @Override
+ public List<Long> getAuthorizedDomains(Account caller, String action) {
+ long accountId = caller.getAccountId();
+ // Get the static Policies of the Caller
+ List<AclPolicy> policies = _iamService.listAclPolicies(accountId);
+ // for each policy, find granted permission with Domain scope
+ List<Long> domainIds = new ArrayList<Long>();
+ for (AclPolicy policy : policies) {
+ List<AclPolicyPermission> pp = _iamService.listPolicyPermissionsByScope(policy.getId(), action, PermissionScope.DOMAIN.toString());
+ if (pp != null) {
+ for (AclPolicyPermission p : pp) {
+ if (p.getScopeId() != null) {
+ if (p.getScopeId().longValue() == -1) {
+ domainIds.add(caller.getDomainId());
+ } else {
+ domainIds.add(p.getScopeId());
+ }
+ }
+ }
+ }
+ }
+ return domainIds;
+ }
+
+ @Override
+ public List<Long> getAuthorizedAccounts(Account caller, String action) {
+ long accountId = caller.getAccountId();
+ // Get the static Policies of the Caller
+ List<AclPolicy> policies = _iamService.listAclPolicies(accountId);
+ // for each policy, find granted permission with Account scope
+ List<Long> accountIds = new ArrayList<Long>();
+ for (AclPolicy policy : policies) {
+ List<AclPolicyPermission> pp = _iamService.listPolicyPermissionsByScope(policy.getId(), action, PermissionScope.ACCOUNT.toString());
+ if (pp != null) {
+ for (AclPolicyPermission p : pp) {
+ if (p.getScopeId() != null) {
+ if (p.getScopeId().longValue() == -1) {
+ accountIds.add(caller.getId());
+ } else {
+ accountIds.add(p.getScopeId());
+ }
+ }
+ }
+ }
+ }
+ return accountIds;
+ }
+
+ @Override
+ public List<Long> getAuthorizedResources(Account caller, String action) {
+ long accountId = caller.getAccountId();
+ // Get the static Policies of the Caller
+ List<AclPolicy> policies = _iamService.listAclPolicies(accountId);
+
+ // add the policies that grant recursive access
+ List<AclGroup> groups = _iamService.listAclGroups(caller.getId());
+ for (AclGroup group : groups) {
+ // for each group find the grand parent groups.
+ List<AclGroup> parentGroups = _iamService.listParentAclGroups(group.getId());
+ for (AclGroup parentGroup : parentGroups) {
+ policies.addAll(_iamService.listRecursiveAclPoliciesByGroup(parentGroup.getId()));
+ }
+ }
+
+ // for each policy, find granted permission with Resource scope
+ List<Long> entityIds = new ArrayList<Long>();
+ for (AclPolicy policy : policies) {
+ List<AclPolicyPermission> pp = _iamService.listPolicyPermissionsByScope(policy.getId(), action, PermissionScope.RESOURCE.toString());
+ if (pp != null) {
+ for (AclPolicyPermission p : pp) {
+ if (p.getScopeId() != null) {
+ entityIds.add(p.getScopeId());
+ }
+ }
+ }
+ }
+ return entityIds;
+ }
+
+ @Override
+ public boolean isGrantedAll(Account caller, String action) {
+ long accountId = caller.getAccountId();
+ // Get the static Policies of the Caller
+ List<AclPolicy> policies = _iamService.listAclPolicies(accountId);
+ // for each policy, find granted permission with ALL scope
+ for (AclPolicy policy : policies) {
+ List<AclPolicyPermission> pp = _iamService.listPolicyPermissionsByScope(policy.getId(), action, PermissionScope.ALL.toString());
+ if (pp != null && pp.size() > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public List<String> listAclGroupsByAccount(long accountId) {
+ List<AclGroup> groups = _iamService.listAclGroups(accountId);
+ List<String> groupNames = new ArrayList<String>();
+ for (AclGroup grp : groups) {
+ groupNames.add(grp.getName());
+ }
+ return groupNames;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b2ba6c05/services/iam/plugin/test/org/apache/cloudstack/acl/AclApiServiceTest.java
----------------------------------------------------------------------
diff --git a/services/iam/plugin/test/org/apache/cloudstack/acl/AclApiServiceTest.java b/services/iam/plugin/test/org/apache/cloudstack/acl/AclApiServiceTest.java
index 02b7331..daf5b64 100644
--- a/services/iam/plugin/test/org/apache/cloudstack/acl/AclApiServiceTest.java
+++ b/services/iam/plugin/test/org/apache/cloudstack/acl/AclApiServiceTest.java
@@ -35,13 +35,13 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
-import org.apache.cloudstack.acl.api.AclApiService;
-import org.apache.cloudstack.acl.api.AclApiServiceImpl;
+import org.apache.cloudstack.iam.AclApiService;
+import org.apache.cloudstack.iam.AclApiServiceImpl;
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
import org.apache.cloudstack.api.response.ListResponse;
-import org.apache.cloudstack.api.response.acl.AclGroupResponse;
-import org.apache.cloudstack.api.response.acl.AclPermissionResponse;
-import org.apache.cloudstack.api.response.acl.AclPolicyResponse;
+import org.apache.cloudstack.api.response.iam.AclGroupResponse;
+import org.apache.cloudstack.api.response.iam.AclPermissionResponse;
+import org.apache.cloudstack.api.response.iam.AclPolicyResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.iam.api.AclGroup;
@@ -273,12 +273,12 @@ public class AclApiServiceTest {
Class clz = ListVMsCmd.class;
when(_apiServer.getCmdClass("listVirtualMachines")).thenReturn(clz);
when(
- _iamSrv.addAclPermissionToAclPolicy(policyId, AclEntityType.VirtualMachine.toString(), PermissionScope.RESOURCE.toString(), resId, "listVirtualMachines",
+ _iamSrv.addAclPermissionToAclPolicy(policyId, IAMEntityType.VirtualMachine.toString(), PermissionScope.RESOURCE.toString(), resId, "listVirtualMachines",
AccessType.UseEntry.toString(), Permission.Allow, false)).thenReturn(policy);
- _aclSrv.addAclPermissionToAclPolicy(policyId, AclEntityType.VirtualMachine.toString(), PermissionScope.RESOURCE, resId, "listVirtualMachines", Permission.Allow, false);
+ _aclSrv.addAclPermissionToAclPolicy(policyId, IAMEntityType.VirtualMachine.toString(), PermissionScope.RESOURCE, resId, "listVirtualMachines", Permission.Allow, false);
Pair<List<AclPolicy>, Integer> policyList = new Pair<List<AclPolicy>, Integer>(policies, 1);
List<AclPolicyPermission> policyPerms = new ArrayList<AclPolicyPermission>();
- AclPolicyPermission perm = new AclPolicyPermissionVO(policyId, "listVirtualMachines", AclEntityType.VirtualMachine.toString(), AccessType.UseEntry.toString(),
+ AclPolicyPermission perm = new AclPolicyPermissionVO(policyId, "listVirtualMachines", IAMEntityType.VirtualMachine.toString(), AccessType.UseEntry.toString(),
PermissionScope.RESOURCE.toString(),
resId, Permission.Allow, false);
policyPerms.add(perm);
@@ -294,7 +294,7 @@ public class AclApiServiceTest {
//remove permission from policy
policyPerms.remove(perm);
- _aclSrv.removeAclPermissionFromAclPolicy(policyId, AclEntityType.VirtualMachine.toString(), PermissionScope.RESOURCE, resId, "listVirtualMachines");
+ _aclSrv.removeAclPermissionFromAclPolicy(policyId, IAMEntityType.VirtualMachine.toString(), PermissionScope.RESOURCE, resId, "listVirtualMachines");
policyResp = _aclSrv.listAclPolicies(null, "policy1", callerDomainId, 0L, 20L);
assertTrue("No. of response items should be one", policyResp.getCount() == 1);
resp = policyResp.getResponses().get(0);