Implemented Project Invitations

This commit is contained in:
alena 2011-09-26 10:07:54 -07:00
parent d32241ec9c
commit ccd47c1b21
45 changed files with 1660 additions and 117 deletions

View File

@ -21,6 +21,7 @@
*/
package com.cloud.acl;
import com.cloud.acl.SecurityChecker.AccessType;
import com.cloud.dc.DataCenter;
import com.cloud.domain.Domain;
import com.cloud.exception.PermissionDeniedException;
@ -39,16 +40,18 @@ public interface SecurityChecker extends Adapter {
public enum AccessType {
ListEntry,
ModifyEntry,
ModifyProject
}
/**
* Checks if the account owns the object.
*
* @param caller account to check against.
* @param accessType TODO
* @param object object that the account is trying to access.
* @return true if access allowed. false if this adapter cannot authenticate ownership.
* @throws PermissionDeniedException if this adapter is suppose to authenticate ownership and the check failed.
*/
boolean checkAccess(Account caller, Domain domain) throws PermissionDeniedException;
boolean checkAccess(Account caller, Domain domain, AccessType accessType) throws PermissionDeniedException;
/**
* Checks if the user belongs to an account that owns the object.

View File

@ -262,5 +262,8 @@ public class ApiConstants {
public static final String MAX_GUESTS_LIMIT = "maxguestslimit";
public static final String PROJECT_ID = "projectid";
public static final String PROJECT = "project";
public static final String ROLE = "role";
public static final String USER = "user";
public static final String ACTIVE_ONLY = "activeonly";
}

View File

@ -44,6 +44,8 @@ import com.cloud.api.response.LoadBalancerResponse;
import com.cloud.api.response.NetworkOfferingResponse;
import com.cloud.api.response.NetworkResponse;
import com.cloud.api.response.PodResponse;
import com.cloud.api.response.ProjectAccountResponse;
import com.cloud.api.response.ProjectInvitationResponse;
import com.cloud.api.response.ProjectResponse;
import com.cloud.api.response.RemoteAccessVpnResponse;
import com.cloud.api.response.ResourceCountResponse;
@ -92,6 +94,8 @@ import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.org.Cluster;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectAccount;
import com.cloud.projects.ProjectInvitation;
import com.cloud.storage.Snapshot;
import com.cloud.storage.StoragePool;
import com.cloud.storage.Volume;
@ -221,5 +225,9 @@ public interface ResponseGenerator {
FirewallResponse createFirewallResponse(FirewallRule fwRule);
HypervisorCapabilitiesResponse createHypervisorCapabilitiesResponse(HypervisorCapabilities hpvCapabilities);
ProjectAccountResponse createProjectAccountResponse(ProjectAccount projectAccount);
ProjectInvitationResponse createProjectInvitationResponse(ProjectInvitation invite);
}

View File

@ -0,0 +1,89 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.api.commands;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseCmd;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.response.SuccessResponse;
import com.cloud.user.Account;
@Implementation(description="Adds acoount to a project", responseObject=SuccessResponse.class)
public class AddAccountToProjectCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(AddAccountToProjectCmd.class.getName());
private static final String s_name = "addaccounttoprojectresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.LONG, required=true, description="id of the project to add the account to")
private Long projectId;
@Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, required=true, description="name of the account to be added to the project")
private String accountName;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getAccountName() {
return accountName;
}
public Long getProjectId() {
return projectId;
}
public void setProjectId(Long projectId) {
this.projectId = projectId;
}
@Override
public String getCommandName() {
return s_name;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute(){
boolean result = _projectService.addAccountToProject(getProjectId(), getAccountName());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to add account to the project");
}
}
@Override
public long getEntityOwnerId() {
//TODO - return project entity ownerId
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
}

View File

@ -80,20 +80,7 @@ public class CreateProjectCmd extends BaseCmd {
@Override
public long getEntityOwnerId() {
Account account = UserContext.current().getCaller();
if ((account == null) || isAdmin(account.getType())) {
if ((domainId != null) && (accountName != null)) {
Account userAccount = _responseGenerator.findAccountByNameDomain(accountName, domainId);
if (userAccount != null) {
return userAccount.getId();
}
}
}
if (account != null) {
return account.getId();
}
//TODO - return project entity ownerId
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}

View File

@ -0,0 +1,87 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.api.commands;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseCmd;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.response.SuccessResponse;
import com.cloud.user.Account;
@Implementation(description="Deletes account from the project", responseObject=SuccessResponse.class)
public class DeleteAccountFromProjectCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(DeleteProjectCmd.class.getName());
private static final String s_name = "deleteaccountfromprojectresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.LONG, required=true, description="id of the project to remove the account from")
private Long projectId;
@Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, required=true, description="name of the account to be removed from the project")
private String accountName;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
public Long getProjectId() {
return projectId;
}
public String getAccountName() {
return accountName;
}
@Override
public void execute(){
boolean result = _projectService.deleteAccountFromProject(projectId, accountName);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to delete account from the project");
}
}
@Override
public long getEntityOwnerId() {
//TODO - return project entity ownerId
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
}

View File

@ -28,8 +28,7 @@ import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.response.SuccessResponse;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.projects.Project;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
@Implementation(description="Deletes a project", responseObject=SuccessResponse.class)
@ -87,11 +86,7 @@ public class DeleteProjectCmd extends BaseAsyncCmd {
@Override
public long getEntityOwnerId() {
Project project = _projectService.getProject(id);
if (project == null) {
throw new InvalidParameterValueException("Project id=" + id + " doesn't exist");
} else {
return _projectService.getProject(id).getProjectAccountId();
}
//TODO - return project entity ownerId
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
}

View File

@ -0,0 +1,82 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.api.commands;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseCmd;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.response.SuccessResponse;
import com.cloud.user.Account;
@Implementation(description="Makes account to join the project", responseObject=SuccessResponse.class)
public class JoinProjectCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(JoinProjectCmd.class.getName());
private static final String s_name = "joinprojectresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.PROJECT_ID, required=true, type=CommandType.LONG, description="list by project id")
private Long projectId;
@Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="list invitations for specified account; this parameter has to be specified with domainId")
private String accountName;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getProjectId() {
return projectId;
}
public String getAccountName() {
return accountName;
}
@Override
public String getCommandName() {
return s_name;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
//TODO - return project entity ownerId
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
@Override
public void execute(){
boolean result = _projectService.joinProject(projectId, accountName);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to join the project");
}
}
}

View File

@ -0,0 +1,93 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.api.commands;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseListCmd;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.response.ListResponse;
import com.cloud.api.response.ProjectAccountResponse;
import com.cloud.api.response.ProjectResponse;
import com.cloud.projects.ProjectAccount;
import com.cloud.user.Account;
@Implementation(description="Lists project's accounts", responseObject=ProjectResponse.class)
public class ListProjectAccountsCmd extends BaseListCmd {
public static final Logger s_logger = Logger.getLogger(ListProjectAccountsCmd.class.getName());
private static final String s_name = "listprojectaccountsresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.LONG, required=true, description="id of the project")
private Long projectId;
@Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="list accounts of the project by account name")
private String accountName;
@Parameter(name=ApiConstants.ROLE, type=CommandType.STRING, description="list accounts of the project by role")
private String role;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getAccountName() {
return accountName;
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
//TODO - return project entity ownerId
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute(){
List<? extends ProjectAccount> projectAccounts = _projectService.listProjectAccounts(projectId, accountName, role, this.getStartIndex(), this.getPageSizeVal());
ListResponse<ProjectAccountResponse> response = new ListResponse<ProjectAccountResponse>();
List<ProjectAccountResponse> projectResponses = new ArrayList<ProjectAccountResponse>();
for (ProjectAccount projectAccount : projectAccounts) {
ProjectAccountResponse projectAccountResponse = _responseGenerator.createProjectAccountResponse(projectAccount);
projectResponses.add(projectAccountResponse);
}
response.setResponses(projectResponses);
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
}

View File

@ -0,0 +1,101 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.api.commands;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseListCmd;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.response.ListResponse;
import com.cloud.api.response.ProjectInvitationResponse;
import com.cloud.projects.ProjectInvitation;
@Implementation(description="Lists projects and provides detailed information for listed projects", responseObject=ProjectInvitationResponse.class)
public class ListProjectInvitationsCmd extends BaseListCmd {
public static final Logger s_logger = Logger.getLogger(ListProjectInvitationsCmd.class.getName());
private static final String s_name = "listprojectinvitationsresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.LONG, description="list by project id")
private Long projectId;
@Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="list invitations for specified account; this parameter has to be specified with domainId")
private String accountName;
@Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="list all invitations in specified domain")
private Long domainId;
@Parameter(name=ApiConstants.ACTIVE_ONLY, type=CommandType.BOOLEAN, description="if true, list only active invitations - having Pending state and ones that are not timed out yet")
private boolean activeOnly;
@Parameter(name=ApiConstants.STATE, type=CommandType.STRING, description="list invitations by state")
private String state;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getProjectId() {
return projectId;
}
public String getAccountName() {
return accountName;
}
public Long getDomainId() {
return domainId;
}
public boolean isActiveOnly() {
return activeOnly;
}
public String getState() {
return state;
}
@Override
public String getCommandName() {
return s_name;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute(){
List<? extends ProjectInvitation> invites = _projectService.listProjectInvitations(projectId, accountName, domainId, state, activeOnly, this.getStartIndex(), this.getPageSizeVal());
ListResponse<ProjectInvitationResponse> response = new ListResponse<ProjectInvitationResponse>();
List<ProjectInvitationResponse> projectInvitationResponses = new ArrayList<ProjectInvitationResponse>();
for (ProjectInvitation invite : invites) {
ProjectInvitationResponse projectResponse = _responseGenerator.createProjectInvitationResponse(invite);
projectInvitationResponses.add(projectResponse);
}
response.setResponses(projectInvitationResponses);
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
}

View File

@ -0,0 +1,97 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.api.commands;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseCmd;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.response.ProjectResponse;
import com.cloud.projects.Project;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
@Implementation(description="Updates a project", responseObject=ProjectResponse.class)
public class UpdateProjectCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(CreateProjectCmd.class.getName());
private static final String s_name = "updateprojectresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.ID, type=CommandType.LONG, required=true, description="id of the project to be modified")
private Long id;
@Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="new account who will own the project, should be specified with domainId")
private String accountName;
@Parameter(name=ApiConstants.DISPLAY_TEXT, type=CommandType.STRING, description="display text of the project")
private String displayText;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getAccountName() {
return accountName;
}
public Long getId() {
return id;
}
public String getDisplayText() {
return displayText;
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
//TODO - return project entity ownerId
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute(){
UserContext.current().setEventDetails("Project id: "+ getId());
Project project = _projectService.updateProject(getId(), getDisplayText(), getAccountName());
if (project != null) {
ProjectResponse response = _responseGenerator.createProjectResponse(project);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to update a project");
}
}
}

View File

@ -0,0 +1,90 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.api.response;
import java.util.List;
import com.cloud.api.ApiConstants;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@SuppressWarnings("unused")
public class ProjectAccountResponse extends BaseResponse implements ControlledEntityResponse {
@SerializedName(ApiConstants.PROJECT_ID) @Param(description="project id")
private Long projectId;
@SerializedName(ApiConstants.PROJECT) @Param(description="project name")
private String projectName;
@SerializedName(ApiConstants.ACCOUNT_ID) @Param(description="the id of the account")
private Long id;
@SerializedName(ApiConstants.ACCOUNT) @Param(description="the name of the account")
private String accountName;
@SerializedName(ApiConstants.ACCOUNT_TYPE) @Param(description="account type (admin, domain-admin, user)")
private Short accountType;
@SerializedName(ApiConstants.ROLE) @Param(description="account role in the project (regular,owner)")
private String role;
@SerializedName(ApiConstants.DOMAIN_ID) @Param(description="id of the Domain the account belongs too")
private Long domainId;
@SerializedName(ApiConstants.DOMAIN) @Param(description="name of the Domain the account belongs too")
private String domainName;
@SerializedName(ApiConstants.USER) @Param(description="the list of users associated with account", responseObject = UserResponse.class)
private List<UserResponse> users;
public void setProjectId(Long projectId) {
this.projectId = projectId;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public void setId(Long id) {
this.id = id;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public void setAccountType(Short accountType) {
this.accountType = accountType;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public void setDomainName(String domainName) {
this.domainName = domainName;
}
public void setUsers(List<UserResponse> users) {
this.users = users;
}
public void setRole(String role) {
this.role = role;
}
}

View File

@ -0,0 +1,52 @@
package com.cloud.api.response;
import com.cloud.api.ApiConstants;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@SuppressWarnings("unused")
public class ProjectInvitationResponse extends BaseResponse implements ControlledEntityResponse{
@SerializedName(ApiConstants.PROJECT_ID) @Param(description="the id of the project")
private Long projectId;
@SerializedName(ApiConstants.PROJECT) @Param(description="the name of the project")
private String projectName;
@SerializedName(ApiConstants.DOMAIN_ID) @Param(description="the domain id the project belongs to")
private Long domainId;
@SerializedName(ApiConstants.DOMAIN) @Param(description="the domain name where the project belongs to")
private String domain;
@SerializedName(ApiConstants.ACCOUNT) @Param(description="the account name of the project's owner")
private String accountName;
@SerializedName(ApiConstants.STATE) @Param(description="the invitation state")
private String invitationState;
public void setProjectId(Long projectId) {
this.projectId = projectId;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public void setDomainName(String domain) {
this.domain = domain;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public void setInvitationState(String invitationState) {
this.invitationState = invitationState;
}
}

View File

@ -25,13 +25,13 @@ import com.google.gson.annotations.SerializedName;
@SuppressWarnings("unused")
public class ProjectResponse extends BaseResponse{
@SerializedName("id") @Param(description="the id of the project")
@SerializedName(ApiConstants.ID) @Param(description="the id of the project")
private Long id;
@SerializedName("name") @Param(description="the name of the project")
@SerializedName(ApiConstants.NAME) @Param(description="the name of the project")
private String name;
@SerializedName("displaytext") @Param(description="the displaytext of the project")
@SerializedName(ApiConstants.DISPLAY_TEXT) @Param(description="the displaytext of the project")
private String displaytext;
@SerializedName(ApiConstants.DOMAIN_ID) @Param(description="the domain id the project belongs to")

View File

@ -9,8 +9,6 @@ public interface ProjectAccount {
long getProjectId();
Role getAccountRole();
long getId();
long getProjectAccountId();

View File

@ -0,0 +1,24 @@
package com.cloud.projects;
import java.util.Date;
public interface ProjectInvitation {
public enum State {Pending, Completed, Expired}
long getId();
long getProjectId();
Long getAccountId();
String getToken();
String getEmail();
Date getCreated();
State getState();
Long getDomainId();
}

View File

@ -49,4 +49,16 @@ public interface ProjectService {
Project findByProjectAccountId(long projectAccountId);
Project findByNameAndDomainId(String name, long domainId);
Project updateProject(long id, String displayText, String newOwnerName);
boolean addAccountToProject(long projectId, String accountName);
boolean deleteAccountFromProject(long projectId, String accountName);
List<? extends ProjectAccount> listProjectAccounts(long projectId, String accountName, String role, Long startIndex, Long pageSizeVal);
List<? extends ProjectInvitation> listProjectInvitations(Long projectId, String accountName, Long domainId, String state, boolean activeOnly, Long startIndex, Long pageSizeVal);
boolean joinProject(long projectId, String accountName);
}

View File

@ -267,7 +267,14 @@ listSSHKeyPairs=com.cloud.api.commands.ListSSHKeyPairsCmd;15
#### Projects commands
createProject=com.cloud.api.commands.CreateProjectCmd;15
deleteProject=com.cloud.api.commands.DeleteProjectCmd;15
updateProject=com.cloud.api.commands.UpdateProjectCmd;15
listProjects=com.cloud.api.commands.ListProjectsCmd;15
addAccountToProject=com.cloud.api.commands.AddAccountToProjectCmd;15
deleteAccountFromProject=com.cloud.api.commands.DeleteAccountFromProjectCmd;15
listProjectAccounts=com.cloud.api.commands.ListProjectAccountsCmd;15
listProjectInvitations=com.cloud.api.commands.ListProjectInvitationsCmd;15
joinProject=com.cloud.api.commands.JoinProjectCmd;15
####
createFirewallRule=com.cloud.api.commands.CreateFirewallRuleCmd;15

View File

@ -29,6 +29,7 @@ import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectManager;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.storage.LaunchPermissionVO;
import com.cloud.storage.dao.LaunchPermissionDao;
import com.cloud.template.VirtualMachineTemplate;
@ -45,29 +46,35 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
@Inject AccountDao _accountDao;
@Inject LaunchPermissionDao _launchPermissionDao;
@Inject ProjectManager _projectMgr;
@Inject ProjectAccountDao _projecAccountDao;
protected DomainChecker() {
super();
}
@Override
public boolean checkAccess(Account caller, Domain domain) throws PermissionDeniedException {
public boolean checkAccess(Account caller, Domain domain, AccessType accessType) throws PermissionDeniedException {
if (caller.getState() != Account.State.enabled) {
throw new PermissionDeniedException(caller + " is disabled.");
}
long domainId = domain.getId();
if (domain.getType() == Domain.Type.Project) {
if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) {
if (!_projectMgr.canAccessDomain(caller, domainId)){
if (accessType != null && accessType == AccessType.ModifyProject) {
if (!_projectMgr.canModifyProjectDomain(caller, domainId)) {
throw new PermissionDeniedException(caller + " does not have permission to operate within " + domain);
}
} else if (!_projectMgr.canAccessDomain(caller, domainId)){
throw new PermissionDeniedException(caller + " does not have permission to operate within " + domain);
}
return true;
} else {
//need to check the domain the project belongs to
Project project = _projectMgr.findByProjectDomainId(domainId);
domainId = project.getProjectDomainId();
}
//need to check the domain the project belongs to
Project project = _projectMgr.findByProjectDomainId(domainId);
domainId = project.getDomainId();
}
if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) {
@ -87,7 +94,7 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
throw new PermissionDeniedException(user + " is no longer active.");
}
Account account = _accountDao.findById(user.getAccountId());
return checkAccess(account, domain);
return checkAccess(account, domain, null);
}
@Override
@ -123,7 +130,12 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
Account account = _accountDao.findById(entity.getAccountId());
if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
if (!_projectMgr.canAccessAccount(caller, account.getId())){
//only project owner can delete/modify the project
if (accessType != null && accessType == AccessType.ModifyProject) {
if (!_projectMgr.canModifyProjectAccount(caller, account.getId())) {
throw new PermissionDeniedException(caller + " does not have permission to operate with resource " + entity);
}
} else if (!_projectMgr.canAccessAccount(caller, account.getId())){
throw new PermissionDeniedException(caller + " does not have permission to operate with resource " + entity);
}
} else {

View File

@ -198,7 +198,7 @@ public class ApiDispatcher {
Object paramObj = unpackedParams.get(parameterAnnotation.name());
if (paramObj == null) {
if (parameterAnnotation.required()) {
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to execute API command " + cmd.getCommandName() + " due to missing parameter " + parameterAnnotation.name());
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to execute API command " + cmd.getCommandName().substring(0, cmd.getCommandName().length()-8) + " due to missing parameter " + parameterAnnotation.name());
}
continue;
}
@ -210,18 +210,18 @@ public class ApiDispatcher {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Unable to execute API command " + cmd.getCommandName() + " due to invalid value " + paramObj + " for parameter " + parameterAnnotation.name());
}
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to execute API command " + cmd.getCommandName() + " due to invalid value " + paramObj + " for parameter "
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to execute API command " + cmd.getCommandName().substring(0, cmd.getCommandName().length()-8) + " due to invalid value " + paramObj + " for parameter "
+ parameterAnnotation.name());
} catch (ParseException parseEx) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Invalid date parameter " + paramObj + " passed to command " + cmd.getCommandName());
s_logger.debug("Invalid date parameter " + paramObj + " passed to command " + cmd.getCommandName().substring(0, cmd.getCommandName().length()-8));
}
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to parse date " + paramObj + " for command " + cmd.getCommandName() + ", please pass dates in the format mentioned in the api documentation");
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to parse date " + paramObj + " for command " + cmd.getCommandName().substring(0, cmd.getCommandName().length()-8) + ", please pass dates in the format mentioned in the api documentation");
} catch (CloudRuntimeException cloudEx) {
// FIXME: Better error message? This only happens if the API command is not executable, which typically means
// there was
// and IllegalAccessException setting one of the parameters.
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Internal error executing API command " + cmd.getCommandName());
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Internal error executing API command " + cmd.getCommandName().substring(0, cmd.getCommandName().length()-8));
}
}
}

View File

@ -63,6 +63,8 @@ import com.cloud.api.response.NetworkOfferingResponse;
import com.cloud.api.response.NetworkResponse;
import com.cloud.api.response.NicResponse;
import com.cloud.api.response.PodResponse;
import com.cloud.api.response.ProjectAccountResponse;
import com.cloud.api.response.ProjectInvitationResponse;
import com.cloud.api.response.ProjectResponse;
import com.cloud.api.response.RemoteAccessVpnResponse;
import com.cloud.api.response.ResourceCountResponse;
@ -132,6 +134,8 @@ import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.org.Cluster;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectAccount;
import com.cloud.projects.ProjectInvitation;
import com.cloud.server.Criteria;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.GuestOS;
@ -177,27 +181,6 @@ public class ApiResponseHelper implements ResponseGenerator {
public final Logger s_logger = Logger.getLogger(ApiResponseHelper.class);
@Override
public UserResponse createUserResponse(UserAccount user) {
UserResponse userResponse = new UserResponse();
userResponse.setAccountName(user.getAccountName());
userResponse.setAccountType(user.getType());
userResponse.setCreated(user.getCreated());
userResponse.setDomainId(user.getDomainId());
userResponse.setDomainName(ApiDBUtils.findDomainById(user.getDomainId()).getName());
userResponse.setEmail(user.getEmail());
userResponse.setFirstname(user.getFirstname());
userResponse.setId(user.getId());
userResponse.setLastname(user.getLastname());
userResponse.setState(user.getState());
userResponse.setTimezone(user.getTimezone());
userResponse.setUsername(user.getUsername());
userResponse.setApiKey(user.getApiKey());
userResponse.setSecretKey(user.getSecretKey());
userResponse.setObjectName("user");
return userResponse;
}
@Override
public UserResponse createUserResponse(User user) {
@ -330,28 +313,36 @@ public class ApiResponseHelper implements ResponseGenerator {
List<UserVO> usersForAccount = ApiDBUtils.listUsersByAccount(account.getAccountId());
List<UserResponse> userResponseList = new ArrayList<UserResponse>();
for (UserVO user : usersForAccount) {
UserResponse userResponse = new UserResponse();
userResponse.setAccountName(account.getAccountName());
userResponse.setAccountType(account.getType());
userResponse.setApiKey(user.getApiKey());
userResponse.setCreated(user.getCreated());
userResponse.setDomainId(account.getDomainId());
userResponse.setDomainName(ApiDBUtils.findDomainById(account.getDomainId()).getName());
userResponse.setEmail(user.getEmail());
userResponse.setFirstname(user.getFirstname());
userResponse.setId(user.getId());
userResponse.setSecretKey(user.getSecretKey());
userResponse.setLastname(user.getLastname());
userResponse.setState(user.getState().toString());
userResponse.setTimezone(user.getTimezone());
userResponse.setUsername(user.getUsername());
UserResponse userResponse = createUserResponse(user);
userResponseList.add(userResponse);
}
accountResponse.setUsers(userResponseList);
return accountResponse;
}
@Override
public UserResponse createUserResponse(UserAccount user) {
UserResponse userResponse = new UserResponse();
userResponse.setAccountName(user.getAccountName());
userResponse.setAccountType(user.getType());
userResponse.setCreated(user.getCreated());
userResponse.setDomainId(user.getDomainId());
userResponse.setDomainName(ApiDBUtils.findDomainById(user.getDomainId()).getName());
userResponse.setEmail(user.getEmail());
userResponse.setFirstname(user.getFirstname());
userResponse.setId(user.getId());
userResponse.setLastname(user.getLastname());
userResponse.setState(user.getState());
userResponse.setTimezone(user.getTimezone());
userResponse.setUsername(user.getUsername());
userResponse.setApiKey(user.getApiKey());
userResponse.setSecretKey(user.getSecretKey());
userResponse.setObjectName("user");
return userResponse;
}
@Override
public DomainResponse createDomainResponse(Domain domain) {
@ -2462,5 +2453,48 @@ public class ApiResponseHelper implements ResponseGenerator {
response.setDomainName(domain.getName());
}
@Override
public ProjectAccountResponse createProjectAccountResponse(ProjectAccount projectAccount) {
Account account = ApiDBUtils.findAccountById(projectAccount.getAccountId());
ProjectAccountResponse projectAccountResponse = new ProjectAccountResponse();
long projectId = projectAccount.getProjectId();
projectAccountResponse.setProjectId(projectId);
projectAccountResponse.setProjectName(ApiDBUtils.findProjectById(projectId).getName());
projectAccountResponse.setId(account.getId());
projectAccountResponse.setAccountName(account.getAccountName());
projectAccountResponse.setAccountType(account.getType());
projectAccountResponse.setRole(projectAccount.getAccountRole().toString());
populateDomain(projectAccountResponse, account.getDomainId());
// add all the users for an account as part of the response obj
List<UserVO> usersForAccount = ApiDBUtils.listUsersByAccount(account.getAccountId());
List<UserResponse> userResponseList = new ArrayList<UserResponse>();
for (UserVO user : usersForAccount) {
UserResponse userResponse = createUserResponse(user);
userResponseList.add(userResponse);
}
projectAccountResponse.setUsers(userResponseList);
projectAccountResponse.setObjectName("projectaccount");
return projectAccountResponse;
}
@Override
public ProjectInvitationResponse createProjectInvitationResponse(ProjectInvitation invite) {
ProjectInvitationResponse response = new ProjectInvitationResponse();
response.setProjectId(invite.getProjectId());
response.setProjectName(ApiDBUtils.findProjectById(invite.getProjectId()).getName());
response.setInvitationState(invite.getState().toString());
Account account = ApiDBUtils.findAccountById(invite.getAccountId());
response.setAccountName(account.getAccountName());
populateDomain(response, account.getDomainId());
response.setObjectName("projectinvitation");
return response;
}
}

View File

@ -242,8 +242,8 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet
if (domain == null) {
throw new CloudRuntimeException("Unable to find the domain " + dc.getDomainId() + " for the zone: " + dc);
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(owner, domain);
_accountMgr.checkAccess(caller, domain, null);
_accountMgr.checkAccess(owner, domain, null);
}
// check if account/domain is with in resource limits to create a new vm

View File

@ -287,7 +287,10 @@ public enum Config {
DefaultMaxProjectPublicIPs("Project Defaults", ManagementServer.class, Long.class, "max.project.public.ips", "20", "The default maximum number of public IPs that can be consumed by a project", null),
DefaultMaxProjectTemplates("Project Defaults", ManagementServer.class, Long.class, "max.project.templates", "20", "The default maximum number of templates that can be deployed for a project", null),
DefaultMaxProjectSnapshots("Project Defaults", ManagementServer.class, Long.class, "max.project.snapshots", "20", "The default maximum number of snapshots that can be created for a project", null),
DefaultMaxProjectVolumes("Project Defaults", ManagementServer.class, Long.class, "max.project.volumes", "20", "The default maximum number of volumes that can be created for a project", null);
DefaultMaxProjectVolumes("Project Defaults", ManagementServer.class, Long.class, "max.project.volumes", "20", "The default maximum number of volumes that can be created for a project", null),
ProjectInviteRequired("Project Defaults", ManagementServer.class, Boolean.class, "project.invite.required", "false", "If invitation confirmation is required when add account to project. Default value is false", null),
ProjectInvitationExpirationTime("Project Defaults", ManagementServer.class, Long.class, "project.invite.timeout", "86400", "Invitation expiration time (in seconds). Default is 1 day - 86400 seconds", null);
private final String _category;
private final Class<?> _componentClass;

View File

@ -107,8 +107,9 @@ import com.cloud.network.security.dao.VmRulesetLogDaoImpl;
import com.cloud.network.vpn.RemoteAccessVpnManagerImpl;
import com.cloud.offerings.dao.NetworkOfferingDaoImpl;
import com.cloud.projects.ProjectManagerImpl;
import com.cloud.projects.dao.ProjectDaoImpl;
import com.cloud.projects.dao.ProjectAccountDaoImpl;
import com.cloud.projects.dao.ProjectDaoImpl;
import com.cloud.projects.dao.ProjectInvitationDaoImpl;
import com.cloud.resource.ResourceManagerImpl;
import com.cloud.resourcelimit.ResourceLimitManagerImpl;
import com.cloud.service.dao.ServiceOfferingDaoImpl;
@ -276,6 +277,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
addDao("InlineLoadBalancerNicMapDao", InlineLoadBalancerNicMapDaoImpl.class);
addDao("ElasticLbVmMap", ElasticLbVmMapDaoImpl.class);
addDao("ProjectsAccountDao", ProjectAccountDaoImpl.class);
addDao("ProjectInvitationDao", ProjectInvitationDaoImpl.class);
info = addDao("HypervisorCapabilitiesDao",HypervisorCapabilitiesDaoImpl.class);
info.addParameter("cache.size", "100");
info.addParameter("cache.time.to.live", "600");

View File

@ -1562,7 +1562,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
if (domain == null) {
throw new InvalidParameterValueException("Unable to find domain by id " + cmd.getDomainId());
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
isDomainSpecific = true;
}
}
@ -1858,7 +1858,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
throw new InvalidParameterValueException("Domain id=" + domainId + " doesn't exist in the system");
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
if (accountName != null) {
Account owner = _accountMgr.getActiveAccountByName(accountName, domainId);
if (owner == null) {

View File

@ -1037,7 +1037,7 @@ public class SecurityGroupManagerImpl implements SecurityGroupManager, SecurityG
if (domain == null) {
throw new InvalidParameterValueException("Unable to find domain by id " + domainId);
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
if (accountName != null) {
Account account = _accountMgr.getActiveAccountByName(accountName, domainId);
if (account == null) {

View File

@ -17,6 +17,8 @@
*/
package com.cloud.projects;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
@ -26,6 +28,8 @@ import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import com.cloud.utils.db.GenericDao;
@Entity
@Table(name="project_account")
public class ProjectAccountVO implements ProjectAccount{
@ -49,6 +53,9 @@ public class ProjectAccountVO implements ProjectAccount{
@Column(name="project_domain_id")
long projectDomainId;
@Column(name=GenericDao.CREATED_COLUMN)
private Date created;
protected ProjectAccountVO(){
@ -62,7 +69,6 @@ public class ProjectAccountVO implements ProjectAccount{
this.projectDomainId = project.getProjectDomainId();
}
@Override
public long getId() {
return id;
}
@ -91,4 +97,8 @@ public class ProjectAccountVO implements ProjectAccount{
public long getProjectDomainId() {
return projectDomainId;
}
public void setAccountRole(Role accountRole) {
this.accountRole = accountRole;
}
}

View File

@ -0,0 +1,109 @@
package com.cloud.projects;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import com.cloud.utils.db.GenericDao;
@Entity
@Table(name="project_invitations")
public class ProjectInvitationVO implements ProjectInvitation{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private long id;
@Column(name="project_id")
private long projectId;
@Column(name="account_id")
private Long accountId;
@Column(name="domain_id")
private Long domainId;
@Column(name="token")
private String token;
@Column(name="email")
private String email;
@Column(name="state")
@Enumerated(value=EnumType.STRING)
private State state = State.Pending;
@Column(name=GenericDao.CREATED_COLUMN)
private Date created;
protected ProjectInvitationVO(){
}
public ProjectInvitationVO(long projectId, Long accountId, Long domainId, String email, String token) {
this.accountId = accountId;
this.domainId = domainId;
this.projectId = projectId;
this.email = email;
this.token = token;
}
@Override
public long getId() {
return id;
}
@Override
public long getProjectId() {
return projectId;
}
@Override
public Long getAccountId() {
return accountId;
}
@Override
public String getToken() {
return token;
}
@Override
public String getEmail() {
return email;
}
@Override
public Date getCreated() {
return created;
}
@Override
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder("ProjectInvitation[");
buf.append(id).append("|projectId=").append(projectId).append("|accountId=").append(accountId).append("]");
return buf.toString();
}
@Override
public Long getDomainId() {
return domainId;
}
}

View File

@ -6,4 +6,10 @@ public interface ProjectManager extends ProjectService {
boolean canAccessAccount(Account caller, long accountId);
boolean canAccessDomain(Account caller, long domainId);
boolean canModifyProjectAccount(Account caller, long accountId);
boolean canModifyProjectDomain(Account caller, long domainId);
boolean deleteAccountFromProject(long projectId, long accountId);
}

View File

@ -1,5 +1,23 @@
/**
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.projects;
import java.sql.Date;
import java.util.List;
import java.util.Map;
@ -8,8 +26,11 @@ import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.acl.SecurityChecker.AccessType;
import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
@ -19,13 +40,17 @@ import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.projects.Project.State;
import com.cloud.projects.ProjectAccount.Role;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.projects.dao.ProjectInvitationDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.DomainManager;
import com.cloud.user.ResourceLimitService;
import com.cloud.user.UserContext;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.component.Inject;
import com.cloud.utils.component.Manager;
import com.cloud.utils.db.DB;
@ -55,11 +80,24 @@ public class ProjectManagerImpl implements ProjectManager, Manager{
ResourceLimitService _resourceLimitMgr;
@Inject
private ProjectAccountDao _projectAccountDao;
@Inject
private AccountDao _accountDao;
@Inject
private ConfigurationDao _configDao;
@Inject
private ProjectInvitationDao _projectInvitationDao;
protected boolean _invitationRequired = false;
protected long _invitationTimeOut = 86400;
@Override
public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
_name = name;
Map<String, String> configs = _configDao.getConfiguration(params);
_invitationRequired = Boolean.valueOf(configs.get(Config.ProjectInviteRequired.key()));
_invitationTimeOut = Long.valueOf(configs.get(Config.ProjectInvitationExpirationTime.key()));
return true;
}
@ -149,7 +187,7 @@ public class ProjectManagerImpl implements ProjectManager, Manager{
throw new InvalidParameterValueException("Unable to find project by id " + projectId);
}
_accountMgr.checkAccess(caller, _domainDao.findById(project.getDomainId()));
_accountMgr.checkAccess(caller, _domainDao.findById(project.getDomainId()), AccessType.ModifyProject);
//mark project as inactive first, so you can't add resources to it
Transaction txn = Transaction.currentTxn();
@ -231,7 +269,7 @@ public class ProjectManagerImpl implements ProjectManager, Manager{
throw new InvalidParameterValueException("Domain id=" + domainId + " doesn't exist in the system");
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
if (accountName != null) {
Account owner = _accountMgr.getActiveAccountByName(accountName, domainId);
@ -301,6 +339,12 @@ public class ProjectManagerImpl implements ProjectManager, Manager{
return _projectAccountDao.persist(new ProjectAccountVO(project, accountId, accountRole));
}
@Override
public boolean deleteAccountFromProject(long projectId, long accountId) {
ProjectAccountVO projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, accountId);
return _projectAccountDao.remove(projectAccount.getId());
}
@Override
public Account getProjectOwner(long projectId) {
long accountId = _projectAccountDao.getProjectOwner(projectId).getAccountId();
@ -331,5 +375,346 @@ public class ProjectManagerImpl implements ProjectManager, Manager{
public boolean canAccessDomain(Account caller, long domainId) {
return _projectAccountDao.canAccessDomain(caller.getId(), domainId);
}
public boolean canModifyProjectAccount(Account caller, long accountId) {
return _projectAccountDao.canModifyProjectAccount(caller.getId(), accountId);
}
@Override
public boolean canModifyProjectDomain(Account caller, long domainId) {
return _projectAccountDao.canModifyProjectDomain(caller.getId(), domainId);
}
@Override @DB
public Project updateProject(long projectId, String displayText, String newOwnerName) {
Account caller = UserContext.current().getCaller();
//check that the project exists
ProjectVO project = getProject(projectId);
if (project == null) {
throw new InvalidParameterValueException("Unable to find the project id=" + projectId);
}
//verify permissions
_accountMgr.checkAccess(caller, _domainDao.findById(project.getProjectDomainId()), AccessType.ModifyProject);
Transaction txn = Transaction.currentTxn();
txn.start();
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.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);
//set new owner
futureOwner.setAccountRole(Role.Owner);
_projectAccountDao.update(futureOwner.getId(), futureOwner);
} else {
s_logger.trace("Future owner " + newOwnerName + "is already the owner of the project id=" + projectId);
}
}
txn.commit();
return _projectDao.findById(projectId);
}
@Override
public boolean addAccountToProject(long projectId, String accountName) {
Account caller = UserContext.current().getCaller();
//check that the project exists
Project project = getProject(projectId);
if (project == null) {
throw new InvalidParameterValueException("Unable to find the project id=" + projectId);
}
//check that account-to-add exists
Account account = _accountMgr.getActiveAccountByName(accountName, project.getDomainId());
if (account == null) {
throw new InvalidParameterValueException("Unable to find account name=" + accountName + " in domain id=" + project.getDomainId());
}
//verify permissions
_accountMgr.checkAccess(caller, _domainDao.findById(project.getProjectDomainId()), AccessType.ModifyProject);
//Check if the account already added to the project
ProjectAccount projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, account.getId());
if (projectAccount != null) {
s_logger.debug("Account " + accountName + " already added to the project id=" + projectId);
return true;
}
if (_invitationRequired) {
//TODO - token based registration
if (generateInvitation(projectId, account.getId()) != null) {
return true;
} else {
s_logger.warn("Failed to generate invitation for account " + accountName + " to project id=" + projectId);
return false;
}
} else {
if (assignAccountToProject(project, account.getId(), ProjectAccount.Role.Regular) != null) {
return true;
} else {
s_logger.warn("Failed to add account " + accountName + " to project id=" + projectId);
return false;
}
}
}
@Override
public boolean deleteAccountFromProject(long projectId, String accountName) {
Account caller = UserContext.current().getCaller();
//check that the project exists
Project project = getProject(projectId);
if (project == null) {
throw new InvalidParameterValueException("Unable to find the project id=" + projectId);
}
//check that account-to-remove exists
Account account = _accountMgr.getActiveAccountByName(accountName, project.getDomainId());
if (account == null) {
throw new InvalidParameterValueException("Unable to find account name=" + accountName + " in domain id=" + project.getDomainId());
}
//verify permissions
_accountMgr.checkAccess(caller, _domainDao.findById(project.getProjectDomainId()), AccessType.ModifyProject);
//Check if the account exists in the project
ProjectAccount projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, account.getId());
if (projectAccount == null) {
throw new InvalidParameterValueException("Account " + accountName + " is not assigned to the project id=" + projectId);
}
//can't remove the owner of the project
if (projectAccount.getAccountRole() == Role.Owner) {
throw new InvalidParameterValueException("Unable to delete account " + accountName + " from the project id=" + projectId + " as the account is the owner of the project");
}
return deleteAccountFromProject(projectId, account.getId());
}
@Override
public List<? extends ProjectAccount> listProjectAccounts(long projectId, String accountName, String role, Long startIndex, Long pageSizeVal) {
Account caller = UserContext.current().getCaller();
//check that the project exists
Project project = getProject(projectId);
if (project == null) {
throw new InvalidParameterValueException("Unable to find the project id=" + projectId);
}
//verify permissions
_accountMgr.checkAccess(caller, _domainDao.findById(project.getProjectDomainId()), null);
Filter searchFilter = new Filter(ProjectAccountVO.class, "id", false, startIndex, pageSizeVal);
SearchBuilder<ProjectAccountVO> sb = _projectAccountDao.createSearchBuilder();
sb.and("accountRole", sb.entity().getAccountRole(), Op.EQ);
SearchBuilder<AccountVO> accountSearch;
if (accountName != null) {
accountSearch = _accountDao.createSearchBuilder();
accountSearch.and("accountName", accountSearch.entity().getAccountName(), SearchCriteria.Op.EQ);
sb.join("accountSearch", accountSearch, sb.entity().getAccountId(), accountSearch.entity().getId(), JoinBuilder.JoinType.INNER);
}
SearchCriteria<ProjectAccountVO> sc = sb.create();
if (role != null) {
sc.setParameters("accountRole", role);
}
if (accountName != null) {
sc.setJoinParameters("accountSearch", "accountName", accountName);
}
return _projectAccountDao.search(sc, searchFilter);
}
public ProjectInvitation generateInvitation(long projectId, Long accountId) {
//verify if the invitation was already generated
ProjectInvitationVO invite = _projectInvitationDao.findPendingByAccountIdProjectId(accountId, projectId);
if (invite != null) {
if (_projectInvitationDao.isActive(invite.getId(), _invitationTimeOut)) {
throw new InvalidParameterValueException("There is already a pending invitation for account id=" + accountId + " to the project id=" + projectId);
} else {
if (invite.getState() == ProjectInvitation.State.Pending) {
expireInvitation(invite);
}
}
}
return _projectInvitationDao.persist(new ProjectInvitationVO(projectId, accountId, _accountMgr.getAccount(accountId).getDomainId(), null, null));
}
private boolean expireInvitation(ProjectInvitationVO invite) {
s_logger.debug("Expiring invitation id=" + invite.getId());
invite.setState(ProjectInvitation.State.Expired);
return _projectInvitationDao.update(invite.getId(), invite);
}
@Override
public List<? extends ProjectInvitation> listProjectInvitations(Long projectId, String accountName, Long domainId, String state, boolean activeOnly, Long startIndex, Long pageSizeVal) {
Account caller = UserContext.current().getCaller();
Long accountId = null;
String domainPath = null;
if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) {
if (domainId == null) {
domainPath = _domainMgr.getDomain(caller.getDomainId()).getPath();
}
} else if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL){
// regular user is constraint to only his account
accountId = caller.getId();
}
if (domainId != null) {
Domain domain = _domainDao.findById(domainId);
if (domain == null) {
throw new InvalidParameterValueException("Domain id=" + domainId + " doesn't exist");
}
_accountMgr.checkAccess(caller, domain, null);
if (accountName != null) {
Account account = _accountDao.findActiveAccount(accountName, domainId);
if (account == null) {
throw new InvalidParameterValueException("Unable to find account by name " + accountName + " in domain " + domainId);
}
_accountMgr.checkAccess(caller, null, account);
accountId = account.getId();
}
}
Filter searchFilter = new Filter(ProjectInvitationVO.class, "id", true, startIndex, pageSizeVal);
SearchBuilder<ProjectInvitationVO> sb = _projectInvitationDao.createSearchBuilder();
sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ);
sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.EQ);
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);
if (domainPath != null) {
// do a domain LIKE match for the admin case if isRecursive is true
SearchBuilder<DomainVO> domainSearch = _domainDao.createSearchBuilder();
domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
sb.join("domainSearch", domainSearch, sb.entity().getDomainId(), domainSearch.entity().getId(), JoinBuilder.JoinType.INNER);
}
SearchCriteria<ProjectInvitationVO> sc = sb.create();
if (domainPath != null) {
sc.setJoinParameters("domainSearch", "path", domainPath);
}
if (accountId != null) {
sc.setParameters("accountId", accountId);
}
if (projectId != null){
sc.setParameters("projectId", projectId);
}
if (state != null) {
sc.setParameters("state", state);
}
if (activeOnly) {
sc.setParameters("state", ProjectInvitation.State.Pending);
sc.setParameters("created", new Date((System.currentTimeMillis() >> 10) - _invitationTimeOut));
}
return _projectInvitationDao.search(sc, searchFilter);
}
@Override @DB
public boolean joinProject(long projectId, String accountName) {
Account caller = UserContext.current().getCaller();
Long accountId = null;
boolean result = true;
//check that the project exists
Project project = getProject(projectId);
if (project == null) {
throw new InvalidParameterValueException("Unable to find the project id=" + projectId);
}
if (accountName != null) {
//check that account-to-remove exists
Account account = _accountMgr.getActiveAccountByName(accountName, project.getDomainId());
if (account == null) {
throw new InvalidParameterValueException("Unable to find account name=" + accountName + " in domain id=" + project.getDomainId());
}
//verify permissions
_accountMgr.checkAccess(caller, _domainDao.findById(project.getProjectDomainId()), AccessType.ModifyProject);
accountId = account.getId();
} else {
accountId = caller.getId();
}
//check that invitation exists
ProjectInvitationVO invite = _projectInvitationDao.findPendingByAccountIdProjectId(accountId, projectId);
if (invite != null) {
if (!_projectInvitationDao.isActive(invite.getId(), _invitationTimeOut)) {
expireInvitation(invite);
throw new InvalidParameterValueException("Invitation is expired for account id=" + accountName + " to the project id=" + projectId);
} else {
Transaction txn = Transaction.currentTxn();
txn.start();
//complete invitation
s_logger.debug("Marking invitation " + invite + " with state " + ProjectInvitation.State.Completed);
invite.setState(ProjectInvitation.State.Completed);
result = _projectInvitationDao.update(invite.getId(), invite);
if (result) {
//check if account already exists for the project (was added before invitation got accepted)
ProjectAccount projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, accountId);
if (projectAccount != null) {
s_logger.debug("Account " + accountName + " already added to the project id=" + projectId);
} else {
assignAccountToProject(project, accountId, ProjectAccount.Role.Regular);
}
} else {
s_logger.warn("Failed to update project invitation " + invite + " with state " + ProjectInvitation.State.Completed);
}
txn.commit();
}
} else {
throw new InvalidParameterValueException("Unable to find invitation for account id=" + accountName + " to the project id=" + projectId);
}
return result;
}
}

View File

@ -113,7 +113,7 @@ public class ProjectVO implements Project{
@Override
public String toString() {
StringBuilder buf = new StringBuilder("Project[");
buf.append(id).append("|").append(name).append("|domainid=").append(domainId).append("]");
buf.append(id).append("|name=").append(name).append("|domainid=").append(domainId).append("]");
return buf.toString();
}

View File

@ -1,3 +1,20 @@
/**
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.projects.dao;
import java.util.List;
@ -13,4 +30,7 @@ public interface ProjectAccountDao extends GenericDao<ProjectAccountVO, Long>{
boolean canAccessAccount(long accountId, long projectAccountId);
boolean canAccessDomain(long accountId, long projectDomainId);
boolean canModifyProjectAccount(long accountId, long projectAccountId);
boolean canModifyProjectDomain(long accountId, long projectDomainId);
}

View File

@ -1,3 +1,20 @@
/**
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.projects.dao;
import java.util.List;
@ -15,10 +32,8 @@ import com.cloud.utils.db.SearchCriteria;
@Local(value={ProjectAccountDao.class})
public class ProjectAccountDaoImpl extends GenericDaoBase<ProjectAccountVO, Long> implements ProjectAccountDao {
private static final Logger s_logger = Logger.getLogger(ProjectAccountDaoImpl.class);
protected final SearchBuilder<ProjectAccountVO> AllFieldsSearch;
protected ProjectAccountDaoImpl() {
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and("role", AllFieldsSearch.entity().getAccountRole(), SearchCriteria.Op.EQ);
@ -80,5 +95,32 @@ public class ProjectAccountDaoImpl extends GenericDaoBase<ProjectAccountVO, Long
return false;
}
}
@Override
public boolean canModifyProjectAccount(long accountId, long projectAccountId) {
SearchCriteria<ProjectAccountVO> sc = AllFieldsSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("projectAccountId", projectAccountId);
sc.setParameters("role", ProjectAccount.Role.Owner);
if (findOneBy(sc) != null) {
return true;
} else {
return false;
}
}
@Override
public boolean canModifyProjectDomain(long accountId, long projectDomainId) {
SearchCriteria<ProjectAccountVO> sc = AllFieldsSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("projectDomainId", projectDomainId);
sc.setParameters("role", ProjectAccount.Role.Owner);
if (findOneBy(sc) != null) {
return true;
} else {
return false;
}
}
}

View File

@ -1,3 +1,20 @@
/**
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.projects.dao;
import com.cloud.projects.ProjectVO;

View File

@ -0,0 +1,30 @@
/**
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.projects.dao;
import java.util.List;
import com.cloud.projects.ProjectInvitationVO;
import com.cloud.utils.db.GenericDao;
public interface ProjectInvitationDao extends GenericDao<ProjectInvitationVO, Long>{
ProjectInvitationVO findPendingByAccountIdProjectId(long accountId, long projectId);
List<ProjectInvitationVO> listExpiredInvitations();
boolean expirePendingInvitations(long timeOut);
boolean isActive(long id, long timeout);
}

View File

@ -0,0 +1,99 @@
package com.cloud.projects.dao;
import java.sql.Date;
import java.util.List;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.projects.ProjectInvitation.State;
import com.cloud.projects.ProjectInvitationVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@Local(value={ProjectInvitationDao.class})
public class ProjectInvitationDaoImpl extends GenericDaoBase<ProjectInvitationVO, Long> implements ProjectInvitationDao {
private static final Logger s_logger = Logger.getLogger(ProjectInvitationDaoImpl.class);
protected final SearchBuilder<ProjectInvitationVO> AllFieldsSearch;
protected final SearchBuilder<ProjectInvitationVO> InactiveSearch;
protected ProjectInvitationDaoImpl() {
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("projectId", AllFieldsSearch.entity().getProjectId(), 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.EQ);
AllFieldsSearch.done();
InactiveSearch = createSearchBuilder();
InactiveSearch.and("id", InactiveSearch.entity().getId(), SearchCriteria.Op.EQ);
InactiveSearch.and("accountId", InactiveSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
InactiveSearch.and("projectId", InactiveSearch.entity().getProjectId(), SearchCriteria.Op.EQ);
InactiveSearch.and("created", InactiveSearch.entity().getCreated(), SearchCriteria.Op.LTEQ);
InactiveSearch.and("state", InactiveSearch.entity().getState(), SearchCriteria.Op.EQ);
InactiveSearch.done();
}
@Override
public ProjectInvitationVO findPendingByAccountIdProjectId(long accountId, long projectId) {
SearchCriteria<ProjectInvitationVO> sc = AllFieldsSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("projectId", projectId);
sc.setParameters("state", State.Pending);
return findOneBy(sc);
}
@Override
public List<ProjectInvitationVO> listExpiredInvitations() {
SearchCriteria<ProjectInvitationVO> sc = AllFieldsSearch.create();
sc.setParameters("state", State.Expired);
return listBy(sc);
}
@Override
public boolean expirePendingInvitations(long timeout) {
boolean success = true;
SearchCriteria<ProjectInvitationVO> sc = InactiveSearch.create();
sc.setParameters("created", new Date((System.currentTimeMillis() >> 10) - timeout));
sc.setParameters("state", State.Pending);
List<ProjectInvitationVO> invitationsToExpire = listBy(sc);
for (ProjectInvitationVO invitationToExpire : invitationsToExpire) {
invitationToExpire.setState(State.Expired);
if (!update(invitationToExpire.getId(), invitationToExpire)) {
s_logger.warn("Fail to expire invitation " + invitationToExpire.toString());
success = false;
}
}
return success;
}
@Override
public boolean isActive(long id, long timeout) {
SearchCriteria<ProjectInvitationVO> sc = InactiveSearch.create();
sc.setParameters("id", id);
if (findOneBy(sc) == null) {
s_logger.warn("Unable to find project invitation by id " + id);
return false;
}
sc.setParameters("created", new Date((System.currentTimeMillis() >> 10) - timeout));
if (findOneBy(sc) == null) {
return true;
} else {
return false;
}
}
}

View File

@ -323,7 +323,7 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
return limits;
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
if (accountId != null) {
//Verify account information and permissions
@ -356,7 +356,7 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
_accountMgr.checkAccess(caller, null, _accountDao.findById(vo.getAccountId()));
limits.add(vo);
} else if (vo.getDomainId() != null) {
_accountMgr.checkAccess(caller, _domainDao.findById(vo.getDomainId()));
_accountMgr.checkAccess(caller, _domainDao.findById(vo.getDomainId()), null);
limits.add(vo);
}
@ -487,7 +487,7 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
ownerId = accountId;
} else if (domainId != null) {
Domain domain = _entityMgr.findById(Domain.class, domainId);
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
if ((caller.getDomainId() == domainId.longValue()) && caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) {
// if the admin is trying to update their own domain, disallow...
throw new PermissionDeniedException("Unable to update resource limit for domain " + domainId + ", permission denied");
@ -547,7 +547,7 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
if (domain == null) {
throw new InvalidParameterValueException("Please specify a valid domain ID.");
}
_accountMgr.checkAccess(callerAccount, domain);
_accountMgr.checkAccess(callerAccount, domain, null);
if (accountName != null) {
Account userAccount = _accountMgr.getActiveAccountByName(accountName, domainId);

View File

@ -1371,7 +1371,7 @@ public class ManagementServerImpl implements ManagementServer {
if (domain == null) {
throw new InvalidParameterValueException("Domain id=" + domainId + " doesn't exist");
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
if (accountName != null) {
Account account = _accountDao.findActiveAccount(accountName, domainId);
@ -1931,7 +1931,7 @@ public class ManagementServerImpl implements ManagementServer {
if (domain == null) {
throw new InvalidParameterValueException("Unable to find domain by id " + domainId);
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
if (accountName != null) {
Account userAccount = _accountDao.findActiveAccount(accountName, domainId);
@ -2288,7 +2288,7 @@ public class ManagementServerImpl implements ManagementServer {
// check permissions
Account caller = UserContext.current().getCaller();
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
//domain name is unique in the cloud
if (domainName != null) {
@ -2617,7 +2617,7 @@ public class ManagementServerImpl implements ManagementServer {
throw new InvalidParameterValueException("Unable to find domain by id " + domainId);
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
if (acctName != null) {
Account userAccount = _accountDao.findActiveAccount(acctName, domainId);

View File

@ -42,7 +42,7 @@ public interface AccountManager extends AccountService {
boolean deleteAccount(AccountVO account, long callerUserId, Account caller);
void checkAccess(Account account, Domain domain) throws PermissionDeniedException;
void checkAccess(Account account, Domain domain, AccessType accessType) throws PermissionDeniedException;
void checkAccess(Account account, AccessType accessType, ControlledEntity... entities) throws PermissionDeniedException;

View File

@ -259,9 +259,9 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
}
@Override
public void checkAccess(Account caller, Domain domain) throws PermissionDeniedException {
public void checkAccess(Account caller, Domain domain, AccessType accessType) throws PermissionDeniedException {
for (SecurityChecker checker : _securityCheckers) {
if (checker.checkAccess(caller, domain)) {
if (checker.checkAccess(caller, domain, accessType)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Access granted to " + caller + " to " + domain + " by " + checker.getName());
}
@ -316,7 +316,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
throw new PermissionDeniedException("Domain is not found.", caller, domain.getValue());
}
try {
checker.checkAccess(caller, d);
checker.checkAccess(caller, d, accessType);
} catch (PermissionDeniedException e) {
e.addDetails(caller, domain.getValue());
throw e;
@ -611,7 +611,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
}
//Check permissions
checkAccess(UserContext.current().getCaller(), domain);
checkAccess(UserContext.current().getCaller(), domain, null);
if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) {
@ -663,7 +663,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
throw new CloudRuntimeException("The user cannot be created as domain " + domain.getName() + " is being deleted");
}
checkAccess(UserContext.current().getCaller(), domain);
checkAccess(UserContext.current().getCaller(), domain, null);
Account account = _accountDao.findActiveAccount(accountName, domainId);
if (account == null) {
@ -1177,7 +1177,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
if (owner == null) {
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
}
checkAccess(caller, domain);
checkAccess(caller, domain, null);
return owner;
} else if (!isAdmin(caller.getType()) && accountName != null && domainId != null) {
@ -1243,7 +1243,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
throw new InvalidParameterValueException("Unable to find the domain by id=" + domainId);
}
checkAccess(caller, domain);
checkAccess(caller, domain, null);
if (accountName != null) {
Account owner = getActiveAccountByName(accountName, domainId);

View File

@ -135,7 +135,7 @@ public class DomainManagerImpl implements DomainManager, DomainService, Manager{
throw new CloudRuntimeException("The domain cannot be created as the parent domain " + parentDomain.getName() + " is being deleted");
}
_accountMgr.checkAccess(caller, parentDomain);
_accountMgr.checkAccess(caller, parentDomain, null);
return createDomain(name, parentId, caller.getId(), networkDomain, null);
@ -213,7 +213,7 @@ public class DomainManagerImpl implements DomainManager, DomainService, Manager{
throw new PermissionDeniedException("Can't delete ROOT domain");
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
//mark domain as inactive
s_logger.debug("Marking domain id=" + domainId + " as " + Domain.State.Inactive + " before actually deleting it");

View File

@ -2372,9 +2372,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
throw new CloudRuntimeException("Unable to find the domain " + zone.getDomainId() + " for the zone: " + zone);
}
// check that caller can operate with domain
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
// check that vm owner can create vm in the domain
_accountMgr.checkAccess(owner, domain);
_accountMgr.checkAccess(owner, domain, null);
}
// check if account/domain is with in resource limits to create a new vm
@ -2979,7 +2979,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
if (domain == null) {
throw new InvalidParameterValueException("Domain id=" + domainId + " doesn't exist");
}
_accountMgr.checkAccess(caller, domain);
_accountMgr.checkAccess(caller, domain, null);
}
boolean isAdmin = false;
@ -3346,7 +3346,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
// VV 5: check that vm owner can create vm in the domain
DomainVO domain = _domainDao.findById(oldAccount.getDomainId());
_accountMgr.checkAccess(newAccount, domain);
_accountMgr.checkAccess(newAccount, domain, null);
DataCenterVO zone = _dcDao.findById(vm.getDataCenterIdToDeployIn());
VMInstanceVO vmoi = _itMgr.findByIdAndType(vm.getType(), vm.getId());

View File

@ -179,7 +179,7 @@ public class MockAccountManagerImpl implements Manager, AccountManager {
}
@Override
public void checkAccess(Account account, Domain domain) throws PermissionDeniedException {
public void checkAccess(Account account, Domain domain, AccessType accessType) throws PermissionDeniedException {
// TODO Auto-generated method stub
}

View File

@ -1672,7 +1672,7 @@ CREATE TABLE `cloud`.`projects` (
`project_domain_id` bigint unsigned NOT NULL,
`domain_id` bigint unsigned NOT NULL,
`created` datetime COMMENT 'date created',
`removed` datetime COMMENT 'date removed',\
`removed` datetime COMMENT 'date removed',
`state` varchar(255) NOT NULL COMMENT 'state of the project (Active/Inactive/Suspended)',
PRIMARY KEY (`id`),
CONSTRAINT `fk_projects__project_account_id` FOREIGN KEY(`project_account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE,
@ -1685,14 +1685,36 @@ CREATE TABLE `cloud`.`projects` (
CREATE TABLE `cloud`.`project_account` (
`id` bigint unsigned NOT NULL auto_increment,
`account_id` bigint unsigned NOT NULL COMMENT'account id',
`account_role` varchar(255) COMMENT 'Account role in the project (Owner or Regular)',
`account_role` varchar(255) NOT NULL DEFAULT 'Regular' COMMENT 'Account role in the project (Owner or Regular)',
`project_id` bigint unsigned NOT NULL COMMENT 'project id',
`project_account_id` bigint unsigned NOT NULL,
`project_domain_id` bigint unsigned NOT NULL,
`created` datetime COMMENT 'date created',
PRIMARY KEY (`id`),
CONSTRAINT `fk_project_account__account_id` FOREIGN KEY(`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_account__project_id` FOREIGN KEY(`project_id`) REFERENCES `projects`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_account__project_account_id` FOREIGN KEY(`project_account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_account__project_domain_id` FOREIGN KEY(`project_domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE,
UNIQUE (`account_id`, `project_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`project_invitations` (
`id` bigint unsigned NOT NULL auto_increment,
`project_id` bigint unsigned NOT NULL COMMENT 'project id',
`account_id` bigint unsigned COMMENT 'account id',
`domain_id` bigint unsigned COMMENT 'domain id',
`email` varchar(255) COMMENT 'email',
`token` varchar(255) COMMENT 'token',
`state` varchar(255) NOT NULL DEFAULT 'Pending' COMMENT 'the state of the invitation',
`created` datetime COMMENT 'date created',
PRIMARY KEY (`id`),
CONSTRAINT `fk_project_invitations__account_id` FOREIGN KEY(`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_invitations__domain_id` FOREIGN KEY(`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_invitations__project_id` FOREIGN KEY(`project_id`) REFERENCES `projects`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`elastic_lb_vm_map` (
`id` bigint unsigned NOT NULL auto_increment,
`ip_addr_id` bigint unsigned NOT NULL,

View File

@ -50,19 +50,43 @@ CREATE TABLE `cloud`.`projects` (
CREATE TABLE `cloud`.`project_account` (
`id` bigint unsigned NOT NULL auto_increment,
`account_id` bigint unsigned NOT NULL COMMENT'account id',
`account_role` varchar(255) COMMENT 'Account role in the project (Owner or Regular)',
`account_role` varchar(255) NOT NULL DEFAULT 'Regular' COMMENT 'Account role in the project (Owner or Regular)',
`project_id` bigint unsigned NOT NULL COMMENT 'project id',
`project_account_id` bigint unsigned NOT NULL,
`project_domain_id` bigint unsigned NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_project_account__account_id` FOREIGN KEY(`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_account__project_id` FOREIGN KEY(`project_id`) REFERENCES `projects`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_account__project_account_id` FOREIGN KEY(`project_account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_account__project_domain_id` FOREIGN KEY(`project_domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE,
UNIQUE (`account_id`, `project_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`project_invitations` (
`id` bigint unsigned NOT NULL auto_increment,
`project_id` bigint unsigned NOT NULL COMMENT 'project id',
`account_id` bigint unsigned COMMENT 'account id',
`domain_id` bigint unsigned COMMENT 'domain id',
`email` varchar(255) COMMENT 'email',
`token` varchar(255) COMMENT 'token',
`state` varchar(255) unsigned NOT NULL DEFAULT 'Pending' COMMENT 'the state of the invitation',
`created` datetime COMMENT 'date created',
PRIMARY KEY (`id`),
CONSTRAINT `fk_project_invitations__account_id` FOREIGN KEY(`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_invitations__domain_id` FOREIGN KEY(`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_project_invitations__project_id` FOREIGN KEY(`project_id`) REFERENCES `projects`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE domain ADD COLUMN `type` varchar(255) NOT NULL DEFAULT 'Normal' COMMENT 'type of the domain - can be Normal or Project';
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'max.project.user.vms', '20', 'The default maximum number of user VMs that can be deployed for a project');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'max.project.public.ips', '20', 'The default maximum number of public IPs that can be consumed by a project');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'max.project.templates', '20', 'The default maximum number of templates that can be deployed for a project');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'max.project.snapshots', '20', 'The default maximum number of snapshots that can be created for a project');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'max.project.volumes', '20', 'The default maximum number of volumes that can be created for a project');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'project.invite.required', 'false', 'If invitation confirmation is required when add account to project. Default value is false');
INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'project.invite.timeout', '86400', 'Invitation expiration time (in seconds). Default is 1 day - 86400 seconds');