diff --git a/services/iam/server/pom.xml b/services/iam/server/pom.xml new file mode 100644 index 00000000000..bed8811d168 --- /dev/null +++ b/services/iam/server/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + cloud-iam + Apache CloudStack IAM - Server + + org.apache.cloudstack + cloudstack-service-iam + 4.4.0-SNAPSHOT + ../pom.xml + + + + commons-io + commons-io + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.apache.cloudstack + cloud-api + ${project.version} + + + org.apache.cloudstack + cloud-api + ${project.version} + test-jar + test + + + diff --git a/services/iam/server/resources/META-INF/cloudstack/core/spring-iam-server-context.xml b/services/iam/server/resources/META-INF/cloudstack/core/spring-iam-server-context.xml new file mode 100644 index 00000000000..c9f383f4f54 --- /dev/null +++ b/services/iam/server/resources/META-INF/cloudstack/core/spring-iam-server-context.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + diff --git a/services/iam/server/src/org/apache/cloudstack/iam/api/IAMGroup.java b/services/iam/server/src/org/apache/cloudstack/iam/api/IAMGroup.java new file mode 100644 index 00000000000..868d0a0d449 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/api/IAMGroup.java @@ -0,0 +1,37 @@ +// 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.api; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface IAMGroup extends InternalIdentity, Identity { + + String getName(); + + String getDescription(); + + @Override + long getId(); + + @Override + String getUuid(); + + String getPath(); + + long getAccountId(); +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/api/IAMPolicy.java b/services/iam/server/src/org/apache/cloudstack/iam/api/IAMPolicy.java new file mode 100644 index 00000000000..e6daeb11c68 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/api/IAMPolicy.java @@ -0,0 +1,41 @@ +// 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.api; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface IAMPolicy extends InternalIdentity, Identity { + + String getName(); + + String getDescription(); + + public enum PolicyType { + Static, Dynamic + } + + @Override + long getId(); + + @Override + String getUuid(); + + String getPath(); + + long getAccountId(); +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/api/IAMPolicyPermission.java b/services/iam/server/src/org/apache/cloudstack/iam/api/IAMPolicyPermission.java new file mode 100644 index 00000000000..b91086fc869 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/api/IAMPolicyPermission.java @@ -0,0 +1,53 @@ +// 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.api; + + +public interface IAMPolicyPermission { + + String getAction(); + + long getAclPolicyId(); + + String getEntityType(); + + String getAccessType(); + + String getScope(); + + Long getScopeId(); + + Permission getPermission(); + + public enum Permission { + Allow(true), Deny(false); + + boolean result; + + Permission(boolean result) { + this.result = result; + } + + public boolean isGranted() { + return result; + } + } + + long getId(); + + public static final long PERMISSION_SCOPE_ID_CURRENT_CALLER = -1; +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/api/IAMService.java b/services/iam/server/src/org/apache/cloudstack/iam/api/IAMService.java new file mode 100644 index 00000000000..74a08851506 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/api/IAMService.java @@ -0,0 +1,92 @@ +// 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.api; + +import java.util.List; + +import org.apache.cloudstack.iam.api.IAMPolicyPermission.Permission; + +import com.cloud.utils.Pair; + +public interface IAMService { + + /* IAM group related interfaces */ + IAMGroup createIAMGroup(String iamGroupName, String description, String path); + + boolean deleteIAMGroup(Long iamGroupId); + + List listIAMGroups(long accountId); + + IAMGroup addAccountsToGroup(List acctIds, Long groupId); + + IAMGroup removeAccountsFromGroup(List acctIds, Long groupId); + + List listAccountsByGroup(long groupId); + + Pair, Integer> listIAMGroups(Long iamGroupId, String iamGroupName, String path, Long startIndex, Long pageSize); + + /* IAM Policy related interfaces */ + IAMPolicy createIAMPolicy(String iamPolicyName, String description, Long parentPolicyId, String path); + + boolean deleteIAMPolicy(long iamPolicyId); + + List listIAMPolicies(long accountId); + + List listIAMPoliciesByGroup(long groupId); + + Pair, Integer> listIAMPolicies(Long iamPolicyId, String iamPolicyName, String path, Long startIndex, Long pageSize); + + IAMGroup attachIAMPoliciesToGroup(List policyIds, Long groupId); + + IAMGroup removeIAMPoliciesFromGroup(List policyIds, Long groupId); + + void attachIAMPolicyToAccounts(Long policyId, List acctIds); + + void removeIAMPolicyFromAccounts(Long policyId, List acctIds); + + IAMPolicy addIAMPermissionToIAMPolicy(long iamPolicyId, String entityType, String scope, Long scopeId, + String action, String accessType, Permission perm, Boolean recursive); + + IAMPolicy removeIAMPermissionFromIAMPolicy(long iamPolicyId, String entityType, String scope, Long scopeId, + String action); + + void removeIAMPermissionForEntity(final String entityType, final Long entityId); + + IAMPolicy getResourceGrantPolicy(String entityType, Long entityId, String accessType, String action); + + IAMPolicy getResourceOwnerPolicy(); + + List listPolicyPermissions(long policyId); + + List listPolicyPermissionsByScope(long policyId, String action, String scope); + + List listPolicyPermissionByActionAndEntity(long policyId, String action, String entityType); + + boolean isActionAllowedForPolicies(String action, List policies); + + List getGrantedEntities(long accountId, String action, String scope); + + IAMPolicy resetIAMPolicy(long iamPolicyId); + + List listPolicyPermissionByAccessAndEntity(long policyId, String accessType, + String entityType); + + List listParentIAMGroups(long groupId); + + List listRecursiveIAMPoliciesByGroup(long groupId); + +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/IAMAccountPolicyMapVO.java b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMAccountPolicyMapVO.java new file mode 100644 index 00000000000..18f085a28fd --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMAccountPolicyMapVO.java @@ -0,0 +1,77 @@ +// 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.server; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = ("iam_account_policy_map")) +public class IAMAccountPolicyMapVO { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "account_id") + private long accountId; + + @Column(name = "policy_id") + private long iamPolicyId; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + public IAMAccountPolicyMapVO() { + } + + public IAMAccountPolicyMapVO(long accountId, long iamPolicyId) { + this.accountId = accountId; + this.iamPolicyId = iamPolicyId; + } + + public long getId() { + return id; + } + + public long getAccountId() { + return accountId; + } + + public long getIamPolicyId() { + return iamPolicyId; + } + + public Date getRemoved() { + return removed; + } + + public Date getCreated() { + return created; + } +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/IAMGroupAccountMapVO.java b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMGroupAccountMapVO.java new file mode 100644 index 00000000000..dac7d35ef67 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMGroupAccountMapVO.java @@ -0,0 +1,78 @@ +// 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.server; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = ("iam_group_account_map")) +public class IAMGroupAccountMapVO { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "group_id") + private long aclGroupId; + + @Column(name = "account_id") + private long accountId; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + public IAMGroupAccountMapVO() { + } + + public IAMGroupAccountMapVO(long aclGroupId, long accountId) { + this.aclGroupId = aclGroupId; + this.accountId = accountId; + } + + public long getId() { + return id; + } + + public long getAclGroupId() { + return aclGroupId; + } + + + public long getAccountId() { + return accountId; + } + + public Date getRemoved() { + return removed; + } + + public Date getCreated() { + return created; + } +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/IAMGroupPolicyMapVO.java b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMGroupPolicyMapVO.java new file mode 100644 index 00000000000..946d1f796a2 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMGroupPolicyMapVO.java @@ -0,0 +1,79 @@ +// 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.server; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + + +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = ("iam_group_policy_map")) +public class IAMGroupPolicyMapVO { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "group_id") + private long aclGroupId; + + @Column(name = "policy_id") + private long aclPolicyId; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + public IAMGroupPolicyMapVO() { + } + + public IAMGroupPolicyMapVO(long aclGroupId, long aclPolicyId) { + this.aclGroupId = aclGroupId; + this.aclPolicyId = aclPolicyId; + } + + public long getId() { + return id; + } + + public long getAclGroupId() { + return aclGroupId; + } + + + public long getAclPolicyId() { + return aclPolicyId; + } + + public Date getRemoved() { + return removed; + } + + public Date getCreated() { + return created; + } +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/IAMGroupVO.java b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMGroupVO.java new file mode 100644 index 00000000000..80edb8977a7 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMGroupVO.java @@ -0,0 +1,122 @@ +// 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.server; + +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.cloudstack.iam.api.IAMGroup; + +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = ("iam_group")) +public class IAMGroupVO implements IAMGroup { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "name") + private String name; + + @Column(name = "description") + private String description; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "path") + private String path; + + @Column(name = "account_id") + private long accountId; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + public IAMGroupVO() { + uuid = UUID.randomUUID().toString(); + } + + public IAMGroupVO(String name, String description) { + this.name = name; + this.description = description; + uuid = UUID.randomUUID().toString(); + path = "/"; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + @Override + public long getAccountId() { + return accountId; + } + + public void setAccountId(long acctId) { + accountId = acctId; + } + + @Override + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Date getRemoved() { + return removed; + } + + public Date getCreated() { + return created; + } +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/IAMPolicyPermissionVO.java b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMPolicyPermissionVO.java new file mode 100644 index 00000000000..13d6b814e53 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMPolicyPermissionVO.java @@ -0,0 +1,181 @@ +// 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.server; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.cloudstack.iam.api.IAMPolicyPermission; +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = ("iam_policy_permission")) +public class IAMPolicyPermissionVO implements IAMPolicyPermission { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "policy_id") + private long aclPolicyId; + + @Column(name = "action") + private String action; + + @Column(name = "resource_type") + private String entityType; + + @Column(name = "access_type") + private String accessType; + + @Column(name = "scope") + private String scope; + + @Column(name = "scope_id") + private Long scopeId; + + @Column(name = "permission") + @Enumerated(value = EnumType.STRING) + private Permission permission; + + @Column(name = "recursive") + private Boolean recursive; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + public IAMPolicyPermissionVO() { + + } + + public IAMPolicyPermissionVO(long aclPolicyId, String action, String entityType, String accessType, String scope, + Long scopeId, Permission permission, Boolean recursive) { + this.aclPolicyId = aclPolicyId; + this.action = action; + this.entityType = entityType; + this.accessType = accessType; + this.scope = scope; + this.scopeId = scopeId; + this.permission = permission; + this.recursive = recursive; + } + + @Override + public long getId() { + return id; + } + + @Override + public long getAclPolicyId() { + return aclPolicyId; + } + + + public void setAclPolicyId(long aclPolicyId) { + this.aclPolicyId = aclPolicyId; + } + + @Override + public String getEntityType() { + return entityType; + } + + @Override + public String getAccessType() { + return accessType; + } + + + public void setEntityType(String entityType) { + this.entityType = entityType; + } + + public void setAccessType(String accessType) { + this.accessType = accessType; + } + + @Override + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + + @Override + public String getAction() { + return action; + } + + @Override + public Long getScopeId() { + // TODO + // handle special -1 scopeId, current caller domain, account + /* + * if ( scopeId < 0 ){ Account caller = + * CallContext.current().getCallingAccount(); if ( scope == + * PermissionScope.DOMAIN){ return caller.getDomainId(); } else if + * (scope == PermissionScope.ACCOUNT) { return caller.getAccountId(); } + * } + */ + return scopeId; + } + + @Override + public Permission getPermission() { + return permission; + } + + public void setAction(String action) { + this.action = action; + } + + public void setScopeId(Long scopeId) { + this.scopeId = scopeId; + } + + public void setPermission(Permission permission) { + this.permission = permission; + } + + public Date getRemoved() { + return removed; + } + + public Date getCreated() { + return created; + } + + public Boolean isRecursive() { + return recursive; + } + +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/IAMPolicyVO.java b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMPolicyVO.java new file mode 100644 index 00000000000..25ebd011f39 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMPolicyVO.java @@ -0,0 +1,138 @@ +// 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.server; + +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.cloudstack.iam.api.IAMPolicy; + +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = ("iam_policy")) +public class IAMPolicyVO implements IAMPolicy { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "name") + private String name; + + @Column(name = "description") + private String description; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "path") + private String path; + + @Column(name = "account_id") + private long accountId; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + @Column(name = "policy_type") + @Enumerated(value = EnumType.STRING) + private IAMPolicy.PolicyType policyType; + + public IAMPolicyVO() { + uuid = UUID.randomUUID().toString(); + } + + public IAMPolicyVO(String name, String description) { + this.name = name; + this.description = description; + uuid = UUID.randomUUID().toString(); + policyType = IAMPolicy.PolicyType.Static; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDescription() { + return description; + } + + + @Override + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Date getRemoved() { + return removed; + } + + public Date getCreated() { + return created; + } + + @Override + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + @Override + public long getAccountId() { + return accountId; + } + + public void setAccountId(long accountId) { + this.accountId = accountId; + } + + public IAMPolicy.PolicyType getPolicyType() { + return policyType; + } + + public void setPolicyType(IAMPolicy.PolicyType policyType) { + this.policyType = policyType; + } + +} 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 new file mode 100644 index 00000000000..097d84f958c --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/IAMServiceImpl.java @@ -0,0 +1,815 @@ +// 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.server; + +import java.util.ArrayList; +import java.util.List; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.acl.PermissionScope; +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 org.apache.cloudstack.iam.server.dao.IAMAccountPolicyMapDao; +import org.apache.cloudstack.iam.server.dao.IAMGroupAccountMapDao; +import org.apache.cloudstack.iam.server.dao.IAMGroupDao; +import org.apache.cloudstack.iam.server.dao.IAMGroupPolicyMapDao; +import org.apache.cloudstack.iam.server.dao.IAMPolicyDao; +import org.apache.cloudstack.iam.server.dao.IAMPolicyPermissionDao; + +import com.cloud.exception.InvalidParameterValueException; +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.utils.db.Filter; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.JoinBuilder.JoinType; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionCallbackNoReturn; +import com.cloud.utils.db.TransactionStatus; + +@Local(value = {IAMService.class}) +public class IAMServiceImpl extends ManagerBase implements IAMService, Manager { + + public static final Logger s_logger = Logger.getLogger(IAMServiceImpl.class); + private String _name; + + @Inject + IAMPolicyDao _aclPolicyDao; + + @Inject + IAMGroupDao _aclGroupDao; + + @Inject + EntityManager _entityMgr; + + @Inject + IAMGroupPolicyMapDao _aclGroupPolicyMapDao; + + @Inject + IAMAccountPolicyMapDao _aclAccountPolicyMapDao; + + @Inject + IAMGroupAccountMapDao _aclGroupAccountMapDao; + + @Inject + IAMPolicyPermissionDao _policyPermissionDao; + + @DB + @Override + public IAMGroup createIAMGroup(String iamGroupName, String description, String path) { + // check if the group is already existing + IAMGroup grp = _aclGroupDao.findByName(path, iamGroupName); + if (grp != null) { + throw new InvalidParameterValueException( + "Unable to create acl group with name " + iamGroupName + + " already exisits for path " + path); + } + IAMGroupVO rvo = new IAMGroupVO(iamGroupName, description); + rvo.setPath(path); + + return _aclGroupDao.persist(rvo); + } + + @DB + @Override + public boolean deleteIAMGroup(final Long iamGroupId) { + // get the Acl Group entity + final IAMGroup grp = _aclGroupDao.findById(iamGroupId); + if (grp == null) { + throw new InvalidParameterValueException("Unable to find acl group: " + iamGroupId + + "; failed to delete acl group."); + } + + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // remove this group related entry in acl_group_role_map + List groupPolicyMap = _aclGroupPolicyMapDao.listByGroupId(grp.getId()); + if (groupPolicyMap != null) { + for (IAMGroupPolicyMapVO gr : groupPolicyMap) { + _aclGroupPolicyMapDao.remove(gr.getId()); + } + } + + // remove this group related entry in acl_group_account table + List groupAcctMap = _aclGroupAccountMapDao.listByGroupId(grp.getId()); + if (groupAcctMap != null) { + for (IAMGroupAccountMapVO grpAcct : groupAcctMap) { + _aclGroupAccountMapDao.remove(grpAcct.getId()); + } + } + + // remove this group from acl_group table + _aclGroupDao.remove(iamGroupId); + } + }); + + return true; + } + + @SuppressWarnings("unchecked") + @Override + public List listIAMGroups(long accountId) { + + GenericSearchBuilder groupSB = _aclGroupAccountMapDao.createSearchBuilder(Long.class); + groupSB.selectFields(groupSB.entity().getAclGroupId()); + groupSB.and("account", groupSB.entity().getAccountId(), Op.EQ); + SearchCriteria groupSc = groupSB.create(); + groupSc.setParameters("account", accountId); + + List groupIds = _aclGroupAccountMapDao.customSearch(groupSc, null); + + SearchBuilder sb = _aclGroupDao.createSearchBuilder(); + sb.and("ids", sb.entity().getId(), Op.IN); + SearchCriteria sc = sb.create(); + sc.setParameters("ids", groupIds.toArray(new Object[groupIds.size()])); + @SuppressWarnings("rawtypes") + List groups = _aclGroupDao.search(sc, null); + return groups; + } + + @DB + @Override + public IAMGroup addAccountsToGroup(final List acctIds, final Long groupId) { + // get the Acl Group entity + IAMGroup group = _aclGroupDao.findById(groupId); + if (group == null) { + throw new InvalidParameterValueException("Unable to find acl group: " + groupId + + "; failed to add accounts to acl group."); + } + + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // add entries in acl_group_account_map table + for (Long acctId : acctIds) { + // check account permissions + IAMGroupAccountMapVO grMap = _aclGroupAccountMapDao.findByGroupAndAccount(groupId, acctId); + if (grMap == null) { + // not there already + grMap = new IAMGroupAccountMapVO(groupId, acctId); + _aclGroupAccountMapDao.persist(grMap); + } + } + } + }); + return group; + } + + @DB + @Override + public IAMGroup removeAccountsFromGroup(final List acctIds, final Long groupId) { + // get the Acl Group entity + IAMGroup group = _aclGroupDao.findById(groupId); + if (group == null) { + throw new InvalidParameterValueException("Unable to find acl group: " + groupId + + "; failed to remove accounts from acl group."); + } + + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // remove entries from acl_group_account_map table + for (Long acctId : acctIds) { + IAMGroupAccountMapVO grMap = _aclGroupAccountMapDao.findByGroupAndAccount(groupId, acctId); + if (grMap != null) { + // not removed yet + _aclGroupAccountMapDao.remove(grMap.getId()); + } + } + } + }); + return group; + } + + @Override + public List listAccountsByGroup(long groupId) { + List grpAcctMap = _aclGroupAccountMapDao.listByGroupId(groupId); + if (grpAcctMap == null || grpAcctMap.size() == 0) { + return new ArrayList(); + } + + List accts = new ArrayList(); + for (IAMGroupAccountMapVO grpAcct : grpAcctMap) { + accts.add(grpAcct.getAccountId()); + } + return accts; + } + + @Override + public Pair, Integer> listIAMGroups(Long iamGroupId, String iamGroupName, String path, Long startIndex, Long pageSize) { + if (iamGroupId != null) { + IAMGroup group = _aclGroupDao.findById(iamGroupId); + if (group == null) { + throw new InvalidParameterValueException("Unable to find acl group by id " + iamGroupId); + } + } + + Filter searchFilter = new Filter(IAMGroupVO.class, "id", true, startIndex, pageSize); + + SearchBuilder sb = _aclGroupDao.createSearchBuilder(); + sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ); + sb.and("path", sb.entity().getPath(), SearchCriteria.Op.LIKE); + sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + + SearchCriteria sc = sb.create(); + + if (iamGroupName != null) { + sc.setParameters("name", iamGroupName); + } + + if (iamGroupId != null) { + sc.setParameters("id", iamGroupId); + } + + sc.setParameters("path", path + "%"); + + Pair, Integer> groups = _aclGroupDao.searchAndCount(sc, searchFilter); + return new Pair, Integer>(new ArrayList(groups.first()), groups.second()); + } + + @Override + public List listParentIAMGroups(long groupId) { + IAMGroup group = _aclGroupDao.findById(groupId); + if (group == null) { + throw new InvalidParameterValueException("Unable to find acl group by id " + groupId); + } + + String path = group.getPath(); + List pathList = new ArrayList(); + + String[] parts = path.split("/"); + + for (String part : parts) { + int start = path.indexOf(part); + if (start > 0) { + String subPath = path.substring(0, start); + pathList.add(subPath); + } + } + + if (pathList.isEmpty()) { + return new ArrayList(); + } + + SearchBuilder sb = _aclGroupDao.createSearchBuilder(); + sb.and("paths", sb.entity().getPath(), SearchCriteria.Op.IN); + + SearchCriteria sc = sb.create(); + sc.setParameters("paths", pathList.toArray()); + + List groups = _aclGroupDao.search(sc, null); + + return new ArrayList(groups); + + } + + @DB + @Override + public IAMPolicy createIAMPolicy(final String iamPolicyName, final String description, final Long parentPolicyId, final String path) { + + // check if the policy is already existing + IAMPolicy ro = _aclPolicyDao.findByName(iamPolicyName); + if (ro != null) { + throw new InvalidParameterValueException( + "Unable to create acl policy with name " + iamPolicyName + + " already exisits"); + } + + IAMPolicy role = Transaction.execute(new TransactionCallback() { + @Override + public IAMPolicy doInTransaction(TransactionStatus status) { + IAMPolicyVO rvo = new IAMPolicyVO(iamPolicyName, description); + rvo.setPath(path); + + IAMPolicy role = _aclPolicyDao.persist(rvo); + if (parentPolicyId != null) { + // copy parent role permissions + List perms = _policyPermissionDao.listByPolicy(parentPolicyId); + if (perms != null) { + for (IAMPolicyPermissionVO perm : perms) { + perm.setAclPolicyId(role.getId()); + _policyPermissionDao.persist(perm); + } + } + } + return role; + } + }); + + + return role; + } + + @DB + @Override + public boolean deleteIAMPolicy(final long iamPolicyId) { + // get the Acl Policy entity + final IAMPolicy policy = _aclPolicyDao.findById(iamPolicyId); + if (policy == null) { + throw new InvalidParameterValueException("Unable to find acl policy: " + iamPolicyId + + "; failed to delete acl policy."); + } + + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // remove this role related entry in acl_group_role_map + List groupPolicyMap = _aclGroupPolicyMapDao.listByPolicyId(policy.getId()); + if (groupPolicyMap != null) { + for (IAMGroupPolicyMapVO gr : groupPolicyMap) { + _aclGroupPolicyMapDao.remove(gr.getId()); + } + } + + // remove this policy related entry in acl_account_policy_map table + List policyAcctMap = _aclAccountPolicyMapDao.listByPolicyId(policy.getId()); + if (policyAcctMap != null) { + for (IAMAccountPolicyMapVO policyAcct : policyAcctMap) { + _aclAccountPolicyMapDao.remove(policyAcct.getId()); + } + } + + // remove this policy related entry in acl_policy_permission table + List policyPermMap = _policyPermissionDao.listByPolicy(policy.getId()); + if (policyPermMap != null) { + for (IAMPolicyPermissionVO policyPerm : policyPermMap) { + _policyPermissionDao.remove(policyPerm.getId()); + } + } + + // remove this role from acl_role table + _aclPolicyDao.remove(iamPolicyId); + } + }); + + return true; + } + + + @SuppressWarnings("unchecked") + @Override + public List listIAMPolicies(long accountId) { + + // static policies of the account + SearchBuilder groupSB = _aclGroupAccountMapDao.createSearchBuilder(); + groupSB.and("account", groupSB.entity().getAccountId(), Op.EQ); + + GenericSearchBuilder policySB = _aclGroupPolicyMapDao.createSearchBuilder(Long.class); + policySB.selectFields(policySB.entity().getAclPolicyId()); + policySB.join("accountgroupjoin", groupSB, groupSB.entity().getAclGroupId(), policySB.entity().getAclGroupId(), + JoinType.INNER); + policySB.done(); + SearchCriteria policySc = policySB.create(); + policySc.setJoinParameters("accountgroupjoin", "account", accountId); + + List policyIds = _aclGroupPolicyMapDao.customSearch(policySc, null); + // add policies directly attached to the account + List acctPolicies = _aclAccountPolicyMapDao.listByAccountId(accountId); + for (IAMAccountPolicyMapVO p : acctPolicies) { + policyIds.add(p.getIamPolicyId()); + } + if (policyIds.size() == 0) { + return new ArrayList(); + } + SearchBuilder sb = _aclPolicyDao.createSearchBuilder(); + sb.and("ids", sb.entity().getId(), Op.IN); + SearchCriteria sc = sb.create(); + sc.setParameters("ids", policyIds.toArray(new Object[policyIds.size()])); + @SuppressWarnings("rawtypes") + List policies = _aclPolicyDao.customSearch(sc, null); + + return policies; + + } + + @SuppressWarnings("unchecked") + @Override + public List listIAMPoliciesByGroup(long groupId) { + List policyGrpMap = _aclGroupPolicyMapDao.listByGroupId(groupId); + if (policyGrpMap == null || policyGrpMap.size() == 0) { + return new ArrayList(); + } + + List policyIds = new ArrayList(); + for (IAMGroupPolicyMapVO pg : policyGrpMap) { + policyIds.add(pg.getAclPolicyId()); + } + + SearchBuilder sb = _aclPolicyDao.createSearchBuilder(); + sb.and("ids", sb.entity().getId(), Op.IN); + SearchCriteria sc = sb.create(); + sc.setParameters("ids", policyIds.toArray(new Object[policyIds.size()])); + @SuppressWarnings("rawtypes") + List policies = _aclPolicyDao.customSearch(sc, null); + + return policies; + } + + @SuppressWarnings("unchecked") + @Override + public List listRecursiveIAMPoliciesByGroup(long groupId) { + List policyGrpMap = _aclGroupPolicyMapDao.listByGroupId(groupId); + if (policyGrpMap == null || policyGrpMap.size() == 0) { + return new ArrayList(); + } + + List policyIds = new ArrayList(); + for (IAMGroupPolicyMapVO pg : policyGrpMap) { + policyIds.add(pg.getAclPolicyId()); + } + + SearchBuilder permSb = _policyPermissionDao.createSearchBuilder(); + permSb.and("isRecursive", permSb.entity().isRecursive(), Op.EQ); + + SearchBuilder sb = _aclPolicyDao.createSearchBuilder(); + sb.and("ids", sb.entity().getId(), Op.IN); + sb.join("recursivePerm", permSb, sb.entity().getId(), permSb.entity().getAclPolicyId(), + JoinBuilder.JoinType.INNER); + + SearchCriteria sc = sb.create(); + sc.setParameters("ids", policyIds.toArray(new Object[policyIds.size()])); + sc.setJoinParameters("recursivePerm", "isRecursive", true); + + @SuppressWarnings("rawtypes") + List policies = _aclPolicyDao.customSearch(sc, null); + + return policies; + } + + + @SuppressWarnings("unchecked") + @Override + public Pair, Integer> listIAMPolicies(Long iamPolicyId, String iamPolicyName, String path, Long startIndex, Long pageSize) { + + if (iamPolicyId != null) { + IAMPolicy policy = _aclPolicyDao.findById(iamPolicyId); + if (policy == null) { + throw new InvalidParameterValueException("Unable to find acl policy by id " + iamPolicyId); + } + } + + Filter searchFilter = new Filter(IAMPolicyVO.class, "id", true, startIndex, pageSize); + + SearchBuilder sb = _aclPolicyDao.createSearchBuilder(); + sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ); + sb.and("path", sb.entity().getPath(), SearchCriteria.Op.LIKE); + sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + + SearchCriteria sc = sb.create(); + + if (iamPolicyName != null) { + sc.setParameters("name", iamPolicyName); + } + + if (iamPolicyId != null) { + sc.setParameters("id", iamPolicyId); + } + + sc.setParameters("path", path + "%"); + + Pair, Integer> policies = _aclPolicyDao.searchAndCount(sc, searchFilter); + @SuppressWarnings("rawtypes") + List policyList = policies.first(); + return new Pair, Integer>(policyList, policies.second()); + } + + @DB + @Override + public IAMGroup attachIAMPoliciesToGroup(final List policyIds, final Long groupId) { + // get the Acl Group entity + IAMGroup group = _aclGroupDao.findById(groupId); + if (group == null) { + throw new InvalidParameterValueException("Unable to find acl group: " + groupId + + "; failed to add roles to acl group."); + } + + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // add entries in acl_group_policy_map table + for (Long policyId : policyIds) { + IAMPolicy policy = _aclPolicyDao.findById(policyId); + if (policy == null) { + throw new InvalidParameterValueException("Unable to find acl policy: " + policyId + + "; failed to add policies to acl group."); + } + + IAMGroupPolicyMapVO grMap = _aclGroupPolicyMapDao.findByGroupAndPolicy(groupId, policyId); + if (grMap == null) { + // not there already + grMap = new IAMGroupPolicyMapVO(groupId, policyId); + _aclGroupPolicyMapDao.persist(grMap); + } + } + } + }); + + return group; + } + + @DB + @Override + public IAMGroup removeIAMPoliciesFromGroup(final List policyIds, final Long groupId) { + // get the Acl Group entity + IAMGroup group = _aclGroupDao.findById(groupId); + if (group == null) { + throw new InvalidParameterValueException("Unable to find acl group: " + groupId + + "; failed to remove roles from acl group."); + } + + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // add entries in acl_group_role_map table + for (Long policyId : policyIds) { + IAMPolicy policy = _aclPolicyDao.findById(policyId); + if (policy == null) { + throw new InvalidParameterValueException("Unable to find acl policy: " + policyId + + "; failed to add policies to acl group."); + } + + IAMGroupPolicyMapVO grMap = _aclGroupPolicyMapDao.findByGroupAndPolicy(groupId, policyId); + if (grMap != null) { + // not removed yet + _aclGroupPolicyMapDao.remove(grMap.getId()); + } + } + } + }); + return group; + } + + + @Override + public void attachIAMPolicyToAccounts(final Long policyId, final List acctIds) { + IAMPolicy policy = _aclPolicyDao.findById(policyId); + if (policy == null) { + throw new InvalidParameterValueException("Unable to find acl policy: " + policyId + + "; failed to add policy to account."); + } + + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // add entries in acl_group_policy_map table + for (Long acctId : acctIds) { + IAMAccountPolicyMapVO acctMap = _aclAccountPolicyMapDao.findByAccountAndPolicy(acctId, policyId); + if (acctMap == null) { + // not there already + acctMap = new IAMAccountPolicyMapVO(acctId, policyId); + _aclAccountPolicyMapDao.persist(acctMap); + } + } + } + }); + } + + @Override + public void removeIAMPolicyFromAccounts(final Long policyId, final List acctIds) { + IAMPolicy policy = _aclPolicyDao.findById(policyId); + if (policy == null) { + throw new InvalidParameterValueException("Unable to find acl policy: " + policyId + + "; failed to add policy to account."); + } + + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // add entries in acl_group_policy_map table + for (Long acctId : acctIds) { + IAMAccountPolicyMapVO acctMap = _aclAccountPolicyMapDao.findByAccountAndPolicy(acctId, policyId); + if (acctMap != null) { + // exists + _aclAccountPolicyMapDao.remove(acctMap.getId()); + } + } + } + }); + } + + @DB + @Override + public IAMPolicy addIAMPermissionToIAMPolicy(long iamPolicyId, String entityType, String scope, Long scopeId, + String action, String accessType, Permission perm, Boolean recursive) { + // get the Acl Policy entity + IAMPolicy policy = _aclPolicyDao.findById(iamPolicyId); + if (policy == null) { + throw new InvalidParameterValueException("Unable to find acl policy: " + iamPolicyId + + "; failed to add permission to policy."); + } + + // add entry in acl_policy_permission table + IAMPolicyPermissionVO permit = _policyPermissionDao.findByPolicyAndEntity(iamPolicyId, entityType, scope, scopeId, action, perm); + if (permit == null) { + // not there already + permit = new IAMPolicyPermissionVO(iamPolicyId, action, entityType, accessType, scope, scopeId, perm, + recursive); + _policyPermissionDao.persist(permit); + } + return policy; + + } + + @DB + @Override + public IAMPolicy removeIAMPermissionFromIAMPolicy(long iamPolicyId, String entityType, String scope, Long scopeId, + String action) { + // get the Acl Policy entity + IAMPolicy policy = _aclPolicyDao.findById(iamPolicyId); + if (policy == null) { + throw new InvalidParameterValueException("Unable to find acl policy: " + iamPolicyId + + "; failed to revoke permission from policy."); + } + // remove entry from acl_entity_permission table + IAMPolicyPermissionVO permit = _policyPermissionDao.findByPolicyAndEntity(iamPolicyId, entityType, scope, scopeId, action, Permission.Allow); + if (permit != null) { + // not removed yet + _policyPermissionDao.remove(permit.getId()); + } + return policy; + } + + @DB + @Override + public void removeIAMPermissionForEntity(final String entityType, final Long entityId) { + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // remove entry from acl_entity_permission table + List permitList = _policyPermissionDao.listByEntity(entityType, entityId); + for (IAMPolicyPermissionVO permit : permitList) { + long policyId = permit.getAclPolicyId(); + _policyPermissionDao.remove(permit.getId()); + + // remove the policy if there are no other permissions + if ((_policyPermissionDao.listByPolicy(policyId)).isEmpty()) { + deleteIAMPolicy(policyId); + } + } + } + }); + } + + @DB + @Override + public IAMPolicy resetIAMPolicy(long iamPolicyId) { + // get the Acl Policy entity + IAMPolicy policy = _aclPolicyDao.findById(iamPolicyId); + if (policy == null) { + throw new InvalidParameterValueException("Unable to find acl policy: " + iamPolicyId + + "; failed to reset the policy."); + } + + SearchBuilder sb = _policyPermissionDao.createSearchBuilder(); + sb.and("policyId", sb.entity().getAclPolicyId(), SearchCriteria.Op.EQ); + sb.and("scope", sb.entity().getScope(), SearchCriteria.Op.EQ); + sb.done(); + SearchCriteria permissionSC = sb.create(); + permissionSC.setParameters("policyId", iamPolicyId); + _policyPermissionDao.expunge(permissionSC); + + return policy; + } + + @Override + public boolean isActionAllowedForPolicies(String action, List policies) { + + boolean allowed = false; + + if (policies == null || policies.size() == 0) { + return allowed; + } + + List policyIds = new ArrayList(); + for (IAMPolicy policy : policies) { + policyIds.add(policy.getId()); + } + + SearchBuilder sb = _policyPermissionDao.createSearchBuilder(); + sb.and("action", sb.entity().getAction(), Op.EQ); + sb.and("policyId", sb.entity().getAclPolicyId(), Op.IN); + + SearchCriteria sc = sb.create(); + sc.setParameters("policyId", policyIds.toArray(new Object[policyIds.size()])); + sc.setParameters("action", action); + + List permissions = _policyPermissionDao.customSearch(sc, null); + + if (permissions != null && !permissions.isEmpty()) { + allowed = true; + } + + return allowed; + } + + + @Override + public List getGrantedEntities(long accountId, String action, String scope) { + // Get the static Policies of the Caller + List policies = listIAMPolicies(accountId); + // for each policy, find granted permission within the given scope + List entityIds = new ArrayList(); + for (IAMPolicy policy : policies) { + List pp = _policyPermissionDao.listGrantedByActionAndScope(policy.getId(), action, + scope); + if (pp != null) { + for (IAMPolicyPermissionVO p : pp) { + if (p.getScopeId() != null) { + entityIds.add(p.getScopeId()); + } + } + } + } + return entityIds; + } + + @Override + @SuppressWarnings("unchecked") + public List listPolicyPermissions(long policyId) { + @SuppressWarnings("rawtypes") + List pp = _policyPermissionDao.listByPolicy(policyId); + return pp; + } + + @SuppressWarnings("unchecked") + @Override + public List listPolicyPermissionsByScope(long policyId, String action, String scope) { + @SuppressWarnings("rawtypes") + List pp = _policyPermissionDao.listGrantedByActionAndScope(policyId, action, scope); + return pp; + } + + @SuppressWarnings("unchecked") + @Override + public List listPolicyPermissionByActionAndEntity(long policyId, String action, + String entityType) { + @SuppressWarnings("rawtypes") + List pp = _policyPermissionDao.listByPolicyActionAndEntity(policyId, action, entityType); + return pp; + } + + @SuppressWarnings("unchecked") + @Override + public List listPolicyPermissionByAccessAndEntity(long policyId, String accessType, + String entityType) { + @SuppressWarnings("rawtypes") + List pp = _policyPermissionDao.listByPolicyAccessAndEntity(policyId, accessType, entityType); + return pp; + } + + @Override + public IAMPolicy getResourceOwnerPolicy() { + return _aclPolicyDao.findByName("RESOURCE_OWNER"); + } + + // search for policy with only one resource grant permission + @Override + public IAMPolicy getResourceGrantPolicy(String entityType, Long entityId, String accessType, String action) { + List policyList = _aclPolicyDao.listAll(); + for (IAMPolicyVO policy : policyList){ + List pp = listPolicyPermissions(policy.getId()); + if ( pp != null && pp.size() == 1){ + // resource grant policy should only have one ACL permission assigned + IAMPolicyPermission 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/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMAccountPolicyMapDao.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMAccountPolicyMapDao.java new file mode 100644 index 00000000000..4caf6590907 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMAccountPolicyMapDao.java @@ -0,0 +1,17 @@ +package org.apache.cloudstack.iam.server.dao; + +import java.util.List; + +import org.apache.cloudstack.iam.server.IAMAccountPolicyMapVO; + +import com.cloud.utils.db.GenericDao; + +public interface IAMAccountPolicyMapDao extends GenericDao { + + List listByAccountId(long acctId); + + List listByPolicyId(long policyId); + + IAMAccountPolicyMapVO findByAccountAndPolicy(long acctId, long policyId); + +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMAccountPolicyMapDaoImpl.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMAccountPolicyMapDaoImpl.java new file mode 100644 index 00000000000..3ecca3bdb1a --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMAccountPolicyMapDaoImpl.java @@ -0,0 +1,61 @@ +package org.apache.cloudstack.iam.server.dao; + +import java.util.List; +import java.util.Map; + +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.iam.server.IAMAccountPolicyMapVO; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +public class IAMAccountPolicyMapDaoImpl extends GenericDaoBase implements IAMAccountPolicyMapDao { + + private SearchBuilder ListByAccountId; + private SearchBuilder ListByPolicyId; + private SearchBuilder findByPolicyAccountId; + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + + ListByAccountId = createSearchBuilder(); + ListByAccountId.and("accountId", ListByAccountId.entity().getAccountId(), SearchCriteria.Op.EQ); + ListByAccountId.done(); + + ListByPolicyId = createSearchBuilder(); + ListByPolicyId.and("policyId", ListByPolicyId.entity().getIamPolicyId(), SearchCriteria.Op.EQ); + ListByPolicyId.done(); + + findByPolicyAccountId = createSearchBuilder(); + findByPolicyAccountId.and("policyId", findByPolicyAccountId.entity().getIamPolicyId(), SearchCriteria.Op.EQ); + findByPolicyAccountId.and("accountId", findByPolicyAccountId.entity().getAccountId(), SearchCriteria.Op.EQ); + findByPolicyAccountId.done(); + + return true; + } + + @Override + public List listByAccountId(long acctId) { + SearchCriteria sc = ListByAccountId.create(); + sc.setParameters("accountId", acctId); + return listBy(sc); + } + + @Override + public List listByPolicyId(long policyId) { + SearchCriteria sc = ListByPolicyId.create(); + sc.setParameters("policyId", policyId); + return listBy(sc); + } + + @Override + public IAMAccountPolicyMapVO findByAccountAndPolicy(long acctId, long policyId) { + SearchCriteria sc = findByPolicyAccountId.create(); + sc.setParameters("policyId", policyId); + sc.setParameters("accountId", acctId); + return findOneBy(sc); + } +} \ No newline at end of file diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupAccountMapDao.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupAccountMapDao.java new file mode 100644 index 00000000000..a94dbaae9c7 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupAccountMapDao.java @@ -0,0 +1,40 @@ +// 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.server.dao; + +import java.util.List; + +import org.apache.cloudstack.iam.server.IAMGroupAccountMapVO; + +import com.cloud.utils.db.GenericDao; + +public interface IAMGroupAccountMapDao extends GenericDao { + + List listByGroupId(long groupId); + + List listByAccountId(long accountId); + + IAMGroupAccountMapVO findAccountInAdminGroup(long accountId); + + IAMGroupAccountMapVO findByGroupAndAccount(long groupId, long acctId); + + void removeAccountFromGroups(long accountId); + + IAMGroupAccountMapVO findAccountInDomainAdminGroup(long accountId); + + IAMGroupAccountMapVO findAccountInUserGroup(long accountId); +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupAccountMapDaoImpl.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupAccountMapDaoImpl.java new file mode 100644 index 00000000000..4bb5d1a59fb --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupAccountMapDaoImpl.java @@ -0,0 +1,119 @@ +// 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.server.dao; + +import java.util.List; +import java.util.Map; + +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.iam.server.IAMGroupAccountMapVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +public class IAMGroupAccountMapDaoImpl extends GenericDaoBase implements IAMGroupAccountMapDao { + private SearchBuilder ListByGroupId; + private SearchBuilder ListByAccountId; + private SearchBuilder _findByAccountAndGroupId; + + public static final Logger s_logger = Logger.getLogger(IAMGroupAccountMapDaoImpl.class.getName()); + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + + ListByGroupId = createSearchBuilder(); + ListByGroupId.and("groupId", ListByGroupId.entity().getAclGroupId(), SearchCriteria.Op.EQ); + ListByGroupId.done(); + + ListByAccountId = createSearchBuilder(); + ListByAccountId.and("accountId", ListByAccountId.entity().getAccountId(), SearchCriteria.Op.EQ); + ListByAccountId.done(); + + _findByAccountAndGroupId = createSearchBuilder(); + _findByAccountAndGroupId + .and("groupId", _findByAccountAndGroupId.entity().getAclGroupId(), SearchCriteria.Op.EQ); + _findByAccountAndGroupId.and("accountId", _findByAccountAndGroupId.entity().getAccountId(), + SearchCriteria.Op.EQ); + _findByAccountAndGroupId.done(); + + return true; + } + + @Override + public List listByGroupId(long groupId) { + SearchCriteria sc = ListByGroupId.create(); + sc.setParameters("groupId", groupId); + return listBy(sc); + } + + @Override + public List listByAccountId(long accountId) { + SearchCriteria sc = ListByAccountId.create(); + sc.setParameters("accountId", accountId); + return listBy(sc); + } + + @Override + public IAMGroupAccountMapVO findAccountInAdminGroup(long accountId) { + SearchCriteria sc = _findByAccountAndGroupId.create(); + sc.setParameters("accountId", accountId); + sc.setParameters("groupId", 2); + return findOneBy(sc); + } + + @Override + public IAMGroupAccountMapVO findAccountInDomainAdminGroup(long accountId) { + SearchCriteria sc = _findByAccountAndGroupId.create(); + sc.setParameters("accountId", accountId); + sc.setParameters("groupId", 3); + return findOneBy(sc); + } + + @Override + public IAMGroupAccountMapVO findAccountInUserGroup(long accountId) { + SearchCriteria sc = _findByAccountAndGroupId.create(); + sc.setParameters("accountId", accountId); + sc.setParameters("groupId", 1); + return findOneBy(sc); + } + + @Override + public IAMGroupAccountMapVO findByGroupAndAccount(long groupId, long acctId) { + SearchCriteria sc = _findByAccountAndGroupId.create(); + sc.setParameters("accountId", acctId); + sc.setParameters("groupId", groupId); + return findOneBy(sc); + } + + @Override + public void removeAccountFromGroups(long accountId) { + SearchCriteria sc = ListByAccountId.create(); + sc.setParameters("accountId", accountId); + + int rowsRemoved = remove(sc); + if (rowsRemoved > 0) { + s_logger.debug("Removed account id=" + accountId + " from " + rowsRemoved + " groups"); + } + } +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupDao.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupDao.java new file mode 100644 index 00000000000..54408a6d390 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupDao.java @@ -0,0 +1,28 @@ +// 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.server.dao; + +import org.apache.cloudstack.iam.api.IAMGroup; +import org.apache.cloudstack.iam.server.IAMGroupVO; + +import com.cloud.utils.db.GenericDao; + +public interface IAMGroupDao extends GenericDao { + + IAMGroup findByName(String path, String groupName); + +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupDaoImpl.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupDaoImpl.java new file mode 100644 index 00000000000..45be0b3f21c --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupDaoImpl.java @@ -0,0 +1,59 @@ +// 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.server.dao; + +import java.util.Map; + +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.iam.api.IAMGroup; +import org.apache.cloudstack.iam.server.IAMGroupVO; +import org.springframework.stereotype.Component; + + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +public class IAMGroupDaoImpl extends GenericDaoBase implements IAMGroupDao { + private SearchBuilder nameSearch; + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + + nameSearch = createSearchBuilder(); + nameSearch.and("name", nameSearch.entity().getName(), SearchCriteria.Op.EQ); + nameSearch.and("path", nameSearch.entity().getPath(), SearchCriteria.Op.EQ); + nameSearch.done(); + + + return true; + } + + @Override + public IAMGroup findByName(String path, String name) { + SearchCriteria sc = nameSearch.create(); + sc.setParameters("name", name); + if (path != null) { + sc.setParameters("path", path); + } + return findOneBy(sc); + } + +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupPolicyMapDao.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupPolicyMapDao.java new file mode 100644 index 00000000000..6a2df89ab75 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupPolicyMapDao.java @@ -0,0 +1,16 @@ +package org.apache.cloudstack.iam.server.dao; + +import java.util.List; + +import org.apache.cloudstack.iam.server.IAMGroupPolicyMapVO; +import com.cloud.utils.db.GenericDao; + +public interface IAMGroupPolicyMapDao extends GenericDao { + + List listByGroupId(long groupId); + + List listByPolicyId(long policyId); + + IAMGroupPolicyMapVO findByGroupAndPolicy(long groupId, long policyId); + +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupPolicyMapDaoImpl.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupPolicyMapDaoImpl.java new file mode 100644 index 00000000000..95b6bac3712 --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMGroupPolicyMapDaoImpl.java @@ -0,0 +1,61 @@ +package org.apache.cloudstack.iam.server.dao; + +import java.util.List; +import java.util.Map; + +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.iam.server.IAMGroupPolicyMapVO; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +public class IAMGroupPolicyMapDaoImpl extends GenericDaoBase implements IAMGroupPolicyMapDao { + + private SearchBuilder ListByGroupId; + private SearchBuilder ListByPolicyId; + private SearchBuilder findByPolicyGroupId; + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + + ListByGroupId = createSearchBuilder(); + ListByGroupId.and("groupId", ListByGroupId.entity().getAclGroupId(), SearchCriteria.Op.EQ); + ListByGroupId.done(); + + ListByPolicyId = createSearchBuilder(); + ListByPolicyId.and("policyId", ListByPolicyId.entity().getAclPolicyId(), SearchCriteria.Op.EQ); + ListByPolicyId.done(); + + findByPolicyGroupId = createSearchBuilder(); + findByPolicyGroupId.and("policyId", findByPolicyGroupId.entity().getAclPolicyId(), SearchCriteria.Op.EQ); + findByPolicyGroupId.and("groupId", findByPolicyGroupId.entity().getAclGroupId(), SearchCriteria.Op.EQ); + findByPolicyGroupId.done(); + + return true; + } + + @Override + public List listByGroupId(long groupId) { + SearchCriteria sc = ListByGroupId.create(); + sc.setParameters("groupId", groupId); + return listBy(sc); + } + + @Override + public List listByPolicyId(long policyId) { + SearchCriteria sc = ListByPolicyId.create(); + sc.setParameters("policyId", policyId); + return listBy(sc); + } + + @Override + public IAMGroupPolicyMapVO findByGroupAndPolicy(long groupId, long policyId) { + SearchCriteria sc = findByPolicyGroupId.create(); + sc.setParameters("policyId", policyId); + sc.setParameters("groupId", groupId); + return findOneBy(sc); + } +} \ No newline at end of file diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyDao.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyDao.java new file mode 100644 index 00000000000..ace7d8585ac --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyDao.java @@ -0,0 +1,28 @@ +// 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.server.dao; + +import org.apache.cloudstack.iam.api.IAMPolicy; +import org.apache.cloudstack.iam.server.IAMPolicyVO; + +import com.cloud.utils.db.GenericDao; + +public interface IAMPolicyDao extends GenericDao { + + IAMPolicy findByName(String policyName); + +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyDaoImpl.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyDaoImpl.java new file mode 100644 index 00000000000..293cf6f59ee --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyDaoImpl.java @@ -0,0 +1,57 @@ +// 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.server.dao; + +import java.util.Map; + +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.iam.api.IAMPolicy; +import org.apache.cloudstack.iam.server.IAMPolicyVO; +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +public class IAMPolicyDaoImpl extends GenericDaoBase implements IAMPolicyDao { + private SearchBuilder nameSearch; + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + + nameSearch = createSearchBuilder(); + nameSearch.and("name", nameSearch.entity().getName(), SearchCriteria.Op.EQ); + // nameSearch.and("domainId", nameSearch.entity().getDomainId(), + // SearchCriteria.Op.EQ); + nameSearch.done(); + + + return true; + } + + @Override + public IAMPolicy findByName(String name) { + SearchCriteria sc = nameSearch.create(); + sc.setParameters("name", name); + + return findOneBy(sc); + } + +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyPermissionDao.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyPermissionDao.java new file mode 100644 index 00000000000..cdcb02b1dee --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyPermissionDao.java @@ -0,0 +1,39 @@ +// 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.server.dao; +import java.util.List; + +import org.apache.cloudstack.iam.api.IAMPolicyPermission.Permission; +import org.apache.cloudstack.iam.server.IAMPolicyPermissionVO; + +import com.cloud.utils.db.GenericDao; + +public interface IAMPolicyPermissionDao extends GenericDao { + + List listByPolicy(long policyId); + + IAMPolicyPermissionVO findByPolicyAndEntity(long policyId, String entityType, String scope, Long scopeId, + String action, Permission perm); + + List listGrantedByActionAndScope(long policyId, String action, String scope); + + List listByPolicyActionAndEntity(long policyId, String action, String entityType); + + List listByPolicyAccessAndEntity(long policyId, String accessType, String entityType); + + List listByEntity(String entityType, Long entityId); +} diff --git a/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyPermissionDaoImpl.java b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyPermissionDaoImpl.java new file mode 100644 index 00000000000..3f976cfefce --- /dev/null +++ b/services/iam/server/src/org/apache/cloudstack/iam/server/dao/IAMPolicyPermissionDaoImpl.java @@ -0,0 +1,129 @@ +// 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.server.dao; + +import java.util.List; +import java.util.Map; + +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.iam.api.IAMPolicyPermission.Permission; +import org.apache.cloudstack.iam.server.IAMPolicyPermissionVO; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +public class IAMPolicyPermissionDaoImpl extends GenericDaoBase implements + IAMPolicyPermissionDao { + + private SearchBuilder policyIdSearch; + private SearchBuilder fullSearch; + private SearchBuilder actionScopeSearch; + private SearchBuilder entitySearch; + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + + policyIdSearch = createSearchBuilder(); + policyIdSearch.and("policyId", policyIdSearch.entity().getAclPolicyId(), SearchCriteria.Op.EQ); + policyIdSearch.done(); + + fullSearch = createSearchBuilder(); + fullSearch.and("policyId", fullSearch.entity().getAclPolicyId(), SearchCriteria.Op.EQ); + fullSearch.and("entityType", fullSearch.entity().getEntityType(), SearchCriteria.Op.EQ); + fullSearch.and("scope", fullSearch.entity().getScope(), SearchCriteria.Op.EQ); + fullSearch.and("scopeId", fullSearch.entity().getScopeId(), SearchCriteria.Op.EQ); + fullSearch.and("action", fullSearch.entity().getAction(), SearchCriteria.Op.EQ); + fullSearch.and("permission", fullSearch.entity().getPermission(), SearchCriteria.Op.EQ); + fullSearch.and("accessType", fullSearch.entity().getAccessType(), SearchCriteria.Op.EQ); + fullSearch.done(); + + actionScopeSearch = createSearchBuilder(); + actionScopeSearch.and("policyId", actionScopeSearch.entity().getAclPolicyId(), SearchCriteria.Op.EQ); + actionScopeSearch.and("scope", actionScopeSearch.entity().getScope(), SearchCriteria.Op.EQ); + actionScopeSearch.and("action", actionScopeSearch.entity().getAction(), SearchCriteria.Op.EQ); + actionScopeSearch.and("permission", actionScopeSearch.entity().getPermission(), SearchCriteria.Op.EQ); + actionScopeSearch.done(); + + entitySearch = createSearchBuilder(); + entitySearch.and("entityType", entitySearch.entity().getEntityType(), SearchCriteria.Op.EQ); + entitySearch.and("scopeId", entitySearch.entity().getScopeId(), SearchCriteria.Op.EQ); + entitySearch.done(); + + return true; + } + + @Override + public List listByPolicy(long policyId) { + SearchCriteria sc = policyIdSearch.create(); + sc.setParameters("policyId", policyId); + return listBy(sc); + } + + @Override + public IAMPolicyPermissionVO findByPolicyAndEntity(long policyId, String entityType, String scope, Long scopeId, + String action, Permission perm) { + SearchCriteria sc = fullSearch.create(); + sc.setParameters("policyId", policyId); + sc.setParameters("entityType", entityType); + sc.setParameters("scope", scope); + sc.setParameters("scopeId", scopeId); + sc.setParameters("action", action); + sc.setParameters("permission", perm); + return findOneBy(sc); + } + + @Override + public List listGrantedByActionAndScope(long policyId, String action, String scope) { + SearchCriteria sc = actionScopeSearch.create(); + sc.setParameters("policyId", policyId); + sc.setParameters("action", action); + sc.setParameters("scope", scope); + sc.setParameters("permission", Permission.Allow); + return listBy(sc); + } + + @Override + public List listByPolicyActionAndEntity(long policyId, String action, String entityType) { + SearchCriteria sc = fullSearch.create(); + sc.setParameters("policyId", policyId); + sc.setParameters("entityType", entityType); + sc.setParameters("action", action); + return listBy(sc); + } + + @Override + public List listByPolicyAccessAndEntity(long policyId, String accessType, + String entityType) { + SearchCriteria sc = fullSearch.create(); + sc.setParameters("policyId", policyId); + sc.setParameters("entityType", entityType); + sc.setParameters("accessType", accessType); + return listBy(sc); + } + + @Override + public List listByEntity(String entityType, Long entityId) { + SearchCriteria sc = fullSearch.create(); + sc.setParameters("entityType", entityType); + sc.setParameters("scopeId", entityId); + return listBy(sc); + } + +} diff --git a/services/iam/server/test/org/apache/cloudstack/iam/IAMServiceUnitTest.java b/services/iam/server/test/org/apache/cloudstack/iam/IAMServiceUnitTest.java new file mode 100644 index 00000000000..53cfc71f936 --- /dev/null +++ b/services/iam/server/test/org/apache/cloudstack/iam/IAMServiceUnitTest.java @@ -0,0 +1,211 @@ +// 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 static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import org.apache.cloudstack.iam.api.IAMGroup; +import org.apache.cloudstack.iam.api.IAMPolicy; +import org.apache.cloudstack.iam.api.IAMService; +import org.apache.cloudstack.iam.server.IAMGroupVO; +import org.apache.cloudstack.iam.server.IAMPolicyVO; +import org.apache.cloudstack.iam.server.IAMServiceImpl; +import org.apache.cloudstack.iam.server.dao.IAMAccountPolicyMapDao; +import org.apache.cloudstack.iam.server.dao.IAMGroupAccountMapDao; +import org.apache.cloudstack.iam.server.dao.IAMGroupDao; +import org.apache.cloudstack.iam.server.dao.IAMGroupPolicyMapDao; +import org.apache.cloudstack.iam.server.dao.IAMPolicyDao; +import org.apache.cloudstack.iam.server.dao.IAMPolicyPermissionDao; +import org.apache.cloudstack.test.utils.SpringUtils; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.db.SearchCriteria; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(loader = AnnotationConfigContextLoader.class) +public class IAMServiceUnitTest { + + @Inject + IAMService _iamService; + + @Inject + IAMPolicyDao _aclPolicyDao; + + @Inject + IAMGroupDao _aclGroupDao; + + @Inject + EntityManager _entityMgr; + + @Inject + IAMGroupPolicyMapDao _aclGroupPolicyMapDao; + + @Inject + IAMGroupAccountMapDao _aclGroupAccountMapDao; + + @Inject + IAMPolicyPermissionDao _policyPermissionDao; + + @BeforeClass + public static void setUpClass() throws ConfigurationException { + } + + @Before + public void setUp() { + ComponentContext.initComponentsLifeCycle(); + IAMGroupVO group = new IAMGroupVO("group1", "my first group"); + Mockito.when(_aclGroupDao.persist(Mockito.any(IAMGroupVO.class))).thenReturn(group); + List groups = new ArrayList(); + groups.add(group); + when(_aclGroupDao.search(Mockito.any(SearchCriteria.class), Mockito.any(com.cloud.utils.db.Filter.class))) + .thenReturn(groups); + + IAMPolicyVO policy = new IAMPolicyVO("policy1", "my first policy"); + Mockito.when(_aclPolicyDao.persist(Mockito.any(IAMPolicyVO.class))).thenReturn(policy); + + } + + @After + public void tearDown() { + } + + @Test(expected = InvalidParameterValueException.class) + public void createAclGroupTest() { + IAMGroup group = _iamService.createIAMGroup("group1", "my first group", "/root/mydomain"); + assertNotNull("Acl group 'group1' failed to create ", group); + + IAMGroupVO group2 = new IAMGroupVO("group1", "my second group"); + when(_aclGroupDao.findByName(eq("/root/mydomain"), eq("group1"))).thenReturn(group2); + + IAMGroup group3 = _iamService.createIAMGroup("group1", "my first group", "/root/mydomain"); + } + + @Test(expected = InvalidParameterValueException.class) + public void deleteAclGroupInvalidIdTest() { + when(_aclGroupDao.findById(20L)).thenReturn(null); + _iamService.deleteIAMGroup(20L); + } + + @Test + public void accountGroupMaptest() { + // create group + IAMGroupVO group = new IAMGroupVO("group1", "my first group"); + + // add account to group + List accountIds = new ArrayList(); + accountIds.add(100L); + when(_aclGroupDao.findById(20L)).thenReturn(group); + _iamService.addAccountsToGroup(accountIds, 20L); + + _iamService.removeAccountsFromGroup(accountIds, 20L); + } + + @Test(expected = InvalidParameterValueException.class) + public void createAclPolicyTest() { + IAMPolicy policy = _iamService.createIAMPolicy("policy1", "my first policy", null, "/root/mydomain"); + assertNotNull("Acl policy 'policy1' failed to create ", policy); + + IAMPolicyVO rvo = new IAMPolicyVO("policy2", "second policy"); + when(_aclPolicyDao.findByName(eq("policy2"))).thenReturn(rvo); + + _iamService.createIAMPolicy("policy2", "second policy", null, "/root/mydomain"); + } + + @Test(expected = InvalidParameterValueException.class) + public void deleteAclPolicyInvalidIdTest() { + when(_aclPolicyDao.findById(34L)).thenReturn(null); + _iamService.deleteIAMPolicy(34L); + } + + @Configuration + @ComponentScan(basePackageClasses = {IAMServiceImpl.class}, includeFilters = {@Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)}, useDefaultFilters = false) + public static class TestConfiguration extends SpringUtils.CloudStackTestConfiguration { + + @Bean + public IAMPolicyDao aclPolicyDao() { + return Mockito.mock(IAMPolicyDao.class); + } + + @Bean + public IAMGroupDao aclGroupDao() { + return Mockito.mock(IAMGroupDao.class); + } + + @Bean + public EntityManager entityManager() { + return Mockito.mock(EntityManager.class); + } + + @Bean + public IAMGroupPolicyMapDao aclGroupPolicyMapDao() { + return Mockito.mock(IAMGroupPolicyMapDao.class); + } + + @Bean + public IAMGroupAccountMapDao aclGroupAccountMapDao() { + return Mockito.mock(IAMGroupAccountMapDao.class); + } + + @Bean + public IAMAccountPolicyMapDao aclAccountPolicyMapDao() { + return Mockito.mock(IAMAccountPolicyMapDao.class); + } + + @Bean + public IAMPolicyPermissionDao aclPolicyPermissionDao() { + return Mockito.mock(IAMPolicyPermissionDao.class); + } + + public static class Library implements TypeFilter { + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + ComponentScan cs = TestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + } + } +} diff --git a/services/iam/server/test/resources/db.properties b/services/iam/server/test/resources/db.properties new file mode 100644 index 00000000000..e1b5fe9a2c1 --- /dev/null +++ b/services/iam/server/test/resources/db.properties @@ -0,0 +1,75 @@ +# 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. + + +# management server clustering parameters, change cluster.node.IP to the machine IP address +# in which the management server(Tomcat) is running +cluster.node.IP=127.0.0.1 +cluster.servlet.port=9090 +region.id=1 + +# CloudStack database settings +db.cloud.username=cloud +db.cloud.password=cloud +db.root.password= +db.cloud.host=localhost +db.cloud.port=3306 +db.cloud.name=cloud + +# CloudStack database tuning parameters +db.cloud.maxActive=250 +db.cloud.maxIdle=30 +db.cloud.maxWait=10000 +db.cloud.autoReconnect=true +db.cloud.validationQuery=SELECT 1 +db.cloud.testOnBorrow=true +db.cloud.testWhileIdle=true +db.cloud.timeBetweenEvictionRunsMillis=40000 +db.cloud.minEvictableIdleTimeMillis=240000 +db.cloud.poolPreparedStatements=false +db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLimit=4096 + +# usage database settings +db.usage.username=cloud +db.usage.password=cloud +db.usage.host=localhost +db.usage.port=3306 +db.usage.name=cloud_usage + +# usage database tuning parameters +db.usage.maxActive=100 +db.usage.maxIdle=30 +db.usage.maxWait=10000 +db.usage.autoReconnect=true + +# awsapi database settings +db.awsapi.username=cloud +db.awsapi.password=cloud +db.awsapi.host=localhost +db.awsapi.port=3306 +db.awsapi.name=cloudbridge + +# Simulator database settings +db.simulator.username=cloud +db.simulator.password=cloud +db.simulator.host=localhost +db.simulator.port=3306 +db.simulator.name=simulator +db.simulator.maxActive=250 +db.simulator.maxIdle=30 +db.simulator.maxWait=10000 +db.simulator.autoReconnect=true