blob: b0dc3839ade9160339b142ea9f548149faf821ca [file] [log] [blame]
// 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.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import org.bouncycastle.util.IPAddress;
import com.amazonaws.auth.policy.Condition;
import com.amazonaws.services.ec2.model.SecurityGroup;
import com.amazonaws.services.ec2.model.Snapshot;
import com.amazonaws.services.ec2.model.Volume;
import com.amazonaws.services.ec2.model.Vpc;
import com.amazonaws.services.elasticache.model.Event;
import org.apache.cloudstack.acl.PermissionScope;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.InternalIdentity;
import org.apache.cloudstack.api.command.iam.AddAccountToIAMGroupCmd;
import org.apache.cloudstack.api.command.iam.AddIAMPermissionToIAMPolicyCmd;
import org.apache.cloudstack.api.command.iam.AttachIAMPolicyToAccountCmd;
import org.apache.cloudstack.api.command.iam.AttachIAMPolicyToIAMGroupCmd;
import org.apache.cloudstack.api.command.iam.CreateIAMGroupCmd;
import org.apache.cloudstack.api.command.iam.CreateIAMPolicyCmd;
import org.apache.cloudstack.api.command.iam.DeleteIAMGroupCmd;
import org.apache.cloudstack.api.command.iam.DeleteIAMPolicyCmd;
import org.apache.cloudstack.api.command.iam.ListIAMGroupsCmd;
import org.apache.cloudstack.api.command.iam.ListIAMPoliciesCmd;
import org.apache.cloudstack.api.command.iam.RemoveAccountFromIAMGroupCmd;
import org.apache.cloudstack.api.command.iam.RemoveIAMPermissionFromIAMPolicyCmd;
import org.apache.cloudstack.api.command.iam.RemoveIAMPolicyFromAccountCmd;
import org.apache.cloudstack.api.command.iam.RemoveIAMPolicyFromIAMGroupCmd;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.iam.IAMGroupResponse;
import org.apache.cloudstack.api.response.iam.IAMPermissionResponse;
import org.apache.cloudstack.api.response.iam.IAMPolicyResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.jobs.AsyncJob;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.framework.messagebus.MessageSubscriber;
import org.apache.cloudstack.iam.api.IAMGroup;
import org.apache.cloudstack.iam.api.IAMPolicy;
import org.apache.cloudstack.iam.api.IAMPolicyPermission;
import org.apache.cloudstack.iam.api.IAMPolicyPermission.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.network.IpAddress;
import com.cloud.network.MonitoringService;
import com.cloud.network.Network;
import com.cloud.network.RemoteAccessVpn;
import com.cloud.network.Site2SiteCustomerGateway;
import com.cloud.network.Site2SiteVpnConnection;
import com.cloud.network.Site2SiteVpnGateway;
import com.cloud.network.UserIpv6Address;
import com.cloud.network.VpnUser;
import com.cloud.network.as.AutoScalePolicy;
import com.cloud.network.as.AutoScaleVmGroup;
import com.cloud.network.as.AutoScaleVmProfile;
import com.cloud.network.lb.SslCert;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.PortForwardingRule;
import com.cloud.network.vpc.StaticRoute;
import com.cloud.network.vpc.VpcGateway;
import com.cloud.projects.ProjectInvitation;
import com.cloud.region.ha.GlobalLoadBalancerRule;
import com.cloud.server.ResourceTag;
import com.cloud.template.TemplateManager;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.DomainManager;
import com.cloud.user.SSHKeyPair;
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;
import com.cloud.vm.InstanceGroup;
import com.cloud.vm.NicIpAlias;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.snapshot.VMSnapshot;
public class IAMApiServiceImpl extends ManagerBase implements IAMApiService, Manager {
public static final Logger s_logger = Logger.getLogger(IAMApiServiceImpl.class);
private String _name;
@Inject
ApiServerService _apiServer;
@Inject
IAMService _iamSrv;
@Inject
DomainDao _domainDao;
@Inject
AccountDao _accountDao;
@Inject
AccountManager _accountMgr;
@Inject
MessageBus _messageBus;
@Inject
EntityManager _entityMgr;
private static final Map<String, Class<?>> s_typeMap = new HashMap<String, Class<?>>();
static {
s_typeMap.put(VirtualMachine.class.getSimpleName(), VirtualMachine.class);
s_typeMap.put(Volume.class.getSimpleName(), Volume.class);
s_typeMap.put(ResourceTag.class.getSimpleName(), ResourceTag.class);
s_typeMap.put(Account.class.getSimpleName(), Account.class);
s_typeMap.put(AffinityGroup.class.getSimpleName(), AffinityGroup.class);
s_typeMap.put(AutoScalePolicy.class.getSimpleName(), AutoScalePolicy.class);
s_typeMap.put(AutoScaleVmProfile.class.getSimpleName(), AutoScaleVmProfile.class);
s_typeMap.put(AutoScaleVmGroup.class.getSimpleName(), AutoScaleVmGroup.class);
s_typeMap.put(Condition.class.getSimpleName(), Condition.class);
s_typeMap.put(Vpc.class.getSimpleName(), Vpc.class);
s_typeMap.put(VpcGateway.class.getSimpleName(), VpcGateway.class);
s_typeMap.put(VpnUser.class.getSimpleName(), VpnUser.class);
s_typeMap.put(VMSnapshot.class.getSimpleName(), VMSnapshot.class);
s_typeMap.put(VirtualMachineTemplate.class.getSimpleName(), VirtualMachineTemplate.class);
s_typeMap.put(UserIpv6Address.class.getSimpleName(), UserIpv6Address.class);
s_typeMap.put(StaticRoute.class.getSimpleName(), StaticRoute.class);
s_typeMap.put(SSHKeyPair.class.getSimpleName(), SSHKeyPair.class);
s_typeMap.put(Snapshot.class.getSimpleName(), Snapshot.class);
s_typeMap.put(Site2SiteVpnGateway.class.getSimpleName(), Site2SiteVpnGateway.class);
s_typeMap.put(Site2SiteCustomerGateway.class.getSimpleName(), Site2SiteCustomerGateway.class);
s_typeMap.put(Site2SiteVpnConnection.class.getSimpleName(), Site2SiteVpnConnection.class);
s_typeMap.put(SecurityGroup.class.getSimpleName(), SecurityGroup.class);
s_typeMap.put(RemoteAccessVpn.class.getSimpleName(), RemoteAccessVpn.class);
s_typeMap.put(ProjectInvitation.class.getSimpleName(), ProjectInvitation.class);
s_typeMap.put(NicSecondaryIp.class.getSimpleName(), NicSecondaryIp.class);
s_typeMap.put(NicIpAlias.class.getSimpleName(), NicIpAlias.class);
s_typeMap.put(Network.class.getSimpleName(), Network.class);
s_typeMap.put(IpAddress.class.getSimpleName(), IPAddress.class);
s_typeMap.put(InstanceGroup.class.getSimpleName(), InstanceGroup.class);
s_typeMap.put(GlobalLoadBalancerRule.class.getSimpleName(), GlobalLoadBalancerRule.class);
s_typeMap.put(FirewallRule.class.getSimpleName(), FirewallRule.class);
s_typeMap.put(PortForwardingRule.class.getSimpleName(), PortForwardingRule.class);
s_typeMap.put(Event.class.getSimpleName(), Event.class);
s_typeMap.put(AsyncJob.class.getSimpleName(), AsyncJob.class);
s_typeMap.put(IAMGroup.class.getSimpleName(), IAMGroup.class);
s_typeMap.put(IAMPolicy.class.getSimpleName(), IAMPolicy.class);
s_typeMap.put(MonitoringService.class.getSimpleName(), MonitoringService.class);
s_typeMap.put(SslCert.class.getSimpleName(), SslCert.class);
}
@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);
addAccountToIAMGroup(accountId, groupId);
// add it to domain group too
AccountVO account = _accountDao.findById(accountId);
Domain domain = _domainDao.findById(account.getDomainId());
if (domain != null) {
List<IAMGroup> domainGroups = listDomainGroup(domain);
if (domainGroups != null) {
for (IAMGroup group : domainGroups) {
addAccountToIAMGroup(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");
removeAccountFromIAMGroups(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.createIAMGroup("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<IAMGroup> groups = listDomainGroup(domain);
for (IAMGroup group : groups) {
_iamSrv.deleteIAMGroup(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 default root admin, domain admin and normal user policies");
_iamSrv.addIAMPermissionToIAMPolicy(new Long(Account.ACCOUNT_TYPE_ADMIN + 1), VirtualMachineTemplate.class.getSimpleName(),
PermissionScope.RESOURCE.toString(), templateId, "listTemplates", AccessType.UseEntry.toString(), Permission.Allow, false);
_iamSrv.addIAMPermissionToIAMPolicy(new Long(Account.ACCOUNT_TYPE_DOMAIN_ADMIN + 1), VirtualMachineTemplate.class.getSimpleName(),
PermissionScope.RESOURCE.toString(), templateId, "listTemplates", AccessType.UseEntry.toString(), Permission.Allow, false);
_iamSrv.addIAMPermissionToIAMPolicy(new Long(Account.ACCOUNT_TYPE_NORMAL + 1), VirtualMachineTemplate.class.getSimpleName(),
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<Class<?>, Long> entity = (Pair<Class<?>, Long>)obj;
if (entity != null) {
String entityType = entity.first().getSimpleName();
Long entityId = entity.second();
s_logger.debug("MessageBus message: delete an entity: (" + entityType + "," + entityId + "), remove its related permission");
_iamSrv.removeIAMPermissionForEntity(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) {
Class<?> entityType = (Class<?>)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.IAM_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.getSimpleName(), 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) {
Class<?> entityType = (Class<?>)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.IAM_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.getSimpleName(), 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);
}
@Override
public boolean start() {
s_logger.info("Populating IAM group and account association for default accounts...");
// populate group <-> account association if not present for CS admin
// and system accounts
populateIAMGroupAdminAccountMap();
return true;
}
private void populateIAMGroupAdminAccountMap() {
List<Long> sysAccts = new ArrayList<Long>();
sysAccts.add(Account.ACCOUNT_ID_SYSTEM);
sysAccts.add(Account.ACCOUNT_ID_SYSTEM + 1);
_iamSrv.addAccountsToGroup(sysAccts, new Long(Account.ACCOUNT_TYPE_ADMIN + 1));
}
private void addDomainWideResourceAccess(Map<String, Object> params) {
Class<?> entityType = (Class<?>)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 == Network.class) {
createPolicyAndAddToDomainGroup("DomainWideNetwork-" + entityId, "domain wide network", entityType.toString(),
entityId, "listNetworks", AccessType.UseEntry, domainId, isRecursive);
} else if (entityType == AffinityGroup.class) {
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) {
IAMPolicy policy = _iamSrv.createIAMPolicy(policyName, description, null, domain.getPath());
_iamSrv.addIAMPermissionToIAMPolicy(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<IAMGroup> domainGroups = listDomainGroup(domain);
if (domainGroups != null) {
for (IAMGroup group : domainGroups) {
_iamSrv.attachIAMPoliciesToGroup(policyList, group.getId());
}
}
}
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_GROUP_CREATE, eventDescription = "Creating Acl Group", create = true)
public IAMGroup createIAMGroup(Account caller, String iamGroupName, 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.createIAMGroup(iamGroupName, description, callerDomain.getPath());
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_GROUP_DELETE, eventDescription = "Deleting Acl Group")
public boolean deleteIAMGroup(final Long iamGroupId) {
return _iamSrv.deleteIAMGroup(iamGroupId);
}
@Override
public List<IAMGroup> listIAMGroups(long accountId) {
return _iamSrv.listIAMGroups(accountId);
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_GROUP_UPDATE, eventDescription = "Adding accounts to acl group")
public IAMGroup addAccountsToGroup(final List<Long> acctIds, final Long groupId) {
return _iamSrv.addAccountsToGroup(acctIds, groupId);
}
private void removeAccountFromIAMGroups(long accountId) {
List<IAMGroup> groups = listIAMGroups(accountId);
List<Long> accts = new ArrayList<Long>();
accts.add(accountId);
if (groups != null) {
for (IAMGroup grp : groups) {
removeAccountsFromGroup(accts, grp.getId());
}
}
}
private void addAccountToIAMGroup(long accountId, long groupId) {
List<Long> accts = new ArrayList<Long>();
accts.add(accountId);
addAccountsToGroup(accts, groupId);
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_GROUP_UPDATE, eventDescription = "Removing accounts from acl group")
public IAMGroup removeAccountsFromGroup(final List<Long> acctIds, final Long groupId) {
return _iamSrv.removeAccountsFromGroup(acctIds, groupId);
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_POLICY_CREATE, eventDescription = "Creating IAM Policy", create = true)
public IAMPolicy createIAMPolicy(Account caller, final String iamPolicyName, 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.createIAMPolicy(iamPolicyName, description, parentPolicyId, callerDomain.getPath());
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_POLICY_DELETE, eventDescription = "Deleting IAM Policy")
public boolean deleteIAMPolicy(final long iamPolicyId) {
return _iamSrv.deleteIAMPolicy(iamPolicyId);
}
@Override
public List<IAMPolicy> listIAMPolicies(long accountId) {
return _iamSrv.listIAMPolicies(accountId);
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_GROUP_UPDATE, eventDescription = "Attaching policy to acl group")
public IAMGroup attachIAMPoliciesToGroup(final List<Long> policyIds, final Long groupId) {
return _iamSrv.attachIAMPoliciesToGroup(policyIds, groupId);
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_GROUP_UPDATE, eventDescription = "Removing policies from acl group")
public IAMGroup removeIAMPoliciesFromGroup(final List<Long> policyIds, final Long groupId) {
return _iamSrv.removeIAMPoliciesFromGroup(policyIds, groupId);
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_ACCOUNT_POLICY_UPDATE, eventDescription = "Attaching policy to accounts")
public void attachIAMPolicyToAccounts(final Long policyId, final List<Long> accountIds) {
_iamSrv.attachIAMPolicyToAccounts(policyId, accountIds);
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_ACCOUNT_POLICY_UPDATE, eventDescription = "Removing policy from accounts")
public void removeIAMPolicyFromAccounts(final Long policyId, final List<Long> accountIds) {
_iamSrv.removeIAMPolicyFromAccounts(policyId, accountIds);
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_POLICY_GRANT, eventDescription = "Granting acl permission to IAM Policy")
public IAMPolicy addIAMPermissionToIAMPolicy(long iamPolicyId, String entityType, PermissionScope scope,
Long scopeId, String action, Permission perm, Boolean recursive, Boolean readOnly) {
Class<?> cmdClass = _apiServer.getCmdClass(action);
AccessType accessType = null;
if (BaseListCmd.class.isAssignableFrom(cmdClass)) {
if (readOnly) {
accessType = AccessType.ListEntry;
} else {
accessType = AccessType.UseEntry;
}
} else {
accessType = AccessType.OperateEntry;
}
String accessTypeStr = (accessType != null) ? accessType.toString() : null;
return _iamSrv.addIAMPermissionToIAMPolicy(iamPolicyId, entityType, scope.toString(), scopeId, action,
accessTypeStr, perm, recursive);
}
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_IAM_POLICY_REVOKE, eventDescription = "Revoking acl permission from IAM Policy")
public IAMPolicy removeIAMPermissionFromIAMPolicy(long iamPolicyId, String entityType, PermissionScope scope, Long scopeId, String action) {
return _iamSrv.removeIAMPermissionFromIAMPolicy(iamPolicyId, entityType, scope.toString(), scopeId, action);
}
@Override
public IAMPolicyPermission getIAMPolicyPermission(long accountId, String entityType, String action) {
List<IAMPolicy> policies = _iamSrv.listIAMPolicies(accountId);
IAMPolicyPermission curPerm = null;
for (IAMPolicy policy : policies) {
List<IAMPolicyPermission> perms = _iamSrv.listPolicyPermissionByActionAndEntity(policy.getId(), action,
entityType);
if (perms == null || perms.size() == 0)
continue;
IAMPolicyPermission 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 IAMPolicyResponse createIAMPolicyResponse(IAMPolicy policy) {
IAMPolicyResponse response = new IAMPolicyResponse();
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<IAMPolicyPermission> permissions = _iamSrv.listPolicyPermissions(policy.getId());
if (permissions != null && permissions.size() > 0) {
for (IAMPolicyPermission permission : permissions) {
IAMPermissionResponse perm = new IAMPermissionResponse();
perm.setAction(permission.getAction());
if (permission.getEntityType() != null) {
perm.setEntityType(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 IAMGroupResponse createIAMGroupResponse(IAMGroup group) {
IAMGroupResponse response = new IAMGroupResponse();
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<IAMPolicy> policies = _iamSrv.listIAMPoliciesByGroup(group.getId());
if (policies != null && policies.size() > 0) {
for (IAMPolicy policy : policies) {
response.addPolicy(policy.getName());
}
}
response.setObjectName("aclgroup");
return response;
}
public List<IAMGroup> listDomainGroup(Domain domain) {
if (domain != null) {
String domainPath = domain.getPath();
// search for groups
Pair<List<IAMGroup>, Integer> result = _iamSrv.listIAMGroups(null, "DomainGrp-" + domain.getUuid(),
domainPath, null, null);
return result.first();
}
return new ArrayList<IAMGroup>();
}
@Override
public ListResponse<IAMGroupResponse> listIAMGroups(Long iamGroupId, String iamGroupName, 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<IAMGroup>, Integer> result = _iamSrv.listIAMGroups(iamGroupId, iamGroupName, domainPath, startIndex, pageSize);
// generate group response
ListResponse<IAMGroupResponse> response = new ListResponse<IAMGroupResponse>();
List<IAMGroupResponse> groupResponses = new ArrayList<IAMGroupResponse>();
for (IAMGroup group : result.first()) {
IAMGroupResponse resp = createIAMGroupResponse(group);
groupResponses.add(resp);
}
response.setResponses(groupResponses, result.second());
return response;
}
@Override
public ListResponse<IAMPolicyResponse> listIAMPolicies(Long iamPolicyId, String iamPolicyName, 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<IAMPolicy>, Integer> result = _iamSrv.listIAMPolicies(iamPolicyId, iamPolicyName, domainPath, startIndex, pageSize);
// generate policy response
ListResponse<IAMPolicyResponse> response = new ListResponse<IAMPolicyResponse>();
List<IAMPolicyResponse> policyResponses = new ArrayList<IAMPolicyResponse>();
for (IAMPolicy policy : result.first()) {
IAMPolicyResponse resp = createIAMPolicyResponse(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
IAMPolicy 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 = createIAMPolicy(caller, aclPolicyName, description, null);
// add permission to this policy
addIAMPermissionToIAMPolicy(policy.getId(), entityType, PermissionScope.RESOURCE, entityId, action,
Permission.Allow, false, false);
}
// attach this policy to list of accounts if not attached already
Long policyId = policy.getId();
for (Long acctId : accountIds) {
if (!isPolicyAttachedToAccount(policyId, acctId)) {
attachIAMPolicyToAccounts(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
IAMPolicy 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)) {
removeIAMPolicyFromAccounts(policyId, Collections.singletonList(acctId));
}
}
}
private boolean isPolicyAttachedToAccount(Long policyId, Long accountId) {
List<IAMPolicy> pList = listIAMPolicies(accountId);
for (IAMPolicy 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.removeIAMPermissionFromIAMPolicy(new Long(Account.ACCOUNT_TYPE_DOMAIN_ADMIN + 1), VirtualMachineTemplate.class.getSimpleName(),
PermissionScope.RESOURCE.toString(), templateId, "listTemplates");
_iamSrv.removeIAMPermissionFromIAMPolicy(new Long(Account.ACCOUNT_TYPE_NORMAL + 1), VirtualMachineTemplate.class.getSimpleName(),
PermissionScope.RESOURCE.toString(), templateId, "listTemplates");
// check if there is a policy with only UseEntry permission for this template added
IAMPolicy policy = _iamSrv.getResourceGrantPolicy(VirtualMachineTemplate.class.getSimpleName(), 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.deleteIAMPolicy(policy.getId());
}
@Override
public Long getPermissionScopeId(String scope, String entityType, String scopeId) {
if (scopeId.equals("-1")) {
return -1L;
}
PermissionScope permScope = PermissionScope.valueOf(scope);
InternalIdentity entity = null;
switch (permScope) {
case DOMAIN:
entity = _domainDao.findByUuid(scopeId);
break;
case ACCOUNT:
entity = _accountDao.findByUuid(scopeId);
break;
case RESOURCE:
Class<?> clazz = s_typeMap.get(entityType);
entity = (InternalIdentity)_entityMgr.findByUuid(clazz, scopeId);
}
if (entity != null) {
return entity.getId();
}
throw new InvalidParameterValueException("Unable to find scopeId " + scopeId + " with scope " + scope + " and type " + entityType);
}
@Override
public List<Class<?>> getCommands() {
List<Class<?>> cmdList = new ArrayList<Class<?>>();
cmdList.add(CreateIAMPolicyCmd.class);
cmdList.add(DeleteIAMPolicyCmd.class);
cmdList.add(ListIAMPoliciesCmd.class);
cmdList.add(AddIAMPermissionToIAMPolicyCmd.class);
cmdList.add(RemoveIAMPermissionFromIAMPolicyCmd.class);
cmdList.add(AttachIAMPolicyToIAMGroupCmd.class);
cmdList.add(RemoveIAMPolicyFromIAMGroupCmd.class);
cmdList.add(CreateIAMGroupCmd.class);
cmdList.add(DeleteIAMGroupCmd.class);
cmdList.add(ListIAMGroupsCmd.class);
cmdList.add(AddAccountToIAMGroupCmd.class);
cmdList.add(RemoveAccountFromIAMGroupCmd.class);
cmdList.add(AttachIAMPolicyToAccountCmd.class);
cmdList.add(RemoveIAMPolicyFromAccountCmd.class);
return cmdList;
}
}