package alien4cloud.rest.deployment;
import java.security.Principal;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.mapping.MappingBuilder;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import alien4cloud.dao.IGenericSearchDAO;
import alien4cloud.exception.NotFoundException;
import alien4cloud.model.application.ApplicationEnvironment;
import alien4cloud.model.deployment.Deployment;
import alien4cloud.paas.IPaasEventListener;
import alien4cloud.paas.IPaasEventService;
import alien4cloud.paas.model.AbstractMonitorEvent;
import alien4cloud.paas.model.AbstractPaaSWorkflowMonitorEvent;
import alien4cloud.paas.model.DeploymentStatus;
import alien4cloud.paas.model.PaaSDeploymentStatusMonitorEvent;
import alien4cloud.rest.websocket.ISecuredHandler;
import alien4cloud.security.AuthorizationUtil;
import alien4cloud.security.model.ApplicationEnvironmentRole;
import alien4cloud.security.model.ApplicationRole;
import alien4cloud.security.model.Role;
import alien4cloud.security.model.User;
@Slf4j
@Component
public class DeploymentEventHandler implements IPaasEventListener<AbstractMonitorEvent>, ISecuredHandler, InitializingBean {
private static final String TOPIC_PREFIX = "/topic/deployment-events";
private static final String ENV_TOPIC_PREFIX = "/topic/environment-events";
private static final Pattern DESTINATION_PATTERN = Pattern.compile(TOPIC_PREFIX + "/(.*?)(:?/.*)?");
private static final Pattern ENV_DESTINATION_PATTERN = Pattern.compile(ENV_TOPIC_PREFIX + "/(.*?)(:?/.*)?");
@Resource
private IPaasEventService paasEventService;
@Resource(name = "alien-es-dao")
private IGenericSearchDAO alienDAO;
@Resource
private SimpMessagingTemplate template;
protected void send(AbstractMonitorEvent event) {
String eventType = MappingBuilder.indexTypeFromClass(event.getClass());
String topicName = TOPIC_PREFIX + '/' + event.getDeploymentId() + '/' + eventType;
dispatchEvent(event, topicName);
if (event instanceof PaaSDeploymentStatusMonitorEvent) {
Deployment deployment = alienDAO.findById(Deployment.class, event.getDeploymentId());
if (deployment != null && deployment.getEnvironmentId() != null) {
// dispatch an event on the environment topic
topicName = ENV_TOPIC_PREFIX + "/" + deployment.getEnvironmentId();
dispatchEvent(event, topicName);
}
}
}
private void dispatchEvent(AbstractMonitorEvent event, String topicName) {
log.debug("Send [{}] to [{}]: {}", event.getClass().getSimpleName(), topicName, event);
template.convertAndSend(topicName, event);
}
/**
* Check if the destination path can be handled by this event handler
*
* @param destination the destination
* @return true if the event handler manage the destination
*/
@Override
public boolean canHandleDestination(String destination) {
Matcher matcher = DESTINATION_PATTERN.matcher(destination);
return matcher.matches();
}
/**
* Check if the current user is authorized for this destination
*
* @param destination the destination
*/
@Override
public void checkAuthorization(Principal user, String destination) {
Matcher matcher = DESTINATION_PATTERN.matcher(destination);
Authentication authentication = (Authentication) user;
User a4cUser = (User) authentication.getPrincipal();
if (matcher.matches()) {
String deploymentId = matcher.group(1);
checkDeploymentAuthorization(authentication, a4cUser, deploymentId);
} else {
matcher = ENV_DESTINATION_PATTERN.matcher(destination);
if (matcher.matches()) {
String environmentId = matcher.group(1);
checkEnvironmentAuthorization(a4cUser, environmentId);
} else {
throw new IllegalArgumentException("Cannot handle this destination [" + destination + "]");
}
}
}
private void checkDeploymentAuthorization(Authentication authentication, User a4cUser, String deploymentId) {
Deployment deployment = alienDAO.findById(Deployment.class, deploymentId);
switch (deployment.getSourceType()) {
case APPLICATION:
// check if the user has right for the environment associated with the deployment.
ApplicationEnvironment environment = alienDAO.findById(ApplicationEnvironment.class, deployment.getEnvironmentId());
if (environment == null) {
log.error("Environment with id [{}] do not exist any more for deployment [{}]", deployment.getEnvironmentId(), deployment.getId());
throw new NotFoundException(
"Environment with id [" + deployment.getEnvironmentId() + "] do not exist any more for deployment [" + deployment.getId() + "]");
}
AuthorizationUtil.checkAuthorization(a4cUser, environment, ApplicationRole.APPLICATION_MANAGER, ApplicationEnvironmentRole.values());
break;
case CSAR:
AuthorizationUtil.checkHasOneRoleIn(authentication, Role.COMPONENTS_MANAGER);
}
}
private void checkEnvironmentAuthorization(User a4cUser, String environmentId) {
ApplicationEnvironment environment = alienDAO.findById(ApplicationEnvironment.class, environmentId);
if (environment == null) {
log.error("Environment with id [{}] do not exist any more", environmentId);
throw new NotFoundException("Environment with id [" + environmentId + "] do not exist any more");
}
AuthorizationUtil.checkAuthorization(a4cUser, environment, ApplicationRole.APPLICATION_MANAGER, ApplicationEnvironmentRole.values());
}
@Override
public void eventHappened(AbstractMonitorEvent event) {
send(event);
if (log.isTraceEnabled()) {
log.trace("Pushed event {} for deployment {}", event, event.getDeploymentId());
}
}
@Override
public boolean canHandle(AbstractMonitorEvent event) {
return AbstractMonitorEvent.class.isAssignableFrom(event.getClass()) && !AbstractPaaSWorkflowMonitorEvent.class.isAssignableFrom(event.getClass());
}
@Override
public void afterPropertiesSet() throws Exception {
paasEventService.addListener(this);
}
}