/* ====================================================================
*
* Copyright (C) 2007 - 2015 GeoSolutions S.A.S.
* http://www.geo-solutions.it
*
* GPLv3 + Classpath exception
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.
*
* ====================================================================
*
* This software consists of voluntary contributions made by developers
* of GeoSolutions. For more information on GeoSolutions, please see
* <http://www.geo-solutions.it/>.
*
*/
package it.geosolutions.geostore.services.rest.auditing;
import it.geosolutions.geostore.core.model.User;
import it.geosolutions.geostore.core.model.UserGroup;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.apache.log4j.Logger;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
final class AuditInfoExtractor {
private static final Logger LOGGER = Logger.getLogger(AuditInfoExtractor.class);
private static final Pattern geoStorePath = Pattern.compile("/geostore/(.*)");
private AuditInfoExtractor() {
}
static Map<String, String> extract(Message message) {
Map<String, String> auditInfo = new HashMap<String, String>();
try {
handleInMessage(auditInfo, message.getExchange().getInMessage());
handleOutSuccessMessage(auditInfo, message.getExchange().getOutMessage());
handleOutFaultMessage(auditInfo, message.getExchange().getOutFaultMessage());
handleTime(auditInfo, message.getExchange().get(AuditInfo.START_TIME.getKey()));
} catch (Exception exception) {
LogUtils.error(LOGGER, exception, "Error obtaining auditing information.");
}
return auditInfo;
}
static Integer
getResponseLength(Message message) {
try {
CachedOutputStream outputStream = (CachedOutputStream) message.getContent(OutputStream.class);
if (outputStream != null) {
return outputStream.size();
}
} catch (Exception exception) {
LogUtils.error(LOGGER, exception, "Error obtaining response length.");
}
return null;
}
private static void handleInMessage(Map<String, String> auditInfo, Message message) {
if (message == null) {
LogUtils.info(LOGGER, "Input message is NULL.");
return;
}
try {
auditInfo.put(AuditInfo.HTTP_METHOD.getKey(), safeToString(message.get(Message.HTTP_REQUEST_METHOD)));
auditInfo.put(AuditInfo.PATH.getKey(), removeGeoStore((String) message.get(Message.PATH_INFO)));
auditInfo.put(AuditInfo.BASE_PATH.getKey(), removeGeoStore((String) message.get(Message.BASE_PATH)));
auditInfo.put(AuditInfo.QUERY_STRING.getKey(), safeToString(message.get(Message.QUERY_STRING)));
HttpServletRequest httpServletRequest = (HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);
auditInfo.put(AuditInfo.REMOTE_ADDR.getKey(), safeToString(httpServletRequest.getRemoteAddr()));
auditInfo.put(AuditInfo.REMOTE_HOST.getKey(), safeToString(httpServletRequest.getRemoteHost()));
auditInfo.put(AuditInfo.REMOTE_USER.getKey(), safeToString(httpServletRequest.getRemoteUser()));
auditInfo.put(AuditInfo.HOST.getKey(), safeToString(httpServletRequest.getServerName()));
fillAuthInfo(auditInfo, httpServletRequest);
auditInfo.put(AuditInfo.BODY_AS_STRING.getKey(), getPaylod(message));
} catch (Exception exception) {
LogUtils.error(LOGGER, exception, "Error obtaining auditing information for input message.");
}
}
private static void handleOutSuccessMessage(Map<String, String> auditInfo, Message message) {
if (message == null) {
return;
}
auditInfo.put(AuditInfo.RESPONSE_STATUS_CODE.getKey(), safeToString(message.get(Message.RESPONSE_CODE)));
auditInfo.put(AuditInfo.RESPONSE_CONTENT_TYPE.getKey(), safeToString(message.get(Message.CONTENT_TYPE)));
auditInfo.put(AuditInfo.RESPONSE_LENGTH.getKey(),
safeToString(message.getExchange().get(AuditInfo.RESPONSE_LENGTH.getKey())));
}
private static void handleOutFaultMessage(Map<String, String> auditInfo, Message message) {
if (message == null) {
return;
}
auditInfo.put(AuditInfo.FAILED.getKey(), "true");
Exception exception = message.getContent(Exception.class);
if (exception != null) {
auditInfo.put(AuditInfo.ERROR_MESSAGE.getKey(), exception.getMessage());
} else {
auditInfo.put(AuditInfo.ERROR_MESSAGE.getKey(), "");
}
auditInfo.put(AuditInfo.RESPONSE_CONTENT_TYPE.getKey(), safeToString(message.get(Message.CONTENT_TYPE)));
auditInfo.put(AuditInfo.RESPONSE_LENGTH.getKey(), safeToString(getResponseLength(message)));
auditInfo.put(AuditInfo.RESPONSE_STATUS_CODE.getKey(), safeToString(safeToString(message.get(Message.RESPONSE_CODE))));
}
private static void handleTime(Map<String, String> auditInfo, Object startTimeObject) {
if (startTimeObject == null) {
return;
}
long startTime = (Long) startTimeObject;
long endTime = System.currentTimeMillis();
auditInfo.put(AuditInfo.START_TIME.getKey(), String.valueOf(startTime));
auditInfo.put(AuditInfo.END_TIME.getKey(), String.valueOf(endTime));
auditInfo.put(AuditInfo.TOTAL_TIME.getKey(), String.valueOf(endTime - startTime));
}
private static String safeToString(Object value) {
if (value == null) {
return "";
}
return value.toString();
}
private static String getPaylod(Message message) {
InputStream inputStream = message.getContent(InputStream.class);
if (inputStream == null) {
return "";
}
try {
return inputStream.toString();
} catch (Exception exception) {
LogUtils.error(LOGGER, exception, "Error reading payload.");
}
return "";
}
private static void fillAuthInfo(Map<String, String> info, HttpServletRequest httpServletRequest) {
Principal userPrincipal = httpServletRequest.getUserPrincipal();
String userName = "";
String userRole = "";
String userGroups = "";
if (userPrincipal != null && userPrincipal instanceof Authentication) {
Authentication authentication = (Authentication) userPrincipal;
Object principal = authentication.getPrincipal();
if (principal != null && principal instanceof User) {
User user = (User) principal;
userName = user.getName();
userRole = user.getRole().name();
userGroups = groupsToString(user.getGroups());
}
}
info.put(AuditInfo.USER_NAME.getKey(), userName);
info.put(AuditInfo.USER_ROLE.getKey(), userRole);
info.put(AuditInfo.USER_GROUPS.getKey(), userGroups);
}
private static String groupsToString(Set<UserGroup> groups) {
if (groups.isEmpty()) {
return null;
}
StringBuilder groupsString = new StringBuilder();
for (UserGroup userGroup : groups) {
groupsString.append(userGroup.getGroupName()).append(",");
}
groupsString.deleteCharAt(groupsString.length() - 1);
return groupsString.toString();
}
private static String removeGeoStore(String path) {
if (path == null) {
return "";
}
Matcher matcher = geoStorePath.matcher(path);
if (matcher.matches()) {
return matcher.group(1);
}
return path;
}
}