blob: 9363ebd2379e7d8c96f65927fbf63a5e5b42d854 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.acl;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.UnavailableCommandException;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectAccount;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.User;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.PluggableService;
public class ProjectRoleBasedApiAccessChecker extends AdapterBase implements APIAclChecker {
@Inject
ProjectAccountDao projectAccountDao;
@Inject
ProjectRoleService projectRoleService;
@Inject
RoleService roleService;
@Inject
AccountService accountService;
private List<PluggableService> services;
private static final Logger LOGGER = Logger.getLogger(ProjectRoleBasedApiAccessChecker.class.getName());
protected ProjectRoleBasedApiAccessChecker() {
super();
}
private void denyApiAccess(final String commandName) throws PermissionDeniedException {
throw new PermissionDeniedException("The API " + commandName + " is denied for the user's/account's project role.");
}
@Override
public boolean isEnabled() {
if (!roleService.isEnabled()) {
LOGGER.trace("RoleService is disabled. We will not use ProjectRoleBasedApiAccessChecker.");
}
return roleService.isEnabled();
}
@Override
public List<String> getApisAllowedToUser(Role role, User user, List<String> apiNames) throws PermissionDeniedException {
if (!isEnabled()) {
return apiNames;
}
Project project = CallContext.current().getProject();
if (project == null) {
LOGGER.warn(String.format("Project is null, ProjectRoleBasedApiAccessChecker only applies to projects, returning APIs [%s] for user [%s] as allowed.", apiNames, user));
return apiNames;
}
long accountID = user.getAccountId();
ProjectAccount projectUser = projectAccountDao.findByProjectIdUserId(project.getId(), accountID, user.getId());
if (projectUser != null) {
if (projectUser.getAccountRole() != ProjectAccount.Role.Admin) {
apiNames.removeIf(apiName -> !isPermitted(project, projectUser, apiName));
}
if (LOGGER.isTraceEnabled()) {
LOGGER.trace(String.format("Returning APIs [%s] as allowed for user [%s].", apiNames, user));
}
return apiNames;
}
ProjectAccount projectAccount = projectAccountDao.findByProjectIdAccountId(project.getId(), accountID);
if (projectAccount == null) {
throw new PermissionDeniedException(String.format("The user [%s] does not belong to the project [%s].", user, project));
}
if (projectAccount.getAccountRole() != ProjectAccount.Role.Admin) {
apiNames.removeIf(apiName -> !isPermitted(project, projectAccount, apiName));
}
if (LOGGER.isTraceEnabled()) {
LOGGER.trace(String.format("Returning APIs [%s] as allowed for user [%s].", apiNames, user));
}
return apiNames;
}
@Override
public boolean checkAccess(User user, String apiCommandName) throws PermissionDeniedException {
if (!isEnabled()) {
return true;
}
Project project = CallContext.current().getProject();
if (project == null) {
LOGGER.warn(String.format("Project is null, ProjectRoleBasedApiAccessChecker only applies to projects, returning API [%s] for user [%s] as allowed.", apiCommandName,
user));
return true;
}
Account userAccount = accountService.getAccount(user.getAccountId());
if (accountService.isRootAdmin(userAccount.getId()) || accountService.isDomainAdmin(userAccount.getAccountId())) {
LOGGER.info(String.format("Account [%s] is Root Admin or Domain Admin, all APIs are allowed.", userAccount.getAccountName()));
return true;
}
ProjectAccount projectUser = projectAccountDao.findByProjectIdUserId(project.getId(), userAccount.getAccountId(), user.getId());
if (projectUser != null) {
if (projectUser.getAccountRole() == ProjectAccount.Role.Admin || isPermitted(project, projectUser, apiCommandName)) {
return true;
}
denyApiAccess(apiCommandName);
}
ProjectAccount projectAccount = projectAccountDao.findByProjectIdAccountId(project.getId(), userAccount.getAccountId());
if (projectAccount != null) {
if (projectAccount.getAccountRole() == ProjectAccount.Role.Admin || isPermitted(project, projectAccount, apiCommandName)) {
return true;
}
denyApiAccess(apiCommandName);
}
// Default deny all
if ("updateProjectInvitation".equals(apiCommandName)) {
return true;
}
throw new UnavailableCommandException(String.format("The API [%s] does not exist or is not available for this account/user in project [%s].", apiCommandName, project.getUuid()));
}
@Override
public boolean checkAccess(Account account, String apiCommandName) throws PermissionDeniedException {
return true;
}
public boolean isPermitted(Project project, ProjectAccount projectUser, String ... apiCommandNames) {
ProjectRole projectRole = null;
if(projectUser.getProjectRoleId() != null) {
projectRole = projectRoleService.findProjectRole(projectUser.getProjectRoleId(), project.getId());
}
if (projectRole == null) {
return true;
}
List<ProjectRolePermission> allProjectRolePermissions = projectRoleService.findAllProjectRolePermissions(project.getId(), projectRole.getId());
for (String api : apiCommandNames) {
for (ProjectRolePermission permission : allProjectRolePermissions) {
if (permission.getRule().matches(api)) {
return Permission.ALLOW.equals(permission.getPermission());
}
}
}
return true;
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
return true;
}
@Override
public boolean start() {
return super.start();
}
public List<PluggableService> getServices() {
return services;
}
@Inject
public void setServices(List<PluggableService> services) {
this.services = services;
}
}