diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 2e8c8ae0234..c7af549574d 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -34,6 +34,8 @@ import com.cloud.vm.ConsoleProxy; import com.cloud.vm.Nic; import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.SecondaryStorageVm; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; import org.apache.cloudstack.config.Configuration; import com.cloud.dc.DataCenter; @@ -167,6 +169,14 @@ public class EventTypes { public static final String EVENT_GLOBAL_LOAD_BALANCER_DELETE = "GLOBAL.LB.DELETE"; public static final String EVENT_GLOBAL_LOAD_BALANCER_UPDATE = "GLOBAL.LB.UPDATE"; + // Role events + public static final String EVENT_ROLE_CREATE = "ROLE.CREATE"; + public static final String EVENT_ROLE_UPDATE = "ROLE.UPDATE"; + public static final String EVENT_ROLE_DELETE = "ROLE.DELETE"; + public static final String EVENT_ROLE_PERMISSION_CREATE = "ROLE.PERMISSION.CREATE"; + public static final String EVENT_ROLE_PERMISSION_UPDATE = "ROLE.PERMISSION.UPDATE"; + public static final String EVENT_ROLE_PERMISSION_DELETE = "ROLE.PERMISSION.DELETE"; + // Account events public static final String EVENT_ACCOUNT_ENABLE = "ACCOUNT.ENABLE"; public static final String EVENT_ACCOUNT_DISABLE = "ACCOUNT.DISABLE"; @@ -598,6 +608,14 @@ public class EventTypes { entityEventDetails.put(EVENT_LB_CERT_ASSIGN, LoadBalancer.class); entityEventDetails.put(EVENT_LB_CERT_REMOVE, LoadBalancer.class); + // Role events + entityEventDetails.put(EVENT_ROLE_CREATE, Role.class); + entityEventDetails.put(EVENT_ROLE_UPDATE, Role.class); + entityEventDetails.put(EVENT_ROLE_DELETE, Role.class); + entityEventDetails.put(EVENT_ROLE_PERMISSION_CREATE, RolePermission.class); + entityEventDetails.put(EVENT_ROLE_PERMISSION_UPDATE, RolePermission.class); + entityEventDetails.put(EVENT_ROLE_PERMISSION_DELETE, RolePermission.class); + // Account events entityEventDetails.put(EVENT_ACCOUNT_ENABLE, Account.class); entityEventDetails.put(EVENT_ACCOUNT_DISABLE, Account.class); diff --git a/api/src/com/cloud/user/Account.java b/api/src/com/cloud/user/Account.java index b912e515bf3..58cedcd5746 100755 --- a/api/src/com/cloud/user/Account.java +++ b/api/src/com/cloud/user/Account.java @@ -46,6 +46,8 @@ public interface Account extends ControlledEntity, InternalIdentity, Identity { public short getType(); + public Long getRoleId(); + public State getState(); public Date getRemoved(); diff --git a/api/src/com/cloud/user/AccountService.java b/api/src/com/cloud/user/AccountService.java index 90e53c77b8e..d43011e8612 100755 --- a/api/src/com/cloud/user/AccountService.java +++ b/api/src/com/cloud/user/AccountService.java @@ -55,9 +55,9 @@ public interface AccountService { * @return the user if created successfully, null otherwise */ UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, - short accountType, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID); + short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID); - UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long domainId, String networkDomain, + UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID, User.Source source); /** diff --git a/api/src/org/apache/cloudstack/acl/Role.java b/api/src/org/apache/cloudstack/acl/Role.java new file mode 100644 index 00000000000..b05d886fdbf --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/Role.java @@ -0,0 +1,27 @@ +// 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 Role extends InternalIdentity, Identity { + String getName(); + RoleType getRoleType(); + String getDescription(); +} diff --git a/api/src/org/apache/cloudstack/acl/RolePermission.java b/api/src/org/apache/cloudstack/acl/RolePermission.java new file mode 100644 index 00000000000..e184d4a0a7d --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/RolePermission.java @@ -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 RolePermission extends InternalIdentity, Identity { + enum Permission {ALLOW, DENY} + + long getRoleId(); + Rule getRule(); + Permission getPermission(); + String getDescription(); +} diff --git a/api/src/org/apache/cloudstack/acl/RoleService.java b/api/src/org/apache/cloudstack/acl/RoleService.java new file mode 100644 index 00000000000..50071cd97f6 --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/RoleService.java @@ -0,0 +1,45 @@ +// 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.framework.config.ConfigKey; + +import java.util.List; + +public interface RoleService { + + ConfigKey EnableDynamicApiChecker = new ConfigKey<>("Advanced", Boolean.class, "dynamic.apichecker.enabled", "false", + "If set to true, this enables the dynamic role-based api access checker and disables the default static role-based api access checker.", + true); + + boolean isEnabled(); + Role findRole(final Long id); + Role createRole(final String name, final RoleType roleType, final String description); + boolean updateRole(final Role role, final String name, final RoleType roleType, final String description); + boolean deleteRole(final Role role); + + RolePermission findRolePermission(final Long id); + RolePermission createRolePermission(final Role role, final Rule rule, final RolePermission.Permission permission, final String description); + boolean updateRolePermission(final RolePermission rolePermission, final Rule rule, final RolePermission.Permission permission, final String description); + boolean deleteRolePermission(final RolePermission rolePermission); + + List listRoles(); + List findRolesByName(final String name); + List findRolesByType(final RoleType roleType); + List findAllPermissionsBy(final Long roleId); +} diff --git a/api/src/org/apache/cloudstack/acl/RoleType.java b/api/src/org/apache/cloudstack/acl/RoleType.java index 90e3d1ef604..a8a64a58df5 100644 --- a/api/src/org/apache/cloudstack/acl/RoleType.java +++ b/api/src/org/apache/cloudstack/acl/RoleType.java @@ -16,18 +16,90 @@ // under the License. package org.apache.cloudstack.acl; +import com.cloud.user.Account; +import com.google.common.base.Enums; +import com.google.common.base.Strings; + // Enum for default roles in CloudStack public enum RoleType { - Admin(1), ResourceAdmin(2), DomainAdmin(4), User(8), Unknown(0); + Admin(1L, Account.ACCOUNT_TYPE_ADMIN, 1), + ResourceAdmin(2L, Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN, 2), + DomainAdmin(3L, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, 4), + User(4L, Account.ACCOUNT_TYPE_NORMAL, 8), + Unknown(-1L, (short) -1, 0); + private long id; + private short accountType; private int mask; - private RoleType(int mask) { + RoleType(final long id, final short accountType, final int mask) { + this.id = id; + this.accountType = accountType; this.mask = mask; } - public int getValue() { + public long getId() { + return id; + } + + public short getAccountType() { + return accountType; + } + + public int getMask() { return mask; } -} + public static RoleType fromString(final String name) { + if (!Strings.isNullOrEmpty(name) + && Enums.getIfPresent(RoleType.class, name).isPresent()) { + return RoleType.valueOf(name); + } + throw new IllegalStateException("Illegal RoleType name provided"); + } + + public static RoleType fromMask(int mask) { + for (RoleType roleType : RoleType.values()) { + if (roleType.getMask() == mask) { + return roleType; + } + } + return Unknown; + } + + public static RoleType getByAccountType(final short accountType) { + RoleType roleType = RoleType.Unknown; + switch (accountType) { + case Account.ACCOUNT_TYPE_ADMIN: + roleType = RoleType.Admin; + break; + case Account.ACCOUNT_TYPE_DOMAIN_ADMIN: + roleType = RoleType.DomainAdmin; + break; + case Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN: + roleType = RoleType.ResourceAdmin; + break; + case Account.ACCOUNT_TYPE_NORMAL: + roleType = RoleType.User; + break; + } + return roleType; + } + + public static Long getRoleByAccountType(final Long roleId, final Short accountType) { + if (roleId == null && accountType != null) { + RoleType defaultRoleType = RoleType.getByAccountType(accountType); + if (defaultRoleType != null && defaultRoleType != RoleType.Unknown) { + return defaultRoleType.getId(); + } + } + return roleId; + } + + public static Short getAccountTypeByRole(final Role role, final Short accountType) { + if (role != null && role.getId() > 0L) { + return role.getRoleType().getAccountType(); + } + return accountType; + } +} diff --git a/api/src/org/apache/cloudstack/acl/Rule.java b/api/src/org/apache/cloudstack/acl/Rule.java new file mode 100644 index 00000000000..27920107fdc --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/Rule.java @@ -0,0 +1,54 @@ +// 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 com.cloud.exception.InvalidParameterValueException; +import com.google.common.base.Strings; + +import java.util.regex.Pattern; + +public final class Rule { + private final String rule; + private final static Pattern ALLOWED_PATTERN = Pattern.compile("^[a-zA-Z0-9*]+$"); + + public Rule(final String rule) { + validate(rule); + this.rule = rule; + } + + public boolean matches(final String commandName) { + return !Strings.isNullOrEmpty(commandName) + && commandName.toLowerCase().matches(rule.toLowerCase().replace("*", "\\w*")); + } + + public String getRuleString() { + return rule; + } + + @Override + public String toString() { + return rule; + } + + private static boolean validate(final String rule) { + if (Strings.isNullOrEmpty(rule) || !ALLOWED_PATTERN.matcher(rule).matches()) { + throw new InvalidParameterValueException("Only API names and wildcards are allowed, invalid rule provided: " + rule); + } + return true; + } +} diff --git a/api/src/org/apache/cloudstack/api/ApiArgValidator.java b/api/src/org/apache/cloudstack/api/ApiArgValidator.java new file mode 100644 index 00000000000..bd2294c6018 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/ApiArgValidator.java @@ -0,0 +1,23 @@ +// 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; + +public enum ApiArgValidator { + NotNullOrEmpty, // does Strings.isNullOrEmpty check + PositiveNumber, // does != null and > 0 check +} diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 2471e088957..c6f0a79e3fd 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -353,6 +353,11 @@ public class ApiConstants { public static final String PROJECT_IDS = "projectids"; public static final String PROJECT = "project"; public static final String ROLE = "role"; + public static final String ROLE_ID = "roleid"; + 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 USER = "user"; public static final String ACTIVE_ONLY = "activeonly"; public static final String TOKEN = "token"; diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 12265665d30..dd2a6b19f33 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -30,6 +30,7 @@ import java.util.regex.Pattern; import javax.inject.Inject; import com.cloud.utils.HttpUtils; +import org.apache.cloudstack.acl.RoleService; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.RoleType; @@ -85,6 +86,7 @@ import com.cloud.vm.snapshot.VMSnapshotService; public abstract class BaseCmd { private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName()); + public static final String RESPONSE_SUFFIX = "response"; public static final String RESPONSE_TYPE_XML = HttpUtils.RESPONSE_TYPE_XML; public static final String RESPONSE_TYPE_JSON = HttpUtils.RESPONSE_TYPE_JSON; public static final DateFormat INPUT_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); @@ -106,12 +108,13 @@ public abstract class BaseCmd { @Parameter(name = "response", type = CommandType.STRING) private String responseType; - @Inject public ConfigurationService _configService; @Inject public AccountService _accountService; @Inject + public RoleService roleService; + @Inject public UserVmService _userVmService; @Inject public ManagementService _mgr; @@ -325,7 +328,7 @@ public abstract class BaseCmd { if (allowedRoles.length > 0) { roleIsAllowed = false; for (final RoleType allowedRole : allowedRoles) { - if (allowedRole.getValue() == caller.getType()) { + if (allowedRole.getAccountType() == caller.getType()) { roleIsAllowed = true; break; } diff --git a/api/src/org/apache/cloudstack/api/Parameter.java b/api/src/org/apache/cloudstack/api/Parameter.java index 7ee6897af29..fa6075dc970 100644 --- a/api/src/org/apache/cloudstack/api/Parameter.java +++ b/api/src/org/apache/cloudstack/api/Parameter.java @@ -49,4 +49,6 @@ public @interface Parameter { String since() default ""; RoleType[] authorized() default {}; + + ApiArgValidator[] validations() default {}; } diff --git a/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java b/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java index ec3090fa6a5..82c4d7944d1 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java @@ -16,11 +16,9 @@ // under the License. package org.apache.cloudstack.api.command.admin.account; -import java.util.Collection; -import java.util.Map; - -import org.apache.log4j.Logger; - +import com.cloud.user.Account; +import com.cloud.user.UserAccount; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -30,11 +28,13 @@ import org.apache.cloudstack.api.ResponseObject.ResponseView; 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.RoleResponse; import org.apache.cloudstack.context.CallContext; import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; -import com.cloud.user.Account; -import com.cloud.user.UserAccount; +import java.util.Collection; +import java.util.Map; @APICommand(name = "createAccount", description = "Creates an account", responseObject = AccountResponse.class, entityType = {Account.class}, @@ -55,10 +55,12 @@ public class CreateAccountCmd extends BaseCmd { @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, - required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") private Short accountType; + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.") + private Long roleId; + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Creates the user under the specified domain.") private Long domainId; @@ -106,7 +108,11 @@ public class CreateAccountCmd extends BaseCmd { } public Short getAccountType() { - return accountType; + return RoleType.getAccountTypeByRole(roleService.findRole(roleId), accountType); + } + + public Long getRoleId() { + return RoleType.getRoleByAccountType(roleId, accountType); } public Long getDomainId() { @@ -178,9 +184,12 @@ public class CreateAccountCmd extends BaseCmd { if (StringUtils.isEmpty(getPassword())) { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Empty passwords are not allowed"); } + if (getAccountType() == null && getRoleId() == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Neither account type and role ID are not provided"); + } CallContext.current().setEventDetails("Account Name: " + getAccountName() + ", Domain Id:" + getDomainId()); UserAccount userAccount = - _accountService.createUserAccount(getUsername(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimeZone(), getAccountName(), getAccountType(), + _accountService.createUserAccount(getUsername(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimeZone(), getAccountName(), getAccountType(), getRoleId(), getDomainId(), getNetworkDomain(), getDetails(), getAccountUUID(), getUserUUID()); if (userAccount != null) { AccountResponse response = _responseGenerator.createUserAccountResponse(ResponseView.Full, userAccount); diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java new file mode 100644 index 00000000000..994573d1796 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java @@ -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; + +import com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +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.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.RoleResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = CreateRoleCmd.APINAME, description = "Creates a role", responseObject = RoleResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class CreateRoleCmd extends BaseCmd { + public static final String APINAME = "createRole"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, + description = "creates a role with this unique name", validations = {ApiArgValidator.NotNullOrEmpty}) + private String roleName; + + @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, + description = "The type of the role, valid options are: Admin, ResourceAdmin, DomainAdmin, User", + validations = {ApiArgValidator.NotNullOrEmpty}) + private String roleType; + + @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "The description of the role") + private String roleDescription; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getRoleName() { + return roleName; + } + + public RoleType getRoleType() { + return RoleType.fromString(roleType); + } + + public String getRoleDescription() { + return roleDescription; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final Role role) { + final RoleResponse response = new RoleResponse(); + response.setId(role.getUuid()); + response.setRoleName(role.getName()); + response.setRoleType(role.getRoleType()); + response.setResponseName(getCommandName()); + response.setObjectName("role"); + setResponseObject(response); + } + + @Override + public void execute() { + CallContext.current().setEventDetails("Role: " + getRoleName() + ", type:" + getRoleType() + ", description: " + getRoleDescription()); + final Role role = roleService.createRole(getRoleName(), getRoleType(), getRoleDescription()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create role"); + } + setupResponse(role); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRolePermissionCmd.java new file mode 100644 index 00000000000..aeb3f4ee11a --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRolePermissionCmd.java @@ -0,0 +1,124 @@ +// 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 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.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, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class CreateRolePermissionCmd extends BaseCmd { + public static final String APINAME = "createRolePermission"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, required = true, entityType = RoleResponse.class, + 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 /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + 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/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final RolePermission rolePermission, final Role role) { + final RolePermissionResponse response = new RolePermissionResponse(); + response.setId(rolePermission.getUuid()); + response.setRoleId(role.getUuid()); + response.setRule(rolePermission.getRule()); + response.setRulePermission(rolePermission.getPermission()); + response.setDescription(rolePermission.getDescription()); + response.setResponseName(getCommandName()); + response.setObjectName("rolepermission"); + setResponseObject(response); + } + + @Override + public void execute() { + final Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided"); + } + CallContext.current().setEventDetails("Role id: " + role.getId() + ", rule:" + getRule() + ", permission: " + getPermission() + ", description: " + getDescription()); + final RolePermission rolePermission = roleService.createRolePermission(role, getRule(), getPermission(), getDescription()); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create role permission"); + } + setupResponse(rolePermission, role); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRoleCmd.java new file mode 100644 index 00000000000..bd4a7cdacb7 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRoleCmd.java @@ -0,0 +1,83 @@ +// 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 com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +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.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.RoleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = DeleteRoleCmd.APINAME, description = "Deletes a role", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class DeleteRoleCmd extends BaseCmd { + public static final String APINAME = "deleteRole"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Cannot find the role with provided id"); + } + CallContext.current().setEventDetails("Role id: " + role.getId()); + boolean result = roleService.deleteRole(role); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRolePermissionCmd.java new file mode 100644 index 00000000000..9c7dc7c9861 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRolePermissionCmd.java @@ -0,0 +1,83 @@ +// 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 com.cloud.user.Account; +import org.apache.cloudstack.acl.RolePermission; +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.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.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = DeleteRolePermissionCmd.APINAME, description = "Deletes a role permission", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class DeleteRolePermissionCmd extends BaseCmd { + public static final String APINAME = "deleteRolePermission"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = RolePermissionResponse.class, + description = "ID of the role permission", validations = {ApiArgValidator.PositiveNumber}) + private Long rolePermissionId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRolePermissionId() { + return rolePermissionId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + RolePermission rolePermission = roleService.findRolePermission(getRolePermissionId()); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role permission id provided"); + } + CallContext.current().setEventDetails("Role permission id: " + rolePermission.getId()); + boolean result = roleService.deleteRolePermission(rolePermission); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolePermissionsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolePermissionsCmd.java new file mode 100644 index 00000000000..f20abf40146 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolePermissionsCmd.java @@ -0,0 +1,106 @@ +// 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 com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +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.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.RolePermissionResponse; +import org.apache.cloudstack.api.response.RoleResponse; + +import java.util.ArrayList; +import java.util.List; + + +@APICommand(name = ListRolePermissionsCmd.APINAME, description = "Lists role permissions", responseObject = RolePermissionResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class ListRolePermissionsCmd extends BaseCmd { + public static final String APINAME = "listRolePermissions"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final List rolePermissions, final Long roleId) { + final Role roleProvided = roleService.findRole(roleId); + final ListResponse response = new ListResponse<>(); + final List rolePermissionResponses = new ArrayList<>(); + for (final RolePermission rolePermission : rolePermissions) { + final RolePermissionResponse rolePermissionResponse = new RolePermissionResponse(); + Role role = roleProvided; + if (role == null) { + role = roleService.findRole(rolePermission.getRoleId()); + } + rolePermissionResponse.setRoleId(role.getUuid()); + rolePermissionResponse.setRoleName(role.getName()); + rolePermissionResponse.setId(rolePermission.getUuid()); + rolePermissionResponse.setRule(rolePermission.getRule()); + rolePermissionResponse.setRulePermission(rolePermission.getPermission()); + rolePermissionResponse.setDescription(rolePermission.getDescription()); + rolePermissionResponse.setObjectName("rolepermission"); + rolePermissionResponses.add(rolePermissionResponse); + } + response.setResponses(rolePermissionResponses); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException { + final List rolePermissions = roleService.findAllPermissionsBy(getRoleId()); + setupResponse(rolePermissions, getRoleId()); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java new file mode 100644 index 00000000000..5cf870bfc06 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java @@ -0,0 +1,128 @@ +// 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 com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.Role; +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.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.RoleResponse; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@APICommand(name = ListRolesCmd.APINAME, description = "Lists dynamic roles in CloudStack", responseObject = RoleResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin}) +public class ListRolesCmd extends BaseCmd { + public static final String APINAME = "listRoles"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "List role by role ID.") + private Long id; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "List role by role name.") + private String roleName; + + @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "List role by role type, valid options are: Admin, ResourceAdmin, DomainAdmin, User.") + private String roleType; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getName() { + return roleName; + } + + public RoleType getRoleType() { + if (!Strings.isNullOrEmpty(roleType)) { + return RoleType.valueOf(roleType); + } + return null; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final List roles) { + final ListResponse response = new ListResponse<>(); + final List roleResponses = new ArrayList<>(); + for (final Role role : roles) { + if (role == null) { + continue; + } + final RoleResponse roleResponse = new RoleResponse(); + roleResponse.setId(role.getUuid()); + roleResponse.setRoleName(role.getName()); + roleResponse.setRoleType(role.getRoleType()); + roleResponse.setDescription(role.getDescription()); + roleResponse.setObjectName("role"); + roleResponses.add(roleResponse); + } + response.setResponses(roleResponses); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final List roles; + if (getId() != null && getId() > 0L) { + roles = Collections.singletonList(roleService.findRole(getId())); + } else if (!Strings.isNullOrEmpty(getName())) { + roles = roleService.findRolesByName(getName()); + } else if (getRoleType() != null){ + roles = roleService.findRolesByType(getRoleType()); + } else { + roles = roleService.listRoles(); + } + setupResponse(roles); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java new file mode 100644 index 00000000000..e17fc6f5714 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java @@ -0,0 +1,108 @@ +// 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 com.cloud.user.Account; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.Role; +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.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.RoleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = UpdateRoleCmd.APINAME, description = "Updates a role", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class UpdateRoleCmd extends BaseCmd { + public static final String APINAME = "updateRole"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + @Parameter(name = ApiConstants.NAME, type = BaseCmd.CommandType.STRING, description = "creates a role with this unique name") + private String roleName; + + @Parameter(name = ApiConstants.TYPE, type = BaseCmd.CommandType.STRING, description = "The type of the role, valid options are: Admin, ResourceAdmin, DomainAdmin, User") + private String roleType; + + @Parameter(name = ApiConstants.DESCRIPTION, type = BaseCmd.CommandType.STRING, description = "The description of the role") + private String roleDescription; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + public String getRoleName() { + return roleName; + } + + public RoleType getRoleType() { + if (!Strings.isNullOrEmpty(roleType)) { + return RoleType.fromString(roleType); + } + return null; + } + + public String getRoleDescription() { + return roleDescription; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided"); + } + CallContext.current().setEventDetails("Role: " + getRoleName() + ", type:" + getRoleType() + ", description: " + getRoleDescription()); + boolean result = roleService.updateRole(role, getRoleName(), getRoleType(), getRoleDescription()); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java new file mode 100644 index 00000000000..fd31750c3d8 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java @@ -0,0 +1,110 @@ +// 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 com.cloud.user.Account; +import com.google.common.base.Strings; +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.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.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = UpdateRolePermissionCmd.APINAME, description = "Updates a role permission", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class UpdateRolePermissionCmd extends BaseCmd { + public static final String APINAME = "updateRolePermission"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, required = true, entityType = RolePermissionResponse.class, + description = "ID of the role permission", validations = {ApiArgValidator.PositiveNumber}) + private Long rolePermissionId; + + @Parameter(name = ApiConstants.RULE, type = CommandType.STRING, required = true, + description = "The name of the API 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 Long getRolePermissionId() { + return rolePermissionId; + } + + 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/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + RolePermission rolePermission = roleService.findRolePermission(getRolePermissionId()); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role permission id provided"); + } + CallContext.current().setEventDetails("Role permission id: " + rolePermission.getId() + ", rule:" + getRule() + ", permission: " + getPermission() + ", description: " + getDescription()); + boolean result = roleService.updateRolePermission(rolePermission, getRule(), getPermission(), getDescription()); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java index 0124d5997b3..45f790fb70b 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.config; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.RoleService; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -81,6 +83,10 @@ public class UpdateCfgCmd extends BaseCmd { return cfgName; } + public void setCfgName(final String cfgName) { + this.cfgName = cfgName; + } + public String getValue() { return value; } @@ -117,6 +123,12 @@ public class UpdateCfgCmd extends BaseCmd { @Override public void execute() { + if (Strings.isNullOrEmpty(getCfgName())) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Empty configuration name provided"); + } + if (getCfgName().equalsIgnoreCase(RoleService.EnableDynamicApiChecker.key())) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Restricted configuration update not allowed"); + } Configuration cfg = _configService.updateConfiguration(this); if (cfg != null) { ConfigurationResponse response = _responseGenerator.createConfigurationResponse(cfg); diff --git a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java index e6696e17ff0..cb6df4b32a2 100644 --- a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java @@ -48,6 +48,7 @@ public class ListCapabilitiesCmd extends BaseCmd { Map capabilities = _mgr.listCapabilities(this); CapabilitiesResponse response = new CapabilitiesResponse(); response.setSecurityGroupsEnabled((Boolean)capabilities.get("securityGroupsEnabled")); + response.setDynamicRolesEnabled(roleService.isEnabled()); response.setCloudStackVersion((String)capabilities.get("cloudStackVersion")); response.setUserPublicTemplateEnabled((Boolean)capabilities.get("userPublicTemplateEnabled")); response.setSupportELB((String)capabilities.get("supportELB")); diff --git a/api/src/org/apache/cloudstack/api/response/AccountResponse.java b/api/src/org/apache/cloudstack/api/response/AccountResponse.java index 2e50c51858a..7b48a1ea8a1 100644 --- a/api/src/org/apache/cloudstack/api/response/AccountResponse.java +++ b/api/src/org/apache/cloudstack/api/response/AccountResponse.java @@ -21,6 +21,7 @@ import java.util.Map; import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; @@ -43,6 +44,18 @@ public class AccountResponse extends BaseResponse implements ResourceLimitAndCou @Param(description = "account type (admin, domain-admin, user)") private Short accountType; + @SerializedName(ApiConstants.ROLE_ID) + @Param(description = "the ID of the role") + private String roleId; + + @SerializedName(ApiConstants.ROLE_TYPE) + @Param(description = "the type of the role (Admin, ResourceAdmin, DomainAdmin, User)") + private String roleType; + + @SerializedName(ApiConstants.ROLE_NAME) + @Param(description = "the name of the role") + private String roleName; + @SerializedName(ApiConstants.DOMAIN_ID) @Param(description = "id of the Domain the account belongs too") private String domainId; @@ -260,6 +273,20 @@ public class AccountResponse extends BaseResponse implements ResourceLimitAndCou this.accountType = accountType; } + public void setRoleId(String roleId) { + this.roleId = roleId; + } + + public void setRoleType(RoleType roleType) { + if (roleType != null) { + this.roleType = roleType.name(); + } + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + public void setDomainId(String domainId) { this.domainId = domainId; } diff --git a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java index f7fdb95fb6e..f3f87072724 100644 --- a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java +++ b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java @@ -29,6 +29,10 @@ public class CapabilitiesResponse extends BaseResponse { @Param(description = "true if security groups support is enabled, false otherwise") private boolean securityGroupsEnabled; + @SerializedName("dynamicrolesenabled") + @Param(description = "true if dynamic role-based api checker is enabled, false otherwise") + private boolean dynamicRolesEnabled; + @SerializedName("cloudstackversion") @Param(description = "version of the cloud stack") private String cloudStackVersion; @@ -77,6 +81,10 @@ public class CapabilitiesResponse extends BaseResponse { this.securityGroupsEnabled = securityGroupsEnabled; } + public void setDynamicRolesEnabled(boolean dynamicRolesEnabled) { + this.dynamicRolesEnabled = dynamicRolesEnabled; + } + public void setCloudStackVersion(String cloudStackVersion) { this.cloudStackVersion = cloudStackVersion; } diff --git a/api/src/org/apache/cloudstack/api/response/RolePermissionResponse.java b/api/src/org/apache/cloudstack/api/response/RolePermissionResponse.java new file mode 100644 index 00000000000..ac1c5298c1e --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/RolePermissionResponse.java @@ -0,0 +1,101 @@ +// 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 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; + +@EntityReference(value = RolePermission.class) +public class RolePermissionResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) + @Param(description = "the ID of the role permission") + private String id; + + @SerializedName(ApiConstants.ROLE_ID) + @Param(description = "the ID of the role to which the role permission belongs") + private String roleId; + + @SerializedName(ApiConstants.ROLE_NAME) + @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; + } + + public void setId(String id) { + this.id = id; + } + + public String getRoleId() { + return roleId; + } + + public void setRoleId(String roleId) { + this.roleId = roleId; + } + + public String getRoleName() { + return roleName; + } + + 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; + } +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/response/RoleResponse.java b/api/src/org/apache/cloudstack/api/response/RoleResponse.java new file mode 100644 index 00000000000..fd4bf28e618 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/RoleResponse.java @@ -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.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; + + @SerializedName(ApiConstants.NAME) + @Param(description = "the name of the role") + private String roleName; + + @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; + + 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; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/UserResponse.java b/api/src/org/apache/cloudstack/api/response/UserResponse.java index 40e1561cb8d..69fe15e9887 100644 --- a/api/src/org/apache/cloudstack/api/response/UserResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserResponse.java @@ -20,6 +20,7 @@ import java.util.Date; import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; @@ -65,6 +66,18 @@ public class UserResponse extends BaseResponse { @Param(description = "the account type of the user") private Short accountType; + @SerializedName(ApiConstants.ROLE_ID) + @Param(description = "the ID of the role") + private String roleId; + + @SerializedName(ApiConstants.ROLE_TYPE) + @Param(description = "the type of the role") + private String roleType; + + @SerializedName(ApiConstants.ROLE_NAME) + @Param(description = "the name of the role") + private String roleName; + @SerializedName("domainid") @Param(description = "the domain ID of the user") private String domainId; @@ -174,6 +187,20 @@ public class UserResponse extends BaseResponse { this.accountType = accountType; } + public void setRoleId(String roleId) { + this.roleId = roleId; + } + + public void setRoleType(RoleType roleType) { + if (roleType != null) { + this.roleType = roleType.name(); + } + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + public String getDomainId() { return domainId; } diff --git a/api/test/org/apache/cloudstack/acl/RoleTypeTest.java b/api/test/org/apache/cloudstack/acl/RoleTypeTest.java new file mode 100644 index 00000000000..611b761014f --- /dev/null +++ b/api/test/org/apache/cloudstack/acl/RoleTypeTest.java @@ -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 com.cloud.user.Account; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Arrays; + +public class RoleTypeTest { + + @Test + public void testValidRoleTypeFromString() { + for (RoleType roleType : RoleType.values()) { + Assert.assertEquals(RoleType.fromString(roleType.name()), roleType); + } + } + + @Test + public void testInvalidRoleTypeFromString() { + for (String roleType : Arrays.asList(null, "", "admin", "12345%&^*")) { + try { + RoleType.fromString(roleType); + Assert.fail("Invalid roletype provided, exception was expected"); + } catch (IllegalStateException e) { + Assert.assertEquals(e.getMessage(), "Illegal RoleType name provided"); + } + } + } + + @Test + public void testDefaultRoleMaskByValue() { + Assert.assertEquals(RoleType.fromMask(1), RoleType.Admin); + Assert.assertEquals(RoleType.fromMask(2), RoleType.ResourceAdmin); + Assert.assertEquals(RoleType.fromMask(4), RoleType.DomainAdmin); + Assert.assertEquals(RoleType.fromMask(8), RoleType.User); + Assert.assertEquals(RoleType.fromMask(0), RoleType.Unknown); + } + + @Test + public void testGetByAccountType() { + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_NORMAL), RoleType.User); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_ADMIN), RoleType.Admin); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_DOMAIN_ADMIN), RoleType.DomainAdmin); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN), RoleType.ResourceAdmin); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_PROJECT), RoleType.Unknown); + } + + @Test + public void testGetRoleByAccountTypeWhenRoleIdIsProvided() { + Assert.assertEquals(RoleType.getRoleByAccountType(123L, Account.ACCOUNT_TYPE_ADMIN), Long.valueOf(123L)); + Assert.assertEquals(RoleType.getRoleByAccountType(1234L, null), Long.valueOf(1234L)); + } + + @Test + public void testGetRoleByAccountTypeForDefaultAccountTypes() { + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_ADMIN), (Long) RoleType.Admin.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_NORMAL), (Long) RoleType.User.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_DOMAIN_ADMIN), (Long) RoleType.DomainAdmin.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN), (Long) RoleType.ResourceAdmin.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_PROJECT), null); + } + + @Test + public void testGetAccountTypeByRoleWhenRoleIsNull() { + for (Short accountType: Arrays.asList( + Account.ACCOUNT_TYPE_NORMAL, + Account.ACCOUNT_TYPE_ADMIN, + Account.ACCOUNT_TYPE_DOMAIN_ADMIN, + Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN, + Account.ACCOUNT_TYPE_PROJECT, + (short) 12345)) { + Assert.assertEquals(RoleType.getAccountTypeByRole(null, accountType), accountType); + } + } + + @Test + public void testGetAccountTypeByRole() { + Role role = Mockito.mock(Role.class); + Mockito.when(role.getRoleType()).thenReturn(RoleType.Admin); + Mockito.when(role.getId()).thenReturn(100L); + Assert.assertEquals(RoleType.getAccountTypeByRole(role, null), (Short) RoleType.Admin.getAccountType()); + } +} \ No newline at end of file diff --git a/api/test/org/apache/cloudstack/acl/RuleTest.java b/api/test/org/apache/cloudstack/acl/RuleTest.java new file mode 100644 index 00000000000..08bd775bd08 --- /dev/null +++ b/api/test/org/apache/cloudstack/acl/RuleTest.java @@ -0,0 +1,98 @@ +// 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 com.cloud.exception.InvalidParameterValueException; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +public class RuleTest { + + @Test + public void testToString() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertEquals(rule.toString(), "someString"); + } + + @Test + public void testMatchesEmpty() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertFalse(rule.matches("")); + } + + @Test + public void testMatchesNull() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertFalse(rule.matches(null)); + } + + @Test + public void testMatchesSpace() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertFalse(rule.matches(" ")); + } + + @Test + public void testMatchesAPI() throws Exception { + Rule rule = new Rule("someApi"); + Assert.assertTrue(rule.matches("someApi")); + } + + @Test + public void testMatchesWildcardSuffix() throws Exception { + Rule rule = new Rule("list*"); + Assert.assertTrue(rule.matches("listHosts")); + } + + @Test + public void testMatchesWildcardPrefix() throws Exception { + Rule rule = new Rule("*User"); + Assert.assertTrue(rule.matches("createUser")); + } + + @Test + public void testMatchesWildcardMiddle() throws Exception { + Rule rule = new Rule("list*s"); + Assert.assertTrue(rule.matches("listClusters")); + } + + @Test + public void testValidateRuleWithValidData() throws Exception { + for (String rule : Arrays.asList("a", "1", "someApi", "someApi321", "123SomeApi", + "prefix*", "*middle*", "*Suffix", + "*", "**", "f***", "m0nk3yMa**g1c*")) { + Assert.assertEquals(new Rule(rule).toString(), rule); + } + } + + @Test + public void testValidateRuleWithInvalidData() throws Exception { + for (String rule : Arrays.asList(null, "", " ", " ", "\n", "\t", "\r", "\"", "\'", + "^someApi$", "^someApi", "some$", "some-Api;", "some,Api", + "^", "$", "^$", ".*", "\\w+", "r**l3rd0@Kr3", "j@s1n|+|0ȷ", + "[a-z0-9-]+", "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$")) { + try { + new Rule(rule); + Assert.fail("Invalid rule, exception was expected"); + } catch (InvalidParameterValueException e) { + Assert.assertTrue(e.getMessage().startsWith("Only API names and wildcards are allowed")); + } + } + } +} \ No newline at end of file diff --git a/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java index a07608a29fc..5557c455263 100644 --- a/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java +++ b/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java @@ -19,6 +19,7 @@ package org.apache.cloudstack.api.command.test; import junit.framework.Assert; import junit.framework.TestCase; +import org.apache.cloudstack.acl.RoleService; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -51,22 +52,46 @@ public class UpdateCfgCmdTest extends TestCase { updateCfgCmd = new UpdateCfgCmd(); } + @Test + public void testExecuteForEmptyCfgName() { + updateCfgCmd._configService = configService; + + try { + updateCfgCmd.execute(); + } catch (ServerApiException exception) { + Assert.assertEquals("Empty configuration name provided", exception.getDescription()); + } + } + + @Test + public void testExecuteForRestrictedCfg() { + updateCfgCmd._configService = configService; + updateCfgCmd.setCfgName(RoleService.EnableDynamicApiChecker.key()); + + try { + updateCfgCmd.execute(); + } catch (ServerApiException exception) { + Assert.assertEquals("Restricted configuration update not allowed", exception.getDescription()); + } + } + @Test public void testExecuteForEmptyResult() { updateCfgCmd._configService = configService; + updateCfgCmd.setCfgName("some.cfg"); try { updateCfgCmd.execute(); } catch (ServerApiException exception) { Assert.assertEquals("Failed to update config", exception.getDescription()); } - } @Test public void testExecuteForNullResult() { updateCfgCmd._configService = configService; + updateCfgCmd.setCfgName("some.cfg"); try { Mockito.when(configService.updateConfiguration(updateCfgCmd)).thenReturn(null); @@ -91,6 +116,7 @@ public class UpdateCfgCmdTest extends TestCase { Configuration cfg = Mockito.mock(Configuration.class); updateCfgCmd._configService = configService; updateCfgCmd._responseGenerator = responseGenerator; + updateCfgCmd.setCfgName("some.cfg"); try { Mockito.when(configService.updateConfiguration(updateCfgCmd)).thenReturn(cfg); diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 54276e45796..badf61bff88 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -1070,9 +1070,16 @@ label.retry.interval=Retry Interval label.review=Review label.revoke.project.invite=Revoke invitation label.role=Role +label.roles=Roles +label.roletype=Role Type +label.add.role=Add Role +label.edit.role=Edit Role +label.delete.role=Delete Role label.root.certificate=Root certificate label.root.disk.controller=Root disk controller label.root.disk.offering=Root Disk Offering +label.permission=Permission +label.rule=Rule label.rules=Rules label.running.vms=Running VMs label.s3.access_key=Access Key diff --git a/client/pom.xml b/client/pom.xml index bcb139109ca..f28526af6a8 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -50,6 +50,11 @@ cloud-plugin-acl-static-role-based ${project.version} + + org.apache.cloudstack + cloud-plugin-acl-dynamic-role-based + ${project.version} + org.apache.cloudstack cloud-plugin-dedicated-resources diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.deprecated similarity index 98% rename from client/tomcatconf/commands.properties.in rename to client/tomcatconf/commands.properties.deprecated index a69605c1ea4..d6c95cf96dc 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.deprecated @@ -782,3 +782,13 @@ listOpenDaylightControllers=1 ### GloboDNS commands addGloboDnsHost=1 + +### Role commands +createRole=1 +listRoles=1 +updateRole=1 +deleteRole=1 +createRolePermission=1 +listRolePermissions=1 +updateRolePermission=1 +deleteRolePermission=1 diff --git a/debian/cloudstack-management.install b/debian/cloudstack-management.install index 4e016dfe292..c66938263e8 100644 --- a/debian/cloudstack-management.install +++ b/debian/cloudstack-management.install @@ -18,7 +18,6 @@ /etc/cloudstack/management/catalina.policy /etc/cloudstack/management/catalina.properties /etc/cloudstack/management/logging.properties -/etc/cloudstack/management/commands.properties /etc/cloudstack/management/ehcache.xml /etc/cloudstack/management/server-ssl.xml /etc/cloudstack/management/server-nonssl.xml diff --git a/developer/developer-prefill.sql b/developer/developer-prefill.sql index 3097203b41d..5d301f5ae40 100644 --- a/developer/developer-prefill.sql +++ b/developer/developer-prefill.sql @@ -78,6 +78,11 @@ INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'pool.storage.capacity.disablethreshold', '0.95'); +-- Enable dynamic RBAC by default for fresh deployments +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'RoleService', + 'dynamic.apichecker.enabled', 'true'); + -- Add developer configuration entry; allows management server to be run as a user other than "cloud" INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', diff --git a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 9dd5571dec4..f541f8d997e 100644 --- a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -113,6 +113,8 @@ + + diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java index dab2b46a575..4dd8aeb330b 100755 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -1568,7 +1568,7 @@ public class Upgrade410to420 implements DbUpgrade { s_logger.debug("Index already exists on host_details - not adding new one"); } else { // add the index - PreparedStatement pstmtUpdate = conn.prepareStatement("ALTER IGNORE TABLE `cloud`.`host_details` ADD INDEX `fk_host_details__host_id` (`host_id`)"); + PreparedStatement pstmtUpdate = conn.prepareStatement("ALTER TABLE `cloud`.`host_details` ADD INDEX `fk_host_details__host_id` (`host_id`)"); pstmtUpdate.executeUpdate(); s_logger.debug("Index did not exist on host_details - added new one"); pstmtUpdate.close(); diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade452to453.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade452to453.java index d1c4661607e..dc0152be775 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade452to453.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade452to453.java @@ -17,12 +17,21 @@ package com.cloud.upgrade.dao; +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.db.ScriptRunner; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; +import org.apache.cloudstack.acl.RoleType; import org.apache.log4j.Logger; import java.io.File; +import java.io.FileReader; +import java.io.IOException; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; public class Upgrade452to453 implements DbUpgrade { final static Logger s_logger = Logger.getLogger(Upgrade452to453.class); @@ -53,6 +62,147 @@ public class Upgrade452to453 implements DbUpgrade { @Override public void performDataMigration(Connection conn) { + setupRolesAndPermissionsForDynamicRBAC(conn); + } + + private void createDefaultRole(final Connection conn, final Long id, final String name, final RoleType roleType) { + final String insertSql = String.format("INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (%d, UUID(), '%s', '%s', 'Default %s role');", + id, name, roleType.name(), roleType.name().toLowerCase()); + try ( PreparedStatement updatePstmt = conn.prepareStatement(insertSql) ) { + updatePstmt.executeUpdate(); + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to create default role with id: " + id + " name: " + name, e); + } + } + + private void createRoleMapping(final Connection conn, final Long roleId, final String apiName) { + final String insertSql = String.format("INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), %d, '%s', 'ALLOW') ON DUPLICATE KEY UPDATE rule=rule;", + roleId, apiName); + try ( PreparedStatement updatePstmt = conn.prepareStatement(insertSql)) { + updatePstmt.executeUpdate(); + } catch (SQLException ignored) { + s_logger.debug("Unable to insert mapping for role id:" + roleId + " apiName: " + apiName); + } + } + + private void addRoleColumnAndMigrateAccountTable(final Connection conn, final RoleType[] roleTypes) { + // Add role_id column to account table + final String alterTableSql = "ALTER TABLE `cloud`.`account` ADD COLUMN `role_id` bigint(20) unsigned COMMENT 'role id for this account' AFTER `type`, " + + "ADD KEY `fk_account__role_id` (`role_id`), " + + "ADD CONSTRAINT `fk_account__role_id` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`);"; + try (PreparedStatement pstmt = conn.prepareStatement(alterTableSql)) { + pstmt.executeUpdate(); + s_logger.info("Altered cloud.account table and added column role_id"); + } catch (SQLException e) { + if (e.getMessage().contains("role_id")) { + s_logger.warn("cloud.account table already has the role_id column, skipping altering table and migration of accounts"); + return; + } else { + throw new CloudRuntimeException("Unable to create column quota_calculated in table cloud_usage.cloud_usage", e); + } + } + // Migrate existing account to one of default roles based on account type + migrateAccountsToDefaultRoles(conn, roleTypes); + } + + private void migrateAccountsToDefaultRoles(final Connection conn, final RoleType[] roleTypes) { + // Migrate existing accounts to default roles based on account type + try (PreparedStatement selectStatement = conn.prepareStatement("SELECT `id`, `type` FROM `cloud`.`account`;"); + ResultSet selectResultSet = selectStatement.executeQuery()) { + while (selectResultSet.next()) { + Long accountId = selectResultSet.getLong(1); + Short accountType = selectResultSet.getShort(2); + Long roleId = null; + for (RoleType roleType : roleTypes) { + if (roleType.getAccountType() == accountType) { + roleId = roleType.getId(); + break; + } + } + // Skip is account type does not match any of the default roles + if (roleId == null) { + continue; + } + try (PreparedStatement updateStatement = conn.prepareStatement("UPDATE `cloud`.`account` SET role_id = ? WHERE id = ?;")) { + updateStatement.setLong(1, roleId); + updateStatement.setLong(2, accountId); + updateStatement.executeUpdate(); + } catch (SQLException e) { + s_logger.error("Failed to update cloud.account role_id for account id:" + accountId + " with exception: " + e.getMessage()); + throw new CloudRuntimeException("Exception while updating cloud.account role_id", e); + } + } + } catch (SQLException e) { + throw new CloudRuntimeException("Exception while migrating existing account table's role_id column to a role based on account type", e); + } + s_logger.debug("Done migrating existing accounts to use one of default roles based on account type"); + } + + private void setupRolesAndPermissionsForDynamicRBAC(final Connection conn) { + // If there are existing roles, avoid resetting data + try (PreparedStatement selectStatement = conn.prepareStatement("SELECT * FROM `cloud`.`roles`")) { + ResultSet resultSet = selectStatement.executeQuery(); + if (resultSet != null && resultSet.next()) { + resultSet.close(); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Found existing roles. Skipping migration of commands.properties to dynamic roles table."); + } + return; + } + } catch (SQLException e) { + s_logger.error("Unable to find existing roles, if you need to add default roles please add them manually. Giving up!"); + return; + } + + // Add default roles + RoleType[] roleTypes = new RoleType[] {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}; + for (RoleType roleType: roleTypes) { + createDefaultRole(conn, roleType.getId(), roleType.name(), roleType); + } + + // Add role_id column to account and map existing accounts to default roles + addRoleColumnAndMigrateAccountTable(conn, roleTypes); + + // Add default set of role-api mapping when commands.properties file is not found + Map apiMap = PropertiesUtil.processConfigFile(new String[] { PropertiesUtil.getDefaultApiCommandsFileName() }); + if (apiMap == null || apiMap.isEmpty()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("The commands.properties file and default role permissions were not found. " + + "Assuming new installation, configuring default role-api mappings."); + } + String script = Script.findScript("", "db/create-default-role-api-mappings.sql"); + if (script == null) { + s_logger.error("Unable to find default role-api mapping sql file, please configure api per role manually"); + return; + } + try(FileReader reader = new FileReader(new File(script));) { + ScriptRunner runner = new ScriptRunner(conn, false, true); + runner.runScript(reader); + } catch (SQLException | IOException e) { + s_logger.error("Unable to insert default api-role mappings from file: " + script + ". Please configure api per role manually, giving up!", e); + } + } else { + // If commands.properties file exists, use it to create the mappings + for (RoleType roleType : roleTypes) { + // Allow all for root admin + if (roleType == RoleType.Admin) { + createRoleMapping(conn, roleType.getId(), "*"); + continue; + } + for (Map.Entry entry : apiMap.entrySet()) { + String apiName = entry.getKey(); + String roleMask = entry.getValue(); + try { + short cmdPermissions = Short.parseShort(roleMask); + if ((cmdPermissions & roleType.getMask()) != 0) { + createRoleMapping(conn, roleType.getId(), apiName); + } + } catch (NumberFormatException nfe) { + s_logger.info("Malformed key=value pair for entry: " + entry.toString()); + } + } + } + } } @Override @@ -61,7 +211,6 @@ public class Upgrade452to453 implements DbUpgrade { if (script == null) { throw new CloudRuntimeException("Unable to find db/schema-452to453-cleanup.sql"); } - return new File[] {new File(script)}; } } diff --git a/engine/schema/src/com/cloud/user/AccountVO.java b/engine/schema/src/com/cloud/user/AccountVO.java index 0f5a0446e93..a504d2fdaec 100644 --- a/engine/schema/src/com/cloud/user/AccountVO.java +++ b/engine/schema/src/com/cloud/user/AccountVO.java @@ -16,8 +16,8 @@ // under the License. package com.cloud.user; -import java.util.Date; -import java.util.UUID; +import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.acl.RoleType; import javax.persistence.Column; import javax.persistence.Entity; @@ -27,8 +27,8 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; - -import com.cloud.utils.db.GenericDao; +import java.util.Date; +import java.util.UUID; @Entity @Table(name = "account") @@ -44,6 +44,9 @@ public class AccountVO implements Account { @Column(name = "type") private short type = ACCOUNT_TYPE_NORMAL; + @Column(name = "role_id") + private Long roleId; + @Column(name = "domain_id") private long domainId; @@ -78,13 +81,21 @@ public class AccountVO implements Account { uuid = UUID.randomUUID().toString(); } - public AccountVO(String accountName, long domainId, String networkDomain, short type, String uuid) { + public AccountVO(final String accountName, final long domainId, final String networkDomain, final short type, final String uuid) { this.accountName = accountName; this.domainId = domainId; this.networkDomain = networkDomain; this.type = type; - state = State.enabled; + this.state = State.enabled; this.uuid = uuid; + this.roleId = RoleType.getRoleByAccountType(null, type); + } + + public AccountVO(final String accountName, final long domainId, final String networkDomain, final short type, final Long roleId, final String uuid) { + this(accountName, domainId, networkDomain, type, uuid); + if (roleId != null) { + this.roleId = roleId; + } } public void setNeedsCleanup(boolean value) { @@ -122,6 +133,14 @@ public class AccountVO implements Account { this.type = type; } + public Long getRoleId() { + return roleId; + } + + public void setRoleId(long roleId) { + this.roleId = roleId; + } + @Override public long getDomainId() { return domainId; diff --git a/engine/schema/src/com/cloud/user/dao/AccountDao.java b/engine/schema/src/com/cloud/user/dao/AccountDao.java index 4c7ce8e31b7..374c9cc43d6 100644 --- a/engine/schema/src/com/cloud/user/dao/AccountDao.java +++ b/engine/schema/src/com/cloud/user/dao/AccountDao.java @@ -41,6 +41,8 @@ public interface AccountDao extends GenericDao { List findActiveAccountsForDomain(Long domain); + List findAccountsByRole(Long roleId); + void markForCleanup(long accountId); List listAccounts(String accountName, Long domainId, Filter filter); diff --git a/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java b/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java index 9ae279fe5f0..955c8d5003a 100755 --- a/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java +++ b/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java @@ -46,7 +46,7 @@ import com.cloud.utils.db.TransactionLegacy; public class AccountDaoImpl extends GenericDaoBase implements AccountDao { private static final Logger s_logger = Logger.getLogger(AccountDaoImpl.class); private static final String FIND_USER_ACCOUNT_BY_API_KEY = "SELECT u.id, u.username, u.account_id, u.secret_key, u.state, " - + "a.id, a.account_name, a.type, a.domain_id, a.state " + "FROM `cloud`.`user` u, `cloud`.`account` a " + + "a.id, a.account_name, a.type, a.role_id, a.domain_id, a.state " + "FROM `cloud`.`user` u, `cloud`.`account` a " + "WHERE u.account_id = a.id AND u.api_key = ? and u.removed IS NULL"; protected final SearchBuilder AllFieldsSearch; @@ -55,6 +55,7 @@ public class AccountDaoImpl extends GenericDaoBase implements A protected final SearchBuilder CleanupForRemovedAccountsSearch; protected final SearchBuilder CleanupForDisabledAccountsSearch; protected final SearchBuilder NonProjectAccountSearch; + protected final SearchBuilder AccountByRoleSearch; protected final GenericSearchBuilder AccountIdsSearch; public AccountDaoImpl() { @@ -98,6 +99,10 @@ public class AccountDaoImpl extends GenericDaoBase implements A AccountIdsSearch.selectFields(AccountIdsSearch.entity().getId()); AccountIdsSearch.and("ids", AccountIdsSearch.entity().getDomainId(), Op.IN); AccountIdsSearch.done(); + + AccountByRoleSearch = createSearchBuilder(); + AccountByRoleSearch.and("roleId", AccountByRoleSearch.entity().getRoleId(), SearchCriteria.Op.EQ); + AccountByRoleSearch.done(); } @Override @@ -142,8 +147,9 @@ public class AccountDaoImpl extends GenericDaoBase implements A AccountVO a = new AccountVO(rs.getLong(6)); a.setAccountName(rs.getString(7)); a.setType(rs.getShort(8)); - a.setDomainId(rs.getLong(9)); - a.setState(State.valueOf(rs.getString(10))); + a.setRoleId(rs.getLong(9)); + a.setDomainId(rs.getLong(10)); + a.setState(State.valueOf(rs.getString(11))); userAcctPair = new Pair(u, a); } @@ -260,6 +266,13 @@ public class AccountDaoImpl extends GenericDaoBase implements A return listBy(sc); } + @Override + public List findAccountsByRole(Long roleId) { + SearchCriteria sc = AccountByRoleSearch.create(); + sc.setParameters("roleId", roleId); + return listBy(sc); + } + @Override public void markForCleanup(long accountId) { AccountVO account = findByIdIncludingRemoved(accountId); diff --git a/engine/schema/src/org/apache/cloudstack/acl/RolePermissionVO.java b/engine/schema/src/org/apache/cloudstack/acl/RolePermissionVO.java new file mode 100644 index 00000000000..af0d67e2ce6 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/RolePermissionVO.java @@ -0,0 +1,109 @@ +// 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.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; + + @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; + + public RolePermissionVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public RolePermissionVO(final long roleId, final String rule, final Permission permission, final String description) { + this(); + 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() { + return roleId; + } + + public void setRoleId(long roleId) { + 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; + } +} \ No newline at end of file diff --git a/engine/schema/src/org/apache/cloudstack/acl/RoleVO.java b/engine/schema/src/org/apache/cloudstack/acl/RoleVO.java new file mode 100644 index 00000000000..f3404ab6d79 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/RoleVO.java @@ -0,0 +1,106 @@ +// 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 com.cloud.utils.db.GenericDao; + +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.Date; +import java.util.UUID; + +@Entity +@Table(name = "roles") +public class RoleVO implements Role { + @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 = "role_type", nullable = false) + @Enumerated(value = EnumType.STRING) + private RoleType roleType = RoleType.User; + + @Column(name = "description") + private String description; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + public RoleVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public RoleVO(final String name, final RoleType roleType, final String description) { + this(); + this.name = name; + this.roleType = roleType; + this.description = description; + } + + public RoleVO(final long id, final String name, final RoleType roleType, final String description) { + this(name, roleType, description); + this.id = id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public RoleType getRoleType() { + return roleType; + } + + public void setRoleType(RoleType roleType) { + this.roleType = roleType; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java new file mode 100644 index 00000000000..e53654d998e --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java @@ -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 com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.acl.RoleVO; + +import java.util.List; + +public interface RoleDao extends GenericDao { + List findAllByName(String roleName); + List findAllByRoleType(RoleType type); +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDaoImpl.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDaoImpl.java new file mode 100644 index 00000000000..c7eb496213e --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDaoImpl.java @@ -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 com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.acl.RoleVO; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.List; + +@Component +@Local(value = {RoleDao.class}) +public class RoleDaoImpl extends GenericDaoBase implements RoleDao { + private final SearchBuilder RoleByNameSearch; + private final SearchBuilder RoleByTypeSearch; + + public RoleDaoImpl() { + super(); + + RoleByNameSearch = createSearchBuilder(); + RoleByNameSearch.and("roleName", RoleByNameSearch.entity().getName(), SearchCriteria.Op.LIKE); + RoleByNameSearch.done(); + + RoleByTypeSearch = createSearchBuilder(); + RoleByTypeSearch.and("roleType", RoleByTypeSearch.entity().getRoleType(), SearchCriteria.Op.EQ); + RoleByTypeSearch.done(); + } + + @Override + public List findAllByName(final String roleName) { + SearchCriteria sc = RoleByNameSearch.create(); + sc.setParameters("roleName", "%" + roleName + "%"); + return listBy(sc); + } + + @Override + public List findAllByRoleType(final RoleType type) { + SearchCriteria sc = RoleByTypeSearch.create(); + sc.setParameters("roleType", type); + return listBy(sc); + } +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java new file mode 100644 index 00000000000..dd68d0f6b2d --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java @@ -0,0 +1,27 @@ +// 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 com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.acl.RolePermissionVO; + +import java.util.List; + +public interface RolePermissionsDao extends GenericDao { + List findAllByRoleId(Long roleId); +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java new file mode 100644 index 00000000000..167cf095dd4 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java @@ -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.acl.dao; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.apache.cloudstack.acl.RolePermissionVO; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.List; + +@Component +@Local(value = {RolePermissionsDao.class}) +public class RolePermissionsDaoImpl extends GenericDaoBase implements RolePermissionsDao { + private final SearchBuilder RolePermissionsSearch; + + public RolePermissionsDaoImpl() { + super(); + + RolePermissionsSearch = createSearchBuilder(); + RolePermissionsSearch.and("roleId", RolePermissionsSearch.entity().getRoleId(), SearchCriteria.Op.EQ); + RolePermissionsSearch.done(); + } + + @Override + public List findAllByRoleId(final Long roleId) { + SearchCriteria sc = RolePermissionsSearch.create(); + if (roleId != null && roleId > 0L) { + sc.setParameters("roleId", roleId); + } + return listBy(sc); + } +} diff --git a/plugins/acl/dynamic-role-based/pom.xml b/plugins/acl/dynamic-role-based/pom.xml new file mode 100644 index 00000000000..7fb4d43e029 --- /dev/null +++ b/plugins/acl/dynamic-role-based/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + cloud-plugin-acl-dynamic-role-based + Apache CloudStack Plugin - ACL Dynamic Role Based + + org.apache.cloudstack + cloudstack-plugins + 4.5.3-SNAPSHOT + ../../pom.xml + + diff --git a/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties new file mode 100644 index 00000000000..dda9998224f --- /dev/null +++ b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties @@ -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-dynamic-role-based +parent=api diff --git a/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/spring-acl-dynamic-role-based-context.xml b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/spring-acl-dynamic-role-based-context.xml new file mode 100644 index 00000000000..9ffe465a9aa --- /dev/null +++ b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/spring-acl-dynamic-role-based-context.xml @@ -0,0 +1,33 @@ + + + + + + + diff --git a/plugins/acl/dynamic-role-based/src/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java b/plugins/acl/dynamic-role-based/src/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java new file mode 100644 index 00000000000..f44b0d8ce45 --- /dev/null +++ b/plugins/acl/dynamic-role-based/src/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java @@ -0,0 +1,167 @@ +// 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 com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +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; +import com.google.common.base.Strings; +import org.apache.cloudstack.api.APICommand; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Local(value = APIChecker.class) +public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements APIChecker { + + protected static final Logger LOGGER = Logger.getLogger(DynamicRoleBasedAPIAccessChecker.class); + + @Inject + private AccountService accountService; + @Inject + private RoleService roleService; + + private List services; + private Map> annotationRoleBasedApisMap = new HashMap<>(); + + protected DynamicRoleBasedAPIAccessChecker() { + super(); + for (RoleType roleType : RoleType.values()) { + annotationRoleBasedApisMap.put(roleType, new HashSet()); + } + } + + private void denyApiAccess(final String commandName) throws PermissionDeniedException { + throw new PermissionDeniedException("The API does not exist or is blacklisted for the account's role. " + + "The account with is not allowed to request the api: " + commandName); + } + + private boolean checkPermission(final List permissions, final RolePermission.Permission permissionToCheck, final String commandName) { + if (permissions == null || permissions.isEmpty() || Strings.isNullOrEmpty(commandName)) { + return false; + } + for (final RolePermission permission : permissions) { + if (permission.getPermission() != permissionToCheck) { + continue; + } + try { + if (permission.getRule().matches(commandName)) { + return true; + } + } catch (InvalidParameterValueException e) { + LOGGER.warn("Invalid rule permission, please fix id=" + permission.getId() + " rule=" + permission.getRule()); + } + } + return false; + } + + public boolean isDisabled() { + return !roleService.isEnabled(); + } + + @Override + public boolean checkAccess(User user, String commandName) throws PermissionDeniedException { + if (isDisabled()) { + return true; + } + Account account = accountService.getAccount(user.getAccountId()); + if (account == null) { + throw new PermissionDeniedException("The account id=" + user.getAccountId() + "for user id=" + user.getId() + "is null"); + } + + final Role accountRole = roleService.findRole(account.getRoleId()); + if (accountRole == null || accountRole.getId() < 1L) { + denyApiAccess(commandName); + } + + // Allow all APIs for root admins + if (accountRole.getRoleType() == RoleType.Admin && accountRole.getId() == RoleType.Admin.getId()) { + return true; + } + + final List rolePermissions = roleService.findAllPermissionsBy(accountRole.getId()); + + // Check for allow rules + if (checkPermission(rolePermissions, RolePermission.Permission.ALLOW, commandName)) { + return true; + } + + // Check for deny rules + if (checkPermission(rolePermissions, RolePermission.Permission.DENY, commandName)) { + denyApiAccess(commandName); + } + + // Check annotations + if (annotationRoleBasedApisMap.get(accountRole.getRoleType()) != null + && annotationRoleBasedApisMap.get(accountRole.getRoleType()).contains(commandName)) { + return true; + } + + denyApiAccess(commandName); + return false; + } + + public void addApiToRoleBasedAnnotationsMap(final RoleType roleType, final String commandName) { + if (roleType == null || Strings.isNullOrEmpty(commandName)) { + return; + } + final Set commands = annotationRoleBasedApisMap.get(roleType); + if (commands != null && !commands.contains(commandName)) { + commands.add(commandName); + } + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + return true; + } + + @Override + public boolean start() { + for (PluggableService service : services) { + for (Class clz : service.getCommands()) { + APICommand command = clz.getAnnotation(APICommand.class); + for (RoleType role : command.authorized()) { + addApiToRoleBasedAnnotationsMap(role, command.name()); + } + } + } + return super.start(); + } + + public List getServices() { + return services; + } + + @Inject + public void setServices(List services) { + this.services = services; + } + +} diff --git a/plugins/acl/dynamic-role-based/test/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessCheckerTest.java b/plugins/acl/dynamic-role-based/test/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessCheckerTest.java new file mode 100644 index 00000000000..d96e11e3efa --- /dev/null +++ b/plugins/acl/dynamic-role-based/test/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessCheckerTest.java @@ -0,0 +1,164 @@ +// 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 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 org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import java.lang.reflect.Field; +import java.util.Collections; + +@RunWith(MockitoJUnitRunner.class) +public class DynamicRoleBasedAPIAccessCheckerTest extends TestCase { + + @Mock + private AccountService accountService; + @Mock + private RoleService roleService; + + private DynamicRoleBasedAPIAccessChecker apiAccessChecker; + + private User getTestUser() { + return new UserVO(12L, "some user", "password", "firstName", "lastName", + "email@gmail.com", "GMT", "uuid", User.Source.UNKNOWN); + } + + private Account getTestAccount() { + return new AccountVO("some name", 1L, "network-domain", (short)0, "some-uuid"); + } + + private Role getTestRole() { + return new RoleVO(4L, "SomeRole", RoleType.User, "some description"); + } + + private void setupMockField(final Object obj, final String fieldName, final Object mock) throws NoSuchFieldException, IllegalAccessException { + Field roleDaoField = DynamicRoleBasedAPIAccessChecker.class.getDeclaredField(fieldName); + roleDaoField.setAccessible(true); + roleDaoField.set(obj, mock); + } + + @Override + @Before + public void setUp() throws NoSuchFieldException, IllegalAccessException { + apiAccessChecker = Mockito.spy(new DynamicRoleBasedAPIAccessChecker()); + setupMockField(apiAccessChecker, "accountService", accountService); + setupMockField(apiAccessChecker, "roleService", roleService); + + Mockito.when(accountService.getAccount(Mockito.anyLong())).thenReturn(getTestAccount()); + Mockito.when(roleService.findRole(Mockito.anyLong())).thenReturn((RoleVO) getTestRole()); + + // Enabled plugin + Mockito.doReturn(false).when(apiAccessChecker).isDisabled(); + Mockito.doCallRealMethod().when(apiAccessChecker).checkAccess(Mockito.any(User.class), Mockito.anyString()); + } + + @Test + public void testInvalidAccountCheckAccess() { + Mockito.when(accountService.getAccount(Mockito.anyLong())).thenReturn(null); + try { + apiAccessChecker.checkAccess(getTestUser(), "someApi"); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testInvalidAccountRoleCheckAccess() { + Mockito.when(roleService.findRole(Mockito.anyLong())).thenReturn(null); + try { + apiAccessChecker.checkAccess(getTestUser(), "someApi"); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testDefaultRootAdminAccess() { + Mockito.when(accountService.getAccount(Mockito.anyLong())).thenReturn(new AccountVO("root admin", 1L, null, (short)1, "some-uuid")); + Mockito.when(roleService.findRole(Mockito.anyLong())).thenReturn(new RoleVO(1L, "SomeRole", RoleType.Admin, "default root admin role")); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), "anyApi")); + } + + @Test + public void testInvalidRolePermissionsCheckAccess() { + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(null); + try { + apiAccessChecker.checkAccess(getTestUser(), "someApi"); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testValidAllowRolePermissionApiCheckAccess() { + final String allowedApiName = "someAllowedApi"; + final RolePermission permission = new RolePermissionVO(1L, allowedApiName, RolePermission.Permission.ALLOW, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName)); + } + + @Test + public void testValidAllowRolePermissionWildcardCheckAccess() { + final String allowedApiName = "someAllowedApi"; + final RolePermission permission = new RolePermissionVO(1L, "some*", RolePermission.Permission.ALLOW, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName)); + } + + @Test + public void testValidDenyRolePermissionApiCheckAccess() { + final String denyApiName = "someDeniedApi"; + final RolePermission permission = new RolePermissionVO(1L, denyApiName, RolePermission.Permission.DENY, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + try { + apiAccessChecker.checkAccess(getTestUser(), denyApiName); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testValidDenyRolePermissionWildcardCheckAccess() { + final String denyApiName = "someDenyApi"; + final RolePermission permission = new RolePermissionVO(1L, "*Deny*", RolePermission.Permission.DENY, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + try { + apiAccessChecker.checkAccess(getTestUser(), denyApiName); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testAnnotationFallbackCheckAccess() { + final String allowedApiName = "someApiWithAnnotations"; + apiAccessChecker.addApiToRoleBasedAnnotationsMap(getTestRole().getRoleType(), allowedApiName); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName)); + } + +} \ No newline at end of file diff --git a/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java b/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java index 1316a92ccb1..23bcf466bd3 100644 --- a/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java +++ b/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java @@ -16,20 +16,6 @@ // under the License. package org.apache.cloudstack.acl; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.APICommand; - import com.cloud.exception.PermissionDeniedException; import com.cloud.user.Account; import com.cloud.user.AccountService; @@ -37,23 +23,36 @@ import com.cloud.user.User; import com.cloud.utils.PropertiesUtil; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.PluggableService; +import org.apache.cloudstack.api.APICommand; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; // This is the default API access checker that grab's the user's account // based on the account type, access is granted @Local(value = APIChecker.class) public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIChecker { - protected static final Logger s_logger = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class); + private static final Logger LOGGER = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class); - Set commandsPropertiesOverrides = new HashSet(); - Map> commandsPropertiesRoleBasedApisMap = new HashMap>(); - Map> annotationRoleBasedApisMap = new HashMap>(); + private Set commandsPropertiesOverrides = new HashSet(); + private Map> commandsPropertiesRoleBasedApisMap = new HashMap>(); + private Map> annotationRoleBasedApisMap = new HashMap>(); + private List services; - List _services; @Inject - AccountService _accountService; + private AccountService accountService; + @Inject + private RoleService roleService; - protected StaticRoleBasedAPIAccessChecker() { + private StaticRoleBasedAPIAccessChecker() { super(); for (RoleType roleType : RoleType.values()) { commandsPropertiesRoleBasedApisMap.put(roleType, new HashSet()); @@ -61,14 +60,22 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIC } } + public boolean isDisabled() { + return roleService.isEnabled(); + } + @Override public boolean checkAccess(User user, String commandName) throws PermissionDeniedException { - Account account = _accountService.getAccount(user.getAccountId()); + if (isDisabled()) { + return true; + } + + Account account = accountService.getAccount(user.getAccountId()); if (account == null) { throw new PermissionDeniedException("The account id=" + user.getAccountId() + "for user id=" + user.getId() + "is null"); } - RoleType roleType = _accountService.getRoleType(account); + RoleType roleType = accountService.getRoleType(account); boolean isAllowed = commandsPropertiesOverrides.contains(commandName) ? commandsPropertiesRoleBasedApisMap.get(roleType).contains(commandName) : annotationRoleBasedApisMap.get( roleType).contains(commandName); @@ -77,20 +84,19 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIC throw new PermissionDeniedException("The API does not exist or is blacklisted. Role type=" + roleType.toString() + " is not allowed to request the api: " + commandName); } - return isAllowed; + return true; } @Override public boolean configure(String name, Map params) throws ConfigurationException { super.configure(name, params); - - processMapping(PropertiesUtil.processConfigFile(new String[] {"commands.properties"})); + processMapping(PropertiesUtil.processConfigFile(new String[] {PropertiesUtil.getDefaultApiCommandsFileName()})); return true; } @Override public boolean start() { - for (PluggableService service : _services) { + for (PluggableService service : services) { for (Class clz : service.getCommands()) { APICommand command = clz.getAnnotation(APICommand.class); for (RoleType role : command.authorized()) { @@ -111,22 +117,22 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIC try { short cmdPermissions = Short.parseShort(roleMask); for (RoleType roleType : RoleType.values()) { - if ((cmdPermissions & roleType.getValue()) != 0) + if ((cmdPermissions & roleType.getMask()) != 0) commandsPropertiesRoleBasedApisMap.get(roleType).add(apiName); } } catch (NumberFormatException nfe) { - s_logger.info("Malformed key=value pair for entry: " + entry.toString()); + LOGGER.info("Malformed key=value pair for entry: " + entry.toString()); } } } public List getServices() { - return _services; + return services; } @Inject public void setServices(List services) { - this._services = services; + this.services = services; } } diff --git a/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java b/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java index be0d5d53260..66d8c5d64e3 100644 --- a/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.api.command.user.discovery; import javax.inject.Inject; +import org.apache.cloudstack.acl.RoleType; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -38,7 +39,7 @@ import com.cloud.user.User; description = "lists all available apis on the server, provided by the Api Discovery plugin", since = "4.1.0", requestHasSensitiveInfo = false, - responseHasSensitiveInfo = false) + responseHasSensitiveInfo = false, authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class ListApisCmd extends BaseCmd { public static final Logger s_logger = Logger.getLogger(ListApisCmd.class.getName()); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java index a4dd09d09b1..2eaf7cd968d 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java @@ -40,6 +40,7 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachineProfile; import com.google.gson.Gson; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.AddBaremetalRctCmd; import org.apache.cloudstack.api.DeleteBaremetalRctCmd; import org.apache.cloudstack.api.ListBaremetalRctCmd; @@ -247,6 +248,8 @@ public class BaremetalVlanManagerImpl extends ManagerBase implements BaremetalVl acnt.setUuid(UUID.randomUUID().toString()); acnt.setState(Account.State.enabled); acnt.setDomainId(1); + acnt.setType(RoleType.User.getAccountType()); + acnt.setRoleId(RoleType.User.getId()); acnt = acntDao.persist(acnt); UserVO user = new UserVO(); diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java index 2ed85bb0714..f9f0d2e2c9f 100644 --- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java +++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java @@ -131,14 +131,14 @@ public class MockAccountManager extends ManagerBase implements AccountManager { } @Override - public UserAccount createUserAccount(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, short arg7, Long arg8, String arg9, + public UserAccount createUserAccount(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, short arg7, Long roleId, Long arg8, String arg9, Map arg10, String arg11, String arg12) { // TODO Auto-generated method stub return null; } @Override - public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, + public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID, User.Source source) { // TODO Auto-generated method stub return null; @@ -389,8 +389,8 @@ public class MockAccountManager extends ManagerBase implements AccountManager { } @Override - public Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid) { - final AccountVO account = new AccountVO(accountName, domainId, networkDomain, accountType, uuid); + public Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String uuid) { + final AccountVO account = new AccountVO(accountName, domainId, networkDomain, accountType, roleId, uuid); Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { diff --git a/plugins/pom.xml b/plugins/pom.xml index 1706fe8a69a..cfeb2c5ab4a 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -41,6 +41,7 @@ api/solidfire-intg-test api/discovery acl/static-role-based + acl/dynamic-role-based affinity-group-processors/host-anti-affinity affinity-group-processors/explicit-dedication deployment-planners/user-concentrated-pod diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java index d4564ff0af2..4da04166b1b 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java @@ -16,11 +16,12 @@ // under the License. package org.apache.cloudstack.api.command; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Map; - -import javax.inject.Inject; +import com.cloud.domain.DomainVO; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.User; +import com.cloud.user.UserAccount; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -30,6 +31,7 @@ import org.apache.cloudstack.api.ResponseObject.ResponseView; 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.RoleResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.ldap.LdapManager; import org.apache.cloudstack.ldap.LdapUser; @@ -37,11 +39,10 @@ import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException; import org.apache.log4j.Logger; import org.bouncycastle.util.encoders.Base64; -import com.cloud.domain.DomainVO; -import com.cloud.user.Account; -import com.cloud.user.AccountService; -import com.cloud.user.User; -import com.cloud.user.UserAccount; +import javax.inject.Inject; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Map; @APICommand(name = "ldapCreateAccount", description = "Creates an account from an LDAP user", responseObject = AccountResponse.class, since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class LdapCreateAccountCmd extends BaseCmd { @@ -54,9 +55,12 @@ public class LdapCreateAccountCmd extends BaseCmd { @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "Creates the user under the specified account. If no account is specified, the username will be used as the account name.") private String accountName; - @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") + @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") private Short accountType; + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.") + private Long roleId; + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Creates the user under the specified domain.") private Long domainId; @@ -91,7 +95,7 @@ public class LdapCreateAccountCmd extends BaseCmd { UserAccount createCloudstackUserAccount(final LdapUser user, String accountName, Long domainId) { Account account = _accountService.getActiveAccountByName(accountName, domainId); if (account == null) { - return _accountService.createUserAccount(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, accountType, + return _accountService.createUserAccount(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, getAccountType(), getRoleId(), domainId, networkDomain, details, accountUUID, userUUID, User.Source.LDAP); } else { User newUser = _accountService.createUser(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, domainId, @@ -100,6 +104,14 @@ public class LdapCreateAccountCmd extends BaseCmd { } } + public Short getAccountType() { + return RoleType.getAccountTypeByRole(roleService.findRole(roleId), accountType); + } + + public Long getRoleId() { + return RoleType.getRoleByAccountType(roleId, accountType); + } + private String getAccountName() { String name = accountName; if (accountName == null) { @@ -118,6 +130,9 @@ public class LdapCreateAccountCmd extends BaseCmd { @Override public void execute() throws ServerApiException { + if (getAccountType() == null && getRoleId() == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Both account type and role ID are not provided"); + } final CallContext callContext = getCurrentContext(); String finalAccountName = getAccountName(); Long finalDomainId = getDomainId(); diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java index b6c86560969..c38dd7031fe 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java @@ -28,6 +28,7 @@ import javax.inject.Inject; import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.user.UserAccount; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -37,6 +38,7 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.LdapUserResponse; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.RoleResponse; import org.apache.cloudstack.ldap.LdapManager; import org.apache.cloudstack.ldap.LdapUser; import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException; @@ -69,10 +71,12 @@ public class LdapImportUsersCmd extends BaseListCmd { @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, - required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") private Short accountType; + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.") + private Long roleId; + @Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters") private Map details; @@ -111,7 +115,7 @@ public class LdapImportUsersCmd extends BaseListCmd { Account account = _accountService.getActiveAccountByName(accountName, domain.getId()); if (account == null) { s_logger.debug("No account exists with name: " + accountName + " creating the account and an user with name: " + user.getUsername() + " in the account"); - _accountService.createUserAccount(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, accountType, + _accountService.createUserAccount(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, getAccountType(), getRoleId(), domain.getId(), domain.getNetworkDomain(), details, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); } else { // check if the user exists. if yes, call update @@ -130,7 +134,9 @@ public class LdapImportUsersCmd extends BaseListCmd { @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { - + if (getAccountType() == null && getRoleId() == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Both account type and role ID are not provided"); + } List users; try { if (StringUtils.isNotBlank(groupName)) { @@ -160,6 +166,14 @@ public class LdapImportUsersCmd extends BaseListCmd { setResponseObject(response); } + public Short getAccountType() { + return RoleType.getAccountTypeByRole(roleService.findRole(roleId), accountType); + } + + public Long getRoleId() { + return RoleType.getRoleByAccountType(roleId, accountType); + } + private String getAccountName(LdapUser user) { String finalAccountName = accountName; if(finalAccountName == null ) { diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy index 6e0759f85c1..3c9b584d7e5 100644 --- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy +++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy @@ -246,7 +246,7 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { 1 * accountService.getActiveAccountByName('ACCOUNT', 0) >> Mock(AccountVO) 1 * accountService.getActiveUserAccount('rmurphy',0) >> Mock(UserAccountVO) 0 * accountService.createUser('rmurphy', _ , 'Ryan', 'Murphy', 'rmurphy@test.com', null, 'ACCOUNT', 0, _) >> Mock(UserVO) - 0 * accountService.createUserAccount('rmurphy', _, 'Ryan', 'Murphy', 'rmurphy@test.com', null, 'ACCOUNT', 2, 0, 'DOMAIN', null, _, _) + 0 * accountService.createUserAccount('rmurphy', _, 'Ryan', 'Murphy', 'rmurphy@test.com', null, 'ACCOUNT', 2, null, 0, 'DOMAIN', null, _, _) 1 * accountService.updateUser(_,'Ryan', 'Murphy', 'rmurphy@test.com', null, null, null, null, null); def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) diff --git a/scripts/installer/windows/client.wxs b/scripts/installer/windows/client.wxs index 6cca15d3e00..3563f7800b1 100644 --- a/scripts/installer/windows/client.wxs +++ b/scripts/installer/windows/client.wxs @@ -595,9 +595,6 @@ - - - diff --git a/scripts/util/migrate-dynamicroles.py b/scripts/util/migrate-dynamicroles.py new file mode 100755 index 00000000000..669de216d04 --- /dev/null +++ b/scripts/util/migrate-dynamicroles.py @@ -0,0 +1,134 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# 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. + +import os +import sys +import uuid + +from contextlib import closing +from optparse import OptionParser + +try: + import MySQLdb +except ImportError: + print("MySQLdb cannot be imported, please install python-mysqldb(apt) or mysql-python(yum)") + sys.exit(1) + +dryrun = False + + +def runSql(conn, query): + if dryrun: + print("Running SQL query: " + query) + return + with closing(conn.cursor()) as cursor: + cursor.execute(query) + + +def migrateApiRolePermissions(apis, conn): + # All allow for root admin role Admin(id:1) + runSql(conn, "INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 1, '*', 'Allow');") + # Migrate rules based on commands.properties rule for ResourceAdmin(id:2), DomainAdmin(id:3), User(id:4) + octetKey = {2:2, 3:4, 4:8} + for role in [2, 3, 4]: + for api in sorted(apis.keys()): + # Ignore auth commands + if api in ['login', 'logout', 'samlSso', 'samlSlo', 'listIdps', 'listAndSwitchSamlAccount', 'getSPMetadata']: + continue + if (octetKey[role] & int(apis[api])) > 0: + runSql(conn, "INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), %d, '%s', 'Allow');" % (role, api)) + + +def main(): + parser = OptionParser() + parser.add_option("-b", "--db", action="store", type="string", dest="db", default="cloud", + help="The name of the database, default: cloud") + parser.add_option("-u", "--user", action="store", type="string", dest="user", default="cloud", + help="User name a MySQL user with privileges on cloud database") + parser.add_option("-p", "--password", action="store", type="string", dest="password", default="cloud", + help="Password of a MySQL user with privileges on cloud database") + parser.add_option("-H", "--host", action="store", type="string", dest="host", default="127.0.0.1", + help="Host or IP of the MySQL server") + parser.add_option("-P", "--port", action="store", type="int", dest="port", default=3306, + help="Host or IP of the MySQL server") + parser.add_option("-f", "--properties-file", action="store", type="string", dest="commandsfile", default="/etc/cloudstack/management/commands.properties", + help="The commands.properties file") + parser.add_option("-d", "--dryrun", action="store_true", dest="dryrun", default=False, + help="Dry run and debug operations this tool will perform") + (options, args) = parser.parse_args() + + print("Apache CloudStack Role Permission Migration Tool") + print("(c) Apache CloudStack Authors and the ASF, under the Apache License, Version 2.0\n") + + global dryrun + if options.dryrun: + dryrun = True + + conn = MySQLdb.connect( + host=options.host, + user=options.user, + passwd=options.password, + port=int(options.port), + db=options.db) + + if not os.path.isfile(options.commandsfile): + print("Provided commands.properties cannot be accessed or does not exist, please check check permissions") + sys.exit(1) + + while True: + choice = raw_input("Running this migration tool will remove any " + + "default-role rules in cloud.role_permissions. " + + "Do you want to continue? [y/N]").lower() + if choice == 'y': + break + else: + print("Aborting!") + sys.exit(1) + + # Generate API to permission octet map + apiMap = {} + with open(options.commandsfile) as f: + for line in f.readlines(): + if not line or line == '' or line == '\n' or line.startswith('#'): + continue + name, value = line.split('=') + apiMap[name.strip()] = value.strip() + + # Rename and deprecate old commands.properties file + if not dryrun: + os.rename(options.commandsfile, options.commandsfile + '.deprecated') + print("The commands.properties file has been deprecated and moved at: " + options.commandsfile + '.deprecated') + + # Truncate any rules in cloud.role_permissions table + runSql(conn, "DELETE FROM `cloud`.`role_permissions` WHERE `role_id` in (1,2,3,4);") + + # Migrate rules from commands.properties to cloud.role_permissions + migrateApiRolePermissions(apiMap, conn) + print("Static role permissions from commands.properties have been migrated into the db") + + # Enable dynamic role based API checker + runSql(conn, "UPDATE `cloud`.`configuration` SET value='true' where name='dynamic.apichecker.enabled'") + conn.commit() + conn.close() + + print("Dynamic role based API checker has been enabled!") + + +if __name__ == '__main__': + main() diff --git a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index e2d4d2798a4..6a96678546e 100644 --- a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -37,6 +37,8 @@ value="#{pluggableAPIAuthenticatorsRegistry.registered}" /> + + diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 86b88d7b2c8..a95b6ba4576 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -27,6 +27,8 @@ import java.util.Set; import javax.annotation.PostConstruct; import javax.inject.Inject; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleService; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; @@ -417,6 +419,7 @@ public class ApiDBUtils { static AffinityGroupJoinDao s_affinityGroupJoinDao; static GlobalLoadBalancingRulesService s_gslbService; static NetworkACLDao s_networkACLDao; + static RoleService s_roleService; static AccountService s_accountService; static ResourceMetaDataService s_resourceDetailsService; static HostGpuGroupsDao s_hostGpuGroupsDao; @@ -638,6 +641,8 @@ public class ApiDBUtils { @Inject private NetworkACLDao networkACLDao; @Inject + private RoleService roleService; + @Inject private AccountService accountService; @Inject private ConfigurationManager configMgr; @@ -759,6 +764,7 @@ public class ApiDBUtils { // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned s_statsCollector = StatsCollector.getInstance(); s_networkACLDao = networkACLDao; + s_roleService = roleService; s_accountService = accountService; s_resourceDetailsService = resourceDetailsService; s_hostGpuGroupsDao = hostGpuGroupsDao; @@ -1658,6 +1664,15 @@ public class ApiDBUtils { public static UserResponse newUserResponse(UserAccountJoinVO usr, Long domainId) { UserResponse response = s_userAccountJoinDao.newUserResponse(usr); + // Populate user account role information + if (usr.getAccountRoleId() != null) { + Role role = s_roleService.findRole( usr.getAccountRoleId()); + if (role != null) { + response.setRoleId(role.getUuid()); + response.setRoleType(role.getRoleType()); + response.setRoleName(role.getName()); + } + } if (domainId != null && usr.getDomainId() != domainId) response.setIsCallerChildDomain(true); else @@ -1780,7 +1795,17 @@ public class ApiDBUtils { public static AccountResponse newAccountResponse(ResponseView view, AccountJoinVO ve) { - return s_accountJoinDao.newAccountResponse(view, ve); + AccountResponse response = s_accountJoinDao.newAccountResponse(view, ve); + // Populate account role information + if (ve.getRoleId() != null) { + Role role = s_roleService.findRole(ve.getRoleId()); + if (role != null) { + response.setRoleId(role.getUuid()); + response.setRoleType(role.getRoleType()); + response.setRoleName(role.getName()); + } + } + return response; } public static AccountJoinVO newAccountView(Account e) { diff --git a/server/src/com/cloud/api/ApiResponseGsonHelper.java b/server/src/com/cloud/api/ApiResponseGsonHelper.java index c2cc9d92dbb..d270a202079 100644 --- a/server/src/com/cloud/api/ApiResponseGsonHelper.java +++ b/server/src/com/cloud/api/ApiResponseGsonHelper.java @@ -58,7 +58,7 @@ public class ApiResponseGsonHelper { boolean permittedParameter = false; Account caller = CallContext.current().getCallingAccount(); for (RoleType allowedRole : allowedRoles) { - if (allowedRole.getValue() == caller.getType()) { + if (allowedRole.getAccountType() == caller.getType()) { permittedParameter = true; break; } diff --git a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java index b990d4aedf4..6c2eb8284b4 100644 --- a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java +++ b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java @@ -33,6 +33,7 @@ import java.util.regex.Matcher; import javax.inject.Inject; +import com.google.common.base.Strings; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.ControlledEntity; @@ -48,6 +49,7 @@ import org.apache.cloudstack.api.EntityReference; import org.apache.cloudstack.api.InternalIdentity; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd; import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd; import org.apache.cloudstack.api.command.admin.usage.GetUsageRecordsCmd; @@ -89,6 +91,55 @@ public class ParamProcessWorker implements DispatchWorker { processParameters(task.getCmd(), task.getParams()); } + private void validateNonEmptyString(final Object param, final String argName) { + if (param == null || Strings.isNullOrEmpty(param.toString())) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Empty or null value provided for API arg: %s", argName)); + } + } + + private void validateNaturalNumber(final Object param, final String argName) { + Long value = null; + if (param != null && param instanceof Long) { + value = (Long) param; + } else if (param != null) { + value = Long.valueOf(param.toString()); + } + if (value == null || value < 1L) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Invalid value provided for API arg: %s", argName)); + } + } + + private void validateField(final Object paramObj, final Parameter annotation) throws ServerApiException { + if (annotation == null) { + return; + } + final String argName = annotation.name(); + for (final ApiArgValidator validator : annotation.validations()) { + if (validator == null) { + continue; + } + switch (validator) { + case NotNullOrEmpty: + switch (annotation.type()) { + case UUID: + case STRING: + validateNonEmptyString(paramObj, argName); + break; + } + break; + case PositiveNumber: + switch (annotation.type()) { + case SHORT: + case INTEGER: + case LONG: + validateNaturalNumber(paramObj, argName); + break; + } + break; + } + } + } + @SuppressWarnings({"unchecked", "rawtypes"}) public void processParameters(final BaseCmd cmd, final Map params) { final Map entitiesToAccess = new HashMap(); @@ -109,6 +160,7 @@ public class ParamProcessWorker implements DispatchWorker { // marshall the parameter into the correct type and set the field value try { + validateField(paramObj, parameterAnnotation); setFieldValue(field, cmd, paramObj, parameterAnnotation); } catch (final IllegalArgumentException argEx) { if (s_logger.isDebugEnabled()) { @@ -409,6 +461,7 @@ public class ParamProcessWorker implements DispatchWorker { for (final Class entity : entities) { CallContext.current().putContextParameter(entity.getName(), internalId); } + validateNaturalNumber(internalId, annotation.name()); return internalId; } } @@ -441,6 +494,7 @@ public class ParamProcessWorker implements DispatchWorker { throw new InvalidParameterValueException("Invalid parameter " + annotation.name() + " value=" + uuid + " due to incorrect long value format, or entity does not exist or due to incorrect parameter annotation for the field in api cmd class."); } + validateNaturalNumber(internalId, annotation.name()); return internalId; } } diff --git a/server/src/com/cloud/api/doc/ApiXmlDocWriter.java b/server/src/com/cloud/api/doc/ApiXmlDocWriter.java index 54fdfbeb0d3..18e3a2a8bfc 100644 --- a/server/src/com/cloud/api/doc/ApiXmlDocWriter.java +++ b/server/src/com/cloud/api/doc/ApiXmlDocWriter.java @@ -41,7 +41,6 @@ import org.apache.log4j.Logger; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; @@ -67,16 +66,10 @@ import java.util.zip.ZipOutputStream; public class ApiXmlDocWriter { public static final Logger s_logger = Logger.getLogger(ApiXmlDocWriter.class.getName()); - private static final short DOMAIN_ADMIN_COMMAND = 4; - private static final short USER_COMMAND = 8; + private static String s_dirName = ""; private static Map> s_apiNameCmdClassMap = new HashMap>(); private static LinkedHashMap s_allApiCommands = new LinkedHashMap(); - private static LinkedHashMap s_domainAdminApiCommands = new LinkedHashMap(); - private static LinkedHashMap s_regularUserApiCommands = new LinkedHashMap(); private static TreeMap s_allApiCommandsSorted = new TreeMap(); - private static TreeMap s_domainAdminApiCommandsSorted = new TreeMap(); - private static TreeMap s_regularUserApiCommandsSorted = new TreeMap(); - private static String s_dirName = ""; private static final List AsyncResponses = setAsyncResponses(); private static List setAsyncResponses() { @@ -120,71 +113,22 @@ public class ApiXmlDocWriter { s_apiNameCmdClassMap.put(apiName, cmdClass); } } - - LinkedProperties preProcessedCommands = new LinkedProperties(); - String[] fileNames = null; - + System.out.printf("Scanned and found %d APIs\n", s_apiNameCmdClassMap.size()); List argsList = Arrays.asList(args); Iterator iter = argsList.iterator(); while (iter.hasNext()) { String arg = iter.next(); - // populate the file names - if (arg.equals("-f")) { - fileNames = iter.next().split(","); - } if (arg.equals("-d")) { s_dirName = iter.next(); } } - if ((fileNames == null) || (fileNames.length == 0)) { - System.out.println("Please specify input file(s) separated by coma using -f option"); - System.exit(2); - } - - for (String fileName : fileNames) { - try(FileInputStream in = new FileInputStream(fileName);) { - preProcessedCommands.load(in); - } catch (FileNotFoundException ex) { - System.out.println("Can't find file " + fileName); - System.exit(2); - } catch (IOException ex1) { - System.out.println("Error reading from file " + ex1); - System.exit(2); - } - } - - Iterator propertiesIterator = preProcessedCommands.keys.iterator(); - // Get command classes and response object classes - while (propertiesIterator.hasNext()) { - String key = (String)propertiesIterator.next(); - String preProcessedCommand = preProcessedCommands.getProperty(key); - int splitIndex = preProcessedCommand.lastIndexOf(";"); - String commandRoleMask = preProcessedCommand.substring(splitIndex + 1); - Class cmdClass = s_apiNameCmdClassMap.get(key); - if (cmdClass == null) { - System.out.println("Check, is this api part of another build profile? Null value for key: " + key + " preProcessedCommand=" + preProcessedCommand); - continue; - } - String commandName = cmdClass.getName(); - s_allApiCommands.put(key, commandName); - - short cmdPermissions = 1; - if (commandRoleMask != null) { - cmdPermissions = Short.parseShort(commandRoleMask); - } - - if ((cmdPermissions & DOMAIN_ADMIN_COMMAND) != 0) { - s_domainAdminApiCommands.put(key, commandName); - } - if ((cmdPermissions & USER_COMMAND) != 0) { - s_regularUserApiCommands.put(key, commandName); - } + for (Map.Entry> entry: s_apiNameCmdClassMap.entrySet()) { + Class cls = entry.getValue(); + s_allApiCommands.put(entry.getKey(), cls.getName()); } s_allApiCommandsSorted.putAll(s_allApiCommands); - s_domainAdminApiCommandsSorted.putAll(s_domainAdminApiCommands); - s_regularUserApiCommandsSorted.putAll(s_regularUserApiCommands); try { // Create object writer @@ -192,83 +136,38 @@ public class ApiXmlDocWriter { xs.alias("command", Command.class); xs.alias("arg", Argument.class); String xmlDocDir = s_dirName + "/xmldoc"; - String rootAdminDirName = xmlDocDir + "/root_admin"; - String domainAdminDirName = xmlDocDir + "/domain_admin"; - String regularUserDirName = xmlDocDir + "/regular_user"; + String rootAdminDirName = xmlDocDir + "/apis"; (new File(rootAdminDirName)).mkdirs(); - (new File(domainAdminDirName)).mkdirs(); - (new File(regularUserDirName)).mkdirs(); ObjectOutputStream out = xs.createObjectOutputStream(new FileWriter(s_dirName + "/commands.xml"), "commands"); - ObjectOutputStream rootAdmin = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + "rootAdminSummary.xml"), "commands"); - ObjectOutputStream rootAdminSorted = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + "rootAdminSummarySorted.xml"), "commands"); - ObjectOutputStream domainAdmin = xs.createObjectOutputStream(new FileWriter(domainAdminDirName + "/" + "domainAdminSummary.xml"), "commands"); - ObjectOutputStream outDomainAdminSorted = xs.createObjectOutputStream(new FileWriter(domainAdminDirName + "/" + "domainAdminSummarySorted.xml"), "commands"); - ObjectOutputStream regularUser = xs.createObjectOutputStream(new FileWriter(regularUserDirName + "/regularUserSummary.xml"), "commands"); - ObjectOutputStream regularUserSorted = xs.createObjectOutputStream(new FileWriter(regularUserDirName + "/regularUserSummarySorted.xml"), "commands"); + ObjectOutputStream rootAdmin = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + "apiSummary.xml"), "commands"); + ObjectOutputStream rootAdminSorted = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + "apiSummarySorted.xml"), "commands"); - // Write commands in the order they are represented in commands.properties.in file Iterator it = s_allApiCommands.keySet().iterator(); while (it.hasNext()) { String key = (String)it.next(); - // Write admin commands writeCommand(out, key); writeCommand(rootAdmin, key); - // Write single commands to separate xml files ObjectOutputStream singleRootAdminCommandOs = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + key + ".xml"), "command"); writeCommand(singleRootAdminCommandOs, key); singleRootAdminCommandOs.close(); - - if (s_domainAdminApiCommands.containsKey(key)) { - writeCommand(domainAdmin, key); - ObjectOutputStream singleDomainAdminCommandOs = xs.createObjectOutputStream(new FileWriter(domainAdminDirName + "/" + key + ".xml"), "command"); - writeCommand(singleDomainAdminCommandOs, key); - singleDomainAdminCommandOs.close(); - } - - if (s_regularUserApiCommands.containsKey(key)) { - writeCommand(regularUser, key); - ObjectOutputStream singleRegularUserCommandOs = xs.createObjectOutputStream(new FileWriter(regularUserDirName + "/" + key + ".xml"), "command"); - writeCommand(singleRegularUserCommandOs, key); - singleRegularUserCommandOs.close(); - } } // Write sorted commands it = s_allApiCommandsSorted.keySet().iterator(); while (it.hasNext()) { String key = (String)it.next(); - writeCommand(rootAdminSorted, key); - - if (s_domainAdminApiCommands.containsKey(key)) { - writeCommand(outDomainAdminSorted, key); - } - - if (s_regularUserApiCommands.containsKey(key)) { - writeCommand(regularUserSorted, key); - } } out.close(); rootAdmin.close(); rootAdminSorted.close(); - domainAdmin.close(); - outDomainAdminSorted.close(); - regularUser.close(); - regularUserSorted.close(); // write alerttypes to xml writeAlertTypes(xmlDocDir); - - // gzip directory with xml doc - // zipDir(dirName + "xmldoc.zip", xmlDocDir); - - // Delete directory - // deleteDir(new File(xmlDocDir)); - } catch (Exception ex) { ex.printStackTrace(); System.exit(2); @@ -532,5 +431,4 @@ public class ApiXmlDocWriter { return super.put(key, value); } } - } diff --git a/server/src/com/cloud/api/query/vo/AccountJoinVO.java b/server/src/com/cloud/api/query/vo/AccountJoinVO.java index 8d642edd7cf..f251abc4726 100644 --- a/server/src/com/cloud/api/query/vo/AccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/AccountJoinVO.java @@ -48,6 +48,9 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident @Column(name = "type") private short type; + @Column(name = "role_id") + private Long roleId; + @Column(name = "state") @Enumerated(value = EnumType.STRING) private State state; @@ -202,6 +205,10 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident return type; } + public Long getRoleId() { + return roleId; + } + public State getState() { return state; } diff --git a/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java b/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java index 0e66ca022c5..e6b1ace0966 100644 --- a/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java @@ -96,6 +96,9 @@ public class UserAccountJoinVO extends BaseViewVO implements InternalIdentity, I @Column(name = "account_type") private short accountType; + @Column(name = "account_role_id") + private Long accountRoleId; + @Column(name = "domain_id") private long domainId; @@ -149,6 +152,10 @@ public class UserAccountJoinVO extends BaseViewVO implements InternalIdentity, I return accountType; } + public Long getAccountRoleId() { + return accountRoleId; + } + public long getDomainId() { return domainId; } diff --git a/server/src/com/cloud/api/response/ApiResponseSerializer.java b/server/src/com/cloud/api/response/ApiResponseSerializer.java index 19d26710540..a5a9dec34c6 100644 --- a/server/src/com/cloud/api/response/ApiResponseSerializer.java +++ b/server/src/com/cloud/api/response/ApiResponseSerializer.java @@ -207,7 +207,7 @@ public class ApiResponseSerializer { boolean permittedParameter = false; Account caller = CallContext.current().getCallingAccount(); for (RoleType allowedRole : allowedRoles) { - if (allowedRole.getValue() == caller.getType()) { + if (allowedRole.getAccountType() == caller.getType()) { permittedParameter = true; break; } diff --git a/server/src/com/cloud/projects/ProjectManagerImpl.java b/server/src/com/cloud/projects/ProjectManagerImpl.java index d10c059bd52..9ee5b138346 100755 --- a/server/src/com/cloud/projects/ProjectManagerImpl.java +++ b/server/src/com/cloud/projects/ProjectManagerImpl.java @@ -213,7 +213,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager { StringBuilder acctNm = new StringBuilder("PrjAcct-"); acctNm.append(name).append("-").append(ownerFinal.getDomainId()); - Account projectAccount = _accountMgr.createAccount(acctNm.toString(), Account.ACCOUNT_TYPE_PROJECT, domainId, null, null, UUID.randomUUID().toString()); + Account projectAccount = _accountMgr.createAccount(acctNm.toString(), Account.ACCOUNT_TYPE_PROJECT, null, domainId, null, null, UUID.randomUUID().toString()); Project project = _projectDao.persist(new ProjectVO(name, displayText, ownerFinal.getDomainId(), projectAccount.getId())); diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java index 194c5d212f2..2cae32eadff 100755 --- a/server/src/com/cloud/user/AccountManager.java +++ b/server/src/com/cloud/user/AccountManager.java @@ -49,7 +49,7 @@ public interface AccountManager extends AccountService { Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId); - Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid); + Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String uuid); /** * Logs out a user diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 20fcbcb3bd5..00df0c4bcd8 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -985,9 +985,9 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, final String timezone, - String accountName, final short accountType, Long domainId, final String networkDomain, final Map details, String accountUUID, final String userUUID) { + String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map details, String accountUUID, final String userUUID) { - return createUserAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, domainId, networkDomain, details, accountUUID, userUUID, + return createUserAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, roleId, domainId, networkDomain, details, accountUUID, userUUID, User.Source.UNKNOWN); } @@ -1002,7 +1002,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User") }) public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, - final String timezone, String accountName, final short accountType, Long domainId, final String networkDomain, final Map details, + final String timezone, String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map details, String accountUUID, final String userUUID, final User.Source source) { if (accountName == null) { @@ -1056,7 +1056,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M if (accountUUID == null) { accountUUID = UUID.randomUUID().toString(); } - AccountVO account = createAccount(accountNameFinal, accountType, domainIdFinal, networkDomain, details, accountUUID); + AccountVO account = createAccount(accountNameFinal, accountType, roleId, domainIdFinal, networkDomain, details, accountUUID); long accountId = account.getId(); // create the first user for the account @@ -1858,27 +1858,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Override public RoleType getRoleType(Account account) { - RoleType roleType = RoleType.Unknown; - if (account == null) - return roleType; - short accountType = account.getType(); - - // Account type to role type translation - switch (accountType) { - case Account.ACCOUNT_TYPE_ADMIN: - roleType = RoleType.Admin; - break; - case Account.ACCOUNT_TYPE_DOMAIN_ADMIN: - roleType = RoleType.DomainAdmin; - break; - case Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN: - roleType = RoleType.ResourceAdmin; - break; - case Account.ACCOUNT_TYPE_NORMAL: - roleType = RoleType.User; - break; + if (account == null) { + return RoleType.Unknown; } - return roleType; + return RoleType.getByAccountType(account.getType()); } @Override @@ -1905,7 +1888,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Override @DB - public AccountVO createAccount(final String accountName, final short accountType, final Long domainId, final String networkDomain, final Map details, + public AccountVO createAccount(final String accountName, final short accountType, final Long roleId, final Long domainId, final String networkDomain, final Map details, final String uuid) { // Validate domain Domain domain = _domainMgr.getDomain(domainId); @@ -1950,7 +1933,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M return Transaction.execute(new TransactionCallback() { @Override public AccountVO doInTransaction(TransactionStatus status) { - AccountVO account = _accountDao.persist(new AccountVO(accountName, domainId, networkDomain, accountType, uuid)); + AccountVO account = _accountDao.persist(new AccountVO(accountName, domainId, networkDomain, accountType, roleId, uuid)); if (account == null) { throw new CloudRuntimeException("Failed to create account name " + accountName + " in domain id=" + domainId); diff --git a/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java b/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java new file mode 100644 index 00000000000..7d21f5d9a7c --- /dev/null +++ b/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java @@ -0,0 +1,268 @@ +// 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 com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.ListUtils; +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.component.PluggableService; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionStatus; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.dao.RoleDao; +import org.apache.cloudstack.acl.dao.RolePermissionsDao; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.admin.acl.CreateRoleCmd; +import org.apache.cloudstack.api.command.admin.acl.CreateRolePermissionCmd; +import org.apache.cloudstack.api.command.admin.acl.DeleteRoleCmd; +import org.apache.cloudstack.api.command.admin.acl.DeleteRolePermissionCmd; +import org.apache.cloudstack.api.command.admin.acl.ListRolePermissionsCmd; +import org.apache.cloudstack.api.command.admin.acl.ListRolesCmd; +import org.apache.cloudstack.api.command.admin.acl.UpdateRoleCmd; +import org.apache.cloudstack.api.command.admin.acl.UpdateRolePermissionCmd; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; + +import javax.ejb.Local; +import javax.inject.Inject; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +@Local(value = {RoleService.class}) +public class RoleManagerImpl extends ManagerBase implements RoleService, Configurable, PluggableService { + @Inject + private AccountDao accountDao; + @Inject + private RoleDao roleDao; + @Inject + private RolePermissionsDao rolePermissionsDao; + + private void checkCallerAccess() { + if (!isEnabled()) { + throw new PermissionDeniedException("Dynamic api checker is not enabled, aborting role operation"); + } + Account caller = CallContext.current().getCallingAccount(); + if (caller == null || caller.getRoleId() == null) { + throw new PermissionDeniedException("Restricted API called by an invalid user account"); + } + Role callerRole = findRole(caller.getRoleId()); + if (callerRole == null || callerRole.getRoleType() != RoleType.Admin) { + throw new PermissionDeniedException("Restricted API called by an user account of non-Admin role type"); + } + } + + @Override + public boolean isEnabled() { + File apiCmdFile = PropertiesUtil.findConfigFile(PropertiesUtil.getDefaultApiCommandsFileName()); + return RoleService.EnableDynamicApiChecker.value() && (apiCmdFile == null || !apiCmdFile.exists()); + } + + @Override + public Role findRole(final Long id) { + if (id == null || id < 1L) { + return null; + } + return roleDao.findById(id); + } + + @Override + public RolePermission findRolePermission(final Long id) { + if (id == null) { + return null; + } + return rolePermissionsDao.findById(id); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_CREATE, eventDescription = "creating Role") + public Role createRole(final String name, final RoleType roleType, final String description) { + checkCallerAccess(); + if (roleType == null || roleType == RoleType.Unknown) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role type provided"); + } + return Transaction.execute(new TransactionCallback() { + @Override + public RoleVO doInTransaction(TransactionStatus status) { + return roleDao.persist(new RoleVO(name, roleType, description)); + } + }); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_UPDATE, eventDescription = "updating Role") + public boolean updateRole(final Role role, final String name, final RoleType roleType, final String description) { + checkCallerAccess(); + if (role == null) { + return false; + } + if (roleType != null && roleType == RoleType.Unknown) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unknown is not a valid role type"); + } + RoleVO roleVO = (RoleVO) role; + if (!Strings.isNullOrEmpty(name)) { + roleVO.setName(name); + } + if (roleType != null) { + if (role.getId() <= RoleType.User.getId()) { + throw new PermissionDeniedException("The role type of default roles cannot be changed"); + } + List accounts = accountDao.findAccountsByRole(role.getId()); + if (accounts == null || accounts.isEmpty()) { + roleVO.setRoleType(roleType); + } else { + throw new PermissionDeniedException("Found accounts that have role in use, won't allow to change role type"); + } + } + if (!Strings.isNullOrEmpty(description)) { + roleVO.setDescription(description); + } + return roleDao.update(role.getId(), roleVO); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_DELETE, eventDescription = "deleting Role") + public boolean deleteRole(final Role role) { + checkCallerAccess(); + if (role == null) { + return false; + } + if (role.getId() <= RoleType.User.getId()) { + throw new PermissionDeniedException("Default roles cannot be deleted"); + } + List accounts = accountDao.findAccountsByRole(role.getId()); + if (accounts == null || accounts.size() == 0) { + return Transaction.execute(new TransactionCallback() { + @Override + public Boolean doInTransaction(TransactionStatus status) { + List rolePermissions = rolePermissionsDao.findAllByRoleId(role.getId()); + if (rolePermissions != null && !rolePermissions.isEmpty()) { + for (RolePermission rolePermission : rolePermissions) { + rolePermissionsDao.remove(rolePermission.getId()); + } + } + return roleDao.remove(role.getId()); + } + }); + } + throw new PermissionDeniedException("Found accounts that have role in use, won't allow to delete role"); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_PERMISSION_CREATE, eventDescription = "creating Role Permission") + public RolePermission createRolePermission(final Role role, final Rule rule, final RolePermission.Permission permission, final String description) { + checkCallerAccess(); + return Transaction.execute(new TransactionCallback() { + @Override + public RolePermissionVO doInTransaction(TransactionStatus status) { + return rolePermissionsDao.persist(new RolePermissionVO(role.getId(), rule.toString(), permission, description)); + } + }); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_PERMISSION_UPDATE, eventDescription = "updating Role Permission") + public boolean updateRolePermission(final RolePermission rolePermission, final Rule rule, final RolePermission.Permission permission, final String description) { + checkCallerAccess(); + if (rolePermission == null) { + return false; + } + RolePermissionVO rolePermissionVO = (RolePermissionVO) rolePermission; + if (rule != null) { + rolePermissionVO.setRule(rule.toString()); + } + if (permission != null) { + rolePermissionVO.setPermission(permission); + } + if (!Strings.isNullOrEmpty(description)) { + rolePermissionVO.setDescription(description); + } + return rolePermissionsDao.update(rolePermission.getId(), rolePermissionVO); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_PERMISSION_DELETE, eventDescription = "deleting Role Permission") + public boolean deleteRolePermission(final RolePermission rolePermission) { + checkCallerAccess(); + return rolePermission != null && rolePermissionsDao.remove(rolePermission.getId()); + } + + @Override + public List findRolesByName(final String name) { + List roles = null; + if (!Strings.isNullOrEmpty(name)) { + roles = roleDao.findAllByName(name); + } + return ListUtils.toListOfInterface(roles); + } + + @Override + public List findRolesByType(final RoleType roleType) { + List roles = null; + if (roleType != null) { + roles = roleDao.findAllByRoleType(roleType); + } + return ListUtils.toListOfInterface(roles); + } + + @Override + public List listRoles() { + List roles = roleDao.listAll(); + return ListUtils.toListOfInterface(roles); + } + + @Override + public List findAllPermissionsBy(final Long roleId) { + List permissions = rolePermissionsDao.findAllByRoleId(roleId); + if (permissions != null) { + return new ArrayList<>(permissions); + } + return null; + } + + @Override + public String getConfigComponentName() { + return RoleService.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[]{RoleService.EnableDynamicApiChecker}; + } + + @Override + public List> getCommands() { + final List> cmdList = new ArrayList<>(); + cmdList.add(CreateRoleCmd.class); + cmdList.add(ListRolesCmd.class); + cmdList.add(UpdateRoleCmd.class); + cmdList.add(DeleteRoleCmd.class); + cmdList.add(CreateRolePermissionCmd.class); + cmdList.add(ListRolePermissionsCmd.class); + cmdList.add(UpdateRolePermissionCmd.class); + cmdList.add(DeleteRolePermissionCmd.class); + return cmdList; + } + } diff --git a/server/test/com/cloud/user/MockAccountManagerImpl.java b/server/test/com/cloud/user/MockAccountManagerImpl.java index 6193d9a1f3c..30aa49c67ef 100644 --- a/server/test/com/cloud/user/MockAccountManagerImpl.java +++ b/server/test/com/cloud/user/MockAccountManagerImpl.java @@ -317,13 +317,13 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco @Override public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, - short accountType, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID) { + short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID) { // TODO Auto-generated method stub return null; } @Override - public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, + public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID, User.Source source) { // TODO Auto-generated method stub return null; @@ -355,7 +355,7 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco } @Override - public Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid) { + public Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String uuid) { // TODO Auto-generated method stub return null; } diff --git a/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java index 3a3ba4dd3f2..d3a28dd1061 100644 --- a/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java +++ b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java @@ -198,7 +198,7 @@ public class RoleBasedAPIAccessChecker extends AdapterBase implements APIChecker try { short cmdPermissions = Short.parseShort(roleMask); for (RoleType roleType : RoleType.values()) { - if ((cmdPermissions & roleType.getValue()) != 0) + if ((cmdPermissions & roleType.getMask()) != 0) commandsPropertiesRoleBasedApisMap.get(roleType).add(apiName); } } catch (NumberFormatException nfe) { diff --git a/setup/db/db/create-default-role-api-mappings.sql b/setup/db/db/create-default-role-api-mappings.sql new file mode 100644 index 00000000000..a03187da935 --- /dev/null +++ b/setup/db/db/create-default-role-api-mappings.sql @@ -0,0 +1,870 @@ +-- 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. + +-- The default admin role (id:1) will be allowed all APIs so need to insert rules for admin role + +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 1, '*', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; + +-- Insert default role-api mappings for rest of the default roles: resourceadmin(id:2), domainadmin(id:3), user(id:4) + +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'activateProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'addAccountToProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'addHost', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'addIpToNic', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'addLdapConfiguration', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'addNicToVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'addVpnUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'archiveEvents', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'assignCertToLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'assignToGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'assignToLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'assignVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'associateIpAddress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'associateLun', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'attachIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'attachVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'authorizeSamlSso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'authorizeSecurityGroupEgress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'authorizeSecurityGroupIngress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'changeServiceForRouter', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'changeServiceForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'configureInternalLoadBalancerElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'configureOvsElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'configureVirtualRouterElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'copyIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'copyTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createAffinityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createAutoScalePolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createAutoScaleVmProfile', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createCondition', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createEgressFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createInstanceGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createInternalLoadBalancerElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createIpForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createLBHealthCheckPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createLBStickinessPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createLunOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createNetworkACL', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createOvsElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createPool', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createPortForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createRemoteAccessVpn', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createSSHKeyPair', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createSecurityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createSnapshotPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createStaticRoute', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createVirtualRouterElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createVolumeOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createVpnCustomerGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'createVpnGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteAccountFromProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteAffinityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteAutoScalePolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteAutoScaleVmProfile', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteCondition', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteEgressFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteEvents', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteHost', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteInstanceGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteIpForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteLBHealthCheckPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteLBStickinessPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteLdapConfiguration', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteNetworkACL', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deletePool', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deletePortForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteProjectInvitation', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteRemoteAccessVpn', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteSSHKeyPair', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteSecurityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteSnapshotPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteSslCert', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteStaticRoute', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteVpnCustomerGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deleteVpnGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'deployVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'destroyLunOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'destroyRouter', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'destroyVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'destroyVolumeOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'detachIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'detachVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'disableAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'disableAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'disableStaticNat', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'disableUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'disassociateIpAddress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'dissociateLun', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'enableAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'enableAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'enableStaticNat', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'enableUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'expungeVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'extractIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'extractTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'extractVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'getApiLimit', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'getCloudIdentifier', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'getSPMetadata', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'getSolidFireAccountId', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'getSolidFireVolumeAccessGroupId', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'getSolidFireVolumeIscsiName', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'getSolidFireVolumeSize', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'getVMPassword', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'getVirtualMachineUserData', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'importLdapUsers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'issueNuageVspResourceRequest', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'ldapCreateAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listAccounts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listAffinityGroupTypes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listAffinityGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listAlerts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listApis', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listAsyncJobs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listAutoScalePolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listAutoScaleVmGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listAutoScaleVmProfiles', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listCapabilities', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listCapacity', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listClusters', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listConditions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listCounters', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listDiskOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listDomainChildren', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listDomains', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listEgressFirewallRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listEventTypes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listEvents', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listFirewallRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listGlobalLoadBalancerRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listHostTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listHosts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listHypervisors', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listIdps', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listInstanceGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listInternalLoadBalancerElements', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listIpForwardingRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listIsoPermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listIsos', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listLBHealthCheckPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listLBStickinessPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listLdapConfigurations', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listLdapUsers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listLoadBalancerRuleInstances', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listLoadBalancerRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listLoadBalancers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listLunsOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listNetworkACLLists', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listNetworkACLs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listNetworkOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listNetworks', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listNics', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listOsCategories', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listOsTypes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listOvsElements', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listPods', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listPools', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listPortForwardingRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listPrivateGateways', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listProjectAccounts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listProjectInvitations', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listProjects', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listPublicIpAddresses', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listRegions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listRemoteAccessVpns', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listResourceDetails', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listResourceLimits', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listRouters', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listSSHKeyPairs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listSamlAuthorization', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listSecurityGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listServiceOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listSnapshotPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listSnapshots', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listSslCerts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listStaticRoutes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listStoragePools', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listStorageProviders', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listStorageTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listSystemVms', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listTemplatePermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listTemplates', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listUsageRecords', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listUsers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVPCOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVPCs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVirtualMachines', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVirtualRouterElements', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVolumes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVolumesOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVpnConnections', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVpnCustomerGateways', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVpnGateways', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listVpnUsers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'listZones', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'lockAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'lockUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'migrateVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'modifyPool', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'queryAsyncJobResult', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'rebootRouter', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'rebootVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'recoverVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'registerIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'registerSSHKeyPair', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'registerTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'registerUserKeys', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'removeCertFromLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'removeFromGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'removeFromLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'removeIpFromNic', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'removeNicFromVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'removeVpnUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'replaceNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'resetPasswordForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'resetSSHKeyForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'resetVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'resizeVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'restartNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'restartVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'restoreVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'revertSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'revertToVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'revokeSecurityGroupEgress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'revokeSecurityGroupIngress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'scaleVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'startRouter', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'startVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'stopRouter', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'stopVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'suspendProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateAutoScalePolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateAutoScaleVmProfile', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateDefaultNicForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateEgressFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateInstanceGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateIpAddress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateIsoPermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateLBHealthCheckPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateLBStickinessPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateNetworkACLItem', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updatePortForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateProjectInvitation', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateRemoteAccessVpn', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateResourceCount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateResourceLimit', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateSnapshotPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateTemplatePermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateVMAffinityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateVpnCustomerGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'updateVpnGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'uploadSslCert', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 2, 'uploadVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'activateProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'addAccountToProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'addIpToNic', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'addNicToVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'addVpnUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'archiveEvents', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'assignCertToLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'assignToGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'assignToLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'assignVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'associateIpAddress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'associateLun', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'attachIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'attachVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'authorizeSamlSso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'authorizeSecurityGroupEgress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'authorizeSecurityGroupIngress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'changeServiceForRouter', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'changeServiceForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'configureInternalLoadBalancerElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'configureOvsElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'configureVirtualRouterElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'copyIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'copyTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createAffinityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createAutoScalePolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createAutoScaleVmProfile', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createCondition', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createEgressFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createInstanceGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createInternalLoadBalancerElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createIpForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createLBHealthCheckPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createLBStickinessPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createLunOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createNetworkACL', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createOvsElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createPool', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createPortForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createRemoteAccessVpn', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createSSHKeyPair', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createSecurityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createSnapshotPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createStaticRoute', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createVirtualRouterElement', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createVolumeOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createVpnCustomerGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'createVpnGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteAccountFromProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteAffinityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteAutoScalePolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteAutoScaleVmProfile', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteCondition', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteEgressFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteEvents', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteInstanceGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteIpForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteLBHealthCheckPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteLBStickinessPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteNetworkACL', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deletePool', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deletePortForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteProjectInvitation', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteRemoteAccessVpn', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteSSHKeyPair', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteSecurityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteSnapshotPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteSslCert', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteStaticRoute', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteVpnCustomerGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deleteVpnGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'deployVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'destroyLunOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'destroyRouter', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'destroyVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'destroyVolumeOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'detachIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'detachVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'disableAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'disableAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'disableStaticNat', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'disableUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'disassociateIpAddress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'dissociateLun', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'enableAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'enableAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'enableStaticNat', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'enableUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'expungeVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'extractIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'extractTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'extractVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'getApiLimit', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'getCloudIdentifier', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'getSPMetadata', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'getSolidFireAccountId', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'getSolidFireVolumeAccessGroupId', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'getSolidFireVolumeIscsiName', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'getSolidFireVolumeSize', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'getVMPassword', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'getVirtualMachineUserData', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'issueNuageVspResourceRequest', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listAccounts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listAffinityGroupTypes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listAffinityGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listApis', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listAsyncJobs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listAutoScalePolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listAutoScaleVmGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listAutoScaleVmProfiles', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listCapabilities', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listConditions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listCounters', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listDiskOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listDomainChildren', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listDomains', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listEgressFirewallRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listEventTypes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listEvents', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listFirewallRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listGlobalLoadBalancerRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listHostTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listHypervisors', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listIdps', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listInstanceGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listInternalLoadBalancerElements', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listIpForwardingRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listIsoPermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listIsos', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listLBHealthCheckPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listLBStickinessPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listLdapConfigurations', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listLoadBalancerRuleInstances', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listLoadBalancerRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listLoadBalancers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listLunsOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listNetworkACLLists', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listNetworkACLs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listNetworkOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listNetworks', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listNics', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listOsCategories', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listOsTypes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listOvsElements', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listPools', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listPortForwardingRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listPrivateGateways', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listProjectAccounts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listProjectInvitations', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listProjects', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listPublicIpAddresses', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listRegions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listRemoteAccessVpns', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listResourceDetails', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listResourceLimits', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listRouters', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listSSHKeyPairs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listSamlAuthorization', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listSecurityGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listServiceOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listSnapshotPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listSnapshots', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listSslCerts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listStaticRoutes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listStorageTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listTemplatePermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listTemplates', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listUsageRecords', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listUsers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVPCOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVPCs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVirtualMachines', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVirtualRouterElements', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVolumes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVolumesOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVpnConnections', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVpnCustomerGateways', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVpnGateways', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listVpnUsers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'listZones', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'lockAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'lockUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'migrateVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'modifyPool', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'queryAsyncJobResult', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'rebootRouter', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'rebootVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'recoverVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'registerIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'registerSSHKeyPair', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'registerTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'registerUserKeys', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'removeCertFromLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'removeFromGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'removeFromLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'removeIpFromNic', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'removeNicFromVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'removeVpnUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'replaceNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'resetPasswordForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'resetSSHKeyForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'resetVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'resizeVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'restartNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'restartVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'restoreVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'revertSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'revertToVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'revokeSecurityGroupEgress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'revokeSecurityGroupIngress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'scaleVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'startRouter', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'startVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'stopRouter', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'stopVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'suspendProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateAccount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateAutoScalePolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateAutoScaleVmProfile', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateDefaultNicForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateEgressFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateInstanceGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateIpAddress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateIsoPermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateLBHealthCheckPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateLBStickinessPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateNetworkACLItem', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updatePortForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateProjectInvitation', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateRemoteAccessVpn', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateResourceCount', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateResourceLimit', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateSnapshotPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateTemplatePermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateVMAffinityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateVpnCustomerGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'updateVpnGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'uploadSslCert', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 3, 'uploadVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'activateProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'addAccountToProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'addIpToNic', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'addNicToVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'addVpnUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'archiveEvents', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'assignCertToLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'assignToGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'assignToLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'associateIpAddress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'associateLun', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'attachIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'attachVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'authorizeSecurityGroupEgress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'authorizeSecurityGroupIngress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'changeServiceForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'copyIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'copyTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createAffinityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createAutoScalePolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createAutoScaleVmProfile', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createCondition', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createEgressFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createInstanceGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createIpForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createLBHealthCheckPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createLBStickinessPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createLunOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createNetworkACL', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createPool', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createPortForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createRemoteAccessVpn', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createSSHKeyPair', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createSecurityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createSnapshotPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createStaticRoute', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createVolumeOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createVpnCustomerGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'createVpnGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteAccountFromProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteAffinityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteAutoScalePolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteAutoScaleVmProfile', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteCondition', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteEgressFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteEvents', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteInstanceGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteIpForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteLBHealthCheckPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteLBStickinessPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteNetworkACL', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deletePool', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deletePortForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteProjectInvitation', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteRemoteAccessVpn', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteSSHKeyPair', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteSecurityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteSnapshotPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteSslCert', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteStaticRoute', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteVpnCustomerGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deleteVpnGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'deployVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'destroyLunOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'destroyVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'destroyVolumeOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'detachIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'detachVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'disableAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'disableStaticNat', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'disassociateIpAddress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'dissociateLun', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'enableAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'enableStaticNat', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'extractIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'extractTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'extractVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'getApiLimit', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'getCloudIdentifier', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'getSPMetadata', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'getSolidFireAccountId', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'getSolidFireVolumeAccessGroupId', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'getSolidFireVolumeIscsiName', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'getSolidFireVolumeSize', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'getVMPassword', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'getVirtualMachineUserData', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'issueNuageVspResourceRequest', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listAccounts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listAffinityGroupTypes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listAffinityGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listApis', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listAsyncJobs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listAutoScalePolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listAutoScaleVmGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listAutoScaleVmProfiles', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listCapabilities', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listConditions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listCounters', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listDiskOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listEgressFirewallRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listEventTypes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listEvents', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listFirewallRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listGlobalLoadBalancerRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listHypervisors', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listIdps', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listInstanceGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listIpForwardingRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listIsoPermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listIsos', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listLBHealthCheckPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listLBStickinessPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listLdapConfigurations', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listLoadBalancerRuleInstances', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listLoadBalancerRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listLoadBalancers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listLunsOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listNetworkACLLists', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listNetworkACLs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listNetworkOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listNetworks', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listNics', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listOsCategories', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listOsTypes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listPools', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listPortForwardingRules', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listPrivateGateways', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listProjectAccounts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listProjectInvitations', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listProjects', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listPublicIpAddresses', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listRegions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listRemoteAccessVpns', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listResourceDetails', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listResourceLimits', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listSSHKeyPairs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listSecurityGroups', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listServiceOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listSnapshotPolicies', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listSnapshots', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listSslCerts', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listStaticRoutes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listTags', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listTemplatePermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listTemplates', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listUsers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listVPCOfferings', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listVPCs', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listVirtualMachines', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listVolumes', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listVolumesOnFiler', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listVpnConnections', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listVpnCustomerGateways', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listVpnGateways', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listVpnUsers', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'listZones', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'migrateVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'modifyPool', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'queryAsyncJobResult', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'rebootVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'registerIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'registerSSHKeyPair', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'registerTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'registerUserKeys', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'removeCertFromLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'removeFromGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'removeFromLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'removeIpFromNic', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'removeNicFromVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'removeVpnUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'replaceNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'resetPasswordForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'resetSSHKeyForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'resetVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'resizeVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'restartNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'restartVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'restoreVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'revertSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'revertToVMSnapshot', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'revokeSecurityGroupEgress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'revokeSecurityGroupIngress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'scaleVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'startVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'stopVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'suspendProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateAutoScalePolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateAutoScaleVmGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateAutoScaleVmProfile', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateDefaultNicForVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateEgressFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateFirewallRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateGlobalLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateInstanceGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateIpAddress', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateIso', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateIsoPermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateLBHealthCheckPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateLBStickinessPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateLoadBalancer', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateLoadBalancerRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateNetwork', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateNetworkACLItem', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateNetworkACLList', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updatePortForwardingRule', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateProject', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateProjectInvitation', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateRemoteAccessVpn', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateSnapshotPolicy', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateTemplate', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateTemplatePermissions', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateUser', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateVMAffinityGroup', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateVPC', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateVirtualMachine', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateVpnConnection', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateVpnCustomerGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'updateVpnGateway', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'uploadSslCert', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`) values (UUID(), 4, 'uploadVolume', 'Allow') ON DUPLICATE KEY UPDATE rule=rule; diff --git a/setup/db/db/schema-452to453-cleanup.sql b/setup/db/db/schema-452to453-cleanup.sql index de1c6fe65c2..83fddabf599 100644 --- a/setup/db/db/schema-452to453-cleanup.sql +++ b/setup/db/db/schema-452to453-cleanup.sql @@ -18,3 +18,192 @@ --; -- Schema cleanup from 4.5.2 to 4.5.3; --; + +DROP VIEW IF EXISTS `cloud`.`account_view`; +CREATE VIEW `cloud`.`account_view` AS + select + account.id, + account.uuid, + account.account_name, + account.type, + account.role_id, + account.state, + account.removed, + account.cleanup_needed, + account.network_domain, + account.default, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + data_center.id data_center_id, + data_center.uuid data_center_uuid, + data_center.name data_center_name, + account_netstats_view.bytesReceived, + account_netstats_view.bytesSent, + vmlimit.max vmLimit, + vmcount.count vmTotal, + runningvm.vmcount runningVms, + stoppedvm.vmcount stoppedVms, + iplimit.max ipLimit, + ipcount.count ipTotal, + free_ip_view.free_ip ipFree, + volumelimit.max volumeLimit, + volumecount.count volumeTotal, + snapshotlimit.max snapshotLimit, + snapshotcount.count snapshotTotal, + templatelimit.max templateLimit, + templatecount.count templateTotal, + vpclimit.max vpcLimit, + vpccount.count vpcTotal, + projectlimit.max projectLimit, + projectcount.count projectTotal, + networklimit.max networkLimit, + networkcount.count networkTotal, + cpulimit.max cpuLimit, + cpucount.count cpuTotal, + memorylimit.max memoryLimit, + memorycount.count memoryTotal, + primary_storage_limit.max primaryStorageLimit, + primary_storage_count.count primaryStorageTotal, + secondary_storage_limit.max secondaryStorageLimit, + secondary_storage_count.count secondaryStorageTotal, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id + from + `cloud`.`free_ip_view`, + `cloud`.`account` + inner join + `cloud`.`domain` ON account.domain_id = domain.id + left join + `cloud`.`data_center` ON account.default_zone_id = data_center.id + left join + `cloud`.`account_netstats_view` ON account.id = account_netstats_view.account_id + left join + `cloud`.`resource_limit` vmlimit ON account.id = vmlimit.account_id + and vmlimit.type = 'user_vm' + left join + `cloud`.`resource_count` vmcount ON account.id = vmcount.account_id + and vmcount.type = 'user_vm' + left join + `cloud`.`account_vmstats_view` runningvm ON account.id = runningvm.account_id + and runningvm.state = 'Running' + left join + `cloud`.`account_vmstats_view` stoppedvm ON account.id = stoppedvm.account_id + and stoppedvm.state = 'Stopped' + left join + `cloud`.`resource_limit` iplimit ON account.id = iplimit.account_id + and iplimit.type = 'public_ip' + left join + `cloud`.`resource_count` ipcount ON account.id = ipcount.account_id + and ipcount.type = 'public_ip' + left join + `cloud`.`resource_limit` volumelimit ON account.id = volumelimit.account_id + and volumelimit.type = 'volume' + left join + `cloud`.`resource_count` volumecount ON account.id = volumecount.account_id + and volumecount.type = 'volume' + left join + `cloud`.`resource_limit` snapshotlimit ON account.id = snapshotlimit.account_id + and snapshotlimit.type = 'snapshot' + left join + `cloud`.`resource_count` snapshotcount ON account.id = snapshotcount.account_id + and snapshotcount.type = 'snapshot' + left join + `cloud`.`resource_limit` templatelimit ON account.id = templatelimit.account_id + and templatelimit.type = 'template' + left join + `cloud`.`resource_count` templatecount ON account.id = templatecount.account_id + and templatecount.type = 'template' + left join + `cloud`.`resource_limit` vpclimit ON account.id = vpclimit.account_id + and vpclimit.type = 'vpc' + left join + `cloud`.`resource_count` vpccount ON account.id = vpccount.account_id + and vpccount.type = 'vpc' + left join + `cloud`.`resource_limit` projectlimit ON account.id = projectlimit.account_id + and projectlimit.type = 'project' + left join + `cloud`.`resource_count` projectcount ON account.id = projectcount.account_id + and projectcount.type = 'project' + left join + `cloud`.`resource_limit` networklimit ON account.id = networklimit.account_id + and networklimit.type = 'network' + left join + `cloud`.`resource_count` networkcount ON account.id = networkcount.account_id + and networkcount.type = 'network' + left join + `cloud`.`resource_limit` cpulimit ON account.id = cpulimit.account_id + and cpulimit.type = 'cpu' + left join + `cloud`.`resource_count` cpucount ON account.id = cpucount.account_id + and cpucount.type = 'cpu' + left join + `cloud`.`resource_limit` memorylimit ON account.id = memorylimit.account_id + and memorylimit.type = 'memory' + left join + `cloud`.`resource_count` memorycount ON account.id = memorycount.account_id + and memorycount.type = 'memory' + left join + `cloud`.`resource_limit` primary_storage_limit ON account.id = primary_storage_limit.account_id + and primary_storage_limit.type = 'primary_storage' + left join + `cloud`.`resource_count` primary_storage_count ON account.id = primary_storage_count.account_id + and primary_storage_count.type = 'primary_storage' + left join + `cloud`.`resource_limit` secondary_storage_limit ON account.id = secondary_storage_limit.account_id + and secondary_storage_limit.type = 'secondary_storage' + left join + `cloud`.`resource_count` secondary_storage_count ON account.id = secondary_storage_count.account_id + and secondary_storage_count.type = 'secondary_storage' + left join + `cloud`.`async_job` ON async_job.instance_id = account.id + and async_job.instance_type = 'Account' + and async_job.job_status = 0; + +DROP VIEW IF EXISTS `cloud`.`user_view`; +CREATE VIEW `cloud`.`user_view` AS + select + user.id, + user.uuid, + user.username, + user.password, + user.firstname, + user.lastname, + user.email, + user.state, + user.api_key, + user.secret_key, + user.created, + user.removed, + user.timezone, + user.registration_token, + user.is_registered, + user.incorrect_login_attempts, + user.default, + account.id account_id, + account.uuid account_uuid, + account.account_name account_name, + account.type account_type, + account.role_id account_role_id, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id + from + `cloud`.`user` + inner join + `cloud`.`account` ON user.account_id = account.id + inner join + `cloud`.`domain` ON account.domain_id = domain.id + left join + `cloud`.`async_job` ON async_job.instance_id = user.id + and async_job.instance_type = 'User' + and async_job.job_status = 0; diff --git a/setup/db/db/schema-452to453.sql b/setup/db/db/schema-452to453.sql index c3ae594873c..209027cce9e 100644 --- a/setup/db/db/schema-452to453.sql +++ b/setup/db/db/schema-452to453.sql @@ -19,3 +19,32 @@ -- Schema upgrade from 4.5.2 to 4.5.3; --; +CREATE TABLE IF NOT EXISTS `cloud`.`roles` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(255) UNIQUE, + `name` varchar(255) COMMENT 'unique name of the dynamic role', + `role_type` varchar(255) NOT NULL COMMENT 'the type of the role', + `removed` datetime COMMENT 'date removed', + `description` text COMMENT 'description of the role', + PRIMARY KEY (`id`), + KEY `i_roles__name` (`name`), + KEY `i_roles__role_type` (`role_type`), + UNIQUE KEY (`name`, `role_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `cloud`.`role_permissions` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(255) UNIQUE, + `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', + PRIMARY KEY (`id`), + KEY `fk_role_details__role_id` (`role_id`), + KEY `i_role_details__rule` (`rule`), + KEY `i_role_details__permission` (`permission`), + UNIQUE KEY (`role_id`, `rule`), + CONSTRAINT `fk_role_detail__role_id` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + diff --git a/setup/db/server-setup.sql b/setup/db/server-setup.sql index b7f5c3fc302..df2c9248552 100644 --- a/setup/db/server-setup.sql +++ b/setup/db/server-setup.sql @@ -25,4 +25,5 @@ INSERT INTO `cloud`.`domain` (id, uuid, name, parent, path, owner) VALUES (1, UU INSERT INTO `cloud`.`configuration` (category, instance, component, name, value, description) VALUES ('Hidden', 'DEFAULT', 'none', 'init', null, null); -- INSERT INTO `cloud`.`configuration` (category, instance, component, name, value, description) VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xenserver.public.network.device', 'public-network', "[OPTIONAL]The name of the XenServer network containing the physical network interface that is connected to the public network "); - +-- Enable dynamic RBAC by default for fresh deployments +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'RoleService', 'dynamic.apichecker.enabled', 'true'); diff --git a/setup/db/server-setup.xml b/setup/db/server-setup.xml index bb8878f8d37..178f29aea35 100755 --- a/setup/db/server-setup.xml +++ b/setup/db/server-setup.xml @@ -239,6 +239,13 @@ under the License. qatest-vmops.com + + dynamic.apichecker.enabled + true + + - - - - - - - - -Apache CloudStack | The Power Behind Your Cloud - - - -
-
-
-
- -
-
- -
-
- -
- -
- -
-
- - -
- -
- -
-
-
-
- - - - Apache CloudStack v4.5.0 Domain Admin API Reference - -

-

-

-
-
- - -
- -
-
-
-

Request parameters

- - - - - - - - - - - - - - - - - - - - - -
Parameter NameDescriptionRequired
-
- - -
-

Response Tags

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Response NameDescription
- -
- - -
-
- - -
-
- - -
-
- - -
-
- diff --git a/tools/apidoc/generateusercommands.xsl b/tools/apidoc/generateusercommands.xsl deleted file mode 100644 index dd4f3a52825..00000000000 --- a/tools/apidoc/generateusercommands.xsl +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - - - -Apache CloudStack | The Power Behind Your Cloud - - - -
-
-
-
-
- -
-
- -
- -
- -
-
- -
- -
- -
-
-
-
- - - - Apache CloudStack v4.5.0 User API Reference - -

-

-

-
-
- - -
- -
-
-
-

Request parameters

- - - - - - - - - - - - - - - - - - - - - -
Parameter NameDescriptionRequired
-
- - -
-

Response Tags

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Response NameDescription
- -
- - -
-
- - -
-
- - -
-
- - -
-
- diff --git a/tools/apidoc/pom.xml b/tools/apidoc/pom.xml index 18b70f43ec8..f0093daee05 100644 --- a/tools/apidoc/pom.xml +++ b/tools/apidoc/pom.xml @@ -55,8 +55,6 @@ ${client.config.jars} ${client.config.jars} ./target - -f - ${client.config.conf}/commands.properties diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index aa7b18ff6c7..d044fdd0eb4 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -143,7 +143,7 @@ class CSConnection(object): ["=".join( [str.lower(r[0]), str.lower( - urllib.quote_plus(str(r[1])) + urllib.quote_plus(str(r[1]), safe="*") ).replace("+", "%20")] ) for r in params] ) diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index e38c39430f8..dc88457e7cc 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -86,13 +86,96 @@ class Domain: return(apiclient.listDomains(cmd)) +class Role: + """Manage Role""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, domainid=None): + """Create role""" + cmd = createRole.createRoleCmd() + cmd.name = services["name"] + cmd.type = services["type"] + if "description" in services: + cmd.description = services["description"] + + return Role(apiclient.createRole(cmd).__dict__) + + def delete(self, apiclient): + """Delete Role""" + + cmd = deleteRole.deleteRoleCmd() + cmd.id = self.id + apiclient.deleteRole(cmd) + + def update(self, apiclient, **kwargs): + """Update the role""" + + cmd = updateRole.updateRoleCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return apiclient.updateRole(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Roles matching criteria""" + + cmd = listRoles.listRolesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listRoles(cmd)) + + +class RolePermission: + """Manage Role Permission""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, domainid=None): + """Create role permission""" + cmd = createRolePermission.createRolePermissionCmd() + cmd.roleid = services["roleid"] + cmd.rule = services["rule"] + cmd.permission = services["permission"] + if "description" in services: + cmd.description = services["description"] + + return RolePermission(apiclient.createRolePermission(cmd).__dict__) + + def delete(self, apiclient): + """Delete role permission""" + + cmd = deleteRolePermission.deleteRolePermissionCmd() + cmd.id = self.id + apiclient.deleteRolePermission(cmd) + + def update(self, apiclient, **kwargs): + """Update the role permission""" + + cmd = updateRolePermission.updateRolePermissionCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return apiclient.updateRolePermission(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all role permissions matching criteria""" + + cmd = listRolePermissions.listRolePermissionsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listRolePermissions(cmd)) + + class Account: """ Account Life Cycle """ def __init__(self, items): self.__dict__.update(items) @classmethod - def create(cls, apiclient, services, admin=False, domainid=None): + def create(cls, apiclient, services, admin=False, domainid=None, roleid=None): """Creates an account""" cmd = createAccount.createAccountCmd() @@ -121,6 +204,10 @@ class Account: if domainid: cmd.domainid = domainid + + if roleid: + cmd.roleid = roleid + account = apiclient.createAccount(cmd) return Account(account.__dict__) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index e928409e6bf..9d07d132c8b 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -2902,6 +2902,15 @@ div.detail-group.actions td { background-position: -366px -239px; } +#navigation ul li.roles span.icon { + background-position: -460px -80px; +} + +#navigation ul li.roles.active span.icon, +#navigation ul li.roles:hover span.icon { + background-position: -469px -750px; +} + #navigation ul li.accounts span.icon { background-position: -458px -19px; } @@ -13117,3 +13126,10 @@ div.gpugroups div.list-view { background: transparent url("../images/icons.png") no-repeat -626px -209px; padding: 0 0 3px 18px; } + +ul.ui-autocomplete.ui-menu { + width: 250px; + background: #ddd; + font-size: 13px; + padding: 5px; +} diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index e0a41c1478f..a2636fcdc1c 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -1067,7 +1067,13 @@ dictionary = { 'label.retry.interval': '', 'label.review': '', 'label.revoke.project.invite': '', +'label.permission': '', 'label.role': '', +'label.roles': '', +'label.roletype': '', +'label.add.role': '', +'label.edit.role': '', +'label.delete.role': '', 'label.root.disk.controller': '', 'label.root.disk.offering': '', }; diff --git a/ui/dictionary2.jsp b/ui/dictionary2.jsp index 20f698f9876..2b4d9209329 100644 --- a/ui/dictionary2.jsp +++ b/ui/dictionary2.jsp @@ -25,6 +25,7 @@ under the License. <% long now = System.currentTimeMillis(); %> + diff --git a/ui/scripts/accounts.js b/ui/scripts/accounts.js index 7db28b3a63d..276bf46185a 100644 --- a/ui/scripts/accounts.js +++ b/ui/scripts/accounts.js @@ -17,7 +17,8 @@ (function(cloudStack) { var domainObjs; - + var roleObjs; + cloudStack.sections.accounts = { title: 'label.accounts', id: 'accounts', @@ -38,11 +39,11 @@ name: { label: 'label.name' }, - accounttype: { - label: 'label.role', - converter: function(args) { - return cloudStack.converters.toRole(args); - } + rolename: { + label: 'label.role' + }, + roletype: { + label: 'label.roletype' }, domain: { label: 'label.domain' @@ -678,11 +679,11 @@ id: { label: 'label.id' }, - accounttype: { - label: 'label.role', - converter: function(args) { - return cloudStack.converters.toRole(args); - } + rolename: { + label: 'label.role' + }, + roletype: { + label: 'label.roletype' }, domain: { label: 'label.domain' @@ -1570,11 +1571,11 @@ account: { label: 'label.account.name' }, - accounttype: { - label: 'label.role', - converter: function(args) { - return cloudStack.converters.toRole(args); - } + rolename: { + label: 'label.role' + }, + roletype: { + label: 'label.roletype' }, domain: { label: 'label.domain' diff --git a/ui/scripts/accountsWizard.js b/ui/scripts/accountsWizard.js index 03dc65c3c0a..3479923f3cc 100644 --- a/ui/scripts/accountsWizard.js +++ b/ui/scripts/accountsWizard.js @@ -110,24 +110,28 @@ required: false } }, - accounttype: { - label: 'label.type', + roleid: { + label: 'label.role', docID: 'helpAccountType', validation: { required: true }, select: function(args) { - var items = []; - items.push({ - id: 0, - description: "User" - }); //regular-user - items.push({ - id: 1, - description: "Admin" - }); //root-admin - args.response.success({ - data: items + $.ajax({ + url: createURL("listRoles"), + success: function(json) { + var items = []; + roleObjs = json.listrolesresponse.role; + $(roleObjs).each(function() { + items.push({ + id: this.id, + description: this.name + ' (' + this.type + ')' + }); + }); + args.response.success({ + data: items + }); + } }); } }, @@ -226,13 +230,9 @@ array1.push("&account=" + account); } - var accountType = args.data.accounttype; - if (accountType == "1") { //if "admin" is selected in account type dropdown - if (rootDomainId == undefined || args.data.domainid != rootDomainId ) { //but current login has no visibility to root domain object, or the selected domain is not root domain - accountType = "2"; // change accountType from root-domain("1") to domain-admin("2") - } + if (args.data.roleid) { + array1.push("&roleid=" + args.data.roleid); } - array1.push("&accounttype=" + accountType); if (args.data.timezone !== null && args.data.timezone.length > 0) { array1.push("&timezone=" + args.data.timezone); diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index 1dcb99470ea..a619e564b60 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -22,7 +22,7 @@ var sections = []; if (isAdmin()) { - sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions", "affinityGroups"]; + sections = ["dashboard", "instances", "storage", "network", "templates", "roles", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions", "affinityGroups"]; } else if (isDomainAdmin()) { sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects", "regions", "affinityGroups"]; } else if (g_userProjectsEnabled) { @@ -52,6 +52,7 @@ templates: {}, events: {}, projects: {}, + roles: {}, accounts: {}, domains: {}, //domain-admin and root-admin only diff --git a/ui/scripts/roles.js b/ui/scripts/roles.js new file mode 100644 index 00000000000..0bf8d91a8a1 --- /dev/null +++ b/ui/scripts/roles.js @@ -0,0 +1,355 @@ +// 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. +(function($, cloudStack) { + var apiList = []; + cloudStack.sections.roles = { + title: 'label.roles', + id: 'roles', + listView: { + id: 'roles', + fields: { + name: { + label: 'label.name' + }, + type: { + label: 'label.type' + }, + description: { + label: 'label.description' + } + }, + disableInfiniteScrolling: true, + dataProvider: function(args) { + var data = {}; + if (args.filterBy.search && args.filterBy.search.value) { + data['name'] = args.filterBy.search.value; + } + $.ajax({ + url: createURL("listRoles"), + data: data, + dataType: "json", + async: true, + success: function(json) { + var jsonObj; + jsonObj = json.listrolesresponse.role; + args.response.success({ + data: jsonObj + }); + } + }); + }, + actions: { + add: { + label: 'label.add.role', + preFilter: function(args) { + if (isAdmin()) + return true; + }, + messages: { + notification: function() { + return 'label.add.role'; + } + }, + createForm: { + title: 'label.add.role', + fields: { + name: { + label: 'label.name', + validation: { + required: true + } + }, + description: { + label: 'label.description', + }, + type: { + label: 'label.type', + validation: { + required: true + }, + select: function(args) { + var items = []; + items.push({ + id: "Admin", + description: "Admin" + }); + items.push({ + id: "DomainAdmin", + description: "Domain Admin" + }); + items.push({ + id: "User", + description: "User" + }); + args.response.success({ + data: items + }); + } + } + } + }, + action: function(args) { + $.ajax({ + url: createURL('createRole'), + data: args.data, + success: function(json) { + var item = json.createroleresponse.role; + args.response.success({ + data: item + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + detailView: { + tabs: { + details: { + title: 'label.details', + fields: { + id: { + label: 'label.id' + }, + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + }, + type: { + label: 'label.type' + }, + description: { + label: 'label.description', + isEditable: true + } + }, + dataProvider: function(args) { + $.ajax({ + url: createURL("listRoles&id=" + args.context.roles[0].id), + dataType: "json", + async: true, + success: function(json) { + var response = json.listrolesresponse.role[0]; + args.response.success({ + data: response + }); + } + }); + } + }, + rules: { + title: 'label.rules', + custom: function(args) { + var context = args.context; + + return $('
').multiEdit({ + context: context, + noSelect: true, + noHeaderActionsColumn: true, + fields: { + 'rule': { + edit: true, + label: 'label.rule', + isOptional: false + }, + 'permission': { + label: 'label.permission', + select: function(args) { + args.response.success({ + data: [{ + name: 'allow', + description: 'Allow' + }, { + name: 'deny', + description: 'Deny' + }] + }); + } + }, + 'description': { + edit: true, + label: 'label.description', + isOptional: true + }, + 'always-hide': { + label: 'label.action', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + var data = { + rule: args.data.rule, + permission: args.data.permission, + description: args.data.description, + roleid: args.context.roles[0].id + }; + + $.ajax({ + url: createURL('createRolePermission'), + data: data, + dataType: 'json', + success: function(json) { + var response = json.createrolepermissionresponse.rolepermission; + args.response.success({ + data: response + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + actions: { + destroy: { + label: 'label.remove.rule', + action: function(args) { + $.ajax({ + url: createURL('deleteRolePermission'), + data: { + id: args.context.multiRule[0].id + }, + dataType: 'json', + success: function(data) { + args.response.success(); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + dataProvider: function(args) { + $.ajax({ + url: createURL('listRolePermissions'), + data: { + roleid: args.context.roles[0].id + }, + dataType: 'json', + success: function(json) { + var addRules = function(type, rules, data) { + $.each(rules, function(idx, rule) { + if (rule.permission != type) { + return; + } + data.push(rule); + }); + } + var rules = json.listrolepermissionsresponse.rolepermission; + var data = []; + addRules('allow', rules, data); + addRules('deny', rules, data); + args.response.success({ + data: data + }); + } + }); + var setupAutocompletion = function() { + $($.find('input[name="rule"]')).autocomplete("destroy"); + $($.find('input[name="rule"]')).autocomplete({ + source: apiList, + autoFocus:true + }); + }; + if (apiList.length == 0) { + $.ajax({ + url: createURL("listApis"), + dataType: "json", + success: function(json) { + var response = json.listapisresponse.api; + $.each(response, function(idx, api) { + apiList.push(api.name); + }); + setupAutocompletion(); + } + }); + } else { + setupAutocompletion(); + } + } + }); + } + } + }, + actions: { + edit: { + label: 'label.edit.role', + action: function(args) { + var data = { + id: args.context.roles[0].id, + name: args.data.name, + description: args.data.description + }; + + $.ajax({ + url: createURL('updateRole'), + data: data, + success: function(json) { + args.response.success(); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + remove: { + label: 'label.delete.role', + messages: { + confirm: function(args) { + return 'label.delete.role'; + }, + notification: function(args) { + return 'label.delete.role'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("deleteRole&id=" + args.context.roles[0].id), + dataType: "json", + success: function(json) { + var response = json.deleteroleresponse; + args.response.success({ + data: response + }); + } + }); + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + } + } + } + } +})(jQuery, cloudStack); diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 31c67e3cd95..d275c4e476a 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -1087,6 +1087,17 @@ cloudStack.converters = { return "Domain-Admin"; } }, + toAccountType: function(roleType) { + if (roleType == 'User') { + return 0; + } else if (roleType == 'Admin') { + return 1; + } else if (roleType == 'DomainAdmin') { + return 2; + } else if (roleType == 'ResourceAdmin') { + return 3; + } + }, toAlertType: function(alertCode) { switch (alertCode) { case 0: diff --git a/ui/scripts/ui/widgets/multiEdit.js b/ui/scripts/ui/widgets/multiEdit.js index c4de8cecbe2..e14f3ef1a14 100755 --- a/ui/scripts/ui/widgets/multiEdit.js +++ b/ui/scripts/ui/widgets/multiEdit.js @@ -278,9 +278,6 @@ $td.addClass('blank'); } - // Align width to main header - _medit.refreshItemWidths($multi); - if (data._hideFields && $.inArray(fieldName, data._hideFields) > -1) { $td.addClass('disabled'); diff --git a/utils/src/com/cloud/utils/ListUtils.java b/utils/src/com/cloud/utils/ListUtils.java new file mode 100644 index 00000000000..fa9332f119d --- /dev/null +++ b/utils/src/com/cloud/utils/ListUtils.java @@ -0,0 +1,31 @@ +// 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 com.cloud.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ListUtils { + public static List toListOfInterface(final List items) { + if (items != null) { + return new ArrayList<>(items); + } + return Collections.emptyList(); + } +} diff --git a/utils/src/com/cloud/utils/PropertiesUtil.java b/utils/src/com/cloud/utils/PropertiesUtil.java index 3b1070c5a42..5340cd5b174 100755 --- a/utils/src/com/cloud/utils/PropertiesUtil.java +++ b/utils/src/com/cloud/utils/PropertiesUtil.java @@ -36,6 +36,10 @@ import org.apache.log4j.Logger; public class PropertiesUtil { private static final Logger s_logger = Logger.getLogger(PropertiesUtil.class); + public static String getDefaultApiCommandsFileName() { + return "commands.properties"; + } + /** * Searches the class path and local paths to find the config file. * @param path path to find. if it starts with / then it's absolute path.