package org.ovirt.engine.core.bll.aaa; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.commons.codec.binary.Base64; import org.ovirt.engine.api.extensions.ExtMap; import org.ovirt.engine.core.aaa.SsoOAuthServiceUtils; import org.ovirt.engine.core.bll.CommandBase; import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute; 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.action.LoginOnBehalfParameters; import org.ovirt.engine.core.common.businessentities.aaa.DbUser; import org.ovirt.engine.core.common.errors.EngineError; import org.ovirt.engine.core.common.errors.EngineException; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.DbUserDao; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @NonTransactiveCommandAttribute public class LoginOnBehalfCommand<T extends LoginOnBehalfParameters> extends CommandBase<T> { protected static final Logger log = LoggerFactory.getLogger(LoginOnBehalfCommand.class); private String logInfo; @Inject private SessionDataContainer sessionDataContainer; @Inject private DirectoryUtils directoryUtils; @Inject private DbUserDao dbUserDao; public LoginOnBehalfCommand(T parameters, CommandContext cmdContext) { super(parameters, cmdContext); } @Override protected boolean validate() { return isInternalExecution() ? true : failValidation(EngineMessage.USER_CANNOT_RUN_ACTION_INTERNAL_COMMAND); } @Override protected void executeCommand() { try { DbUser dbUser = getDbUser(); logInfo = String.format("for user %s", dbUser.getLoginName()); getReturnValue().setActionReturnValue(createSession(dbUser, dbUser.getDomain(), loginOnBehalf(dbUser))); setSucceeded(true); } catch (Exception ex) { log.error("Unable to create engine session: {}", ex.getMessage()); log.debug("Unable to create engine session", ex); } } private DbUser getDbUser() { DbUser dbUser = null; switch (getParameters().getQueryType()) { case ByInternalId: logInfo = String.format("for internal id %s", getParameters().getUserId()); dbUser = dbUserDao.get(getParameters().getUserId()); break; case ByPrincipalName: logInfo = String.format("for principal name: %s, authz name: %s", getParameters().getPrincipalName(), getParameters().getAuthzName()); dbUser = getDbUserForPrincipalName(getParameters().getPrincipalName(), getParameters().getAuthzName()); break; case ByExternalId: logInfo = String.format("for external id: %s, authz name: %s", getParameters().getExternalId(), getParameters().getAuthzName()); dbUser = dbUserDao.getByExternalId(getParameters().getAuthzName(), getParameters().getExternalId()); break; } if (dbUser == null) { throw new EngineException(EngineError.PRINCIPAL_NOT_FOUND, "User not found in database"); } return dbUser; } private DbUser getDbUserForPrincipalName(String principalName, String authzName) { Map<String, Object> response = SsoOAuthServiceUtils.fetchPrincipalRecord( getSessionDataContainer().getSsoAccessToken(getParameters().getSessionId()), authzName, principalName, false, false ); ExtMap principalRecord = null; if (response.containsKey("result")) { Collection<ExtMap> records = (Collection<ExtMap>) response.get("result"); if (!records.isEmpty()) { principalRecord = records.iterator().next(); } } if (principalRecord == null) { throw new EngineException(EngineError.PRINCIPAL_NOT_FOUND, String.format("%s in domain '%s", principalName, authzName)); } DbUser user = new DbUser(directoryUtils.mapPrincipalRecordToDirectoryUser(authzName, principalRecord)); user.setId(Guid.newGuid()); return user; } private ExtMap loginOnBehalf(DbUser dbUser) { Map<String, Object> response = SsoOAuthServiceUtils.findLoginOnBehalfPrincipalById( dbUser.getDomain(), dbUser.getNamespace(), Arrays.asList(dbUser.getExternalId()), true, true); Collection<ExtMap> principalRecords = Collections.emptyList(); if (response.containsKey("result")) { principalRecords = (Collection<ExtMap>) response.get("result"); } if (principalRecords.isEmpty()) { throw new EngineException(EngineError.PRINCIPAL_NOT_FOUND, String.format(" user %s in domain '%s", dbUser.getLoginName(), dbUser.getDomain())); } return principalRecords.iterator().next(); } private String createSession(DbUser mappedUser, String authzName, ExtMap principalRecord) { directoryUtils.flatGroups(principalRecord); DbUser dbUser = directoryUtils.mapPrincipalRecordToDbUser(authzName, principalRecord); dbUser.setId(mappedUser.getId()); String engineSessionId; try { byte[] s = new byte[64]; SecureRandom.getInstance("SHA1PRNG").nextBytes(s); engineSessionId = new Base64(0).encodeToString(s); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } sessionDataContainer.setUser(engineSessionId, dbUser); sessionDataContainer.refresh(engineSessionId); return engineSessionId; } @Override public List<PermissionSubject> getPermissionCheckSubjects() { return Collections.emptyList(); } @Override public AuditLogType getAuditLogTypeValue() { addCustomValue("LoginOnBehalfLogInfo", logInfo); return getSucceeded() ? AuditLogType.USER_LOGIN_ON_BEHALF : AuditLogType.USER_LOGIN_ON_BEHALF_FAILED; } }