projects: Role based users in Projects (#4128)

Enabling Role Based users in projects
Primate PR related to the FR: apache/cloudstack-primate#382
Doc PR: https://github.com/apache/cloudstack-documentation/pull/145

Co-authored-by: Pearl Dsilva <pearl.dsilva@shapeblue.com>
Co-authored-by: Suresh Kumar Anaparti <suresh.anaparti@shapeblue.com>
This commit is contained in:
Pearl Dsilva 2020-08-13 15:45:39 +05:30 committed by GitHub
parent 3adee270c7
commit c578004fe5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
107 changed files with 4881 additions and 538 deletions

View File

@ -22,6 +22,10 @@ import java.util.Map;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RolePermission;
import org.apache.cloudstack.annotation.Annotation;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.PodResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.config.Configuration;
import org.apache.cloudstack.ha.HAConfig;
import org.apache.cloudstack.usage.Usage;
@ -76,10 +80,6 @@ import com.cloud.user.User;
import com.cloud.vm.Nic;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.PodResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
public class EventTypes {
@ -190,6 +190,14 @@ public class EventTypes {
public static final String EVENT_ROLE_PERMISSION_UPDATE = "ROLE.PERMISSION.UPDATE";
public static final String EVENT_ROLE_PERMISSION_DELETE = "ROLE.PERMISSION.DELETE";
// Project Role events
public static final String EVENT_PROJECT_ROLE_CREATE = "PROJECT.ROLE.CREATE";
public static final String EVENT_PROJECT_ROLE_UPDATE = "PROJECT.ROLE.UPDATE";
public static final String EVENT_PROJECT_ROLE_DELETE = "PROJECT.ROLE.DELETE";
public static final String EVENT_PROJECT_ROLE_PERMISSION_CREATE = "PROJECT.ROLE.PERMISSION.CREATE";
public static final String EVENT_PROJECT_ROLE_PERMISSION_UPDATE = "PROJECT.ROLE.PERMISSION.UPDATE";
public static final String EVENT_PROJECT_ROLE_PERMISSION_DELETE = "PROJECT.ROLE.PERMISSION.DELETE";
// CA events
public static final String EVENT_CA_CERTIFICATE_ISSUE = "CA.CERTIFICATE.ISSUE";
public static final String EVENT_CA_CERTIFICATE_REVOKE = "CA.CERTIFICATE.REVOKE";
@ -399,9 +407,11 @@ public class EventTypes {
public static final String EVENT_PROJECT_ACTIVATE = "PROJECT.ACTIVATE";
public static final String EVENT_PROJECT_SUSPEND = "PROJECT.SUSPEND";
public static final String EVENT_PROJECT_ACCOUNT_ADD = "PROJECT.ACCOUNT.ADD";
public static final String EVENT_PROJECT_USER_ADD = "PROJECT.USER.ADD";
public static final String EVENT_PROJECT_INVITATION_UPDATE = "PROJECT.INVITATION.UPDATE";
public static final String EVENT_PROJECT_INVITATION_REMOVE = "PROJECT.INVITATION.REMOVE";
public static final String EVENT_PROJECT_ACCOUNT_REMOVE = "PROJECT.ACCOUNT.REMOVE";
public static final String EVENT_PROJECT_USER_REMOVE = "PROJECT.USER.REMOVE";
// Network as a Service
public static final String EVENT_NETWORK_ELEMENT_CONFIGURE = "NETWORK.ELEMENT.CONFIGURE";

View File

@ -23,8 +23,12 @@ public interface ProjectAccount {
long getAccountId();
Long getUserId();
long getProjectId();
Long getProjectRoleId();
Role getAccountRole();
long getProjectAccountId();

View File

@ -41,4 +41,10 @@ public interface ProjectInvitation extends ControlledEntity, Identity, InternalI
Long getInDomainId();
ProjectAccount.Role getAccountRole();
Long getForUserId();
Long getProjectRoleId();
}

View File

@ -16,6 +16,8 @@
// under the License.
package com.cloud.projects;
import java.util.List;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
@ -34,10 +36,17 @@ public interface ProjectService {
* - account name of the project owner
* @param domainId
* - domainid of the project owner
*
* @param userId
* - id of the user to be made as project owner
*
* @param accountId
* - id of the account to which the user belongs
*
* @return the project if created successfully, null otherwise
* @throws ResourceAllocationException
*/
Project createProject(String name, String displayText, String accountName, Long domainId) throws ResourceAllocationException;
Project createProject(String name, String displayText, String accountName, Long domainId, Long userId, Long accountId) throws ResourceAllocationException;
/**
* Deletes a project
@ -57,10 +66,12 @@ public interface ProjectService {
*/
Project getProject(long id);
ProjectAccount assignAccountToProject(Project project, long accountId, Role accountRole);
ProjectAccount assignAccountToProject(Project project, long accountId, Role accountRole, Long userId, Long projectRoleId);
Account getProjectOwner(long projectId);
List<Long> getProjectOwners(long projectId);
boolean unassignAccountFromProject(long projectId, long accountId);
Project findByProjectAccountId(long projectAccountId);
@ -69,11 +80,15 @@ public interface ProjectService {
Project updateProject(long id, String displayText, String newOwnerName) throws ResourceAllocationException;
boolean addAccountToProject(long projectId, String accountName, String email);
Project updateProject(long id, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException;
boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType);
boolean deleteAccountFromProject(long projectId, String accountName);
boolean updateInvitation(long projectId, String accountName, String token, boolean accept);
boolean deleteUserFromProject(long projectId, long userId);
boolean updateInvitation(long projectId, String accountName, Long userId, String token, boolean accept);
Project activateProject(long projectId);
@ -84,4 +99,7 @@ public interface ProjectService {
boolean deleteProjectInvitation(long invitationId);
Project findByProjectAccountIdIncludingRemoved(long projectAccountId);
boolean addUserToProject(Long projectId, String username, String email, Long projectRoleId, Role projectRole);
}

View File

@ -0,0 +1,26 @@
// 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.acl;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
public interface ProjectRole extends RoleEntity, InternalIdentity, Identity {
Long getProjectId();
}

View File

@ -0,0 +1,24 @@
// 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.acl;
public interface ProjectRolePermission extends RolePermissionEntity {
long getProjectRoleId();
long getProjectId();
long getSortOrder();
}

View File

@ -0,0 +1,118 @@
// 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.acl;
import java.util.List;
import org.apache.cloudstack.api.command.admin.acl.project.CreateProjectRolePermissionCmd;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
public interface ProjectRoleService {
/**
* Creates a Project role in a Project to be mapped to a user/ account (all users of an account)
* @param projectId ID of the project where the project role is to be created
* @param name Name of the project role
* @param description description provided for the project role
* @return the Instance of the project role created
*/
ProjectRole createProjectRole(Long projectId, String name, String description);
/**
* Updates a Project role created
* @param role Project role reference to be updated
* @param projectId ID of the project where the Project role exists
* @param name new name to be given to the project role
* @param description description for the project role
* @return the updated instance of the project role
*/
ProjectRole updateProjectRole(ProjectRole role, Long projectId, String name, String description);
/**
*
* @param projectId ID of the project in which the project role is to be searched for
* @param roleName name/ part of a project role name
* @return List of Project roles matching the given name in the project
*/
List<ProjectRole> findProjectRolesByName(Long projectId, String roleName);
/**
*
* @param role Project role to be deleted
* @param projectId ID of the project where the role is present
* @return success/failure of the delete operation
*/
boolean deleteProjectRole(ProjectRole role, Long projectId);
/**
* Determines if Dynamic Roles feature is enabled , if it isn't then the project roles will not be applied
*/
boolean isEnabled();
/**
*
* @param roleId Project role ID which needs to be found
* @param projectId ID of the project where the role is to be found
* @return the corresponding project role
*/
ProjectRole findProjectRole(Long roleId, Long projectId);
/**
*
* @param projectId ID of the project whosr project roles are to be listed
* @return List of all available project roles
*/
List<ProjectRole> findProjectRoles(Long projectId);
/**
* Creates a project role permission to be mapped to a project role.
* All accounts/users mapped to this project role will impose restrictions on API access
* to users based on the project role. This is to further limit restrictions on users in projects
*/
ProjectRolePermission createProjectRolePermission(CreateProjectRolePermissionCmd cmd);
/**
* Updates the order of the project role permission
* @param projectId ID of the project where the project role permission exists
* @param projectRole project role to which the permission is mapped to
* @param rolePermissionsOrder re-arranged order of permissions
* @return success/failure of operation
*/
boolean updateProjectRolePermission(Long projectId, ProjectRole projectRole, List<ProjectRolePermission> rolePermissionsOrder);
/**
*
* Updates the permission of the project role permission
*/
boolean updateProjectRolePermission(Long projectId, ProjectRole projectRole, ProjectRolePermission projectRolePermission, Permission newPermission);
/**
* Finds the project role permission for the given ID
*/
ProjectRolePermission findProjectRolePermission(final Long projRolePermissionId);
/**
* deletes the given project role
*/
boolean deleteProjectRolePermission(ProjectRolePermission projectRolePermission);
/**
* returns list of all project role permissions mapped to the requested project role
*/
List<ProjectRolePermission> findAllProjectRolePermissions(Long projectId, Long projectRoleId);
}

View File

@ -20,9 +20,7 @@ package org.apache.cloudstack.acl;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
public interface Role extends InternalIdentity, Identity {
String getName();
public interface Role extends RoleEntity, InternalIdentity, Identity {
RoleType getRoleType();
String getDescription();
boolean isDefault();
}

View File

@ -0,0 +1,26 @@
// 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.acl;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
public interface RoleEntity extends InternalIdentity, Identity {
String getName();
String getDescription();
}

View File

@ -17,15 +17,7 @@
package org.apache.cloudstack.acl;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
public interface RolePermission extends InternalIdentity, Identity {
enum Permission {ALLOW, DENY}
public interface RolePermission extends RolePermissionEntity {
long getRoleId();
Rule getRule();
Permission getPermission();
String getDescription();
long getSortOrder();
}

View File

@ -0,0 +1,30 @@
// 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.acl;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
public interface RolePermissionEntity extends InternalIdentity, Identity {
public enum Permission {
ALLOW, DENY
}
Rule getRule();
Permission getPermission();
String getDescription();
}

View File

@ -22,7 +22,7 @@ import java.util.Map;
import com.cloud.utils.Pair;
import org.apache.cloudstack.acl.RolePermission.Permission;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.framework.config.ConfigKey;
public interface RoleService {

View File

@ -348,6 +348,8 @@ public class ApiConstants {
public static final String STORAGE_POLICY = "storagepolicy";
public static final String STORAGE_MOTION_ENABLED = "storagemotionenabled";
public static final String STORAGE_CAPABILITIES = "storagecapabilities";
public static final String OWNER = "owner";
public static final String SWAP_OWNER = "swapowner";
public static final String SYSTEM_VM_TYPE = "systemvmtype";
public static final String TAGS = "tags";
public static final String TARGET_IQN = "targetiqn";
@ -474,12 +476,15 @@ public class ApiConstants {
public static final String PROJECT = "project";
public static final String ROLE = "role";
public static final String ROLE_ID = "roleid";
public static final String PROJECT_ROLE_ID = "projectroleid";
public static final String PROJECT_ROLE_NAME = "projectrolename";
public static final String ROLE_TYPE = "roletype";
public static final String ROLE_NAME = "rolename";
public static final String PERMISSION = "permission";
public static final String RULE = "rule";
public static final String RULES = "rules";
public static final String RULE_ID = "ruleid";
public static final String PROJECT_ROLE_PERMISSION_ID = "projectrolepermissionid";
public static final String RULE_ORDER = "ruleorder";
public static final String USER = "user";
public static final String ACTIVE_ONLY = "activeonly";

View File

@ -39,7 +39,7 @@ public interface ApiServerService {
public String getSerializedApiError(ServerApiException ex, Map<String, Object[]> apiCommandParams, String responseType);
public String handleRequest(Map params, String responseType, StringBuilder auditTrailSb) throws ServerApiException;
public String handleRequest(Map<String, Object[]> params, String responseType, StringBuilder auditTrailSb) throws ServerApiException;
public Class<?> getCmdClass(String cmdName);

View File

@ -17,6 +17,32 @@
package org.apache.cloudstack.api;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import javax.inject.Inject;
import org.apache.cloudstack.acl.ProjectRoleService;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.affinity.AffinityGroupService;
import org.apache.cloudstack.alert.AlertService;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
import org.apache.cloudstack.query.QueryService;
import org.apache.cloudstack.usage.UsageService;
import org.apache.log4j.Logger;
import com.cloud.configuration.ConfigurationService;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
@ -58,29 +84,6 @@ import com.cloud.utils.db.EntityManager;
import com.cloud.utils.db.UUIDManager;
import com.cloud.vm.UserVmService;
import com.cloud.vm.snapshot.VMSnapshotService;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.affinity.AffinityGroupService;
import org.apache.cloudstack.alert.AlertService;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
import org.apache.cloudstack.query.QueryService;
import org.apache.cloudstack.usage.UsageService;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public abstract class BaseCmd {
private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName());
@ -112,6 +115,8 @@ public abstract class BaseCmd {
@Inject
public RoleService roleService;
@Inject
public ProjectRoleService projRoleService;
@Inject
public UserVmService _userVmService;
@Inject
public ManagementService _mgr;
@ -264,6 +269,10 @@ public abstract class BaseCmd {
*/
public abstract long getEntityOwnerId();
public List<Long> getEntityOwnerIds() {
return null;
}
public Object getResponseObject() {
return _responseObject;
}

View File

@ -0,0 +1,63 @@
// 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.api.command.admin.acl;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.acl.Rule;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import com.google.common.base.Strings;
public abstract class BaseRolePermissionCmd extends BaseCmd {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.RULE, type = CommandType.STRING, required = true, description = "The API name or wildcard rule such as list*",
validations = {ApiArgValidator.NotNullOrEmpty})
private String rule;
@Parameter(name = ApiConstants.PERMISSION, type = CommandType.STRING, required = true, description = "The rule permission, allow or deny. Default: deny.")
private String permission;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "The description of the role permission")
private String description;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Rule getRule() {
return new Rule(rule);
}
public Permission getPermission() {
if (Strings.isNullOrEmpty(permission)) {
return null;
}
return Permission.valueOf(permission.toUpperCase());
}
public String getDescription() {
return description;
}
}

View File

@ -17,28 +17,27 @@
package org.apache.cloudstack.api.command.admin.acl;
import com.cloud.user.Account;
import com.google.common.base.Strings;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RolePermission;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.Rule;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.response.RolePermissionResponse;
import org.apache.cloudstack.api.response.RoleResponse;
import org.apache.cloudstack.context.CallContext;
@APICommand(name = CreateRolePermissionCmd.APINAME, description = "Adds a API permission to a role", responseObject = RolePermissionResponse.class,
import com.cloud.user.Account;
@APICommand(name = CreateRolePermissionCmd.APINAME, description = "Adds an API permission to a role", responseObject = RolePermissionResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.9.0",
authorized = {RoleType.Admin})
public class CreateRolePermissionCmd extends BaseCmd {
public class CreateRolePermissionCmd extends BaseRolePermissionCmd {
public static final String APINAME = "createRolePermission";
/////////////////////////////////////////////////////
@ -49,16 +48,6 @@ public class CreateRolePermissionCmd extends BaseCmd {
description = "ID of the role", validations = {ApiArgValidator.PositiveNumber})
private Long roleId;
@Parameter(name = ApiConstants.RULE, type = CommandType.STRING, required = true, description = "The API name or wildcard rule such as list*",
validations = {ApiArgValidator.NotNullOrEmpty})
private String rule;
@Parameter(name = ApiConstants.PERMISSION, type = CommandType.STRING, required = true, description = "The rule permission, allow or deny. Default: deny.")
private String permission;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "The description of the role permission")
private String description;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -67,21 +56,6 @@ public class CreateRolePermissionCmd extends BaseCmd {
return roleId;
}
public Rule getRule() {
return new Rule(rule);
}
public RolePermission.Permission getPermission() {
if (Strings.isNullOrEmpty(permission)) {
return null;
}
return RolePermission.Permission.valueOf(permission.toUpperCase());
}
public String getDescription() {
return description;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -17,10 +17,12 @@
package org.apache.cloudstack.api.command.admin.acl;
import com.cloud.user.Account;
import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RolePermission;
import org.apache.cloudstack.acl.RolePermission.Permission;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
@ -34,8 +36,7 @@ import org.apache.cloudstack.api.response.RoleResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
import java.util.ArrayList;
import java.util.List;
import com.cloud.user.Account;
@APICommand(name = UpdateRolePermissionCmd.APINAME, description = "Updates a role permission order", responseObject = SuccessResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,

View File

@ -0,0 +1,80 @@
// 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.api.command.admin.acl.project;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
import org.apache.cloudstack.context.CallContext;
import com.cloud.user.Account;
@APICommand(name = CreateProjectRoleCmd.APINAME, description = "Creates a Project role", responseObject = ProjectRoleResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
authorized = {RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin, RoleType.User}, since = "4.15.0")
public class CreateProjectRoleCmd extends ProjectRoleCmd {
public static final String APINAME = "createProjectRole";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.NAME, type = BaseCmd.CommandType.STRING, required = true,
description = "creates a project role with this unique name", validations = {ApiArgValidator.NotNullOrEmpty})
private String projectRoleName;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getProjectRoleName() {
return projectRoleName;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
CallContext.current().setEventDetails("Role: " + getProjectRoleName() + ", description: " + getProjectRoleDescription());
ProjectRole projectRole = projRoleService.createProjectRole(getProjectId(), getProjectRoleName(), getProjectRoleDescription());
if (projectRole == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create project role");
}
setupProjectRoleResponse(projectRole);
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,105 @@
// 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.api.command.admin.acl.project;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.ProjectRolePermission;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.acl.BaseRolePermissionCmd;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ProjectRolePermissionResponse;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
import org.apache.cloudstack.context.CallContext;
@APICommand(name = CreateProjectRolePermissionCmd.APINAME, description = "Adds API permissions to a project role", responseObject = ProjectRolePermissionResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {
RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}, since = "4.15.0")
public class CreateProjectRolePermissionCmd extends BaseRolePermissionCmd {
public static final String APINAME = "createProjectRolePermission";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.PROJECT_ROLE_ID, type = CommandType.UUID, required = true, entityType = ProjectRoleResponse.class,
description = "ID of the project role", validations = {ApiArgValidator.PositiveNumber})
private Long projectRoleId;
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, required = true, entityType = ProjectResponse.class,
description = "ID of project where project role permission is to be created", validations = {ApiArgValidator.NotNullOrEmpty})
private Long projectId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getProjectRoleId() {
return projectRoleId;
}
public Long getProjectId() {
return projectId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
ProjectRole projectRole = projRoleService.findProjectRole(getProjectRoleId(), getProjectId());
if (projectRole == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid project role ID provided");
}
CallContext.current().setEventDetails("Project Role ID: " + projectRole.getId() + ", Rule:" + getRule() + ", Permission: " + getPermission() + ", Description: " + getDescription());
final ProjectRolePermission projectRolePermission = projRoleService.createProjectRolePermission(this);
if (projectRolePermission == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create project role permission");
}
setupResponse(projectRolePermission, projectRole);
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}
private void setupResponse(final ProjectRolePermission rolePermission, final ProjectRole role) {
final ProjectRolePermissionResponse response = new ProjectRolePermissionResponse();
response.setId(rolePermission.getUuid());
response.setProjectId(_projectService.getProject(rolePermission.getProjectId()).getUuid());
response.setProjectRoleId(role.getUuid());
response.setRule(rolePermission.getRule());
response.setRulePermission(rolePermission.getPermission());
response.setDescription(rolePermission.getDescription());
response.setResponseName(getCommandName());
response.setObjectName("projectrolepermission");
setResponseObject(response);
}
}

View File

@ -0,0 +1,88 @@
// 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.api.command.admin.acl.project;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
@APICommand(name = DeleteProjectRoleCmd.APINAME, description = "Delete Project roles in CloudStack", responseObject = SuccessResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.15.0", authorized = {
RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class DeleteProjectRoleCmd extends BaseCmd {
public static final String APINAME = "deleteProjectRole" ;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ProjectRoleResponse.class,
description = "ID of the project role to be deleted", validations = {ApiArgValidator.PositiveNumber})
private Long id;
@Parameter(name = ApiConstants.PROJECT_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ProjectResponse.class,
description = "ID of the project from where the role is to be deleted", validations = {ApiArgValidator.PositiveNumber})
private Long projectId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getId() {
return id;
}
public Long getProjectId() { return projectId; }
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
ProjectRole role = projRoleService.findProjectRole(getId(), getProjectId());
if (role == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Cannot find project role with provided id");
}
CallContext.current().setEventDetails("Deleting Project Role with id: " + role.getId());
boolean result = projRoleService.deleteProjectRole(role, getProjectId());
SuccessResponse response = new SuccessResponse(getCommandName());
response.setSuccess(result);
setResponseObject(response);
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}
}

View File

@ -0,0 +1,89 @@
// 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.api.command.admin.acl.project;
import org.apache.cloudstack.acl.ProjectRolePermission;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ProjectRolePermissionResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
@APICommand(name = DeleteProjectRolePermissionCmd.APINAME, description = "Deletes a project role permission in the project", responseObject = SuccessResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {
RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}, since = "4.15.0")
public class DeleteProjectRolePermissionCmd extends BaseCmd {
public static final String APINAME = "deleteProjectRolePermission";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.PROJECT_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ProjectResponse.class,
description = "ID of the project where the project role permission is to be deleted", validations = {ApiArgValidator.PositiveNumber})
private Long projectId;
@Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ProjectRolePermissionResponse.class,
description = "ID of the project role permission to be deleted", validations = {ApiArgValidator.PositiveNumber})
private Long projectRolePermissionId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getProjectId() {
return projectId;
}
public Long getProjectRolePermissionId() {
return projectRolePermissionId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
ProjectRolePermission rolePermission = projRoleService.findProjectRolePermission(getProjectRolePermissionId());
if (rolePermission == null || rolePermission.getProjectId() != getProjectId()) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role permission id provided for the project");
}
CallContext.current().setEventDetails("Deleting Project Role permission with id: " + rolePermission.getId());
boolean result = projRoleService.deleteProjectRolePermission(rolePermission);
SuccessResponse response = new SuccessResponse();
response.setSuccess(result);
setResponseObject(response);
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}
}

View File

@ -0,0 +1,113 @@
// 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.api.command.admin.acl.project;
import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.ProjectRolePermission;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ProjectRolePermissionResponse;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
@APICommand(name = ListProjectRolePermissionsCmd.APINAME, description = "Lists a project's project role permissions", responseObject = SuccessResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {
RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}, since = "4.15.0")
public class ListProjectRolePermissionsCmd extends BaseCmd {
public static final String APINAME = "listProjectRolePermissions";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, required = true, description = "ID of the project")
private Long projectId;
@Parameter(name = ApiConstants.PROJECT_ROLE_ID, type = CommandType.UUID, entityType = ProjectRoleResponse.class,
description = "ID of the project role", validations = {ApiArgValidator.PositiveNumber})
private Long projectRoleId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getProjectId() {
return projectId;
}
public Long getProjectRoleId() {
return projectRoleId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
List<ProjectRolePermission> projectRolePermissions = projRoleService.findAllProjectRolePermissions(getProjectId(), getProjectRoleId());
final ProjectRole projectRole = projRoleService.findProjectRole(getProjectRoleId(), getProjectId());
final ListResponse<ProjectRolePermissionResponse> response = new ListResponse<>();
final List<ProjectRolePermissionResponse> rolePermissionResponses = new ArrayList<>();
for (final ProjectRolePermission rolePermission : projectRolePermissions) {
ProjectRole role = projectRole;
if (role == null) {
role = projRoleService.findProjectRole(rolePermission.getProjectRoleId(), rolePermission.getProjectId());
}
rolePermissionResponses.add(setupResponse(role, rolePermission));
}
response.setResponses(rolePermissionResponses);
response.setResponseName(getCommandName());
setResponseObject(response);
}
private ProjectRolePermissionResponse setupResponse(ProjectRole role, ProjectRolePermission rolePermission) {
final ProjectRolePermissionResponse rolePermissionResponse = new ProjectRolePermissionResponse();
rolePermissionResponse.setProjectId(_projectService.getProject(rolePermission.getProjectId()).getUuid());
rolePermissionResponse.setProjectRoleId(role.getUuid());
rolePermissionResponse.setProjectRoleName(role.getName());
rolePermissionResponse.setId(rolePermission.getUuid());
rolePermissionResponse.setRule(rolePermission.getRule());
rolePermissionResponse.setRulePermission(rolePermission.getPermission());
rolePermissionResponse.setDescription(rolePermission.getDescription());
rolePermissionResponse.setObjectName("projectrolepermission");
return rolePermissionResponse;
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}
}

View File

@ -0,0 +1,116 @@
// 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.api.command.admin.acl.project;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.commons.lang3.StringUtils;
@APICommand(name = ListProjectRolesCmd.APINAME, description = "Lists Project roles in CloudStack", responseObject = ProjectRoleResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.15.0", authorized = {
RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class ListProjectRolesCmd extends BaseCmd {
public static final String APINAME = "listProjectRoles";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.PROJECT_ROLE_ID, type = CommandType.UUID, entityType = ProjectRoleResponse.class, description = "List project role by project role ID.")
private Long projectRoleId;
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, required = true, description = "List project role by project ID.")
private Long projectId;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "List project role by project role name.")
private String roleName;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getProjectRoleId() { return projectRoleId; }
public Long getProjectId() {
return projectId;
}
public String getRoleName() {
return roleName;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
List<ProjectRole> projectRoles;
if (getProjectId() != null && getProjectRoleId() != null) {
projectRoles = Collections.singletonList(projRoleService.findProjectRole(getProjectRoleId(), getProjectId()));
} else if (StringUtils.isNotBlank(getRoleName())) {
projectRoles = projRoleService.findProjectRolesByName(getProjectId(), getRoleName());
} else {
projectRoles = projRoleService.findProjectRoles(getProjectId());
}
final ListResponse<ProjectRoleResponse> response = new ListResponse<>();
final List<ProjectRoleResponse> roleResponses = new ArrayList<>();
for (ProjectRole role : projectRoles) {
if (role == null) {
continue;
}
roleResponses.add(setupProjectRoleResponse(role));
}
response.setResponses(roleResponses);
response.setResponseName(getCommandName());
setResponseObject(response);
}
private ProjectRoleResponse setupProjectRoleResponse(final ProjectRole role) {
final ProjectRoleResponse response = new ProjectRoleResponse();
response.setId(role.getUuid());
response.setProjectId(_projectService.getProject(role.getProjectId()).getUuid());
response.setRoleName(role.getName());
response.setDescription(role.getDescription());
response.setObjectName("projectrole");
return response;
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}
}

View File

@ -0,0 +1,62 @@
// 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.api.command.admin.acl.project;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
public abstract class ProjectRoleCmd extends BaseCmd {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, required = true, entityType = ProjectResponse.class,
description = "ID of project where role is being created", validations = {ApiArgValidator.NotNullOrEmpty})
private Long projectId;
@Parameter(name = ApiConstants.DESCRIPTION, type = BaseCmd.CommandType.STRING, description = "The description of the Project role")
private String projectRoleDescription;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getProjectId() {
return projectId;
}
public String getProjectRoleDescription() {
return projectRoleDescription;
}
protected void setupProjectRoleResponse(final ProjectRole role) {
final ProjectRoleResponse response = new ProjectRoleResponse();
response.setId(role.getUuid());
response.setProjectId(_projectService.getProject(role.getProjectId()).getUuid());
response.setRoleName(role.getName());
response.setDescription(role.getDescription());
response.setResponseName(getCommandName());
response.setObjectName("projectrole");
setResponseObject(response);
}
}

View File

@ -0,0 +1,85 @@
// 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.api.command.admin.acl.project;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
@APICommand(name = UpdateProjectRoleCmd.APINAME, description = "Creates a Project role", responseObject = ProjectRoleResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
authorized = {RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin, RoleType.User}, since = "4.15.0")
public class UpdateProjectRoleCmd extends ProjectRoleCmd {
public static final String APINAME = "updateProjectRole";
/////////////////////////////////////////////////////
//////////////// API Parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, required = true, entityType = ProjectRoleResponse.class,
description = "ID of the Project role", validations = {ApiArgValidator.PositiveNumber})
private Long id;
@Parameter(name = ApiConstants.NAME, type = BaseCmd.CommandType.STRING,
description = "creates a project role with this unique name", validations = {ApiArgValidator.NotNullOrEmpty})
private String projectRoleName;
/////////////////////////////////////////////////////
//////////////// Accessors //////////////////////////
/////////////////////////////////////////////////////
public Long getId() {
return id;
}
public String getProjectRoleName() {
return projectRoleName;
}
/////////////////////////////////////////////////////
//////////////// API Implementation /////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
ProjectRole role = projRoleService.findProjectRole(getId(), getProjectId());
if (role == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid project role id provided");
}
role = projRoleService.updateProjectRole(role, getProjectId(), getProjectRoleName(), getProjectRoleDescription());
setupProjectRoleResponse(role);
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return 0;
}
}

View File

@ -0,0 +1,163 @@
// 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.api.command.admin.acl.project;
import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.ProjectRolePermission;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ProjectRolePermissionResponse;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.commons.lang3.EnumUtils;
@APICommand(name = UpdateProjectRolePermissionCmd.APINAME, description = "Updates a project role permission and/or order", responseObject = SuccessResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {
RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}, since = "4.15.0")
public class UpdateProjectRolePermissionCmd extends BaseCmd {
public static final String APINAME = "updateProjectRolePermission";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.PROJECT_ROLE_ID, type = CommandType.UUID, required = true, entityType = ProjectRoleResponse.class,
description = "ID of the project role", validations = {ApiArgValidator.PositiveNumber})
private Long projectRoleId;
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, required = true, entityType = ProjectResponse.class,
description = "ID of project where project role permission is to be updated", validations = {ApiArgValidator.NotNullOrEmpty})
private Long projectId;
@Parameter(name = ApiConstants.RULE_ORDER, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = ProjectRolePermissionResponse.class,
description = "The parent role permission uuid, use 0 to move this rule at the top of the list")
private List<Long> projectRulePermissionOrder;
@Parameter(name = ApiConstants.PROJECT_ROLE_PERMISSION_ID, type = CommandType.UUID, entityType = ProjectRolePermissionResponse.class,
description = "Project Role permission rule id")
private Long projectRuleId;
@Parameter(name = ApiConstants.PERMISSION, type = CommandType.STRING,
description = "Rule permission, can be: allow or deny")
private String projectRolePermission;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getProjectRoleId() {
return projectRoleId;
}
public List<Long> getProjectRulePermissionOrder() {
return projectRulePermissionOrder;
}
public Long getProjectRuleId() {
return projectRuleId;
}
public Permission getProjectRolePermission() {
if (this.projectRolePermission == null) {
return null;
}
if (!EnumUtils.isValidEnum(Permission.class, projectRolePermission.toUpperCase())) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Values for permission parameter should be: allow or deny");
}
return Permission.valueOf(projectRolePermission.toUpperCase());
}
public Long getProjectId() {
return projectId;
}
/////////////////////////////////////////////////////
/////////////////// API Implementation //////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
ProjectRole projectRole = projRoleService.findProjectRole(getProjectRoleId(), getProjectId());
boolean result = false;
if (projectRole == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided");
}
if (getProjectRulePermissionOrder() != null) {
if (getProjectRuleId() != null || getProjectRolePermission() != null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Parameters permission and ruleid must be mutually exclusive with ruleorder");
}
CallContext.current().setEventDetails("Reordering permissions for role id: " + projectRole.getId());
result = updateProjectRolePermissionOrder(projectRole);
} else if (getProjectRuleId() != null || getProjectRolePermission() != null ) {
if (getProjectRulePermissionOrder() != null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Parameters permission and ruleid must be mutually exclusive with ruleorder");
}
ProjectRolePermission rolePermission = getValidProjectRolePermission();
CallContext.current().setEventDetails("Updating project role permission for rule id: " + getProjectRuleId() + " to: " + getProjectRolePermission().toString());
result = projRoleService.updateProjectRolePermission(projectId, projectRole, rolePermission, getProjectRolePermission());
}
SuccessResponse response = new SuccessResponse(getCommandName());
response.setSuccess(result);
setResponseObject(response);
}
private ProjectRolePermission getValidProjectRolePermission() {
ProjectRolePermission rolePermission = projRoleService.findProjectRolePermission(getProjectRuleId());
if (rolePermission == null || rolePermission.getProjectId() != getProjectId()) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Role permission doesn't exist in the project, probably because of invalid rule id");
}
return rolePermission;
}
private boolean updateProjectRolePermissionOrder(ProjectRole projectRole) {
final List<ProjectRolePermission> rolePermissionsOrder = new ArrayList<>();
for (Long rolePermissionId : getProjectRulePermissionOrder()) {
final ProjectRolePermission rolePermission = projRoleService.findProjectRolePermission(rolePermissionId);
if (rolePermission == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Provided project role permission(s) do not exist");
}
rolePermissionsOrder.add(rolePermission);
}
return projRoleService.updateProjectRolePermission(projectId, projectRole, rolePermissionsOrder);
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}
}

