/*
Copyright 2009-2013 Josh Drummond
This file is part of WebPasswordSafe.
WebPasswordSafe 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.
WebPasswordSafe 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 WebPasswordSafe; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.webpasswordsafe.server.report;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.springframework.web.context.support.WebApplicationContextUtils;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.export.JRXmlExporter;
import net.sf.jasperreports.engine.type.WhenNoDataTypeEnum;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import net.webpasswordsafe.common.model.User;
import net.webpasswordsafe.common.util.Constants;
import net.webpasswordsafe.common.util.Utils;
import net.webpasswordsafe.server.plugin.audit.AuditLogger;
import net.webpasswordsafe.server.plugin.authorization.Authorizer;
import net.webpasswordsafe.server.plugin.encryption.Encryptor;
/**
* Servlet that handles generation of specified reports using Jasper Reports
*
* @author Josh Drummond
*
*/
public class JasperReportServlet extends HttpServlet
{
private static Logger LOG = Logger.getLogger(JasperReportServlet.class);
private static final long serialVersionUID = 2493946517487023931L;
public static ThreadLocal<Encryptor> encryptorRef = new ThreadLocal<Encryptor>();
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
processRequest(request, response);
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
processRequest(request, response);
}
private void processRequest(HttpServletRequest req, HttpServletResponse res)
{
OutputStream outputStream = null;
Connection jdbcConnection = null;
try
{
String reportName = req.getParameter(Constants.NAME);
String type = req.getParameter(Constants.TYPE).trim().toLowerCase();
String locale = req.getParameter("locale");
setNoCache(res);
if (isAuthorizedReport(req, reportName))
{
JasperDesign jasperDesign = JRXmlLoader.load(getServletConfig().getServletContext().getResourceAsStream(
"/WEB-INF/reports/"+reportName+".jrxml"));
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
jasperReport.setWhenNoDataType(WhenNoDataTypeEnum.ALL_SECTIONS_NO_DETAIL);
Map<String, Object> parameters = new HashMap<String, Object>();
if (null != locale) parameters.put(JRParameter.REPORT_LOCALE, new Locale(locale));
parameters.put(Constants.SESSION_KEY_USERNAME, (String)req.getSession().getAttribute(Constants.SESSION_KEY_USERNAME));
parameters.put(Constants.Function.BYPASS_PASSWORD_PERMISSIONS.name(), isAuthorized(req, Constants.Function.BYPASS_PASSWORD_PERMISSIONS.name()) ? "1":"0");
ReportConfig reportConfig = (ReportConfig)WebApplicationContextUtils.getWebApplicationContext(getServletContext()).getBean("reportConfig");
@SuppressWarnings("unchecked")
Enumeration<String> e = req.getParameterNames();
while (e.hasMoreElements())
{
String param = e.nextElement();
if (param.startsWith(Constants.REPORT_PARAM_PREFIX))
{
String pKey = param.substring(Constants.REPORT_PARAM_PREFIX.length());
String pValue = Utils.safeString(req.getParameter(param));
if (reportConfig.isDateParam(reportName, pKey))
{
parameters.put(pKey, convertToDateTime(pValue));
}
else
{
parameters.put(pKey, pValue);
}
}
}
encryptorRef.set((Encryptor)WebApplicationContextUtils.getWebApplicationContext(getServletContext()).getBean("encryptor"));
DataSource dataSource = (DataSource)WebApplicationContextUtils.getWebApplicationContext(getServletContext()).getBean("dataSource");
jdbcConnection = dataSource.getConnection();
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, jdbcConnection);
JRExporter exporter = null;
if (type.equals(Constants.REPORT_TYPE_PDF))
{
res.setContentType("application/pdf");
exporter = new JRPdfExporter();
}
else if (type.equals("rtf"))
{
res.setContentType("application/rtf");
exporter = new JRRtfExporter();
}
else if (type.equals(Constants.REPORT_TYPE_CSV))
{
res.setContentType("text/csv");
exporter = new JRCsvExporter();
}
else if (type.equals("xml"))
{
res.setContentType("text/xml");
exporter = new JRXmlExporter();
}
if (exporter != null)
{
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
res.setHeader("Content-Disposition", "attachment; filename=" + reportName +
dateFormat.format(System.currentTimeMillis())+"."+type);
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
outputStream = res.getOutputStream();
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
exporter.exportReport();
}
else
{
throw new RuntimeException("Invalid report type: "+type);
}
}
}
catch(Exception e)
{
LOG.error("JasperReportServlet Error " + e.getMessage(), e);
}
finally
{
// close the output stream
if (outputStream != null)
{
try
{
outputStream.close();
}
catch (IOException io)
{
LOG.error("JasperReportServlet Error " + io.getMessage(), io);
}
}
// close the db connection
if (jdbcConnection != null)
{
try
{
jdbcConnection.close();
}
catch (SQLException sql)
{
LOG.error("JasperReportServlet Error "+sql.getMessage(), sql);
}
finally
{
jdbcConnection = null;
}
}
}
}
private Timestamp convertToDateTime(String pValue)
throws ParseException
{
Timestamp pDateValue = null;
if (!"".equals(pValue))
{
// try with timestamp
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
try
{
pDateValue = new Timestamp(dateFormat.parse(pValue).getTime());
}
catch (ParseException pe)
{
// try without timestamp
dateFormat = new SimpleDateFormat("yyyy-MM-dd");
pDateValue = new Timestamp(dateFormat.parse(pValue).getTime());
// throw exception if neither parsed
}
}
return pDateValue;
}
private boolean isAuthorizedReport(HttpServletRequest req, String reportName)
{
boolean isAuthorized = isAuthorized(req, Constants.VIEW_REPORT_PREFIX+reportName);
User user = new User();
user.setUsername((String)req.getSession().getAttribute(Constants.SESSION_KEY_USERNAME));
AuditLogger auditLogger = (AuditLogger)WebApplicationContextUtils.getWebApplicationContext(getServletContext()).getBean("auditLogger");
auditLogger.log(new Date(), user.getUsername(), req.getRemoteAddr(), "view report", reportName, isAuthorized, (isAuthorized ? "" : "not authorized"));
return isAuthorized;
}
@SuppressWarnings("unchecked")
private boolean isAuthorized(HttpServletRequest req, String action)
{
boolean isAuthorized = false;
Authorizer authorizer = (Authorizer)WebApplicationContextUtils.getWebApplicationContext(getServletContext()).getBean("authorizer");
User user = new User();
user.setUsername((String)req.getSession().getAttribute(Constants.SESSION_KEY_USERNAME));
user.setRoles((Set<Constants.Role>)req.getSession().getAttribute(Constants.SESSION_KEY_ROLES));
try
{
isAuthorized = authorizer.isAuthorized(user, action);
}
catch (Exception e)
{
isAuthorized = false;
}
return isAuthorized;
}
private void setNoCache(HttpServletResponse res)
{
res.setHeader("Pragma", "no-cache");
res.setHeader("Cache-Control", "no-cache,no-store");
res.setDateHeader("Expires", 0);
}
}