package org.ovirt.engine.core.bll;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.AddGroupParameters;
import org.ovirt.engine.core.common.action.AddUserParameters;
import org.ovirt.engine.core.common.action.PermissionsOperationsParameters;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.businessentities.ActionGroup;
import org.ovirt.engine.core.common.businessentities.Permission;
import org.ovirt.engine.core.common.businessentities.Role;
import org.ovirt.engine.core.common.businessentities.RoleType;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.aaa.DbGroup;
import org.ovirt.engine.core.common.businessentities.aaa.DbUser;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.DbGroupDao;
import org.ovirt.engine.core.dao.DbUserDao;
import org.ovirt.engine.core.dao.PermissionDao;
import org.ovirt.engine.core.dao.RoleDao;
import org.ovirt.engine.core.dao.VmDao;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
@ValidateSupportsTransaction
public class AddPermissionCommand<T extends PermissionsOperationsParameters> extends PermissionsCommandBase<T> {
@Inject
private PermissionDao permissionDao;
@Inject
private RoleDao roleDao;
@Inject
private DbUserDao dbUserDao;
@Inject
private DbGroupDao dbGroupDao;
@Inject
private VmDao vmDao;
public AddPermissionCommand(T parameters, CommandContext commandContext) {
super(parameters, commandContext);
}
public AddPermissionCommand(Guid commandId) {
super(commandId);
}
@Override
protected boolean validate() {
Permission perm = getParameters().getPermission();
if (perm == null) {
addValidationMessage(EngineMessage.PERMISSION_ADD_FAILED_PERMISSION_NOT_SENT);
return false;
}
// Try to find the requested role, first by id and then by name:
Role role = null;
Guid roleId = perm.getRoleId();
String roleName = perm.getRoleName();
if (!Guid.isNullOrEmpty(roleId)) {
role = roleDao.get(roleId);
if (role != null) {
roleName = role.getName();
perm.setRoleName(roleName);
}
}
else if (roleName != null) {
role = roleDao.getByName(roleName);
if (role != null) {
roleId = role.getId();
perm.setRoleId(roleId);
}
}
if (role == null) {
addValidationMessage(EngineMessage.PERMISSION_ADD_FAILED_INVALID_ROLE_ID);
return false;
}
Guid adElementId = perm.getAdElementId();
if (perm.getObjectType() == null
|| getVdcObjectName() == null) {
addValidationMessage(EngineMessage.PERMISSION_ADD_FAILED_INVALID_OBJECT_ID);
return false;
}
// if user and group not sent check user/group is in the db in order to
// give permission
if (getParameters().getUser() == null
&& getParameters().getGroup() == null
&& dbUserDao.get(adElementId) == null
&& dbGroupDao.get(adElementId) == null) {
getReturnValue().getValidationMessages().add(EngineMessage.USER_MUST_EXIST_IN_DB.toString());
return false;
}
// only system super user can give permissions with admin roles
if (!isSystemSuperUser() && role.getType() == RoleType.ADMIN) {
addValidationMessage(EngineMessage.PERMISSION_ADD_FAILED_ONLY_SYSTEM_SUPER_USER_CAN_GIVE_ADMIN_ROLES);
return false;
}
// don't allow adding permissions to vms from pool externally
if (!isInternalExecution() && perm.getObjectType() == VdcObjectType.VM) {
VM vm = vmDao.get(perm.getObjectId());
if (vm != null && vm.getVmPoolId() != null) {
addValidationMessage(EngineMessage.PERMISSION_ADD_FAILED_VM_IN_POOL);
return false;
}
}
return true;
}
@Override
protected void executeCommand() {
// Get the parameters:
T parameters = getParameters();
// The user or group given in the parameters may haven't been added to the database yet, if this is the case
// then they need to be added to the database now, before the permission:
DbUser user = parameters.getUser();
if (user != null) {
Guid id = user.getId();
String directory = user.getDomain();
String externalId = user.getExternalId();
DbUser existing = dbUserDao.getByIdOrExternalId(id, directory, externalId);
if (existing != null) {
user = existing;
}
else {
user = addUser(user);
if (user == null) {
setSucceeded(false);
return;
}
}
}
DbGroup group = parameters.getGroup();
if (group != null) {
Guid id = group.getId();
String directory = group.getDomain();
String externalId = group.getExternalId();
DbGroup existing = dbGroupDao.getByIdOrExternalId(id, directory, externalId);
if (existing != null) {
group = existing;
}
else {
group = addGroup(group);
if (group == null) {
setSucceeded(false);
return;
}
}
}
// The identifier of the principal of the permission can come from the parameters directly or from the
// user/group objects:
Guid principalId;
if (user != null) {
principalId = user.getId();
}
else if (group != null) {
principalId = group.getId();
}
else {
principalId = parameters.getPermission().getAdElementId();
}
final Permission paramPermission = parameters.getPermission();
Permission permission =
permissionDao.getForRoleAndAdElementAndObject(paramPermission.getRoleId(), principalId,
paramPermission.getObjectId());
if (permission == null) {
paramPermission.setAdElementId(principalId);
TransactionSupport.executeInNewTransaction(() -> {
permissionDao.save(paramPermission);
getCompensationContext().snapshotNewEntity(paramPermission);
getCompensationContext().stateChanged();
return null;
});
permission = paramPermission;
}
getReturnValue().setActionReturnValue(permission.getId());
if (user != null) {
updateAdminStatus(permission);
}
setSucceeded(true);
}
private void updateAdminStatus(Permission perm) {
// if the role of the permission is of type admin update the user
// lastAdminCheckStatus to true
Role role = roleDao.get(perm.getRoleId());
if (role.getType() == RoleType.ADMIN) {
MultiLevelAdministrationHandler.setIsAdminGUIFlag(perm.getAdElementId(), true);
}
}
@Override
public AuditLogType getAuditLogTypeValue() {
return getSucceeded() ? AuditLogType.USER_ADD_PERMISSION : AuditLogType.USER_ADD_PERMISSION_FAILED;
}
@Override
public List<PermissionSubject> getPermissionCheckSubjects() {
Permission permission = getParameters().getPermission();
List<PermissionSubject> permissionsSubject = new ArrayList<>();
permissionsSubject.add(new PermissionSubject(permission.getObjectId(),
permission.getObjectType(),
getActionType().getActionGroup()));
initUserAndGroupData();
// if the user does not exist in the database we need to
// check if the logged in user has permissions to add another
// user from the directory service
if ((getParameters().getUser() != null && dbUser == null)
|| (getParameters().getGroup() != null && dbGroup == null)) {
permissionsSubject.add(new PermissionSubject(permission.getObjectId(),
permission.getObjectType(), ActionGroup.ADD_USERS_AND_GROUPS_FROM_DIRECTORY));
}
return permissionsSubject;
}
private DbUser addUser(DbUser dbUser) {
// Try to add the user with the external id:
if (dbUser.getDomain() != null && dbUser.getExternalId() != null) {
AddUserParameters parameters = new AddUserParameters(dbUser);
VdcReturnValueBase result = runInternalAction(VdcActionType.AddUser, parameters, cloneContextAndDetachFromParent());
if (result.getSucceeded()) {
Guid id = result.getActionReturnValue();
if (id != null) {
return dbUserDao.get(id);
}
return null;
}
}
// There is no such user in the directory:
return null;
}
private DbGroup addGroup(DbGroup groupToAdd) {
// Try to add the user with the external id:
if (groupToAdd.getDomain() != null && groupToAdd.getExternalId() != null) {
AddGroupParameters parameters = new AddGroupParameters(groupToAdd);
VdcReturnValueBase result = runInternalAction(VdcActionType.AddGroup, parameters, cloneContextAndDetachFromParent());
if (result.getSucceeded()) {
Guid id = result.getActionReturnValue();
if (id != null) {
return dbGroupDao.get(id);
}
return null;
}
}
// There is no such group in the directory:
return null;
}
}