View File

@ -16,6 +16,12 @@
// under the License.
package org.apache.cloudstack.api.command.user.account;
import java.util.List;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
import org.apache.commons.lang3.EnumUtils;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@ -31,6 +37,8 @@ import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectAccount;
import com.google.common.base.Strings;
@APICommand(name = "addAccountToProject", description = "Adds account to a project", responseObject = SuccessResponse.class, since = "3.0.0",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@ -56,6 +64,14 @@ public class AddAccountToProjectCmd extends BaseAsyncCmd {
@Parameter(name = ApiConstants.EMAIL, type = CommandType.STRING, description = "email to which invitation to the project is going to be sent")
private String email;
@Parameter(name = ApiConstants.PROJECT_ROLE_ID, type = CommandType.UUID, entityType = ProjectRoleResponse.class,
description = "ID of the project role", validations = {ApiArgValidator.PositiveNumber})
private Long projectRoleId;
@Parameter(name = ApiConstants.ROLE_TYPE, type = BaseCmd.CommandType.STRING,
description = "Project role type to be assigned to the user - Admin/Regular; default: Regular")
private String roleType;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -72,6 +88,21 @@ public class AddAccountToProjectCmd extends BaseAsyncCmd {
return email;
}
public Long getProjectRoleId() {
return projectRoleId;
}
public ProjectAccount.Role getRoleType() {
if (!Strings.isNullOrEmpty(roleType)) {
String role = roleType.substring(0, 1).toUpperCase() + roleType.substring(1).toLowerCase();
if (!EnumUtils.isValidEnum(ProjectAccount.Role.class, role)) {
throw new InvalidParameterValueException("Only Admin or Regular project role types are valid");
}
return Enum.valueOf(ProjectAccount.Role.class, role);
}
return null;
}
@Override
public String getCommandName() {
return s_name;
@ -88,7 +119,7 @@ public class AddAccountToProjectCmd extends BaseAsyncCmd {
}
CallContext.current().setEventDetails("Project ID: " + projectId + "; accountName " + accountName);
boolean result = _projectService.addAccountToProject(getProjectId(), getAccountName(), getEmail());
boolean result = _projectService.addAccountToProject(getProjectId(), getAccountName(), getEmail(), getProjectRoleId(), getRoleType());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
@ -110,6 +141,11 @@ public class AddAccountToProjectCmd extends BaseAsyncCmd {
return _projectService.getProjectOwner(getProjectId()).getId();
}
@Override
public List<Long> getEntityOwnerIds() {
return _projectService.getProjectOwners(projectId);
}
@Override
public String getEventType() {
return EventTypes.EVENT_PROJECT_ACCOUNT_ADD;

View File

@ -0,0 +1,150 @@
// 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.api.command.user.account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.commons.lang3.EnumUtils;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.projects.ProjectAccount;
import com.google.common.base.Strings;
@APICommand(name = AddUserToProjectCmd.APINAME, description = "Adds user to a project", responseObject = SuccessResponse.class, since = "4.14",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin, RoleType.User})
public class AddUserToProjectCmd extends BaseAsyncCmd {
public static final String APINAME = "addUserToProject";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.PROJECT_ID,
type = BaseCmd.CommandType.UUID,
entityType = ProjectResponse.class,
required = true,
description = "ID of the project to add the user to")
private Long projectId;
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = true, description = "Name of the user to be added to the project")
private String username;
@Parameter(name = ApiConstants.EMAIL, type = CommandType.STRING, description = "email ID of user to which invitation to the project is going to be sent")
private String email;
@Parameter(name = ApiConstants.PROJECT_ROLE_ID, type = BaseCmd.CommandType.UUID, entityType = ProjectRoleResponse.class,
description = "ID of the project role", validations = {ApiArgValidator.PositiveNumber})
private Long projectRoleId;
@Parameter(name = ApiConstants.ROLE_TYPE, type = BaseCmd.CommandType.STRING,
description = "Project role type to be assigned to the user - Admin/Regular")
private String roleType;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getProjectId() {
return projectId;
}
public String getUsername() {
return username;
}
public String getEmail() { return email; }
public Long getProjectRoleId() {
return projectRoleId;
}
public ProjectAccount.Role getRoleType() {
if (!Strings.isNullOrEmpty(roleType)) {
String role = roleType.substring(0, 1).toUpperCase() + roleType.substring(1).toLowerCase();
if (!EnumUtils.isValidEnum(ProjectAccount.Role.class, role)) {
throw new InvalidParameterValueException("Only Admin or Regular project role types are valid");
}
return Enum.valueOf(ProjectAccount.Role.class, role);
}
return null;
}
@Override
public String getEventType() {
return EventTypes.EVENT_PROJECT_USER_ADD;
}
@Override
public String getEventDescription() {
return "Adding user "+getUsername()+" to Project "+getProjectId();
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
validateInput();
boolean result = _projectService.addUserToProject(getProjectId(), getUsername(), getEmail(), getProjectRoleId(), getRoleType());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add account to the project");
}
}
private void validateInput() {
if (email == null && username == null) {
throw new InvalidParameterValueException("Must specify atleast username");
}
if (email != null && username == null) {
throw new InvalidParameterValueException("Must specify username for given email ID");
}
if (getProjectId() < 1L) {
throw new InvalidParameterValueException("Invalid Project ID provided");
}
if (projectRoleId != null && projectRoleId < 1L) {
throw new InvalidParameterValueException("Invalid Project role ID provided");
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}
}

View File

@ -16,6 +16,8 @@
// under the License.
package org.apache.cloudstack.api.command.user.account;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@ -97,6 +99,11 @@ public class DeleteAccountFromProjectCmd extends BaseAsyncCmd {
return _projectService.getProjectOwner(projectId).getId();
}
@Override
public List<Long> getEntityOwnerIds() {
return _projectService.getProjectOwners(projectId);
}
@Override
public String getEventType() {
return EventTypes.EVENT_PROJECT_ACCOUNT_REMOVE;

View File

@ -0,0 +1,118 @@
// 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.api.command.user.account;
import java.util.List;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.user.project.DeleteProjectCmd;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.projects.Project;
@APICommand(name = DeleteUserFromProjectCmd.APINAME, description = "Deletes user from the project", responseObject = SuccessResponse.class, since = "4.15.0",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin, RoleType.User})
public class DeleteUserFromProjectCmd extends BaseAsyncCmd {
public static final Logger LOGGER = Logger.getLogger(DeleteProjectCmd.class.getName());
public static final String APINAME = "deleteUserFromProject";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.PROJECT_ID,
type = BaseCmd.CommandType.UUID,
entityType = ProjectResponse.class,
required = true,
description = "ID of the project to remove the user from")
private Long projectId;
@Parameter(name = ApiConstants.USER_ID, type = BaseCmd.CommandType.UUID, entityType = UserResponse.class,
required = true, description = "Id of the user to be removed from the project")
private Long userId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getProjectId() {
return projectId;
}
public Long getUserId() {
return userId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getEventType() {
return EventTypes.EVENT_PROJECT_USER_REMOVE;
}
@Override
public String getEventDescription() {
return "Removing user " + userId + " from project: " + projectId;
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
Project project = _projectService.getProject(projectId);
if (project == null) {
throw new InvalidParameterValueException("Unable to find project by ID " + projectId);
}
return _projectService.getProjectOwner(projectId).getId();
}
@Override
public List<Long> getEntityOwnerIds() {
return _projectService.getProjectOwners(projectId);
}
@Override
public void execute() {
CallContext.current().setEventDetails("Project ID: " + projectId + "; user ID: " + userId);
boolean result = _projectService.deleteUserFromProject(getProjectId(), getUserId());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete account from the project");
}
}
}

View File

