package alien4cloud.audit; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; import javax.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.index.query.FilterBuilder; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.method.HandlerMethod; import alien4cloud.audit.annotation.Audit; import alien4cloud.audit.model.AuditConfiguration; import alien4cloud.audit.model.AuditTrace; import alien4cloud.audit.model.Method; import alien4cloud.dao.IGenericSearchDAO; import alien4cloud.dao.model.FacetedSearchResult; import alien4cloud.exception.NotFoundException; import alien4cloud.security.AuthorizationUtil; import lombok.extern.slf4j.Slf4j; @Component @Slf4j public class AuditService { public static final String CONTROLLER_SUFFIX = "Controller"; @Resource(name = "alien-audit-dao") private IGenericSearchDAO alienDAO; /** * Cache the instance of audit configuration bad idea ? */ private AuditConfiguration auditConfiguration; /** * Get the audit configuration, this method will cache the configuration in memory * * @return the audit configuration */ public synchronized AuditConfiguration getAuditConfiguration() { if (this.auditConfiguration == null) { this.auditConfiguration = alienDAO.findById(AuditConfiguration.class, AuditConfiguration.ID); } return this.auditConfiguration; } public synchronized void saveAuditConfiguration(AuditConfiguration auditConfiguration) { alienDAO.save(auditConfiguration); this.auditConfiguration = auditConfiguration; } public void saveAuditTrace(AuditTrace auditTrace) { alienDAO.save(auditTrace); } public AuditConfiguration getMandatoryAuditConfiguration() { AuditConfiguration auditConfiguration = getAuditConfiguration(); if (auditConfiguration == null) { throw new NotFoundException("Audit configuration not found"); } return auditConfiguration; } public FacetedSearchResult searchAuditTrace(String query, Map<String, String[]> filters, int from, int size) { FilterBuilder authorizationFilter = AuthorizationUtil.getResourceAuthorizationFilters(); return alienDAO.facetedSearch(AuditTrace.class, query, filters, authorizationFilter, null, from, size, "timestamp", true); } private String getRequestMappingMethod(RequestMapping requestMapping) { RequestMethod[] methods = requestMapping.method(); if (methods.length == 0) { return null; } if (methods.length > 1) { log.error("Audit does not support more than one http method on the same Spring Controller method : " + Arrays.stream(methods).map(Enum::toString).collect(Collectors.joining(", ")) + " on " + Arrays.stream(requestMapping.path()).collect(Collectors.joining(", "))); return null; } return methods[0].toString(); } public Method getAuditedMethod(HandlerMethod controllerMethod) { RequestMapping methodMapping = AnnotationUtils.findAnnotation(controllerMethod.getMethod(), RequestMapping.class); RequestMapping controllerMapping = AnnotationUtils.findAnnotation(controllerMethod.getMethod().getDeclaringClass(), RequestMapping.class); String httpMethod = null; if (controllerMapping != null) { httpMethod = getRequestMappingMethod(controllerMapping); if (methodMapping != null) { String methodHttpMethod = getRequestMappingMethod(methodMapping); if (httpMethod == null) { // Controller http method override method http method httpMethod = methodHttpMethod; } } } else if (methodMapping != null) { httpMethod = getRequestMappingMethod(methodMapping); } if (httpMethod == null) { return null; } Audit audit = getAuditAnnotation(controllerMethod); return new Method(controllerMethod.getMethod().toGenericString(), httpMethod, getAuditCategoryName(controllerMethod, audit), getAuditActionName(controllerMethod, audit)); } public boolean isMethodAudited(AuditConfiguration auditConfiguration, HandlerMethod controllerMethod) { Method method = getAuditedMethod(controllerMethod); return method != null && Boolean.TRUE.equals(auditConfiguration.getAuditedMethodsMap().get(method)); } public String getAuditCategoryName(HandlerMethod method, Audit audit) { if (audit != null && StringUtils.isNotBlank(audit.category())) { return audit.category(); } String auditCategory = method.getMethod().getDeclaringClass().getSimpleName(); if (auditCategory.endsWith(CONTROLLER_SUFFIX) && auditCategory.length() > CONTROLLER_SUFFIX.length()) { auditCategory = auditCategory.substring(0, auditCategory.length() - CONTROLLER_SUFFIX.length()); } return auditCategory; } public String getAuditActionName(HandlerMethod method, Audit audit) { if (audit != null && StringUtils.isNotBlank(audit.action())) { return audit.action(); } return method.getMethod().getName(); } public Audit getAuditAnnotation(HandlerMethod method) { Audit audit = method.getMethodAnnotation(Audit.class); if (audit == null) { audit = AnnotationUtils.findAnnotation(method.getMethod().getDeclaringClass(), Audit.class); } return audit; } }