@ -16,8 +16,6 @@
// under the License.
package org.apache.cloudstack.api.command.user.account;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
@ -25,6 +23,9 @@ import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ProjectAccountResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ProjectRoleResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.log4j.Logger;
import com.cloud.user.Account;
@ -45,9 +46,15 @@ public class ListProjectAccountsCmd extends BaseListCmd {
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "list accounts of the project by account name")
private String accountName;
@Parameter(name = ApiConstants.USER_ID, type = CommandType.UUID, entityType = UserResponse.class, description = "list invitation by user ID")
private Long userId;
@Parameter(name = ApiConstants.ROLE, type = CommandType.STRING, description = "list accounts of the project by role")
private String role;
@Parameter(name = ApiConstants.PROJECT_ROLE_ID, type = CommandType.UUID, entityType = ProjectRoleResponse.class, description = "list accounts of the project by project role id")
private Long projectRoleId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -64,6 +71,12 @@ public class ListProjectAccountsCmd extends BaseListCmd {
return role;
}
public Long getUserId() { return userId; }
public Long getProjectRoleId() {
return projectRoleId;
}
@Override
public String getCommandName() {
return s_name;

View File

@ -16,6 +16,8 @@
// under the License.
package org.apache.cloudstack.api.command.user.project;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@ -69,6 +71,11 @@ public class ActivateProjectCmd extends BaseAsyncCmd {
return _projectService.getProjectOwner(getId()).getId();
}
@Override
public List<Long> getEntityOwnerIds() {
return _projectService.getProjectOwners(id);
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -16,18 +16,19 @@
// under the License.
package org.apache.cloudstack.api.command.user.project;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCreateCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
@ -49,9 +50,16 @@ public class CreateProjectCmd extends BaseAsyncCreateCmd {
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "account who will be Admin for the project")
private String accountName;
@Parameter(name = ApiConstants.USER_ID, type = CommandType.UUID, entityType = UserResponse.class,
description = "user ID of the account to be assigned as owner of the project i.e., Project Admin", since = "4.15.0")
private Long userId;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "domain ID of the account owning a project")
private Long domainId;
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "ID of the account owning a project")
private Long accountId;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, validations = ApiArgValidator.NotNullOrEmpty, description = "name of the project")
private String name;
@ -73,16 +81,24 @@ public class CreateProjectCmd extends BaseAsyncCreateCmd {
public Long getDomainId() {
if (domainId != null) {
return domainId;
} else {
return CallContext.current().getCallingAccount().getDomainId();
}
return CallContext.current().getCallingAccount().getDomainId();
}
public String getName() {
return name;
}
public Long getUserId() {
return userId;
}
public Long getAccountId() {
return accountId;
}
public String getDisplayText() {
return displayText;
}
@ -96,10 +112,13 @@ public class CreateProjectCmd extends BaseAsyncCreateCmd {
public long getEntityOwnerId() {
Account caller = CallContext.current().getCallingAccount();
if ((accountName != null && domainId == null) || (domainId != null && accountName == null)) {
if ((accountName != null && domainId == null)) {
throw new InvalidParameterValueException("Account name and domain id must be specified together");
}
if (userId != null && (accountId == null && domainId == null)) {
throw new InvalidParameterValueException("Account ID and Domain ID must be specified with userID");
}
if (accountName != null) {
return _accountService.finalizeOwner(caller, accountName, domainId, null).getId();
}
@ -126,7 +145,7 @@ public class CreateProjectCmd extends BaseAsyncCreateCmd {
@Override
public void create() throws ResourceAllocationException {
CallContext.current().setEventDetails("Project Name: " + getName());
Project project = _projectService.createProject(getName(), getDisplayText(), getAccountName(), getDomainId());
Project project = _projectService.createProject(getName(), getDisplayText(), getAccountName(), getDomainId(), getUserId(), getAccountId());
if (project != null) {
this.setEntityId(project.getId());
this.setEntityUuid(project.getUuid());

View File

@ -16,6 +16,8 @@
// under the License.
package org.apache.cloudstack.api.command.user.project;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@ -96,4 +98,9 @@ public class DeleteProjectCmd extends BaseAsyncCmd {
return _projectService.getProjectOwner(id).getId();
}
@Override
public List<Long> getEntityOwnerIds() {
return _projectService.getProjectOwners(id);
}
}

View File

@ -16,6 +16,7 @@
// under the License.
package org.apache.cloudstack.api.command.user.project;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@ -53,6 +54,9 @@ public class ListProjectInvitationsCmd extends BaseListAccountResourcesCmd {
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ProjectInvitationResponse.class, description = "list invitations by id")
private Long id;
@Parameter(name = ApiConstants.USER_ID, type = CommandType.UUID, entityType = UserResponse.class, description = "list invitation by user ID")
private Long userId;
// ///////////////////////////////////////////////////
// ///////////////// Accessors ///////////////////////
// ///////////////////////////////////////////////////
@ -72,6 +76,10 @@ public class ListProjectInvitationsCmd extends BaseListAccountResourcesCmd {
return id;
}
public Long getUserId() {
return userId;
}
@Override
public String getCommandName() {
return s_name;

View File

@ -63,6 +63,9 @@ public class ListProjectsCmd extends BaseListAccountResourcesCmd {
@Parameter(name = ApiConstants.TAGS, type = CommandType.MAP, description = "List projects by tags (key/value pairs)")
private Map tags;
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "List projects by username")
private String username;
@Parameter(name = ApiConstants.DETAILS,
type = CommandType.LIST,
collectionType = CommandType.STRING,
@ -89,6 +92,10 @@ public class ListProjectsCmd extends BaseListAccountResourcesCmd {
return state;
}
public String getUsername() {
return username;
}
@Override
public String getCommandName() {
return s_name;

View File

@ -16,6 +16,8 @@
// under the License.
package org.apache.cloudstack.api.command.user.project;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@ -98,4 +100,9 @@ public class SuspendProjectCmd extends BaseAsyncCmd {
return _projectService.getProjectOwner(id).getId();
}
@Override
public List<Long> getEntityOwnerIds() {
return _projectService.getProjectOwners(id);
}
}

View File

@ -16,7 +16,7 @@
// under the License.
package org.apache.cloudstack.api.command.user.project;
import org.apache.log4j.Logger;
import java.util.List;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
@ -25,12 +25,17 @@ import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.commons.lang3.EnumUtils;
import org.apache.log4j.Logger;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectAccount;
import com.google.common.base.Strings;
@APICommand(name = "updateProject", description = "Updates a project", responseObject = ProjectResponse.class, since = "3.0.0",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@ -52,6 +57,17 @@ public class UpdateProjectCmd extends BaseAsyncCmd {
@Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, description = "display text of the project")
private String displayText;
@Parameter(name = ApiConstants.USER_ID, type = CommandType.UUID, entityType = UserResponse.class, description = "ID of the user to be promoted/demoted")
private Long userId;
@Parameter(name = ApiConstants.ROLE_TYPE, type = CommandType.STRING, description = "Account level role to be assigned to the user/account : Admin/Regular")
private String roleType;
@Parameter(name = ApiConstants.SWAP_OWNER, type = CommandType.BOOLEAN, description = "when true, it swaps ownership with the account/ user provided. " +
"Ideally to be used when a single project administrator is present. In case of multiple project admins, swapowner is to be set to false," +
"to promote or demote the user/account based on the roleType (Regular or Admin) provided. Defaults to true")
private Boolean swapOwner;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -68,11 +84,34 @@ public class UpdateProjectCmd extends BaseAsyncCmd {
return displayText;
}
public Long getUserId() {
return userId;
}
public ProjectAccount.Role getRoleType(String role) {
String type = role.substring(0, 1).toUpperCase() + role.substring(1).toLowerCase();
if (!EnumUtils.isValidEnum(ProjectAccount.Role.class, type)) {
throw new InvalidParameterValueException("Only Admin or Regular project role types are valid");
}
return Enum.valueOf(ProjectAccount.Role.class, type);
}
public ProjectAccount.Role getAccountRole() {
if (!Strings.isNullOrEmpty(roleType)) {
return getRoleType(roleType);
}
return ProjectAccount.Role.Regular;
}
@Override
public String getCommandName() {
return s_name;
}
public Boolean isSwapOwner() {
return swapOwner != null ? swapOwner : true;
}
@Override
public long getEntityOwnerId() {
Project project = _projectService.getProject(id);
@ -84,6 +123,11 @@ public class UpdateProjectCmd extends BaseAsyncCmd {
return _projectService.getProjectOwner(id).getId();
}
@Override
public List<Long> getEntityOwnerIds() {
return _projectService.getProjectOwners(id);
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@ -91,7 +135,17 @@ public class UpdateProjectCmd extends BaseAsyncCmd {
@Override
public void execute() throws ResourceAllocationException {
CallContext.current().setEventDetails("Project id: " + getId());
Project project = _projectService.updateProject(getId(), getDisplayText(), getAccountName());
if (getAccountName() != null && getUserId() != null) {
throw new InvalidParameterValueException("Account name and user ID are mutually exclusive. Provide either account name" +
"to update account or user ID to update the user of the project");
}
Project project = null;
if (isSwapOwner()) {
project = _projectService.updateProject(getId(), getDisplayText(), getAccountName());
} else {
project = _projectService.updateProject(getId(), getDisplayText(), getAccountName(), getUserId(), getAccountRole());
}
if (project != null) {
ProjectResponse response = _responseGenerator.createProjectResponse(project);
response.setResponseName(getCommandName());

View File

@ -16,17 +16,18 @@
// under the License.
package org.apache.cloudstack.api.command.user.project;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import com.cloud.event.EventTypes;
import com.cloud.user.Account;
@ -46,6 +47,10 @@ public class UpdateProjectInvitationCmd extends BaseAsyncCmd {
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "account that is joining the project")
private String accountName;
@Parameter(name = ApiConstants.USER_ID, type = BaseCmd.CommandType.UUID, entityType = UserResponse.class,
description = "User UUID, required for adding account from external provisioning system")
private Long userId;
@Parameter(name = ApiConstants.TOKEN,
type = CommandType.STRING,
description = "list invitations for specified account; this parameter has to be specified with domainId")
@ -65,6 +70,8 @@ public class UpdateProjectInvitationCmd extends BaseAsyncCmd {
return accountName;
}
public Long getUserId() { return userId; }
@Override
public String getCommandName() {
return s_name;
@ -93,8 +100,15 @@ public class UpdateProjectInvitationCmd extends BaseAsyncCmd {
@Override
public void execute() {
CallContext.current().setEventDetails("Project id: " + projectId + "; accountName " + accountName + "; accept " + getAccept());
boolean result = _projectService.updateInvitation(projectId, accountName, token, getAccept());
String eventDetails = "Project id: " + projectId + ";";
if (accountName != null) {
eventDetails += " accountName: " + accountName + ";";
} else if (userId != null) {
eventDetails += " userId: " + userId + ";";
}
eventDetails += " accept " + getAccept();
CallContext.current().setEventDetails(eventDetails);
boolean result = _projectService.updateInvitation(projectId, accountName, userId, token, getAccept());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);

View File

@ -0,0 +1,64 @@
// 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.api.response;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.acl.Rule;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
public class BaseRolePermissionResponse extends BaseResponse {
@SerializedName(ApiConstants.RULE)
@Param(description = "the api name or wildcard rule")
private String rule;
@SerializedName(ApiConstants.PERMISSION)
@Param(description = "the permission type of the api name or wildcard rule, allow/deny")
private String rulePermission;
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "the description of the role permission")
private String ruleDescription;
public String getRule() {
return rule;
}
public void setRule(Rule rule) {
if (rule != null) {
this.rule = rule.getRuleString();
}
}
public String getRulePermission() {
return rulePermission;
}
public void setRulePermission(Permission rulePermission) {
if (rulePermission != null) {
this.rulePermission = rulePermission.name().toLowerCase();
}
}
public void setDescription(String description) {
this.ruleDescription = description;
}
}

View File

@ -0,0 +1,50 @@
// 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.api.response;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
public class BaseRoleResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "the ID of the role")
private String id;
@SerializedName(ApiConstants.NAME)
@Param(description = "the name of the role")
private String roleName;
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "the description of the role")
private String roleDescription;
public void setId(String id) {
this.id = id;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public void setDescription(String description) {
this.roleDescription = description;
}
}

View File

@ -18,14 +18,13 @@ package org.apache.cloudstack.api.response;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import com.cloud.projects.ProjectAccount;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = ProjectAccount.class)
@SuppressWarnings("unused")
@ -46,10 +45,22 @@ public class ProjectAccountResponse extends BaseResponse implements ControlledVi
@Param(description = "the name of the account")
private String accountName;
@SerializedName(ApiConstants.USERNAME)
@Param(description = "Name of the user")
private String username;
@SerializedName(ApiConstants.ACCOUNT_TYPE)
@Param(description = "account type (admin, domain-admin, user)")
private Short accountType;
@SerializedName(ApiConstants.USER_ID)
@Param(description = "Id of the user")
private String userId;
@SerializedName(ApiConstants.PROJECT_ROLE_ID)
@Param(description = "Id of the project role associated with the account/user")
private String projectRoleId;
@SerializedName(ApiConstants.ROLE)
@Param(description = "account role in the project (regular,owner)")
private String role;
@ -99,6 +110,12 @@ public class ProjectAccountResponse extends BaseResponse implements ControlledVi
this.domainName = domainName;
}
public void setUserId(String userId) { this.userId = userId; }
public void setProjectRoleId(String projectRoleId) {
this.projectRoleId = projectRoleId;
}
public void setUsers(List<UserResponse> users) {
this.users = users;
}
@ -106,4 +123,8 @@ public class ProjectAccountResponse extends BaseResponse implements ControlledVi
public void setRole(String role) {
this.role = role;
}
public void setUsername(String username) {
this.username = username;
}
}

View File

@ -16,14 +16,13 @@
// under the License.
package org.apache.cloudstack.api.response;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import com.cloud.projects.ProjectInvitation;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = ProjectInvitation.class)
@SuppressWarnings("unused")
@ -44,6 +43,10 @@ public class ProjectInvitationResponse extends BaseResponse implements Controlle
@Param(description = "the domain id the project belongs to")
private String domainId;
@SerializedName(ApiConstants.USER_ID)
@Param(description = "the User ID")
private String userId;
@SerializedName(ApiConstants.DOMAIN)
@Param(description = "the domain name where the project belongs to")
private String domainName;
@ -89,6 +92,8 @@ public class ProjectInvitationResponse extends BaseResponse implements Controlle
this.accountName = accountName;
}
public void setUserId(String userId) { this.userId = userId; }
public void setInvitationState(String invitationState) {
this.invitationState = invitationState;
}

View File

@ -18,8 +18,7 @@ package org.apache.cloudstack.api.response;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import java.util.Map;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
@ -27,6 +26,7 @@ import org.apache.cloudstack.api.EntityReference;
import com.cloud.projects.Project;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = Project.class)
public class ProjectResponse extends BaseResponse implements ResourceLimitAndCountResponse {
@ -55,6 +55,10 @@ public class ProjectResponse extends BaseResponse implements ResourceLimitAndCou
@Param(description = "the account name of the project's owner")
private String ownerName;
@SerializedName(ApiConstants.OWNER)
@Param(description = "the account name of the project's owners")
private List<Map<String, String>> owners;
@SerializedName("projectaccountname")
@Param(description="the project account name of the project")
private String projectAccountName;
@ -422,4 +426,7 @@ public class ProjectResponse extends BaseResponse implements ResourceLimitAndCou
this.secondaryStorageAvailable = secondaryStorageAvailable;
}
public void setOwners(List<Map<String, String>> owners) {
this.owners = owners;
}
}

View File

@ -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.api.response;
import org.apache.cloudstack.acl.ProjectRolePermission;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.EntityReference;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = ProjectRolePermission.class)
public class ProjectRolePermissionResponse extends BaseRolePermissionResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "the ID of the project role permission")
private String id;
@SerializedName(ApiConstants.PROJECT_ROLE_ID)
@Param(description = "the ID of the project role to which the role permission belongs")
private String projectRoleId;
@SerializedName(ApiConstants.PROJECT_ID)
@Param(description = "the ID of the project")
private String projectId;
@SerializedName(ApiConstants.PROJECT_ROLE_NAME)
@Param(description = "the name of the project role to which the role permission belongs")
private String projectRoleName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getProjectId() {
return projectId;
}
public void setProjectId(String projectId) {
this.projectId = projectId;
}
public String getProjectRoleId() {
return projectRoleId;
}
public void setProjectRoleId(String projectRoleId) {
this.projectRoleId = projectRoleId;
}
public String getProjectRoleName() {
return projectRoleName;
}
public void setProjectRoleName(String projectRoleName) {
this.projectRoleName = projectRoleName;
}
}

View File

@ -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.api.response;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.EntityReference;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = ProjectRole.class)
public class ProjectRoleResponse extends BaseRoleResponse {
@SerializedName(ApiConstants.PROJECT_ID)
@Param(description = "the id of the project")
private String projectId;
public String getProjectId() {
return projectId;
}
public void setProjectId(String projectId) {
this.projectId = projectId;
}
}

View File

@ -17,16 +17,15 @@
package org.apache.cloudstack.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.acl.RolePermission;
import org.apache.cloudstack.acl.Rule;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = RolePermission.class)
public class RolePermissionResponse extends BaseResponse {
public class RolePermissionResponse extends BaseRolePermissionResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "the ID of the role permission")
private String id;
@ -39,18 +38,6 @@ public class RolePermissionResponse extends BaseResponse {
@Param(description = "the name of the role to which the role permission belongs")
private String roleName;
@SerializedName(ApiConstants.RULE)
@Param(description = "the api name or wildcard rule")
private String rule;
@SerializedName(ApiConstants.PERMISSION)
@Param(description = "the permission type of the api name or wildcard rule, allow/deny")
private String rulePermission;
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "the description of the role permission")
private String ruleDescription;
public String getId() {
return id;
}
@ -74,28 +61,4 @@ public class RolePermissionResponse extends BaseResponse {
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRule() {
return rule;
}
public void setRule(Rule rule) {
if (rule != null) {
this.rule = rule.getRuleString();
}
}
public String getRulePermission() {
return rulePermission;
}
public void setRulePermission(RolePermission.Permission rulePermission) {
if (rulePermission != null) {
this.rulePermission = rulePermission.name().toLowerCase();
}
}
public void setDescription(String description) {
this.ruleDescription = description;
}
}

View File

@ -17,54 +17,31 @@
package org.apache.cloudstack.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
@EntityReference(value = Role.class)
public class RoleResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "the ID of the role")
private String id;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@SerializedName(ApiConstants.NAME)
@Param(description = "the name of the role")
private String roleName;
@EntityReference(value = Role.class)
public class RoleResponse extends BaseRoleResponse {
@SerializedName(ApiConstants.TYPE)
@Param(description = "the type of the role")
private String roleType;
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "the description of the role")
private String roleDescription;
@SerializedName(ApiConstants.IS_DEFAULT)
@Param(description = "true if role is default, false otherwise")
private Boolean isDefault;
public void setId(String id) {
this.id = id;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public void setRoleType(RoleType roleType) {
if (roleType != null) {
this.roleType = roleType.name();
}
}
public void setDescription(String description) {
this.roleDescription = description;
}
public void setIsDefault(Boolean isDefault) {
this.isDefault = isDefault;
}

View File

@ -21,13 +21,12 @@ import java.util.Map;
import java.util.Stack;
import java.util.UUID;
import com.cloud.projects.Project;
import org.apache.cloudstack.managed.threadlocal.ManagedThreadLocal;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import org.apache.cloudstack.managed.threadlocal.ManagedThreadLocal;
import com.cloud.exception.CloudAuthenticationException;
import com.cloud.projects.Project;
import com.cloud.user.Account;
import com.cloud.user.User;
import com.cloud.utils.UuidUtils;
@ -61,6 +60,7 @@ public class CallContext {
private long userId;
private final Map<Object, Object> context = new HashMap<Object, Object>();
private Project project;
private String apiName;
static EntityManager s_entityMgr;
@ -335,6 +335,14 @@ public class CallContext {
this.project = project;
}
public String getApiName() {
return apiName;
}
public void setApiName(String apiName) {
this.apiName = apiName;
}
/**
* Whether to display the event to the end user.
* @return true - if the event is to be displayed to the end user, false otherwise.

View File

@ -102,6 +102,11 @@
<artifactId>cloud-plugin-acl-dynamic-role-based</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-acl-project-role-based</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-ca-rootca</artifactId>

View File

@ -46,6 +46,9 @@ public class ProjectAccountVO implements ProjectAccount, InternalIdentity {
@Column(name = "account_id")
private long accountId;
@Column(name="user_id")
private Long userId;
@Column(name = "account_role")
@Enumerated(value = EnumType.STRING)
private Role accountRole = Role.Regular;
@ -53,17 +56,26 @@ public class ProjectAccountVO implements ProjectAccount, InternalIdentity {
@Column(name = "project_account_id")
long projectAccountId;
@Column(name = "project_role_id")
private Long projectRoleId;
@Column(name = GenericDao.CREATED_COLUMN)
private Date created;
protected ProjectAccountVO() {
}
public ProjectAccountVO(Project project, long accountId, Role accountRole) {
public ProjectAccountVO(Project project, long accountId, Role accountRole, Long userId, Long projectRoleId) {
this.accountId = accountId;
this.accountRole = accountRole;
if (accountRole != null) {
this.accountRole = accountRole;
} else {
this.accountRole = Role.Regular;
}
this.projectId = project.getId();
this.projectAccountId = project.getProjectAccountId();
this.userId = userId;
this.projectRoleId = projectRoleId;
}
@Override
@ -81,6 +93,13 @@ public class ProjectAccountVO implements ProjectAccount, InternalIdentity {
return accountId;
}
@Override
public Long getUserId() { return userId; }
public void setUserId(Long userId) {
this.userId = userId;
}
@Override
public Role getAccountRole() {
return accountRole;
@ -91,6 +110,13 @@ public class ProjectAccountVO implements ProjectAccount, InternalIdentity {
return projectAccountId;
}
public void setProjectRoleId(Long projectRoleId) {
this.projectRoleId = projectRoleId;
}
@Override
public Long getProjectRoleId() { return projectRoleId; }
public void setAccountRole(Role accountRole) {
this.accountRole = accountRole;
}

View File

@ -47,6 +47,13 @@ public class ProjectInvitationVO implements ProjectInvitation {
@Column(name = "domain_id")
private Long inDomainId;
@Column(name = "account_role")
@Enumerated(value = EnumType.STRING)
private ProjectAccount.Role accountRole = ProjectAccount.Role.Regular;
@Column(name = "project_role_id")
private Long projectRoleId;
@Column(name = "token")
private String token;
@ -63,6 +70,9 @@ public class ProjectInvitationVO implements ProjectInvitation {
@Column(name = "uuid")
private String uuid;
@Column(name = "user_id")
private Long forUserId;
protected ProjectInvitationVO() {
uuid = UUID.randomUUID().toString();
}
@ -127,6 +137,24 @@ public class ProjectInvitationVO implements ProjectInvitation {
return inDomainId;
}
@Override
public ProjectAccount.Role getAccountRole() {
return accountRole;
}
public void setAccountRole(ProjectAccount.Role accountRole) {
this.accountRole = accountRole;
}
@Override
public Long getProjectRoleId() {
return projectRoleId;
}
public void setProjectRoleId(Long projectRoleId) {
this.projectRoleId = projectRoleId;
}
@Override
public String getUuid() {
return uuid;
@ -146,6 +174,15 @@ public class ProjectInvitationVO implements ProjectInvitation {
return forAccountId == null ? -1 : forAccountId;
}
@Override
public Long getForUserId() {
return forUserId == null ? -1 : forUserId;
}
public void setForUserId(Long forUserId) {
this.forUserId = forUserId;
}
@Override
public Class<?> getEntityType() {
return ProjectInvitation.class;

View File

@ -25,10 +25,16 @@ import com.cloud.utils.db.GenericDao;
public interface ProjectAccountDao extends GenericDao<ProjectAccountVO, Long> {
ProjectAccountVO getProjectOwner(long projectId);
List<ProjectAccountVO> getProjectOwners(long projectId);
List<ProjectAccountVO> listByProjectId(long projectId);
ProjectAccountVO findByProjectIdAccountId(long projectId, long accountId);
ProjectAccountVO findByProjectIdUserId(long projectId, long accountId, long userId);
boolean canUserAccessProjectAccount(long accountId, long userId, long projectAccountId);
boolean canAccessProjectAccount(long accountId, long projectAccountId);
boolean canModifyProjectAccount(long accountId, long projectAccountId);
@ -40,4 +46,8 @@ public interface ProjectAccountDao extends GenericDao<ProjectAccountVO, Long> {
Long countByAccountIdAndRole(long accountId, ProjectAccount.Role role);
void removeAccountFromProjects(long accountId);
boolean canUserModifyProject(long projectId, long accountId, long userId);
List<ProjectAccountVO> listUsersOrAccountsByRole(long id);
}

View File

@ -18,7 +18,6 @@ package com.cloud.projects.dao;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -34,9 +33,11 @@ import com.cloud.utils.db.SearchCriteria.Op;
@Component
public class ProjectAccountDaoImpl extends GenericDaoBase<ProjectAccountVO, Long> implements ProjectAccountDao {
protected final SearchBuilder<ProjectAccountVO> AllFieldsSearch;
protected final SearchBuilder<ProjectAccountVO> ProjectAccountSearch;
final GenericSearchBuilder<ProjectAccountVO, Long> AdminSearch;
final GenericSearchBuilder<ProjectAccountVO, Long> ProjectAccountSearch;
final GenericSearchBuilder<ProjectAccountVO, Long> ProjectAccountsSearch;
final GenericSearchBuilder<ProjectAccountVO, Long> CountByRoleSearch;
public static final Logger s_logger = Logger.getLogger(ProjectAccountDaoImpl.class.getName());
protected ProjectAccountDaoImpl() {
@ -45,18 +46,27 @@ public class ProjectAccountDaoImpl extends GenericDaoBase<ProjectAccountVO, Long
AllFieldsSearch.and("projectId", AllFieldsSearch.entity().getProjectId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("projectAccountId", AllFieldsSearch.entity().getProjectAccountId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("userId", AllFieldsSearch.entity().getUserId(), Op.EQ);
AllFieldsSearch.and("projectRoleId", AllFieldsSearch.entity().getProjectRoleId(), Op.EQ);
AllFieldsSearch.done();
ProjectAccountSearch = createSearchBuilder();
ProjectAccountSearch.and("projectId", ProjectAccountSearch.entity().getProjectId(), SearchCriteria.Op.EQ);
ProjectAccountSearch.and("accountId", ProjectAccountSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
ProjectAccountSearch.and("userId", ProjectAccountSearch.entity().getUserId(), Op.NULL);
ProjectAccountSearch.done();
AdminSearch = createSearchBuilder(Long.class);
AdminSearch.selectFields(AdminSearch.entity().getProjectId());
AdminSearch.and("role", AdminSearch.entity().getAccountRole(), Op.EQ);
AdminSearch.and("accountId", AdminSearch.entity().getAccountId(), Op.EQ);
AdminSearch.done();
ProjectAccountSearch = createSearchBuilder(Long.class);
ProjectAccountSearch.selectFields(ProjectAccountSearch.entity().getProjectAccountId());
ProjectAccountSearch.and("accountId", ProjectAccountSearch.entity().getAccountId(), Op.EQ);
ProjectAccountSearch.done();
ProjectAccountsSearch = createSearchBuilder(Long.class);
ProjectAccountsSearch.selectFields(ProjectAccountsSearch.entity().getProjectAccountId());
ProjectAccountsSearch.and("accountId", ProjectAccountsSearch.entity().getAccountId(), Op.EQ);
ProjectAccountsSearch.done();
CountByRoleSearch = createSearchBuilder(Long.class);
CountByRoleSearch.select(null, Func.COUNT, CountByRoleSearch.entity().getId());
@ -74,6 +84,14 @@ public class ProjectAccountDaoImpl extends GenericDaoBase<ProjectAccountVO, Long
return findOneBy(sc);
}
public List<ProjectAccountVO> getProjectOwners(long projectId) {
SearchCriteria<ProjectAccountVO> sc = AllFieldsSearch.create();
sc.setParameters("role", ProjectAccount.Role.Admin);
sc.setParameters("projectId", projectId);
return listBy(sc);
}
@Override
public List<ProjectAccountVO> listByProjectId(long projectId) {
SearchCriteria<ProjectAccountVO> sc = AllFieldsSearch.create();
@ -84,13 +102,36 @@ public class ProjectAccountDaoImpl extends GenericDaoBase<ProjectAccountVO, Long
@Override
public ProjectAccountVO findByProjectIdAccountId(long projectId, long accountId) {
SearchCriteria<ProjectAccountVO> sc = ProjectAccountSearch.create();
sc.setParameters("projectId", projectId);
sc.setParameters("accountId", accountId);
return findOneBy(sc);
}
@Override
public ProjectAccountVO findByProjectIdUserId(long projectId, long accountId, long userId) {
SearchCriteria<ProjectAccountVO> sc = AllFieldsSearch.create();
sc.setParameters("projectId", projectId);
sc.setParameters("userId", userId);
sc.setParameters("accountId", accountId);
return findOneBy(sc);
}
@Override
public boolean canUserAccessProjectAccount(long accountId, long userId, long projectAccountId) {
SearchCriteria<ProjectAccountVO> sc = AllFieldsSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("userId", userId);
sc.setParameters("projectAccountId", projectAccountId);
if (findOneBy(sc) != null) {
return true;
} else {
return false;
}
}
@Override
public boolean canAccessProjectAccount(long accountId, long projectAccountId) {
SearchCriteria<ProjectAccountVO> sc = AllFieldsSearch.create();
@ -120,7 +161,7 @@ public class ProjectAccountDaoImpl extends GenericDaoBase<ProjectAccountVO, Long
@Override
public List<Long> listPermittedAccountIds(long accountId) {
SearchCriteria<Long> sc = ProjectAccountSearch.create();
SearchCriteria<Long> sc = ProjectAccountsSearch.create();
sc.setParameters("accountId", accountId);
return customSearch(sc, null);
}
@ -152,4 +193,23 @@ public class ProjectAccountDaoImpl extends GenericDaoBase<ProjectAccountVO, Long
}
}
@Override
public boolean canUserModifyProject(long projectId, long accountId, long userId) {
SearchCriteria<ProjectAccountVO> sc = AllFieldsSearch.create();
sc.setParameters("role", ProjectAccount.Role.Admin);
sc.setParameters("projectId",projectId);
sc.setParameters("accountId", accountId);
sc.setParameters("userId", userId);
if (findOneBy(sc) != null) {
return true;
}
return false;
}
@Override
public List<ProjectAccountVO> listUsersOrAccountsByRole(long id) {
SearchCriteria<ProjectAccountVO> sc = AllFieldsSearch.create();
sc.setParameters("projectRoleId", id);
return listBy(sc);
}
}

View File

@ -25,6 +25,8 @@ import com.cloud.utils.db.GenericDao;
public interface ProjectInvitationDao extends GenericDao<ProjectInvitationVO, Long> {
ProjectInvitationVO findByAccountIdProjectId(long accountId, long projectId, State... inviteState);
ProjectInvitationVO findByUserIdProjectId(long userId, long accountId, long projectId, State... inviteState);
List<ProjectInvitationVO> listExpiredInvitations();
boolean expirePendingInvitations(long timeOut);

View File

@ -19,7 +19,6 @@ package com.cloud.projects.dao;
import java.sql.Date;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -35,11 +34,13 @@ public class ProjectInvitationDaoImpl extends GenericDaoBase<ProjectInvitationVO
private static final Logger s_logger = Logger.getLogger(ProjectInvitationDaoImpl.class);
protected final SearchBuilder<ProjectInvitationVO> AllFieldsSearch;
protected final SearchBuilder<ProjectInvitationVO> InactiveSearch;
protected final SearchBuilder<ProjectInvitationVO> ProjectAccountInviteSearch;
protected ProjectInvitationDaoImpl() {
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getForAccountId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("projectId", AllFieldsSearch.entity().getProjectId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("userId", AllFieldsSearch.entity().getForUserId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("created", AllFieldsSearch.entity().getCreated(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("projectAccountId", AllFieldsSearch.entity().getState(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), SearchCriteria.Op.IN);
@ -48,6 +49,12 @@ public class ProjectInvitationDaoImpl extends GenericDaoBase<ProjectInvitationVO
AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), SearchCriteria.Op.EQ);
AllFieldsSearch.done();
ProjectAccountInviteSearch = createSearchBuilder();
ProjectAccountInviteSearch.and("accountId", ProjectAccountInviteSearch.entity().getForAccountId(), SearchCriteria.Op.EQ);
ProjectAccountInviteSearch.and("projectId", ProjectAccountInviteSearch.entity().getProjectId(), SearchCriteria.Op.EQ);
ProjectAccountInviteSearch.and("userId", ProjectAccountInviteSearch.entity().getForUserId(), SearchCriteria.Op.NULL);
ProjectAccountInviteSearch.done();
InactiveSearch = createSearchBuilder();
InactiveSearch.and("id", InactiveSearch.entity().getId(), SearchCriteria.Op.EQ);
InactiveSearch.and("accountId", InactiveSearch.entity().getForAccountId(), SearchCriteria.Op.EQ);
@ -59,7 +66,7 @@ public class ProjectInvitationDaoImpl extends GenericDaoBase<ProjectInvitationVO
@Override
public ProjectInvitationVO findByAccountIdProjectId(long accountId, long projectId, State... inviteState) {
SearchCriteria<ProjectInvitationVO> sc = AllFieldsSearch.create();
SearchCriteria<ProjectInvitationVO> sc = ProjectAccountInviteSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("projectId", projectId);
if (inviteState != null && inviteState.length > 0) {
@ -69,6 +76,21 @@ public class ProjectInvitationDaoImpl extends GenericDaoBase<ProjectInvitationVO
return findOneBy(sc);
}
@Override
public ProjectInvitationVO findByUserIdProjectId(long userId, long accountId, long projectId, State... inviteState) {
SearchCriteria<ProjectInvitationVO> sc = AllFieldsSearch.create();
sc.setParameters("userId", userId);
sc.setParameters("accountId", accountId);
if (projectId != -1) {
sc.setParameters("projectId", projectId);
}
if (inviteState != null && inviteState.length > 0) {
sc.setParameters("state", (Object[])inviteState);
}
return findOneBy(sc);
}
@Override
public List<ProjectInvitationVO> listExpiredInvitations() {
SearchCriteria<ProjectInvitationVO> sc = AllFieldsSearch.create();

View File

@ -27,6 +27,8 @@ import com.cloud.utils.db.GenericDao;
public interface UserDao extends GenericDao<UserVO, Long> {
UserVO getUser(String username, String password);
UserVO getUserByName(String username, Long domainId);
UserVO getUser(String username);
UserVO getUser(long userId);

View File

@ -19,6 +19,8 @@ package com.cloud.user.dao;
import java.util.List;
import javax.inject.Inject;
import org.springframework.stereotype.Component;
import com.cloud.user.UserVO;
@ -38,6 +40,9 @@ public class UserDaoImpl extends GenericDaoBase<UserVO, Long> implements UserDao
protected SearchBuilder<UserVO> SecretKeySearch;
protected SearchBuilder<UserVO> RegistrationTokenSearch;
@Inject
private AccountDao accountDao;
protected UserDaoImpl() {
UsernameSearch = createSearchBuilder();
UsernameSearch.and("username", UsernameSearch.entity().getUsername(), SearchCriteria.Op.EQ);
@ -77,6 +82,17 @@ public class UserDaoImpl extends GenericDaoBase<UserVO, Long> implements UserDao
return findOneBy(sc);
}
@Override
public UserVO getUserByName(String username, Long domainId) {
List<UserVO> users = findUsersByName(username);
for (UserVO u : users) {
if (accountDao.findActiveAccountById(u.getAccountId(), domainId) != null) {
return u;
}
}
return null;
}
@Override
public List<UserVO> listByAccount(long accountId) {
SearchCriteria<UserVO> sc = AccountIdSearch.create();

View File

@ -0,0 +1,72 @@
// 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.acl;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "project_role_permissions")
public class ProjectRolePermissionVO extends RolePermissionBaseVO implements ProjectRolePermission {
@Column(name = "project_id")
private long projectId;
@Column(name = "project_role_id")
private long projectRoleId;
@Column(name = "sort_order")
private long sortOrder = 0;
public ProjectRolePermissionVO() {
super();
}
public ProjectRolePermissionVO(final long projectId, final long projectRoleId, final String rule, final Permission permission, final String description) {
super(rule, permission, description);
this.projectId = projectId;
this.projectRoleId = projectRoleId;
}
@Override
public long getProjectRoleId() {
return projectRoleId;
}
public void setProjectRoleId(long projectRoleId) {
this.projectRoleId = projectRoleId;
}
@Override
public long getProjectId() {
return projectId;
}
public void setProjectId(long projectId) {
this.projectId = projectId;
}
public long getSortOrder() {
return sortOrder;
}
public void setSortOrder(long sortOrder) {
this.sortOrder = sortOrder;
}
}

View File

@ -0,0 +1,100 @@
// 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.acl;
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 com.cloud.utils.db.GenericDao;
@Entity
@Table(name = "project_role")
@SuppressWarnings("unused")
public class ProjectRoleVO implements ProjectRole {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "uuid")
private String uuid;
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;
@Column(name = "project_id")
private Long projectId;
@Column(name = GenericDao.REMOVED_COLUMN)
private Date removed;
public ProjectRoleVO() {
this.uuid = UUID.randomUUID().toString();
}
public ProjectRoleVO(final String name, final String description, final Long projectId) {
this();
this.name = name;
this.description = description;
this.projectId = projectId;
}
@Override
public String getUuid() {
return uuid;
}
@Override
public long getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setDescription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public Long getProjectId() {
return projectId;
}
public void setProjectId(Long projectId) {
this.projectId = projectId;
}
}

View File

@ -0,0 +1,96 @@
// 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.acl;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
@MappedSuperclass
public class RolePermissionBaseVO implements RolePermissionEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "uuid")
private String uuid;
@Column(name = "rule")
private String rule;
@Column(name = "permission", nullable = false)
@Enumerated(value = EnumType.STRING)
private Permission permission = Permission.DENY;
@Column(name = "description")
private String description;
public RolePermissionBaseVO() { this.uuid = UUID.randomUUID().toString(); }
public RolePermissionBaseVO(final String rule, final Permission permission, final String description) {
this();
this.rule = rule;
this.permission = permission;
this.description = description;
}
@Override
public long getId() {
return id;
}
@Override
public String getUuid() {
return uuid;
}
@Override
public Rule getRule() {
return new Rule(rule);
}
public void setRule(String rule) {
this.rule = rule;
}
@Override
public Permission getPermission() {
return permission;
}
public void setPermission(Permission permission) {
this.permission = permission;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@ -19,61 +19,23 @@ package org.apache.cloudstack.acl;
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 java.util.UUID;
@Entity
@Table(name = "role_permissions")
public class RolePermissionVO implements RolePermission {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "uuid")
private String uuid;
public class RolePermissionVO extends RolePermissionBaseVO implements RolePermission {
@Column(name = "role_id")
private long roleId;
@Column(name = "rule")
private String rule;
@Column(name = "permission", nullable = false)
@Enumerated(value = EnumType.STRING)
private Permission permission = RolePermission.Permission.DENY;
@Column(name = "description")
private String description;
@Column(name = "sort_order")
private long sortOrder = 0;
public RolePermissionVO() {
this.uuid = UUID.randomUUID().toString();
}
public RolePermissionVO() { super(); }
public RolePermissionVO(final long roleId, final String rule, final Permission permission, final String description) {
this();
public RolePermissionVO(final Long roleId, final String rule, final Permission permission, final String description) {
super(rule, permission, description);
this.roleId = roleId;
this.rule = rule;
this.permission = permission;
this.description = description;
}
@Override
public long getId() {
return id;
}
@Override
public String getUuid() {
return uuid;
}
public long getRoleId() {
@ -84,32 +46,6 @@ public class RolePermissionVO implements RolePermission {
this.roleId = roleId;
}
@Override
public Rule getRule() {
return new Rule(rule);
}
public void setRule(String rule) {
this.rule = rule;
}
@Override
public Permission getPermission() {
return permission;
}
public void setPermission(Permission permission) {
this.permission = permission;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public long getSortOrder() {
return sortOrder;
}
@ -117,4 +53,5 @@ public class RolePermissionVO implements RolePermission {
public void setSortOrder(long sortOrder) {
this.sortOrder = sortOrder;
}
}

View File

@ -0,0 +1,29 @@
// 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.acl.dao;
import java.util.List;
import org.apache.cloudstack.acl.ProjectRoleVO;
import com.cloud.utils.db.GenericDao;
public interface ProjectRoleDao extends GenericDao<ProjectRoleVO, Long> {
List<ProjectRoleVO> findByName(String name, Long projectId);
List<ProjectRoleVO> findAllRoles(Long projectId);
}

View File

@ -0,0 +1,61 @@
// 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.acl.dao;
import java.util.List;
import org.apache.cloudstack.acl.ProjectRoleVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.google.common.base.Strings;
public class ProjectRoleDaoImpl extends GenericDaoBase<ProjectRoleVO, Long> implements ProjectRoleDao{
private final SearchBuilder<ProjectRoleVO> ProjectRoleSearch;
public ProjectRoleDaoImpl() {
super();
ProjectRoleSearch = createSearchBuilder();
ProjectRoleSearch.and("name", ProjectRoleSearch.entity().getName(), SearchCriteria.Op.LIKE);
ProjectRoleSearch.and("project_id", ProjectRoleSearch.entity().getProjectId(), SearchCriteria.Op.EQ);
ProjectRoleSearch.done();
}
@Override
public List<ProjectRoleVO> findByName(String name, Long projectId) {
SearchCriteria<ProjectRoleVO> sc = ProjectRoleSearch.create();
if (!Strings.isNullOrEmpty(name)) {
sc.setParameters("name", "%" + name + "%");
}
if (projectId != null) {
sc.setParameters("project_id", projectId);
}
return listBy(sc);
}
@Override
public List<ProjectRoleVO> findAllRoles(Long projectId) {
SearchCriteria<ProjectRoleVO> sc = ProjectRoleSearch.create();
if (projectId != null) {
sc.setParameters("project_id", projectId);
}
return listBy(sc);
}
}

View File

@ -0,0 +1,34 @@
// 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.acl.dao;
import java.util.List;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.ProjectRolePermission;
import org.apache.cloudstack.acl.ProjectRolePermissionVO;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import com.cloud.utils.db.GenericDao;
public interface ProjectRolePermissionsDao extends GenericDao<ProjectRolePermissionVO, Long> {
List<ProjectRolePermissionVO> findAllByRoleIdSorted(Long roleId, Long projectId);
boolean update(final ProjectRole role, final Long projectId, final List<ProjectRolePermission> newOrder);
boolean update(final ProjectRole role, ProjectRolePermission rolePermission, Permission permission);
ProjectRolePermissionVO persist(final ProjectRolePermissionVO projectRolePermissionVO);
}

View File

@ -0,0 +1,147 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.acl.dao;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.acl.ProjectRolePermission;
import org.apache.cloudstack.acl.ProjectRolePermissionVO;
import org.apache.log4j.Logger;
import com.cloud.utils.db.Attribute;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.db.UpdateBuilder;
import com.cloud.utils.exception.CloudRuntimeException;
public class ProjectRolePermissionsDaoImpl extends GenericDaoBase<ProjectRolePermissionVO, Long> implements ProjectRolePermissionsDao{
private static final Logger LOGGER = Logger.getLogger(ProjectRolePermissionsDaoImpl.class);
private final SearchBuilder<ProjectRolePermissionVO> ProjectRolePermissionsSearch;
private Attribute sortOrderAttribute;
public ProjectRolePermissionsDaoImpl() {
super();
ProjectRolePermissionsSearch = createSearchBuilder();
ProjectRolePermissionsSearch.and("uuid", ProjectRolePermissionsSearch.entity().getUuid(), SearchCriteria.Op.EQ);
ProjectRolePermissionsSearch.and("projectRoleId", ProjectRolePermissionsSearch.entity().getProjectRoleId(), SearchCriteria.Op.EQ);
ProjectRolePermissionsSearch.and("projectId", ProjectRolePermissionsSearch.entity().getProjectId(), SearchCriteria.Op.EQ);
ProjectRolePermissionsSearch.and("sortOrder", ProjectRolePermissionsSearch.entity().getSortOrder(), SearchCriteria.Op.EQ);
ProjectRolePermissionsSearch.done();
sortOrderAttribute = _allAttributes.get("sortOrder");
assert (sortOrderAttribute != null) : "Couldn't find one of these attributes";
}
@Override
public List<ProjectRolePermissionVO> findAllByRoleIdSorted(Long roleId, Long projectId) {
final SearchCriteria<ProjectRolePermissionVO> sc = ProjectRolePermissionsSearch.create();
if (roleId != null && roleId > 0L) {
sc.setParameters("projectRoleId", roleId);
}
if (projectId != null && projectId > 0L) {
sc.setParameters("projectId", projectId);
}
final Filter searchBySorted = new Filter(ProjectRolePermissionVO.class, "sortOrder", true, null, null);
final List<ProjectRolePermissionVO> projectRolePermissionList = listBy(sc, searchBySorted);
if (projectRolePermissionList == null) {
return Collections.emptyList();
}
return projectRolePermissionList;
}
@Override
public boolean update(ProjectRole role, Long projectId, List<ProjectRolePermission> newOrder) {
if (role == null || newOrder == null || newOrder.isEmpty()) {
return false;
}
return Transaction.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
final String failMsg = "Project role's rule permissions list has changed while you were making updates, aborted re-ordering of rules. Please try again.";
final List<ProjectRolePermissionVO> currentOrder = findAllByRoleIdSorted(role.getId(), projectId);
if (role.getId() < 1L || newOrder.size() != currentOrder.size()) {
throw new CloudRuntimeException(failMsg);
}
Set<Long> newOrderSet = new HashSet<>();
newOrderSet = newOrder.stream().map(perm -> perm.getId()).collect(Collectors.toSet());
Set<Long> currOrderSet = new HashSet<>();
currOrderSet = currentOrder.stream().map(perm -> perm.getId()).collect(Collectors.toSet());
long sortOrder = 0L;
if (!newOrderSet.equals(currOrderSet)) {
throw new CloudRuntimeException(failMsg);
}
for (ProjectRolePermission projectRolePermission : newOrder) {
final SearchCriteria<ProjectRolePermissionVO> sc = ProjectRolePermissionsSearch.create();
sc.setParameters("uuid", projectRolePermission.getUuid());
sc.setParameters("projectRoleId", role.getId());
sc.setParameters("projectId", role.getProjectId());
sc.setParameters("sortOrder", projectRolePermission.getSortOrder());
final UpdateBuilder ub = getUpdateBuilder(projectRolePermission);
ub.set(projectRolePermission, sortOrderAttribute, sortOrder);
final int result = update(ub, sc, null);
if (result < 1) {
throw new CloudRuntimeException(failMsg);
}
sortOrder++;
}
return true;
}
});
}
@Override
public boolean update(ProjectRole role, ProjectRolePermission rolePermission, Permission permission) {
if (role == null || rolePermission == null || permission == null) {
return false;
}
ProjectRolePermissionVO projectRolePermissionVO = findById(rolePermission.getId());
if (projectRolePermissionVO == null) {
return false;
}
projectRolePermissionVO.setPermission(permission);
return update(rolePermission.getId(), projectRolePermissionVO);
}
@Override
public ProjectRolePermissionVO persist(final ProjectRolePermissionVO item) {
item.setSortOrder(0);
final List<ProjectRolePermissionVO> permissionsList = findAllByRoleIdSorted(item.getProjectRoleId(), item.getProjectId());
if (permissionsList != null && permissionsList.size() > 0) {
ProjectRolePermission lastRule = permissionsList.get(permissionsList.size() - 1);
item.setSortOrder(lastRule.getSortOrder() + 1);
}
return super.persist(item);
}
}

View File

@ -17,13 +17,14 @@
package org.apache.cloudstack.acl.dao;
import com.cloud.utils.db.GenericDao;
import java.util.List;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RolePermission;
import org.apache.cloudstack.acl.RolePermission.Permission;
import org.apache.cloudstack.acl.RolePermissionEntity;
import org.apache.cloudstack.acl.RolePermissionVO;
import java.util.List;
import com.cloud.utils.db.GenericDao;
public interface RolePermissionsDao extends GenericDao<RolePermissionVO, Long> {
/**
@ -48,7 +49,7 @@ public interface RolePermissionsDao extends GenericDao<RolePermissionVO, Long> {
* @param permission permission
* @return true on success, false if not
*/
boolean update(final Role role, final RolePermission rolePermission, final Permission permission);
boolean update(final Role role, final RolePermission rolePermission, final RolePermissionEntity.Permission permission);
/**
* Returns ordered linked-list of role permission for a given role

View File

@ -17,6 +17,19 @@
package org.apache.cloudstack.acl.dao;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RolePermission;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.acl.RolePermissionVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.utils.db.Attribute;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
@ -27,18 +40,6 @@ import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.db.UpdateBuilder;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RolePermission;
import org.apache.cloudstack.acl.RolePermission.Permission;
import org.apache.cloudstack.acl.RolePermissionVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Component
public class RolePermissionsDaoImpl extends GenericDaoBase<RolePermissionVO, Long> implements RolePermissionsDao {

View File

@ -41,6 +41,8 @@
<bean id="dedicatedResourceDaoImpl" class="com.cloud.dc.dao.DedicatedResourceDaoImpl" />
<bean id="roleDaoImpl" class="org.apache.cloudstack.acl.dao.RoleDaoImpl" />
<bean id="rolePermissionsDaoImpl" class="org.apache.cloudstack.acl.dao.RolePermissionsDaoImpl" />
<bean id="projectRoleDaoImpl" class="org.apache.cloudstack.acl.dao.ProjectRoleDaoImpl"/>
<bean id="projectRolePermissionsDaoImpl" class="org.apache.cloudstack.acl.dao.ProjectRolePermissionsDaoImpl" />
<bean id="accountDaoImpl" class="com.cloud.user.dao.AccountDaoImpl" />
<bean id="accountDetailsDaoImpl" class="com.cloud.user.AccountDetailsDaoImpl" />
<bean id="accountJoinDaoImpl" class="com.cloud.api.query.dao.AccountJoinDaoImpl" />

View File

@ -19,6 +19,156 @@
-- Schema upgrade from 4.14.0.0 to 4.15.0.0
--;
-- Project roles
CREATE TABLE IF NOT EXISTS `cloud`.`project_role` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(255) UNIQUE,
`name` varchar(255) COMMENT 'unique name of the dynamic project role',
`removed` datetime COMMENT 'date removed',
`description` text COMMENT 'description of the project role',
`project_id` bigint(20) unsigned COMMENT 'Id of the project to which the role belongs',
PRIMARY KEY (`id`),
KEY `i_project_role__name` (`name`),
UNIQUE KEY (`name`, `project_id`),
CONSTRAINT `fk_project_role__project_id` FOREIGN KEY(`project_id`) REFERENCES `projects`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Project role permissions table
CREATE TABLE IF NOT EXISTS `cloud`.`project_role_permissions` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(255) UNIQUE,
`project_id` bigint(20) unsigned NOT NULL COMMENT 'id of the role',
`project_role_id` bigint(20) unsigned NOT NULL COMMENT 'id of the role',
`rule` varchar(255) NOT NULL COMMENT 'rule for the role, api name or wildcard',
`permission` varchar(255) NOT NULL COMMENT 'access authority, allow or deny',
`description` text COMMENT 'description of the rule',
`sort_order` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT 'permission sort order',
PRIMARY KEY (`id`),
KEY `fk_project_role_permissions__project_role_id` (`project_role_id`),
KEY `i_project_role_permissions__sort_order` (`sort_order`),
UNIQUE KEY (`project_role_id`, `rule`),
CONSTRAINT `fk_project_role_permissions__project_id` FOREIGN KEY(`project_id`) REFERENCES `projects`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_role_permissions__project_role_id` FOREIGN KEY (`project_role_id`) REFERENCES `project_role` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Alter project accounts table to include user_id and project_role_id for role based users in projects
ALTER TABLE `cloud`.`project_account`
ADD COLUMN `user_id` bigint unsigned COMMENT 'ID of user to be added to the project' AFTER `account_id`,
ADD CONSTRAINT `fk_project_account__user_id` FOREIGN KEY `fk_project_account__user_id`(`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE,
ADD COLUMN `project_role_id` bigint unsigned COMMENT 'Project role id' AFTER `project_account_id`,
ADD CONSTRAINT `fk_project_account__project_role_id` FOREIGN KEY (`project_role_id`) REFERENCES `project_role` (`id`) ON DELETE SET NULL,
DROP FOREIGN KEY `fk_project_account__account_id`,
DROP INDEX `account_id`;
ALTER TABLE `cloud`.`project_account`
ADD CONSTRAINT `fk_project_account__account_id` FOREIGN KEY(`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE ,
ADD CONSTRAINT `uc_project_account__project_id_account_id_user_id` UNIQUE (`project_id`, `account_id`, `user_id`) ;
-- Alter project invitations table to include user_id for invites sent to specific users of an account
ALTER TABLE `cloud`.`project_invitations`
ADD COLUMN `user_id` bigint unsigned COMMENT 'ID of user to be added to the project' AFTER `account_id`,
ADD COLUMN `account_role` varchar(255) NOT NULL DEFAULT 'Regular' COMMENT 'Account role in the project (Owner or Regular)' AFTER `domain_id`,
ADD COLUMN `project_role_id` bigint unsigned COMMENT 'Project role id' AFTER `account_role`,
ADD CONSTRAINT `fk_project_invitations__user_id` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_project_invitations__project_role_id` FOREIGN KEY (`project_role_id`) REFERENCES `project_role` (`id`) ON DELETE SET NULL,
DROP INDEX `project_id`,
ADD CONSTRAINT `uc_project_invitations__project_id_account_id_user_id` UNIQUE (`project_id`, `account_id`,`user_id`);
-- Alter project_invitation_view to incorporate user_id as a field
ALTER VIEW `cloud`.`project_invitation_view` AS
select
project_invitations.id,
project_invitations.uuid,
project_invitations.email,
project_invitations.created,
project_invitations.state,
project_invitations.project_role_id,
projects.id project_id,
projects.uuid project_uuid,
projects.name project_name,
account.id account_id,
account.uuid account_uuid,
account.account_name,
account.type account_type,
user.id user_id,
domain.id domain_id,
domain.uuid domain_uuid,
domain.name domain_name,
domain.path domain_path
from
`cloud`.`project_invitations`
left join
`cloud`.`account` ON project_invitations.account_id = account.id
left join
`cloud`.`domain` ON project_invitations.domain_id = domain.id
left join
`cloud`.`projects` ON projects.id = project_invitations.project_id
left join
`cloud`.`user` ON project_invitations.user_id = user.id;
-- Alter project_account_view to incorporate user id
ALTER VIEW `cloud`.`project_account_view` AS
select
project_account.id,
account.id account_id,
account.uuid account_uuid,
account.account_name,
account.type account_type,
user.id user_id,
user.uuid user_uuid,
user.username user_name,
project_account.account_role,
project_role.id project_role_id,
project_role.uuid project_role_uuid,
projects.id project_id,
projects.uuid project_uuid,
projects.name project_name,
domain.id domain_id,
domain.uuid domain_uuid,
domain.name domain_name,
domain.path domain_path
from
`cloud`.`project_account`
inner join
`cloud`.`account` ON project_account.account_id = account.id
inner join
`cloud`.`domain` ON account.domain_id = domain.id
inner join
`cloud`.`projects` ON projects.id = project_account.project_id
left join
`cloud`.`project_role` ON project_account.project_role_id = project_role.id
left join
`cloud`.`user` ON (project_account.user_id = user.id);
ALTER VIEW `cloud`.`project_view` AS
select
projects.id,
projects.uuid,
projects.name,
projects.display_text,
projects.state,
projects.removed,
projects.created,
projects.project_account_id,
account.account_name owner,
pacct.account_id,
pacct.user_id,
domain.id domain_id,
domain.uuid domain_uuid,
domain.name domain_name,
domain.path domain_path
from
`cloud`.`projects`
inner join
`cloud`.`domain` ON projects.domain_id = domain.id
inner join
`cloud`.`project_account` ON projects.id = project_account.project_id
and project_account.account_role = 'Admin'
inner join
`cloud`.`account` ON account.id = project_account.account_id
left join
`cloud`.`project_account` pacct ON projects.id = pacct.project_id;
-- Fix Debian 10 32-bit hypervisor mappings on VMware, debian10-32bit OS ID in guest_os table is 292, not 282
UPDATE `cloud`.`guest_os_hypervisor` SET guest_os_id=292 WHERE guest_os_id=282 AND hypervisor_type="VMware" AND guest_os_name="debian10Guest";
-- Fix CentOS 32-bit mapping for VMware 5.5 which does not have a centos6Guest but only centosGuest and centos64Guest

View File

@ -905,7 +905,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
try {
JmxUtil.registerMBean("ClusterManager", "Node " + mshost.getId(), new ClusterManagerMBeanImpl(this, mshost));
} catch (final Exception e) {
s_logger.warn("Unable to regiester cluster node into JMX monitoring due to exception " + ExceptionUtil.toString(e));
s_logger.warn("Unable to register cluster node into JMX monitoring due to exception " + ExceptionUtil.toString(e));
}
}
}
@ -985,7 +985,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
_mshostPeerDao.clearPeerInfo(_mshostId);
// use seperate thread for heartbeat updates
// use separate thread for heartbeat updates
_heartbeatScheduler.scheduleAtFixedRate(getHeartbeatTask(), HeartbeatInterval.value(), HeartbeatInterval.value(), TimeUnit.MILLISECONDS);
_notificationExecutor.submit(getNotificationTask());

View File

@ -25,10 +25,12 @@ import java.util.Set;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.exception.UnavailableCommandException;
import org.apache.cloudstack.api.APICommand;
import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.UnavailableCommandException;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.User;
@ -44,7 +46,9 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
private RoleService roleService;
private List<PluggableService> services;
private Map<RoleType, Set<String>> annotationRoleBasedApisMap = new HashMap<>();
private Map<RoleType, Set<String>> annotationRoleBasedApisMap = new HashMap<RoleType, Set<String>>();
private static final Logger logger = Logger.getLogger(DynamicRoleBasedAPIAccessChecker.class.getName());
protected DynamicRoleBasedAPIAccessChecker() {
super();
@ -84,7 +88,7 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
// Check against current list of permissions
for (final RolePermission permission : roleService.findAllPermissionsBy(accountRole.getId())) {
if (permission.getRule().matches(commandName)) {
if (RolePermission.Permission.ALLOW.equals(permission.getPermission())) {
if (Permission.ALLOW.equals(permission.getPermission())) {
return true;
} else {
denyApiAccess(commandName);

View File

@ -16,13 +16,9 @@
// under the License.
package org.apache.cloudstack.acl;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.AccountVO;
import com.cloud.user.User;
import com.cloud.user.UserVO;
import junit.framework.TestCase;
import java.lang.reflect.Field;
import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -30,8 +26,16 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.util.Collections;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.AccountVO;
import com.cloud.user.User;
import com.cloud.user.UserVO;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import junit.framework.TestCase;
@RunWith(MockitoJUnitRunner.class)
public class DynamicRoleBasedAPIAccessCheckerTest extends TestCase {
@ -117,7 +121,7 @@ public class DynamicRoleBasedAPIAccessCheckerTest extends TestCase {
@Test
public void testValidAllowRolePermissionApiCheckAccess() {
final String allowedApiName = "someAllowedApi";
final RolePermission permission = new RolePermissionVO(1L, allowedApiName, RolePermission.Permission.ALLOW, null);
final RolePermission permission = new RolePermissionVO(1L, allowedApiName, Permission.ALLOW, null);
Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission));
assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName));
}
@ -125,7 +129,7 @@ public class DynamicRoleBasedAPIAccessCheckerTest extends TestCase {
@Test
public void testValidAllowRolePermissionWildcardCheckAccess() {
final String allowedApiName = "someAllowedApi";
final RolePermission permission = new RolePermissionVO(1L, "some*", RolePermission.Permission.ALLOW, null);
final RolePermission permission = new RolePermissionVO(1L, "some*", Permission.ALLOW, null);
Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission));
assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName));
}
@ -133,7 +137,7 @@ public class DynamicRoleBasedAPIAccessCheckerTest extends TestCase {
@Test
public void testValidDenyRolePermissionApiCheckAccess() {
final String denyApiName = "someDeniedApi";
final RolePermission permission = new RolePermissionVO(1L, denyApiName, RolePermission.Permission.DENY, null);
final RolePermission permission = new RolePermissionVO(1L, denyApiName, Permission.DENY, null);
Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission));
try {
apiAccessChecker.checkAccess(getTestUser(), denyApiName);
@ -145,7 +149,7 @@ public class DynamicRoleBasedAPIAccessCheckerTest extends TestCase {
@Test
public void testValidDenyRolePermissionWildcardCheckAccess() {
final String denyApiName = "someDenyApi";
final RolePermission permission = new RolePermissionVO(1L, "*Deny*", RolePermission.Permission.DENY, null);
final RolePermission permission = new RolePermissionVO(1L, "*Deny*", Permission.DENY, null);
Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission));
try {
apiAccessChecker.checkAccess(getTestUser(), denyApiName);

View File

@ -0,0 +1,30 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-plugin-acl-project-role-based</artifactId>
<name>Apache CloudStack Plugin - ACL Project Role Based</name>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
<version>4.15.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>

View File

@ -0,0 +1,148 @@
// 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.acl;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.UnavailableCommandException;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectAccount;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.User;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.PluggableService;
public class ProjectRoleBasedApiAccessChecker extends AdapterBase implements APIAclChecker {
@Inject
ProjectAccountDao projectAccountDao;
@Inject
ProjectRoleService projectRoleService;
@Inject
RoleService roleService;
@Inject
AccountService accountService;
private List<PluggableService> services;
private static final Logger LOGGER = Logger.getLogger(ProjectRoleBasedApiAccessChecker.class.getName());
protected ProjectRoleBasedApiAccessChecker() {
super();
}
private void denyApiAccess(final String commandName) throws PermissionDeniedException {
throw new PermissionDeniedException("The API " + commandName + " is blacklisted for the user's/account's project role.");
}
public boolean isDisabled() {
return !roleService.isEnabled();
}
@Override
public boolean checkAccess(User user, String apiCommandName) throws PermissionDeniedException {
if (isDisabled()) {
return true;
}
Account userAccount = accountService.getAccount(user.getAccountId());
Project project = CallContext.current().getProject();
if (project == null) {
return true;
}
if (accountService.isRootAdmin(userAccount.getId()) || accountService.isDomainAdmin(userAccount.getAccountId())) {
return true;
}
ProjectAccount projectUser = projectAccountDao.findByProjectIdUserId(project.getId(), userAccount.getAccountId(), user.getId());
if (projectUser != null) {
if (projectUser.getAccountRole() == ProjectAccount.Role.Admin) {
return true;
} else {
return isPermitted(project, projectUser, apiCommandName);
}
}
ProjectAccount projectAccount = projectAccountDao.findByProjectIdAccountId(project.getId(), userAccount.getAccountId());
if (projectAccount != null) {
if (projectAccount.getAccountRole() == ProjectAccount.Role.Admin) {
return true;
} else {
return isPermitted(project, projectAccount, apiCommandName);
}
}
// Default deny all
if ("updateProjectInvitation".equals(apiCommandName)) {
return true;
}
throw new UnavailableCommandException("The API " + apiCommandName + " does not exist or is not available for this account/user in project "+project.getUuid());
}
private boolean isPermitted(Project project, ProjectAccount projectUser, String apiCommandName) {
ProjectRole projectRole = null;
if(projectUser.getProjectRoleId() != null) {
projectRole = projectRoleService.findProjectRole(projectUser.getProjectRoleId(), project.getId());
}
if (projectRole == null) {
return true;
}
for (ProjectRolePermission permission : projectRoleService.findAllProjectRolePermissions(project.getId(), projectRole.getId())) {
if (permission.getRule().matches(apiCommandName)) {
if (Permission.ALLOW.equals(permission.getPermission())) {
return true;
} else {
denyApiAccess(apiCommandName);
}
}
}
return true;
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
return true;
}
@Override
public boolean start() {
return super.start();
}
public List<PluggableService> getServices() {
return services;
}
@Inject
public void setServices(List<PluggableService> services) {
this.services = services;
}
}

View File

@ -0,0 +1,18 @@
# 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.
name=acl-project-role-based
parent=api

View File

@ -0,0 +1,33 @@
<!--
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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
<bean id="ProjectRoleBasedAPIAccessChecker" class="org.apache.cloudstack.acl.ProjectRoleBasedApiAccessChecker" >
<property name="services" value="#{apiCommandsRegistry.registered}" />
</bean>
</beans>

View File

@ -16,13 +16,16 @@
// under the License.
package org.apache.cloudstack.discovery;
import com.cloud.serializer.Param;
import com.cloud.user.User;
import com.cloud.utils.ReflectUtil;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentLifecycleBase;
import com.cloud.utils.component.PluggableService;
import com.google.gson.annotations.SerializedName;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import org.apache.cloudstack.acl.APIChecker;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseAsyncCmd;
@ -39,14 +42,13 @@ import org.apache.log4j.Logger;
import org.reflections.ReflectionUtils;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.cloud.serializer.Param;
import com.cloud.user.User;
import com.cloud.utils.ReflectUtil;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentLifecycleBase;
import com.cloud.utils.component.PluggableService;
import com.google.gson.annotations.SerializedName;
@Component
public class ApiDiscoveryServiceImpl extends ComponentLifecycleBase implements ApiDiscoveryService {

View File

@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
<version>4.15.0.0-SNAPSHOT</version>
<version>4.15.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>cloud-plugin-hypervisor-baremetal</artifactId>
@ -32,20 +32,20 @@
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${cs.jaxb.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>${cs.jaxb.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${cs.jaxb.version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${cs.jaxb.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>${cs.jaxb.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${cs.jaxb.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -45,6 +45,7 @@
<!-- keep in alphabetic order -->
<module>acl/dynamic-role-based</module>
<module>acl/static-role-based</module>
<module>acl/project-role-based</module>
<module>affinity-group-processors/explicit-dedication</module>
<module>affinity-group-processors/host-affinity</module>

View File

@ -23,15 +23,18 @@ import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupService;
import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
import org.apache.cloudstack.context.CallContext;
import org.springframework.stereotype.Component;
import com.cloud.domain.DomainVO;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.projects.ProjectAccount;
import com.cloud.projects.ProjectVO;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.User;
import com.cloud.utils.exception.CloudRuntimeException;
@Component
@ -75,12 +78,22 @@ public class AffinityGroupAccessChecker extends DomainChecker {
//acl_type account
if (caller.getId() != group.getAccountId()) {
//check if the group belongs to a project
User user = CallContext.current().getCallingUser();
ProjectVO project = _projectDao.findByProjectAccountId(group.getAccountId());
ProjectAccount userProjectAccount = _projectAccountDao.findByProjectIdUserId(project.getId(), user.getAccountId(), user.getId());
if (project != null) {
if (AccessType.ModifyProject.equals(accessType) && _projectAccountDao.canModifyProjectAccount(caller.getId(), group.getAccountId())) {
return true;
} else if (!AccessType.ModifyProject.equals(accessType) && _projectAccountDao.canAccessProjectAccount(caller.getId(), group.getAccountId())) {
return true;
if (userProjectAccount != null) {
if (AccessType.ModifyProject.equals(accessType) && _projectAccountDao.canUserModifyProject(project.getId(), user.getAccountId(), user.getId())) {
return true;
} else if (!AccessType.ModifyProject.equals(accessType) && _projectAccountDao.canUserAccessProjectAccount(user.getAccountId(), user.getId(), group.getAccountId())) {
return true;
}
} else {
if (AccessType.ModifyProject.equals(accessType) && _projectAccountDao.canModifyProjectAccount(caller.getId(), group.getAccountId())) {
return true;
} else if (!AccessType.ModifyProject.equals(accessType) && _projectAccountDao.canAccessProjectAccount(caller.getId(), group.getAccountId())) {
return true;
}
}
}
throw new PermissionDeniedException(caller + " does not have permission to operate with resource " + entity);

View File

@ -21,9 +21,15 @@ import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.ProjectRolePermission;
import org.apache.cloudstack.acl.ProjectRoleService;
import org.apache.cloudstack.acl.RolePermissionEntity;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.dc.DataCenter;
@ -32,6 +38,7 @@ import com.cloud.dc.dao.DedicatedResourceDao;
import com.cloud.domain.Domain;
import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.UnavailableCommandException;
import com.cloud.network.Network;
import com.cloud.network.NetworkModel;
import com.cloud.network.vpc.VpcOffering;
@ -40,8 +47,11 @@ import com.cloud.offering.DiskOffering;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectAccount;
import com.cloud.projects.ProjectManager;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.LaunchPermissionVO;
import com.cloud.storage.dao.LaunchPermissionDao;
@ -64,7 +74,7 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
@Inject
ProjectManager _projectMgr;
@Inject
ProjectAccountDao _projecAccountDao;
ProjectAccountDao _projectAccountDao;
@Inject
NetworkModel _networkMgr;
@Inject
@ -79,7 +89,14 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
NetworkOfferingDetailsDao networkOfferingDetailsDao;
@Inject
VpcOfferingDetailsDao vpcOfferingDetailsDao;
@Inject
private ProjectRoleService projectRoleService;
@Inject
private ProjectDao projectDao;
@Inject
private AccountService accountService;
public static final Logger s_logger = Logger.getLogger(DomainChecker.class.getName());
protected DomainChecker() {
super();
}
@ -107,6 +124,7 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
if (user.getRemoved() != null) {
throw new PermissionDeniedException(user + " is no longer active.");
}
Account account = _accountDao.findById(user.getAccountId());
return checkAccess(account, domain);
}
@ -115,7 +133,6 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
public boolean checkAccess(Account caller, ControlledEntity entity, AccessType accessType)
throws PermissionDeniedException {
if (entity instanceof VirtualMachineTemplate) {
VirtualMachineTemplate template = (VirtualMachineTemplate)entity;
Account owner = _accountDao.findById(template.getAccountId());
// validate that the template is usable by the account
@ -154,7 +171,6 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
} else {
if (_accountService.isNormalUser(caller.getId())) {
Account account = _accountDao.findById(entity.getAccountId());
if (account != null && account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
//only project owner can delete/modify the project
if (accessType != null && accessType == AccessType.ModifyProject) {
@ -164,6 +180,7 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
} else if (!_projectMgr.canAccessProjectAccount(caller, account.getId())) {
throw new PermissionDeniedException(caller + " does not have permission to operate with resource " + entity);
}
checkOperationPermitted(caller, entity);
} else {
if (caller.getId() != entity.getAccountId()) {
throw new PermissionDeniedException(caller + " does not have permission to operate with resource " + entity);
@ -171,10 +188,59 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
}
}
}
return true;
}
private boolean checkOperationPermitted(Account caller, ControlledEntity entity) {
User user = CallContext.current().getCallingUser();
Project project = projectDao.findByProjectAccountId(entity.getAccountId());
ProjectAccount projectUser = _projectAccountDao.findByProjectIdUserId(project.getId(), user.getAccountId(), user.getId());
String apiCommandName = CallContext.current().getApiName();
if (accountService.isRootAdmin(caller.getId()) || accountService.isDomainAdmin(caller.getAccountId())) {
return true;
}
if (projectUser != null) {
if (projectUser.getAccountRole() == ProjectAccount.Role.Admin) {
return true;
} else {
return isPermitted(project, projectUser, apiCommandName);
}
}
ProjectAccount projectAccount = _projectAccountDao.findByProjectIdAccountId(project.getId(), caller.getAccountId());
if (projectAccount != null) {
if (projectAccount.getAccountRole() == ProjectAccount.Role.Admin) {
return true;
} else {
return isPermitted(project, projectAccount, apiCommandName);
}
}
throw new UnavailableCommandException("The given command '" + apiCommandName + "' either does not exist or is not available for the user");
}
private boolean isPermitted(Project project, ProjectAccount projectUser, String apiCommandName) {
ProjectRole projectRole = null;
if(projectUser.getProjectRoleId() != null) {
projectRole = projectRoleService.findProjectRole(projectUser.getProjectRoleId(), project.getId());
}
if (projectRole == null) {
return true;
}
for (ProjectRolePermission permission : projectRoleService.findAllProjectRolePermissions(project.getId(), projectRole.getId())) {
if (permission.getRule().matches(apiCommandName)) {
if (RolePermissionEntity.Permission.ALLOW.equals(permission.getPermission())) {
return true;
} else {
throw new PermissionDeniedException("The given command '" + apiCommandName + "' either does not exist or is not available for the user");
}
}
}
return true;
}
@Override
public boolean checkAccess(User user, ControlledEntity entity) throws PermissionDeniedException {
Account account = _accountDao.findById(user.getAccountId());

View File

@ -1142,6 +1142,10 @@ public class ApiDBUtils {
return s_userDao.findById(userId);
}
public static UserAccountJoinVO findUserAccountById(Long id) {
return s_userAccountJoinDao.findById(id);
}
public static UserVm findUserVmById(Long vmId) {
return s_userVmDao.findById(vmId);
}
@ -1833,6 +1837,7 @@ public class ApiDBUtils {
}
public static List<ProjectJoinVO> newProjectView(Project proj) {
return s_projectJoinDao.newProjectView(proj);
}

View File

@ -31,7 +31,6 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import com.cloud.resource.RollingMaintenanceManager;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.affinity.AffinityGroup;
@ -45,9 +44,6 @@ import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.ApplicationLoadBalancerInstanceResponse;
import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse;
import org.apache.cloudstack.api.response.RollingMaintenanceHostSkippedResponse;
import org.apache.cloudstack.api.response.RollingMaintenanceHostUpdatedResponse;
import org.apache.cloudstack.api.response.RollingMaintenanceResponse;
import org.apache.cloudstack.api.response.ApplicationLoadBalancerRuleResponse;
import org.apache.cloudstack.api.response.AsyncJobResponse;
import org.apache.cloudstack.api.response.AutoScalePolicyResponse;
@ -68,7 +64,6 @@ import org.apache.cloudstack.api.response.CreateCmdResponse;
import org.apache.cloudstack.api.response.CreateSSHKeyPairResponse;
import org.apache.cloudstack.api.response.DiskOfferingResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.RouterHealthCheckResultResponse;
import org.apache.cloudstack.api.response.DomainRouterResponse;
import org.apache.cloudstack.api.response.EventResponse;
import org.apache.cloudstack.api.response.ExtractResponse;
@ -116,6 +111,10 @@ import org.apache.cloudstack.api.response.RemoteAccessVpnResponse;
import org.apache.cloudstack.api.response.ResourceCountResponse;
import org.apache.cloudstack.api.response.ResourceLimitResponse;
import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.api.response.RollingMaintenanceHostSkippedResponse;
import org.apache.cloudstack.api.response.RollingMaintenanceHostUpdatedResponse;
import org.apache.cloudstack.api.response.RollingMaintenanceResponse;
import org.apache.cloudstack.api.response.RouterHealthCheckResultResponse;
import org.apache.cloudstack.api.response.SSHKeyPairResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.SecurityGroupRuleResponse;
@ -296,6 +295,7 @@ import com.cloud.projects.Project;
import com.cloud.projects.ProjectAccount;
import com.cloud.projects.ProjectInvitation;
import com.cloud.region.ha.GlobalLoadBalancerRule;
import com.cloud.resource.RollingMaintenanceManager;
import com.cloud.server.ResourceTag;
import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.service.ServiceOfferingVO;

View File

@ -16,49 +16,45 @@
// under the License.
package com.cloud.api;
import com.cloud.api.dispatch.DispatchChainFactory;
import com.cloud.api.dispatch.DispatchTask;
import com.cloud.api.response.ApiResponseSerializer;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventCategory;
import com.cloud.event.EventTypes;
import com.cloud.exception.AccountLimitException;
import com.cloud.exception.CloudAuthenticationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.OriginDeniedException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.RequestLimitException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.UnavailableCommandException;
import com.cloud.storage.VolumeApiService;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.DomainManager;
import com.cloud.user.User;
import com.cloud.user.UserAccount;
import com.cloud.user.UserVO;
import com.cloud.utils.ConstantTimeComparator;
import com.cloud.utils.DateUtil;
import com.cloud.utils.HttpUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.ReflectUtil;
import com.cloud.utils.StringUtils;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.component.PluggableService;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.EntityManager;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.UUIDManager;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.exception.ExceptionProxyObject;
import com.google.gson.reflect.TypeToken;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.Security;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.cloudstack.acl.APIChecker;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
@ -141,43 +137,50 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.stereotype.Component;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.lang.reflect.Type;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.Security;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.cloud.api.dispatch.DispatchChainFactory;
import com.cloud.api.dispatch.DispatchTask;
import com.cloud.api.response.ApiResponseSerializer;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventCategory;
import com.cloud.event.EventTypes;
import com.cloud.exception.AccountLimitException;
import com.cloud.exception.CloudAuthenticationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.OriginDeniedException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.RequestLimitException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.UnavailableCommandException;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.storage.VolumeApiService;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.DomainManager;
import com.cloud.user.User;
import com.cloud.user.UserAccount;
import com.cloud.user.UserVO;
import com.cloud.utils.ConstantTimeComparator;
import com.cloud.utils.DateUtil;
import com.cloud.utils.HttpUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.ReflectUtil;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.component.PluggableService;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.EntityManager;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.UUIDManager;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.exception.ExceptionProxyObject;
import com.cloud.utils.net.NetUtils;
import com.google.gson.reflect.TypeToken;
@Component
public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiServerService, Configurable {
@ -209,6 +212,8 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
private EntityManager entityMgr;
@Inject
private APIAuthenticationManager authManager;
@Inject
private ProjectDao projectDao;
private List<PluggableService> pluggableServices;
@ -843,7 +848,6 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
// if userId not null, that mean that user is logged in
if (userId != null) {
final User user = ApiDBUtils.findUserById(userId);
return commandAvailable(remoteAddress, commandName, user);
} else {
// check against every available command to see if the command exists or not

View File

@ -47,6 +47,8 @@ import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import com.cloud.projects.Project;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.User;
@ -75,6 +77,8 @@ public class ApiServlet extends HttpServlet {
ManagedContext managedContext;
@Inject
APIAuthenticationManager authManager;
@Inject
private ProjectDao projectDao;
public ApiServlet() {
}
@ -202,6 +206,7 @@ public class ApiServlet extends HttpServlet {
}
}
session = req.getSession(true);
if (ApiServer.EnableSecureSessionCookie.value()) {
resp.setHeader("SET-COOKIE", String.format("JSESSIONID=%s;Secure;HttpOnly;Path=/client", session.getId()));
if (s_logger.isDebugEnabled()) {
@ -305,13 +310,14 @@ public class ApiServlet extends HttpServlet {
} else {
CallContext.register(accountMgr.getSystemUser(), accountMgr.getSystemAccount());
}
setProjectContext(params);
if (apiServer.verifyRequest(params, userId, remoteAddress)) {
auditTrailSb.insert(0, "(userId=" + CallContext.current().getCallingUserId() + " accountId=" + CallContext.current().getCallingAccount().getId() +
" sessionId=" + (session != null ? session.getId() : null) + ")");
// Add the HTTP method (GET/POST/PUT/DELETE) as well into the params map.
params.put("httpmethod", new String[]{req.getMethod()});
setProjectContext(params);
final String response = apiServer.handleRequest(params, responseType, auditTrailSb);
HttpUtils.writeHttpResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType, ApiServer.JSONcontentType.value());
} else {
@ -347,6 +353,41 @@ public class ApiServlet extends HttpServlet {
}
}
private void setProjectContext(Map<String, Object[]> requestParameters) {
final String[] command = (String[])requestParameters.get(ApiConstants.COMMAND);
if (command == null) {
s_logger.info("missing command, ignoring request...");
return;
}
final String commandName = command[0];
CallContext.current().setApiName(commandName);
for (Map.Entry<String, Object[]> entry: requestParameters.entrySet()) {
if (entry.getKey().equals(ApiConstants.PROJECT_ID) || isSpecificAPI(commandName)) {
String projectId = null;
if (isSpecificAPI(commandName)) {
projectId = String.valueOf(requestParameters.entrySet().stream()
.filter(e -> e.getKey().equals(ApiConstants.ID))
.map(Map.Entry::getValue).findFirst().get()[0]);
} else {
projectId = String.valueOf(entry.getValue()[0]);
}
Project project = projectDao.findByUuid(projectId);
if (project != null) {
CallContext.current().setProject(project);
}
}
}
}
private boolean isSpecificAPI(String commandName) {
List<String> commands = Arrays.asList("suspendProject", "updateProject", "activateProject", "deleteProject");
if (commands.contains(commandName)) {
return true;
}
return false;
}
//This method will try to get login IP of user even if servlet is behind reverseProxy or loadBalancer
static InetAddress getClientAddress(final HttpServletRequest request) throws UnknownHostException {
for(final String header : s_clientAddressHeaders) {

View File

@ -269,20 +269,24 @@ public class ParamProcessWorker implements DispatchWorker {
doAccessChecks(cmd, entitiesToAccess);
}
private void doAccessChecks(BaseCmd cmd, Map<Object, AccessType> entitiesToAccess) {
Account caller = CallContext.current().getCallingAccount();
// due to deleteAccount design flaw CLOUDSTACK-6588, we should still include those removed account as well to clean up leftover resources from that account
Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId());
List<Long> entityOwners = cmd.getEntityOwnerIds();
Account[] owners = null;
if (entityOwners != null) {
owners = entityOwners.stream().map(id -> _accountMgr.getAccount(id)).toArray(Account[]::new);
} else {
owners = new Account[]{_accountMgr.getAccount(cmd.getEntityOwnerId())};
}
if (cmd instanceof BaseAsyncCreateCmd) {
// check that caller can access the owner account.
_accountMgr.checkAccess(caller, null, false, owner);
_accountMgr.checkAccess(caller, null, false, owners);
}
if (!entitiesToAccess.isEmpty()) {
// check that caller can access the owner account.
_accountMgr.checkAccess(caller, null, false, owner);
_accountMgr.checkAccess(caller, null, false, owners);
for (Map.Entry<Object,AccessType>entry : entitiesToAccess.entrySet()) {
Object entity = entry.getKey();
if (entity instanceof ControlledEntity) {

View File

@ -196,6 +196,7 @@ import com.cloud.projects.ProjectManager;
import com.cloud.projects.ProjectVO;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.projects.dao.ProjectInvitationDao;
import com.cloud.resource.ResourceManager;
import com.cloud.server.ResourceMetaDataService;
import com.cloud.server.ResourceTag;
@ -223,7 +224,9 @@ import com.cloud.template.VirtualMachineTemplate.TemplateFilter;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.DomainManager;
import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.DateUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
@ -410,6 +413,11 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Inject
private RouterHealthCheckResultDao routerHealthCheckResultDao;
@Inject
private ProjectInvitationDao projectInvitationDao;
@Inject
private UserDao userDao;
/*
* (non-Javadoc)
*
@ -1386,6 +1394,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
String displayText = cmd.getDisplayText();
String state = cmd.getState();
String accountName = cmd.getAccountName();
String username = cmd.getUsername();
Long domainId = cmd.getDomainId();
String keyword = cmd.getKeyword();
Long startIndex = cmd.getStartIndex();
@ -1394,8 +1403,11 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
boolean isRecursive = cmd.isRecursive();
cmd.getTags();
Account caller = CallContext.current().getCallingAccount();
User user = CallContext.current().getCallingUser();
Long accountId = null;
Long userId = null;
String path = null;
Filter searchFilter = new Filter(ProjectJoinVO.class, "id", false, startIndex, pageSize);
@ -1419,11 +1431,23 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
}
accountId = owner.getId();
}
if (!Strings.isNullOrEmpty(username)) {
User owner = userDao.getUserByName(username, domainId);
if (owner == null) {
throw new InvalidParameterValueException("Unable to find user " + username + " in domain " + domainId);
}
userId = owner.getId();
if (accountName == null) {
accountId = owner.getAccountId();
}
}
} else { // domainId == null
if (accountName != null) {
throw new InvalidParameterValueException("could not find account " + accountName + " because domain is not specified");
}
if (!Strings.isNullOrEmpty(username)) {
throw new InvalidParameterValueException("could not find user " + username + " because domain is not specified");
}
}
} else {
if (accountName != null && !accountName.equals(caller.getAccountName())) {
@ -1434,11 +1458,17 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
throw new PermissionDeniedException("Can't list domain id= " + domainId + " projects; unauthorized");
}
if (!Strings.isNullOrEmpty(username) && !username.equals(user.getUsername())) {
throw new PermissionDeniedException("Can't list user " + username + " projects; unauthorized");
}
accountId = caller.getId();
userId = user.getId();
}
if (domainId == null && accountId == null && (_accountMgr.isNormalUser(caller.getId()) || !listAll)) {
accountId = caller.getId();
userId = user.getId();
} else if (_accountMgr.isDomainAdmin(caller.getId()) || (isRecursive && !listAll)) {
DomainVO domain = _domainDao.findById(caller.getDomainId());
path = domain.getPath();
@ -1452,6 +1482,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ);
}
if (userId != null) {
sb.and().op("userId", sb.entity().getUserId(), Op.EQ);
sb.or("userIdNull", sb.entity().getUserId(), Op.NULL);
sb.cp();
} else {
sb.and("userIdNull", sb.entity().getUserId(), Op.NULL);
}
SearchCriteria<ProjectJoinVO> sc = sb.create();
if (id != null) {
@ -1474,6 +1512,10 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sc.setParameters("accountId", accountId);
}
if (userId != null) {
sc.setParameters("userId", userId);
}
if (state != null) {
sc.addAnd("state", Op.EQ, state);
}
@ -1525,10 +1567,12 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
boolean activeOnly = cmd.isActiveOnly();
Long startIndex = cmd.getStartIndex();
Long pageSizeVal = cmd.getPageSizeVal();
Long userId = cmd.getUserId();
boolean isRecursive = cmd.isRecursive();
boolean listAll = cmd.listAll();
Account caller = CallContext.current().getCallingAccount();
User callingUser = CallContext.current().getCallingUser();
List<Long> permittedAccounts = new ArrayList<Long>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(domainId, isRecursive, null);
@ -1540,7 +1584,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Filter searchFilter = new Filter(ProjectInvitationJoinVO.class, "id", true, startIndex, pageSizeVal);
SearchBuilder<ProjectInvitationJoinVO> sb = _projectInvitationJoinDao.createSearchBuilder();
_accountMgr.buildACLViewSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
ProjectInvitation invitation = projectInvitationDao.findByUserIdProjectId(callingUser.getId(), callingUser.getAccountId(), projectId == null ? -1 : projectId);
sb.and("projectId", sb.entity().getProjectId(), SearchCriteria.Op.EQ);
sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
sb.and("created", sb.entity().getCreated(), SearchCriteria.Op.GT);
@ -1553,6 +1597,12 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sc.setParameters("projectId", projectId);
}
if (invitation != null) {
sc.setParameters("userId", invitation.getForUserId());
} else if (userId != null) {
sc.setParameters("userId", userId);
}
if (state != null) {
sc.setParameters("state", state);
}
@ -1566,7 +1616,11 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sc.setParameters("created", new Date((DateUtil.currentGMTTime().getTime()) - _projectMgr.getInvitationTimeout()));
}
return _projectInvitationJoinDao.searchAndCount(sc, searchFilter);
Pair<List<ProjectInvitationJoinVO>, Integer> projectInvitations = _projectInvitationJoinDao.searchAndCount(sc, searchFilter);
List<ProjectInvitationJoinVO> invitations = projectInvitations.first();
invitations = invitations.stream().filter(invite -> invite.getUserId() == null || Long.parseLong(invite.getUserId()) == callingUser.getId()).collect(Collectors.toList());
return new Pair<>(invitations, invitations.size());
}
@ -1582,14 +1636,15 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
public Pair<List<ProjectAccountJoinVO>, Integer> listProjectAccountsInternal(ListProjectAccountsCmd cmd) {
long projectId = cmd.getProjectId();
String accountName = cmd.getAccountName();
Long userId = cmd.getUserId();
String role = cmd.getRole();
Long startIndex = cmd.getStartIndex();
Long pageSizeVal = cmd.getPageSizeVal();
Long projectRoleId = cmd.getProjectRoleId();
// long projectId, String accountName, String role, Long startIndex,
// Long pageSizeVal) {
Account caller = CallContext.current().getCallingAccount();
User callingUser = CallContext.current().getCallingUser();
// check that the project exists
Project project = _projectDao.findById(projectId);
@ -1599,7 +1654,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// verify permissions - only accounts belonging to the project can list
// project's account
if (!_accountMgr.isAdmin(caller.getId()) && _projectAccountDao.findByProjectIdAccountId(projectId, caller.getAccountId()) == null) {
if (!_accountMgr.isAdmin(caller.getId()) && _projectAccountDao.findByProjectIdUserId(projectId, callingUser.getAccountId(), callingUser.getId()) == null &&
_projectAccountDao.findByProjectIdAccountId(projectId, caller.getAccountId()) == null) {
throw new PermissionDeniedException("Account " + caller + " is not authorized to list users of the project id=" + projectId);
}
@ -1612,6 +1668,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sb.and("accountName", sb.entity().getAccountName(), Op.EQ);
}
if (userId != null) {
sb.and("userId", sb.entity().getUserId(), Op.EQ);
}
SearchCriteria<ProjectAccountJoinVO> sc = sb.create();
sc.setParameters("projectId", projectId);
@ -1624,6 +1683,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sc.setParameters("accountName", accountName);
}
if (projectRoleId != null) {
sc.setParameters("projectRoleId", projectRoleId);
}
if (userId != null) {
sc.setParameters("userId", userId);
}
return _projectAccountJoinDao.searchAndCount(sc, searchFilter);
}

View File

@ -26,9 +26,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.cloud.configuration.Resource;
import com.cloud.domain.Domain;
import org.apache.log4j.Logger;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ApiConstants.DomainDetails;
import org.apache.cloudstack.api.ApiConstants.HostDetails;
@ -59,6 +56,7 @@ import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.query.vo.AccountJoinVO;
@ -84,8 +82,10 @@ import com.cloud.api.query.vo.TemplateJoinVO;
import com.cloud.api.query.vo.UserAccountJoinVO;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.api.query.vo.VolumeJoinVO;
import com.cloud.storage.StoragePoolTagVO;
import com.cloud.configuration.Resource;
import com.cloud.domain.Domain;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.StoragePoolTagVO;
import com.cloud.storage.VolumeStats;
import com.cloud.user.Account;
@ -216,7 +216,12 @@ public class ViewResponseHelper {
// update user list
Account caller = CallContext.current().getCallingAccount();
if (ApiDBUtils.isAdmin(caller)) {
List<UserAccountJoinVO> users = ApiDBUtils.findUserViewByAccountId(proj.getAccountId());
List<UserAccountJoinVO> users = null;
if (proj.getUserUuid() != null) {
users = Collections.singletonList(ApiDBUtils.findUserAccountById(proj.getUserId()));
} else {
users = ApiDBUtils.findUserViewByAccountId(proj.getAccountId());
}
resp.setUsers(ViewResponseHelper.createUserResponse(users.toArray(new UserAccountJoinVO[users.size()])));
}
responseList.add(resp);

View File

@ -52,9 +52,11 @@ public class ProjectAccountJoinDaoImpl extends GenericDaoBase<ProjectAccountJoin
projectAccountResponse.setProjectId(proj.getProjectUuid());
projectAccountResponse.setProjectName(proj.getProjectName());
projectAccountResponse.setProjectRoleId(proj.getProjectRoleUuid());
projectAccountResponse.setAccountId(proj.getAccountUuid());
projectAccountResponse.setAccountName(proj.getAccountName());
projectAccountResponse.setUserId(proj.getUserUuid());
projectAccountResponse.setUsername(proj.getUsername());
projectAccountResponse.setAccountType(proj.getAccountType());
projectAccountResponse.setRole(proj.getAccountRole().toString());
projectAccountResponse.setDomainId(proj.getDomainUuid());

View File

@ -57,7 +57,11 @@ public class ProjectInvitationJoinDaoImpl extends GenericDaoBase<ProjectInvitati
if (invite.getAccountName() != null) {
response.setAccountName(invite.getAccountName());
} else {
}
if (invite.getUserId() != null) {
response.setUserId(invite.getUserId());
}
if (invite.getEmail() != null) {
response.setEmail(invite.getEmail());
}

View File

@ -18,7 +18,10 @@ package com.cloud.api.query.dao;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
@ -35,9 +38,14 @@ import com.cloud.api.query.vo.AccountJoinVO;
import com.cloud.api.query.vo.ProjectJoinVO;
import com.cloud.api.query.vo.ResourceTagJoinVO;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectAccount;
import com.cloud.projects.ProjectAccountVO;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.user.Account;
import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@ -52,6 +60,10 @@ public class ProjectJoinDaoImpl extends GenericDaoBase<ProjectJoinVO, Long> impl
private AccountJoinDao _accountJoinDao;
@Inject
private AccountDao _accountDao;
@Inject
private ProjectAccountDao projectAccountDao;
@Inject
private UserDao userDao;
private final SearchBuilder<ProjectJoinVO> prjSearch;
@ -82,7 +94,22 @@ public class ProjectJoinDaoImpl extends GenericDaoBase<ProjectJoinVO, Long> impl
response.setDomainId(proj.getDomainUuid());
response.setDomain(proj.getDomainName());
response.setOwner(proj.getOwner());
List<ProjectAccountVO> projectAccounts = projectAccountDao.listByProjectId(proj.getId());
projectAccounts = projectAccounts.stream().filter(projectAccount -> projectAccount.getAccountRole() == ProjectAccount.Role.Admin).collect(Collectors.toList());
List<Map<String, String>> ownersList = new ArrayList<>();
for (ProjectAccount projectAccount: projectAccounts) {
Map<String, String> ownerDetails = new HashMap<>();
if (projectAccount.getUserId() != null) {
User user = userDao.findById(projectAccount.getUserId());
ownerDetails.put("account", _accountDao.findById(projectAccount.getAccountId()).getAccountName());
ownerDetails.put("user", user.getUsername());
ownerDetails.put("userid", user.getUuid());
} else {
ownerDetails.put("account", _accountDao.findById(projectAccount.getAccountId()).getAccountName());
}
ownersList.add(ownerDetails);
}
response.setOwners(ownersList);
// update tag information
List<ResourceTagJoinVO> tags = ApiDBUtils.listResourceTagViewByResourceUUID(proj.getUuid(), ResourceObjectType.Project);

View File

@ -72,6 +72,21 @@ public class ProjectAccountJoinVO extends BaseViewVO implements InternalIdentity
@Column(name = "project_name")
private String projectName;
@Column(name = "user_id")
private Long userId;
@Column(name = "user_name")
private String username;
@Column(name = "project_role_id")
private Long projectRoleId;
@Column(name = "project_role_uuid")
private String projectRoleUuid;
@Column(name = "user_uuid")
private String userUuid;
public ProjectAccountJoinVO() {
}
@ -127,4 +142,21 @@ public class ProjectAccountJoinVO extends BaseViewVO implements InternalIdentity
public String getProjectName() {
return projectName;
}
public Long getUserId() { return userId; }
public Long getProjectRoleId() {
return projectRoleId;
}
public String getProjectRoleUuid() {
return projectRoleUuid;
}
public String getUserUuid() { return userUuid; }
public String getUsername() {
return username;
}
}

View File

@ -83,6 +83,9 @@ public class ProjectInvitationJoinVO extends BaseViewVO implements ControlledVie
@Column(name = "project_name")
private String projectName;
@Column(name = "user_id")
private String userId;
public ProjectInvitationJoinVO() {
}
@ -162,6 +165,8 @@ public class ProjectInvitationJoinVO extends BaseViewVO implements ControlledVie
return domainPath;
}
public String getUserId() { return userId; }
@Override
public Class<?> getEntityType() {
return ProjectInvitation.class;

View File

@ -76,6 +76,9 @@ public class ProjectJoinVO extends BaseViewVO implements InternalIdentity, Ident
@Column(name = "domain_path")
private String domainPath;
@Column(name = "user_id")
private long userId;
@Column(name = "project_account_id")
private long projectAccountId;
@ -139,4 +142,8 @@ public class ProjectJoinVO extends BaseViewVO implements InternalIdentity, Ident
public long getProjectAccountId() {
return projectAccountId;
}
public long getUserId() {
return userId;
}
}

View File

@ -34,6 +34,7 @@ import java.util.TreeSet;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.context.CallContext;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
@ -104,11 +105,15 @@ import com.cloud.offerings.NetworkOfferingVO;
import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectAccount;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.DomainManager;
import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.AdapterBase;
@ -162,6 +167,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
PodVlanMapDao _podVlanMapDao;
@Inject
VpcGatewayDao _vpcGatewayDao;
@Inject
ProjectDao projectDao;
private List<NetworkElement> networkElements;
@ -1649,9 +1656,19 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() +
", network does not have an owner");
if (owner.getType() != Account.ACCOUNT_TYPE_PROJECT && networkOwner.getType() == Account.ACCOUNT_TYPE_PROJECT) {
if (!_projectAccountDao.canAccessProjectAccount(owner.getAccountId(), network.getAccountId())) {
throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() +
", permission denied");
User user = CallContext.current().getCallingUser();
Project project = projectDao.findByProjectAccountId(network.getAccountId());
ProjectAccount projectAccountUser = _projectAccountDao.findByProjectIdUserId(project.getId(), user.getAccountId(), user.getId());
if (projectAccountUser != null) {
if (!_projectAccountDao.canUserAccessProjectAccount(user.getAccountId(), user.getId(), network.getAccountId())) {
throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() +
", permission denied");
}
} else {
if (!_projectAccountDao.canAccessProjectAccount(owner.getAccountId(), network.getAccountId())) {
throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO) network).getUuid() +
", permission denied");
}
}
} else {
List<NetworkVO> networkMap = _networksDao.listBy(owner.getId(), network.getId());

View File

@ -20,6 +20,7 @@ import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Random;
import java.util.TimeZone;
@ -27,6 +28,7 @@ import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.mail.Authenticator;
@ -38,7 +40,9 @@ import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.acl.dao.ProjectRoleDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
@ -74,6 +78,7 @@ import com.cloud.user.DomainManager;
import com.cloud.user.ResourceLimitService;
import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.DateUtil;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.ManagerBase;
@ -122,6 +127,10 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
private ProjectInvitationJoinDao _projectInvitationJoinDao;
@Inject
protected ResourceTagDao _resourceTagDao;
@Inject
private ProjectRoleDao projectRoleDao;
@Inject
private UserDao userDao;
protected boolean _invitationRequired = false;
protected long _invitationTimeOut = 86400000;
@ -171,10 +180,38 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
return true;
}
private User validateUser(Long userId, Long accountId, Long domainId) {
User user = null;
if (userId != null) {
user = userDao.findById(userId);
if (user == null ) {
throw new InvalidParameterValueException("Invalid user ID provided");
}
if (user.getAccountId() != accountId || _accountDao.findById(user.getAccountId()).getDomainId() != domainId) {
throw new InvalidParameterValueException("User doesn't belong to the specified account or domain");
}
}
return user;
}
private User validateUser(Long userId, Long domainId) {
User user = null;
if (userId != null) {
user = userDao.findById(userId);
if (user == null) {
throw new InvalidParameterValueException("Invalid user ID provided");
}
if (_accountDao.findById(user.getAccountId()).getDomainId() != domainId) {
throw new InvalidParameterValueException("User doesn't belong to the specified account or domain");
}
}
return user;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_CREATE, eventDescription = "creating project", create = true)
@DB
public Project createProject(final String name, final String displayText, String accountName, final Long domainId) throws ResourceAllocationException {
public Project createProject(final String name, final String displayText, String accountName, final Long domainId, final Long userId, final Long accountId) throws ResourceAllocationException {
Account caller = CallContext.current().getCallingAccount();
Account owner = caller;
@ -188,6 +225,10 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
throw new InvalidParameterValueException("Account name and domain id must be specified together");
}
if (userId != null && (accountId == null && domainId == null)) {
throw new InvalidParameterValueException("Domain ID and account ID must be provided with User ID");
}
if (accountName != null) {
owner = _accountMgr.finalizeOwner(caller, accountName, domainId, null);
}
@ -197,10 +238,13 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
throw new InvalidParameterValueException("Project with name " + name + " already exists in domain id=" + owner.getDomainId());
}
User user = validateUser(userId, accountId, domainId);
//do resource limit check
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.project);
final Account ownerFinal = owner;
User finalUser = user;
return Transaction.execute(new TransactionCallback<Project>() {
@Override
public Project doInTransaction(TransactionStatus status) {
@ -214,7 +258,8 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
Project project = _projectDao.persist(new ProjectVO(name, displayText, ownerFinal.getDomainId(), projectAccount.getId()));
//assign owner to the project
assignAccountToProject(project, ownerFinal.getId(), ProjectAccount.Role.Admin);
assignAccountToProject(project, ownerFinal.getId(), ProjectAccount.Role.Admin,
Optional.ofNullable(finalUser).map(User::getId).orElse(null), null);
if (project != null) {
CallContext.current().setEventDetails("Project id=" + project.getId());
@ -241,6 +286,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
throw new InvalidParameterValueException("Unable to find project by id " + projectId);
}
CallContext.current().setProject(project);
_accountMgr.checkAccess(caller, AccessType.ModifyProject, true, _accountMgr.getAccount(project.getProjectAccountId()));
//at this point enabling project doesn't require anything, so just update the state
@ -261,6 +307,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
throw new InvalidParameterValueException("Unable to find project by id " + projectId);
}
CallContext.current().setProject(project);
_accountMgr.checkAccess(ctx.getCallingAccount(), AccessType.ModifyProject, true, _accountMgr.getAccount(project.getProjectAccountId()));
return deleteProject(ctx.getCallingAccount(), ctx.getCallingUserId(), project);
@ -277,11 +324,11 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
project.setState(State.Disabled);
boolean updateResult = _projectDao.update(project.getId(), project);
//owner can be already removed at this point, so adding the conditional check
Account projectOwner = getProjectOwner(project.getId());
if (projectOwner != null) {
_resourceLimitMgr.decrementResourceCount(projectOwner.getId(), ResourceType.project);
List<Long> projectOwners = getProjectOwners(project.getId());
if (projectOwners != null) {
for (Long projectOwner : projectOwners)
_resourceLimitMgr.decrementResourceCount(projectOwner, ResourceType.project);
}
return updateResult;
}
});
@ -323,7 +370,6 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
s_logger.debug("Removing all invitations for the project " + project + " as a part of project cleanup...");
_projectInvitationDao.cleanupInvitations(project.getId());
return result;
}
});
@ -364,8 +410,13 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
}
@Override
public ProjectAccount assignAccountToProject(Project project, long accountId, ProjectAccount.Role accountRole) {
return _projectAccountDao.persist(new ProjectAccountVO(project, accountId, accountRole));
public ProjectAccount assignAccountToProject(Project project, long accountId, ProjectAccount.Role accountRole, Long userId, Long projectRoleId) {
ProjectAccountVO projectAccountVO = new ProjectAccountVO(project, accountId, accountRole, userId, projectRoleId);
return _projectAccountDao.persist(projectAccountVO);
}
public ProjectAccount assignUserToProject(Project project, long userId, long accountId, Role userRole, Long projectRoleId) {
return assignAccountToProject(project, accountId, userRole, userId, projectRoleId);
}
@Override
@ -404,6 +455,15 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
return null;
}
@Override
public List<Long> getProjectOwners(long projectId) {
List<? extends ProjectAccount> projectAccounts = _projectAccountDao.getProjectOwners(projectId);
if (projectAccounts != null || !projectAccounts.isEmpty()) {
return projectAccounts.stream().map(acc -> _accountMgr.getAccount(acc.getAccountId()).getId()).collect(Collectors.toList());
}
return null;
}
@Override
public ProjectVO findByProjectAccountId(long projectAccountId) {
return _projectDao.findByProjectAccountId(projectAccountId);
@ -414,6 +474,74 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
return _projectDao.findByProjectAccountIdIncludingRemoved(projectAccountId);
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_USER_ADD, eventDescription = "adding user to project", async = true)
public boolean addUserToProject(Long projectId, String username, String email, Long projectRoleId, Role projectRole) {
Account caller = CallContext.current().getCallingAccount();
Project project = getProject(projectId);
if (project == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find project with specified id");
ex.addProxyObject(String.valueOf(projectId), "projectId");
throw ex;
}
if (project.getState() != State.Active) {
InvalidParameterValueException ex =
new InvalidParameterValueException("Can't add user to the specified project id in state=" + project.getState() + " as it isn't currently active");
ex.addProxyObject(project.getUuid(), "projectId");
throw ex;
}
User user = userDao.getUserByName(username, project.getDomainId());
if (user == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Invalid user ID provided");
ex.addProxyObject(String.valueOf(username), "userId");
throw ex;
}
CallContext.current().setProject(project);
_accountMgr.checkAccess(caller, AccessType.ModifyProject, true, _accountMgr.getAccount(project.getProjectAccountId()));
Account userAccount = _accountDao.findById(user.getAccountId());
if (_projectAccountDao.findByProjectIdAccountId(projectId, userAccount.getAccountId()) != null) {
throw new InvalidParameterValueException("User belongs to account " + userAccount.getAccountId() + " which is already part of the project");
}
ProjectAccount projectAccountUser = _projectAccountDao.findByProjectIdUserId(projectId, user.getAccountId(), user.getId());
if (projectAccountUser != null) {
s_logger.info("User with id: " + user.getId() + " is already added to the project with id: " + projectId);
return true;
}
if (projectRoleId != null && projectRoleId < 1L) {
throw new InvalidParameterValueException("Invalid project role id provided");
}
ProjectRole role = null;
if (projectRoleId != null) {
role = projectRoleDao.findById(projectRoleId);
if (role == null || !role.getProjectId().equals(projectId)) {
throw new InvalidParameterValueException("Invalid project role ID for the given project");
}
}
if (_invitationRequired) {
return inviteUserToProject(project, user, email, projectRole, role);
} else {
if (username == null) {
throw new InvalidParameterValueException("User information (ID) is required to add user to the project");
}
if (assignUserToProject(project, user.getId(), user.getAccountId(), projectRole,
Optional.ofNullable(role).map(ProjectRole::getId).orElse(null)) != null) {
return true;
}
s_logger.warn("Failed to add user to project with id: " + projectId);
return false;
}
}
@Override
public Project findByNameAndDomainId(String name, long domainId) {
return _projectDao.findByNameAndDomain(name, domainId);
@ -429,7 +557,12 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
_accountMgr.checkAccess(caller, _domainDao.findById(owner.getDomainId()));
return true;
}
User user = CallContext.current().getCallingUser();
ProjectVO project = _projectDao.findByProjectAccountId(accountId);
ProjectAccount userProjectAccount = _projectAccountDao.findByProjectIdUserId(project.getId(), user.getAccountId(), user.getId());
if (userProjectAccount != null) {
return _projectAccountDao.canUserAccessProjectAccount(user.getAccountId(), user.getId(), accountId);
}
return _projectAccountDao.canAccessProjectAccount(caller.getId(), accountId);
}
@ -443,9 +576,29 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
_accountMgr.checkAccess(caller, _domainDao.findById(owner.getDomainId()));
return true;
}
User user = CallContext.current().getCallingUser();
Project project = CallContext.current().getProject();
if (project != null) {
ProjectAccountVO projectUser = _projectAccountDao.findByProjectIdUserId(project.getId(), caller.getAccountId(), user.getId());
if (projectUser != null) {
return _projectAccountDao.canUserModifyProject(project.getId(), caller.getAccountId(), user.getId());
}
}
return _projectAccountDao.canModifyProjectAccount(caller.getId(), accountId);
}
private void updateProjectAccount(ProjectAccountVO futureOwner, Role newAccRole, Long accountId) throws ResourceAllocationException {
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(accountId), ResourceType.project);
futureOwner.setAccountRole(newAccRole);
_projectAccountDao.update(futureOwner.getId(), futureOwner);
if (newAccRole != null && Role.Admin == newAccRole) {
_resourceLimitMgr.incrementResourceCount(accountId, ResourceType.project);
} else {
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.project);
}
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_UPDATE, eventDescription = "updating project", async = true)
@ -465,47 +618,47 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<ResourceAllocationException>() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) throws ResourceAllocationException {
if (displayText != null) {
project.setDisplayText(displayText);
_projectDao.update(projectId, project);
}
if (newOwnerName != null) {
//check that the new owner exists
Account futureOwnerAccount = _accountMgr.getActiveAccountByName(newOwnerName, project.getDomainId());
if (futureOwnerAccount == null) {
throw new InvalidParameterValueException("Unable to find account name=" + newOwnerName + " in domain id=" + project.getDomainId());
}
Account currentOwnerAccount = getProjectOwner(projectId);
if (currentOwnerAccount == null) {
s_logger.error("Unable to find the current owner for the project id=" + projectId);
throw new InvalidParameterValueException("Unable to find the current owner for the project id=" + projectId);
}
if (currentOwnerAccount.getId() != futureOwnerAccount.getId()) {
ProjectAccountVO futureOwner = _projectAccountDao.findByProjectIdAccountId(projectId, futureOwnerAccount.getAccountId());
if (futureOwner == null) {
throw new InvalidParameterValueException("Account " + newOwnerName +
" doesn't belong to the project. Add it to the project first and then change the project's ownership");
if (displayText != null) {
project.setDisplayText(displayText);
_projectDao.update(projectId, project);
}
//do resource limit check
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(futureOwnerAccount.getId()), ResourceType.project);
if (newOwnerName != null) {
//check that the new owner exists
Account futureOwnerAccount = _accountMgr.getActiveAccountByName(newOwnerName, project.getDomainId());
if (futureOwnerAccount == null) {
throw new InvalidParameterValueException("Unable to find account name=" + newOwnerName + " in domain id=" + project.getDomainId());
}
Account currentOwnerAccount = getProjectOwner(projectId);
if (currentOwnerAccount == null) {
s_logger.error("Unable to find the current owner for the project id=" + projectId);
throw new InvalidParameterValueException("Unable to find the current owner for the project id=" + projectId);
}
if (currentOwnerAccount.getId() != futureOwnerAccount.getId()) {
ProjectAccountVO futureOwner = _projectAccountDao.findByProjectIdAccountId(projectId, futureOwnerAccount.getAccountId());
if (futureOwner == null) {
throw new InvalidParameterValueException("Account " + newOwnerName +
" doesn't belong to the project. Add it to the project first and then change the project's ownership");
}
//unset the role for the old owner
ProjectAccountVO currentOwner = _projectAccountDao.findByProjectIdAccountId(projectId, currentOwnerAccount.getId());
currentOwner.setAccountRole(Role.Regular);
_projectAccountDao.update(currentOwner.getId(), currentOwner);
_resourceLimitMgr.decrementResourceCount(currentOwnerAccount.getId(), ResourceType.project);
//do resource limit check
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(futureOwnerAccount.getId()), ResourceType.project);
//set new owner
futureOwner.setAccountRole(Role.Admin);
_projectAccountDao.update(futureOwner.getId(), futureOwner);
_resourceLimitMgr.incrementResourceCount(futureOwnerAccount.getId(), ResourceType.project);
//unset the role for the old owner
ProjectAccountVO currentOwner = _projectAccountDao.findByProjectIdAccountId(projectId, currentOwnerAccount.getId());
currentOwner.setAccountRole(Role.Regular);
_projectAccountDao.update(currentOwner.getId(), currentOwner);
_resourceLimitMgr.decrementResourceCount(currentOwnerAccount.getId(), ResourceType.project);
} else {
s_logger.trace("Future owner " + newOwnerName + "is already the owner of the project id=" + projectId);
}
}
//set new owner
futureOwner.setAccountRole(Role.Admin);
_projectAccountDao.update(futureOwner.getId(), futureOwner);
_resourceLimitMgr.incrementResourceCount(futureOwnerAccount.getId(), ResourceType.project);
} else {
s_logger.trace("Future owner " + newOwnerName + "is already the owner of the project id=" + projectId);
}
}
}
});
@ -513,9 +666,76 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_UPDATE, eventDescription = "updating project", async = true)
public Project updateProject(final long projectId, final String displayText, final String newOwnerName, Long userId,
Role newRole) throws ResourceAllocationException {
Account caller = CallContext.current().getCallingAccount();
//check that the project exists
final ProjectVO project = getProject(projectId);
if (project == null) {
throw new InvalidParameterValueException("Unable to find the project id=" + projectId);
}
CallContext.current().setProject(project);
//verify permissions
_accountMgr.checkAccess(caller, AccessType.ModifyProject, true, _accountMgr.getAccount(project.getProjectAccountId()));
List<? extends ProjectAccount> projectOwners = _projectAccountDao.getProjectOwners(projectId);
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<ResourceAllocationException>() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) throws ResourceAllocationException {
if (displayText != null) {
project.setDisplayText(displayText);
_projectDao.update(projectId, project);
}
if (newOwnerName != null) {
//check that the new owner exists
Account updatedAcc = _accountMgr.getActiveAccountByName(newOwnerName, project.getDomainId());
if (updatedAcc == null) {
throw new InvalidParameterValueException("Unable to find account name=" + newOwnerName + " in domain id=" + project.getDomainId());
}
ProjectAccountVO newProjectAcc = _projectAccountDao.findByProjectIdAccountId(projectId, updatedAcc.getAccountId());
if (newProjectAcc == null) {
throw new InvalidParameterValueException("Account " + newOwnerName +
" doesn't belong to the project. Add it to the project first and then change the project's ownership");
}
if (isTheOnlyProjectOwner(projectId, newProjectAcc, caller) && newRole != Role.Admin) {
throw new InvalidParameterValueException("Cannot demote the only admin of the project");
}
updateProjectAccount(newProjectAcc, newRole, updatedAcc.getId());
} else if (userId != null) {
User user = validateUser(userId, project.getDomainId());
if (user == null) {
throw new InvalidParameterValueException("Unable to find user= " + user.getUsername() + " in domain id = " + project.getDomainId());
}
ProjectAccountVO newProjectUser = _projectAccountDao.findByProjectIdUserId(projectId, user.getAccountId(), userId);
if (newProjectUser == null) {
throw new InvalidParameterValueException("User " + userId +
" doesn't belong to the project. Add it to the project first and then change the project's ownership");
}
if (projectOwners.size() == 1 && newProjectUser.getUserId().equals(projectOwners.get(0).getUserId())
&& newRole != Role.Admin ) {
throw new InvalidParameterValueException("Cannot demote the only admin of the project");
}
updateProjectAccount(newProjectUser, newRole, user.getAccountId());
}
}
});
return _projectDao.findById(projectId);
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_ACCOUNT_ADD, eventDescription = "adding account to project", async = true)
public boolean addAccountToProject(long projectId, String accountName, String email) {
public boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType) {
Account caller = CallContext.current().getCallingAccount();
//check that the project exists
@ -550,6 +770,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
throw ex;
}
CallContext.current().setProject(project);
//verify permissions - only project owner can assign
_accountMgr.checkAccess(caller, AccessType.ModifyProject, true, _accountMgr.getAccount(project.getProjectAccountId()));
@ -561,13 +782,26 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
}
}
if (projectRoleId != null && projectRoleId < 1L) {
throw new InvalidParameterValueException("Invalid project role id provided");
}
ProjectRole projectRole = null;
if (projectRoleId != null) {
projectRole = projectRoleDao.findById(projectRoleId);
if (projectRole == null || projectRole.getProjectId() != projectId) {
throw new InvalidParameterValueException("Invalid project role ID for the given project");
}
}
if (_invitationRequired) {
return inviteAccountToProject(project, account, email);
return inviteAccountToProject(project, account, email, projectRoleType, projectRole);
} else {
if (account == null) {
throw new InvalidParameterValueException("Account information is required for assigning account to the project");
}
if (assignAccountToProject(project, account.getId(), ProjectAccount.Role.Regular) != null) {
if (assignAccountToProject(project, account.getId(), projectRoleType, null,
Optional.ofNullable(projectRole).map(ProjectRole::getId).orElse(null)) != null) {
return true;
} else {
s_logger.warn("Failed to add account " + accountName + " to project id=" + projectId);
@ -576,9 +810,10 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
}
}
private boolean inviteAccountToProject(Project project, Account account, String email) {
private boolean inviteAccountToProject(Project project, Account account, String email, Role role,ProjectRole projectRole) {
if (account != null) {
if (createAccountInvitation(project, account.getId()) != null) {
if (createAccountInvitation(project, account.getId(), null, role,
Optional.ofNullable(projectRole).map(ProjectRole::getId).orElse(null)) != null) {
return true;
} else {
s_logger.warn("Failed to generate invitation for account " + account.getAccountName() + " to project id=" + project);
@ -589,7 +824,8 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
if (email != null) {
//generate the token
String token = generateToken(10);
if (generateTokenBasedInvitation(project, email, token) != null) {
if (generateTokenBasedInvitation(project, null, email, token, role,
Optional.ofNullable(projectRole).map(ProjectRole::getId).orElse(null)) != null) {
return true;
} else {
s_logger.warn("Failed to generate invitation for email " + email + " to project id=" + project);
@ -600,6 +836,37 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
return false;
}
private boolean inviteUserToProject(Project project, User user, String email, Role role, ProjectRole projectRole) {
if (email == null) {
if (createAccountInvitation(project, user.getAccountId(), user.getId(), role,
Optional.ofNullable(projectRole).map(ProjectRole::getId).orElse(null)) != null) {
return true;
} else {
s_logger.warn("Failed to generate invitation for account " + user.getUsername() + " to project id=" + project);
return false;
}
} else {
//generate the token
String token = generateToken(10);
if (generateTokenBasedInvitation(project, user.getId(), email, token, role,
Optional.ofNullable(projectRole).map(ProjectRole::getId).orElse(null)) != null) {
return true;
} else {
s_logger.warn("Failed to generate invitation for email " + email + " to project id=" + project);
return false;
}
}
}
private boolean isTheOnlyProjectOwner(Long projectId, ProjectAccount projectAccount, Account caller) {
List<? extends ProjectAccount> projectOwners = _projectAccountDao.getProjectOwners(projectId);
if ((projectOwners.size() == 1 && projectOwners.get(0).getAccountId() == projectAccount.getAccountId()
&& projectAccount.getAccountRole() == Role.Admin )) {
return true;
}
return false;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_ACCOUNT_REMOVE, eventDescription = "removing account from project", async = true)
public boolean deleteAccountFromProject(long projectId, String accountName) {
@ -628,11 +895,12 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
throw ex;
}
CallContext.current().setProject(project);
//verify permissions
_accountMgr.checkAccess(caller, AccessType.ModifyProject, true, _accountMgr.getAccount(project.getProjectAccountId()));
//Check if the account exists in the project
ProjectAccount projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, account.getId());
ProjectAccount projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, account.getId());
if (projectAccount == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Account " + accountName + " is not assigned to the project with specified id");
// Use the projectVO object and not the projectAccount object to inject the projectId.
@ -641,7 +909,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
}
//can't remove the owner of the project
if (projectAccount.getAccountRole() == Role.Admin) {
if (isTheOnlyProjectOwner(projectId, projectAccount, caller)) {
InvalidParameterValueException ex =
new InvalidParameterValueException("Unable to delete account " + accountName +
" from the project with specified id as the account is the owner of the project");
@ -652,18 +920,104 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
return deleteAccountFromProject(projectId, account.getId());
}
public ProjectInvitation createAccountInvitation(Project project, Long accountId) {
if (activeInviteExists(project, accountId, null)) {
throw new InvalidParameterValueException("There is already a pending invitation for account id=" + accountId + " to the project id=" + project);
@Override
public boolean deleteUserFromProject(long projectId, long userId) {
Account caller = CallContext.current().getCallingAccount();
//check that the project exists
Project project = getProject(projectId);
if (project == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find project with specified id");
ex.addProxyObject(String.valueOf(projectId), "projectId");
throw ex;
}
ProjectInvitation invitation = _projectInvitationDao.persist(new ProjectInvitationVO(project.getId(), accountId, project.getDomainId(), null, null));
User user = userDao.findById(userId);
if (user == null) {
throw new InvalidParameterValueException("Invalid userId provided");
}
Account userAcc = _accountDao.findActiveAccountById(user.getAccountId(), project.getDomainId());
if (userAcc == null) {
InvalidParameterValueException ex =
new InvalidParameterValueException("Unable to find user "+ user.getUsername() + " in domain id=" + project.getDomainId());
DomainVO domain = ApiDBUtils.findDomainById(project.getDomainId());
String domainUuid = String.valueOf(project.getDomainId());
if (domain != null) {
domainUuid = domain.getUuid();
}
ex.addProxyObject(domainUuid, "domainId");
throw ex;
}
return invitation;
CallContext.current().setProject(project);
//verify permissions
_accountMgr.checkAccess(caller, AccessType.ModifyProject, true, _accountMgr.getAccount(project.getProjectAccountId()));
//Check if the user exists in the project
ProjectAccount projectUser = _projectAccountDao.findByProjectIdUserId(projectId, user.getAccountId(), user.getId());
if (projectUser == null) {
deletePendingInvite(projectId, user);
InvalidParameterValueException ex = new InvalidParameterValueException("User " + user.getUsername() + " is not assigned to the project with specified id");
// Use the projectVO object and not the projectAccount object to inject the projectId.
ex.addProxyObject(project.getUuid(), "projectId");
throw ex;
}
return deleteUserFromProject(projectId, user);
}
private void deletePendingInvite(Long projectId, User user) {
ProjectInvitation invite = _projectInvitationDao.findByUserIdProjectId(user.getId(), user.getAccountId(), projectId);
if (invite != null) {
boolean success = _projectInvitationDao.remove(invite.getId());
if (success){
s_logger.info("Successfully deleted invite pending for the user : "+user.getUsername());
} else {
s_logger.info("Failed to delete project invite for user: "+ user.getUsername());
}
}
}
@DB
public boolean activeInviteExists(final Project project, final Long accountId, final String email) {
private boolean deleteUserFromProject(Long projectId, User user) {
return Transaction.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
boolean success = true;
ProjectAccountVO projectAccount = _projectAccountDao.findByProjectIdUserId(projectId, user.getAccountId(), user.getId());
success = _projectAccountDao.remove(projectAccount.getId());
if (success) {
s_logger.debug("Removed user " + user.getId() + " from project. Removing any invite sent to the user");
ProjectInvitation invite = _projectInvitationDao.findByUserIdProjectId(user.getId(), user.getAccountId(), projectId);
if (invite != null) {
success = success && _projectInvitationDao.remove(invite.getId());
}
}
return success;
}
});
}
public ProjectInvitation createAccountInvitation(Project project, Long accountId, Long userId, Role role, Long projectRoleId) {
if (activeInviteExists(project, accountId, userId, null)) {
throw new InvalidParameterValueException("There is already a pending invitation for account id=" + accountId + " to the project id=" + project);
}
ProjectInvitationVO invitationVO = new ProjectInvitationVO(project.getId(), accountId, project.getDomainId(), null, null);
if (userId != null) {
invitationVO.setForUserId(userId);
}
if (role != null) {
invitationVO.setAccountRole(role);
}
if (projectRoleId != null) {
invitationVO.setProjectRoleId(projectRoleId);
}
return _projectInvitationDao.persist(invitationVO);
}
@DB
public boolean activeInviteExists(final Project project, final Long accountId, Long userId, final String email) {
return Transaction.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
@ -671,6 +1025,8 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
ProjectInvitationVO invite = null;
if (accountId != null) {
invite = _projectInvitationDao.findByAccountIdProjectId(accountId, project.getId());
} else if (userId != null) {
invite = _projectInvitationDao.findByUserIdProjectId(userId, accountId, project.getId());
} else if (email != null) {
invite = _projectInvitationDao.findByEmailAndProjectId(email, project.getId());
}
@ -686,6 +1042,8 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
//remove the expired/declined invitation
if (accountId != null) {
s_logger.debug("Removing invitation in state " + invite.getState() + " for account id=" + accountId + " to project " + project);
} else if (userId != null) {
s_logger.debug("Removing invitation in state " + invite.getState() + " for user id=" + userId + " to project " + project);
} else if (email != null) {
s_logger.debug("Removing invitation in state " + invite.getState() + " for email " + email + " to project " + project);
}
@ -699,13 +1057,24 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
});
}
public ProjectInvitation generateTokenBasedInvitation(Project project, String email, String token) {
public ProjectInvitation generateTokenBasedInvitation(Project project, Long userId, String email, String token, Role role, Long projectRoleId) {
//verify if the invitation was already generated
if (activeInviteExists(project, null, email)) {
if (activeInviteExists(project, null, null, email)) {
throw new InvalidParameterValueException("There is already a pending invitation for email " + email + " to the project id=" + project);
}
ProjectInvitation projectInvitation = _projectInvitationDao.persist(new ProjectInvitationVO(project.getId(), null, project.getDomainId(), email, token));
ProjectInvitationVO projectInvitationVO = new ProjectInvitationVO(project.getId(), null, project.getDomainId(), email, token);
if (userId != null) {
projectInvitationVO.setForUserId(userId);
}
if (role != null) {
projectInvitationVO.setAccountRole(role);
}
if (projectRoleId != null) {
projectInvitationVO.setProjectRoleId(projectRoleId);
}
ProjectInvitation projectInvitation = _projectInvitationDao.persist(projectInvitationVO);
try {
_emailInvite.sendInvite(token, email, project.getId());
} catch (Exception ex) {
@ -726,23 +1095,19 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_INVITATION_UPDATE, eventDescription = "updating project invitation", async = true)
public boolean updateInvitation(final long projectId, String accountName, String token, final boolean accept) {
public boolean updateInvitation(final long projectId, String accountName, Long userId, String token, final boolean accept) {
Account caller = CallContext.current().getCallingAccount();
Long accountId = null;
User user = null;
boolean result = true;
//if accountname and token are null, default accountname to caller's account name
if (accountName == null && token == null) {
accountName = caller.getAccountName();
}
//check that the project exists
final Project project = getProject(projectId);
if (project == null) {
throw new InvalidParameterValueException("Unable to find the project id=" + projectId);
}
CallContext.current().setProject(project);
if (accountName != null) {
//check that account-to-remove exists
Account account = _accountMgr.getActiveAccountByName(accountName, project.getDomainId());
@ -752,16 +1117,30 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
//verify permissions
_accountMgr.checkAccess(caller, null, true, account);
accountId = account.getId();
} else if (userId != null) {
user = userDao.findById(userId);
if (user == null) {
throw new InvalidParameterValueException("Invalid user ID provided. Please provide a valid user ID or " +
"account name whose invitation is to be updated");
}
Account userAccount = _accountDao.findById(user.getAccountId());
if (userAccount.getDomainId() != project.getDomainId()) {
throw new InvalidParameterValueException("Unable to find user =" + userId + " in domain id=" + project.getDomainId());
}
} else {
accountId = caller.getId();
user = CallContext.current().getCallingUser();
}
//check that invitation exists
ProjectInvitationVO invite = null;
if (token == null) {
invite = _projectInvitationDao.findByAccountIdProjectId(accountId, projectId, ProjectInvitation.State.Pending);
if (accountName != null) {
invite = _projectInvitationDao.findByAccountIdProjectId(accountId, projectId, ProjectInvitation.State.Pending);
} else {
invite = _projectInvitationDao.findByUserIdProjectId(user.getId(), user.getAccountId(), projectId, ProjectInvitation.State.Pending);
}
} else {
invite = _projectInvitationDao.findPendingByTokenAndProjectId(token, projectId, ProjectInvitation.State.Pending);
}
@ -771,10 +1150,11 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
expireInvitation(invite);
throw new InvalidParameterValueException("Invitation is expired for account id=" + accountName + " to the project id=" + projectId);
} else {
final ProjectInvitationVO inviteFinal = invite;
final Long accountIdFinal = accountId;
final String accountNameFinal = accountName;
final User finalUser = user;
ProjectInvitationVO finalInvite = invite;
result = Transaction.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
@ -783,25 +1163,32 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
ProjectInvitation.State newState = accept ? ProjectInvitation.State.Completed : ProjectInvitation.State.Declined;
//update invitation
s_logger.debug("Marking invitation " + inviteFinal + " with state " + newState);
inviteFinal.setState(newState);
result = _projectInvitationDao.update(inviteFinal.getId(), inviteFinal);
s_logger.debug("Marking invitation " + inviteFinal + " with state " + newState);
inviteFinal.setState(newState);
result = _projectInvitationDao.update(inviteFinal.getId(), inviteFinal);
if (result && accept) {
//check if account already exists for the project (was added before invitation got accepted)
ProjectAccount projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, accountIdFinal);
if (projectAccount != null) {
s_logger.debug("Account " + accountNameFinal + " already added to the project id=" + projectId);
if (finalInvite.getForUserId() == -1) {
ProjectAccount projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, accountIdFinal);
if (projectAccount != null) {
s_logger.debug("Account " + accountNameFinal + " already added to the project id=" + projectId);
} else {
assignAccountToProject(project, accountIdFinal, finalInvite.getAccountRole(), null, finalInvite.getProjectRoleId());
}
} else {
assignAccountToProject(project, accountIdFinal, ProjectAccount.Role.Regular);
ProjectAccount projectAccount = _projectAccountDao.findByProjectIdUserId(projectId, finalUser.getAccountId(), finalUser.getId());
if (projectAccount != null) {
s_logger.debug("User " + finalUser.getId() + "has already been added to the project id=" + projectId);
} else {
assignUserToProject(project, finalInvite.getForUserId(), finalUser.getAccountId(), finalInvite.getAccountRole(), finalInvite.getProjectRoleId());
}
}
} else {
s_logger.warn("Failed to update project invitation " + inviteFinal + " with state " + newState);
s_logger.warn("Failed to update project invitation " + inviteFinal + " with state " + newState);
}
return result;
}
});
return result;
}});
}
} else {
throw new InvalidParameterValueException("Unable to find invitation for account name=" + accountName + " to the project id=" + projectId);
@ -830,6 +1217,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
throw ex;
}
CallContext.current().setProject(project);
//verify permissions
_accountMgr.checkAccess(caller, AccessType.ModifyProject, true, _accountMgr.getAccount(project.getProjectAccountId()));
@ -871,6 +1259,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
throw ex;
}
CallContext.current().setProject(project);
_accountMgr.checkAccess(caller, AccessType.ModifyProject, true, _accountMgr.getAccount(project.getProjectAccountId()));
if (suspendProject(project)) {
@ -911,7 +1300,6 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
}
return sb.toString();
}
class EmailInvite {
private Session _smtpSession;
private final String _smtpHost;
@ -1012,6 +1400,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
//check that the project exists
Project project = getProject(invitation.getProjectId());
CallContext.current().setProject(project);
//check permissions - only project owner can remove the invitations
_accountMgr.checkAccess(caller, AccessType.ModifyProject, true, _accountMgr.getAccount(project.getProjectAccountId()));

View File

@ -288,7 +288,9 @@ import org.apache.cloudstack.api.command.admin.zone.ListZonesCmdByAdmin;
import org.apache.cloudstack.api.command.admin.zone.MarkDefaultZoneForAccountCmd;
import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd;
import org.apache.cloudstack.api.command.user.account.AddAccountToProjectCmd;
import org.apache.cloudstack.api.command.user.account.AddUserToProjectCmd;
import org.apache.cloudstack.api.command.user.account.DeleteAccountFromProjectCmd;
import org.apache.cloudstack.api.command.user.account.DeleteUserFromProjectCmd;
import org.apache.cloudstack.api.command.user.account.ListAccountsCmd;
import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
import org.apache.cloudstack.api.command.user.address.AssociateIPAddrCmd;
@ -696,6 +698,7 @@ import com.cloud.vm.ConsoleProxyVO;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.InstanceGroupVO;
import com.cloud.vm.SecondaryStorageVmVO;
import com.cloud.vm.UserVmDetailVO;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
@ -708,9 +711,8 @@ import com.cloud.vm.dao.ConsoleProxyDao;
import com.cloud.vm.dao.InstanceGroupDao;
import com.cloud.vm.dao.SecondaryStorageVmDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.UserVmDetailVO;
import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
public class ManagementServerImpl extends ManagerBase implements ManagementServer, Configurable {
public static final Logger s_logger = Logger.getLogger(ManagementServerImpl.class.getName());
@ -2808,7 +2810,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(MarkDefaultZoneForAccountCmd.class);
cmdList.add(UpdateZoneCmd.class);
cmdList.add(AddAccountToProjectCmd.class);
cmdList.add(AddUserToProjectCmd.class);
cmdList.add(DeleteAccountFromProjectCmd.class);
cmdList.add(DeleteUserFromProjectCmd.class);
cmdList.add(ListAccountsCmd.class);
cmdList.add(ListProjectAccountsCmd.class);
cmdList.add(AssociateIPAddrCmd.class);

View File

@ -37,7 +37,6 @@ import javax.crypto.spec.SecretKeySpec;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.QuerySelector;
import org.apache.cloudstack.acl.Role;
@ -521,6 +520,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (s_logger.isTraceEnabled()) {
s_logger.trace("No need to make permission check for System/RootAdmin account, returning true");
}
return;
}
@ -2034,7 +2034,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
return caller;
}
} else {
if ((accountName == null && domainId != null) || (accountName != null && domainId == null)) {
if (accountName != null && domainId == null) {
throw new InvalidParameterValueException("AccountName and domainId must be specified together");
}
// regular user can't create/list resources for other people

Some files were not shown because too many files have changed in this diff Show More