/*
* Copyright (c) 2006 by Know-Center, Graz, Austria
*
* This software is the confidential and proprietary information of Know-Center,
* Graz, Austria. You shall not disclose such Confidential Information and shall
* use it only in accordance with the terms of the license agreement you entered
* into with Know-Center.
*
* KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
* NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
* LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES.
*
* $Id: Verify.java,v 1.7 2006/10/11 07:39:13 wprinz Exp $
*/
package at.knowcenter.wag.egov.egiz.web.servlets;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import at.gv.egiz.pdfas.exceptions.ErrorCode;
import at.gv.egiz.pdfas.framework.config.SettingsHelper;
import at.gv.egiz.pdfas.framework.input.DataSource;
import at.gv.egiz.pdfas.framework.input.ExtractionStage;
import at.gv.egiz.pdfas.framework.input.PdfDataSource;
import at.gv.egiz.pdfas.framework.input.TextDataSource;
import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters;
import at.gv.egiz.pdfas.utils.WebUtils;
import at.gv.egiz.pdfas.web.VerifySessionInformation;
import at.gv.egiz.pdfas.web.helper.TempDirHelper;
import at.knowcenter.wag.egov.egiz.PdfAS;
import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException;
import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException;
import at.knowcenter.wag.egov.egiz.pdf.NoSignatureHolder;
import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder;
import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory;
import at.knowcenter.wag.egov.egiz.sig.SignatureResponse;
import at.knowcenter.wag.egov.egiz.web.FormFields;
import at.knowcenter.wag.egov.egiz.web.LocalRequestHelper;
import at.knowcenter.wag.egov.egiz.web.SessionAttributes;
/**
* This method is the verify servlet for the pdf-as web application. It takes
* get and post requests fill out jsp templates and give the user feedback about
* the results of the verify process.
*
* @author wlackner
* @author wprinz
*/
public class VerifyServlet extends HttpServlet
{
/**
* SVUID.
*/
private static final long serialVersionUID = 309198792358636766L;
/**
* The log.
*/
private static Log log = LogFactory.getLog(SignServlet.class);
protected void dispatch(HttpServletRequest request, HttpServletResponse response, String resource) throws ServletException, IOException
{
response.setContentType("text/html"); //$NON-NLS-1$
response.setCharacterEncoding("UTF-8"); //$NON-NLS-1$
RequestDispatcher disp = getServletContext().getRequestDispatcher(resource);
disp.forward(request, response);
}
protected void dispatchToResults(List results, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
request.setAttribute("results", results); //$NON-NLS-1$
dispatch(request, response, "/jsp/results.jsp"); //$NON-NLS-1$
}
/**
* Processes the verify upload.
*
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// for performance measurement
long startTime = 0;
long fileSize = 0;
if (log.isInfoEnabled()) {
startTime = System.currentTimeMillis();
}
try
{
UploadedData ud = retrieveUploadedDataFromRequest(request);
VerifySessionInformation si = new VerifySessionInformation();
si.connector = ud.sig_app;
si.application = "verify";
si.mode = null;
si.inputDataSource = ud.dataSource;
si.type = null;
// si.user_name = null;
// si.user_password = null;
// List signature_holders = extractSignatureHoldersFromFile(ud.file_name,
// ud.file_data);
List signature_holders = extractSignatureHolders(ud.dataSource);
TempDirHelper.storeTextSignatureHoldersIfApplicable(signature_holders, "_textholder.utf8.txt");
si.signature_holders = signature_holders;
request.getSession().setAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION, si);
if (ud.preview)
{
dispatch(request, response, "/jsp/verifylist.jsp");
// VerifyPreview.formatPreview(signature_holders, connector, request,
// response);
}
else
{
if (ConnectorFactory.isConnectorLocal(si.connector))
{
String dispatch_to = LocalRequestHelper.processLocalVerify(si, si.signature_holders, request, response);
dispatch(request, response, dispatch_to);
return;
}
String host = request.getServerName();
// TODO still required for old communication with MOA-SS/SP
// URL loc_ref_URL = new URL(WebUtils.addJSessionID(LocalRequestHelper.getLocalContextAddress(request, response) + "/RetrieveSignatureData", request));
URL loc_ref_URL = new URL(WebUtils.buildRetrieveSignatureDataURL(request, response));
String loc_ref_url = response.encodeURL(loc_ref_URL.toString());
List results = PdfAS.verifySignatureHoldersWeb(signature_holders, si, loc_ref_url);
dispatchToResults(results, request, response);
// for performance measurement
if (log.isInfoEnabled()) {
long endTime = System.currentTimeMillis();
String toReport = "VERIFY;"+ ud.file_name + ";"+ 0 + ";" + (endTime - startTime) + ";" + debugVerifyResults(results);
log.info(toReport);
}
}
}
catch (FileUploadException e)
{
request.setAttribute("error", "Fehler beim Upload der Daten");
request.setAttribute("cause", "Beim Upload der Daten ist ein Fehler aufgetreten.");
dispatch(request, response, "/jsp/error_verify.jsp");
}
catch (PresentableException e)
{
log.error(e.getMessage(), e);
SignServlet.prepareDispatchToErrorPage(e, request);
dispatch(request, response, "/jsp/error_verify.jsp");
}
}
protected UploadedData retrieveUploadedDataFromRequest(HttpServletRequest request) throws ServletException, UnsupportedEncodingException, FileUploadException, PDFDocumentException
{
DiskFileItemFactory fif = new DiskFileItemFactory();
fif.setRepository(SettingsReader.getTemporaryDirectory());
ServletFileUpload sfu = new ServletFileUpload(fif);
List items = sfu.parseRequest(request);
FileItem upload_fi = null;
FileItem connector_fi = null;
// FileItem mode_fi = null;
FileItem preview_fi = null;
String characterEncoding = request.getCharacterEncoding();
log.debug("request character encoding = " + characterEncoding);
{
Iterator it = items.iterator();
while (it.hasNext())
{
FileItem item = (FileItem) it.next();
log.debug("item = " + item.getFieldName()); //$NON-NLS-1$
if (item.isFormField())
{
String item_string = item.getString("UTF-8"); //$NON-NLS-1$
log.debug(" form field string = " + item_string); //$NON-NLS-1$
}
else
{
log.debug(" filename = " + item.getName()); //$NON-NLS-1$
log.debug(" filesize = " + item.getSize()); //$NON-NLS-1$
}
if (item.getFieldName().equals(FormFields.FIELD_UPLOAD))
{
upload_fi = item;
continue;
}
if (item.getFieldName().equals(FormFields.FIELD_CONNECTOR))
{
connector_fi = item;
continue;
}
// if (item.getFieldName().equals(FormFields.FIELD_MODE))
// {
// mode_fi = item;
// continue;
// }
if (item.getFieldName().equals(FormFields.FIELD_PREVIEW))
{
preview_fi = item;
continue;
}
throw new ServletException("unrecognized POST data."); //$NON-NLS-1$
}
}
if (upload_fi == null || connector_fi == null || /* mode_fi == null || */preview_fi == null)
{
throw new ServletException("Unsufficient data provided in request."); //$NON-NLS-1$
}
String connector = connector_fi.getString("UTF-8"); //$NON-NLS-1$
// String mode = mode_fi.getString("UTF-8");
// if (!mode.equals(FormFields.VALUE_MODE_BINARY) &&
// !mode.equals(FormFields.VALUE_MODE_TEXTUAL))
// {
// throw new ServletException("The mode '" + mode + "' is unrecognized.");
// }
String preview_str = preview_fi.getString("UTF-8"); //$NON-NLS-1$
if (!preview_str.equals(FormFields.VALUE_TRUE) && !preview_str.equals(FormFields.VALUE_FALSE))
{
throw new ServletException("The preview '" + preview_str + "' is unrecognized."); //$NON-NLS-1$//$NON-NLS-2$
}
boolean preview = false;
if (preview_str.equals(FormFields.VALUE_TRUE))
{
preview = true;
}
// process the request
DataSource dataSource = convertUploadToDataSource(upload_fi);
UploadedData ud = new UploadedData();
ud.preview = preview;
ud.sig_app = connector;
ud.file_name = upload_fi.getName();
ud.dataSource = dataSource;
// ud.file_data = document_bytes;
return ud;
}
protected DataSource convertUploadToDataSource(FileItem upload_fi) throws PDFDocumentException
{
log.debug("file content type =" + upload_fi.getContentType()); //$NON-NLS-1$
log.debug("file size = " + upload_fi.getSize()); //$NON-NLS-1$
if (upload_fi.getSize() <= 0)
{
throw new PDFDocumentException(250, "The document is empty."); //$NON-NLS-1$
}
// TR: do not check MIME-type of incoming file - might vary depending on the browser used
if ((upload_fi.getContentType() != null ) && ((upload_fi.getContentType().startsWith("application/pdf") || upload_fi.getContentType().startsWith("application/x-download") )))
{
try
{
String fileNameSuffix = TempDirHelper.extractFileNameSuffix(upload_fi.getName());
PdfDataSource pdfDataSource = TempDirHelper.placePdfIntoTempDir(upload_fi.getInputStream(), fileNameSuffix);
return pdfDataSource;
}
catch (IOException e)
{
throw new PDFDocumentException(201, "The document could not be placed in the temp dir.", e); //$NON-NLS-1$
}
// byte[] document_bytes = upload_fi.get();
}
try
{
String fileNameSuffix = TempDirHelper.extractFileNameSuffix(upload_fi.getName());
String text = new String(upload_fi.get(), "UTF-8"); //$NON-NLS-1$
TextDataSource textDataSource = TempDirHelper.placeTextIntoTempDir(text, fileNameSuffix);
return textDataSource;
}
catch (IOException e)
{
throw new PDFDocumentException(201, e);
}
}
protected List extractSignatureHolders(DataSource dataSource) throws PresentableException
{
VerificationFilterParameters parameters = SettingsHelper.readVerificationFilterParametersFromSettings();
ExtractionStage es = new ExtractionStage();
List signature_holders = es.extractSignatureHolders(dataSource, parameters);
// filter out NoSignatureHolders that are possibly present due to the direct call method extractSignatureHolders()
List filtered_signature_holders = new ArrayList();
Iterator it = signature_holders.iterator();
while(it.hasNext()) {
SignatureHolder current = (SignatureHolder) it.next();
if(!(current instanceof NoSignatureHolder)) {
filtered_signature_holders.add(current);
}
}
if (filtered_signature_holders.size() == 0)
{
throw new PDFDocumentException(ErrorCode.DOCUMENT_NOT_SIGNED, "PDF document not signed."); //$NON-NLS-1$
}
return filtered_signature_holders;
}
// TODO obsolete method - remove
// protected List extractSignatureHoldersFromFile(String file_name, byte[]
// data) throws UnsupportedEncodingException, PresentableException
// {
// VerificationFilterParameters parameters = new
// VerificationFilterParametersImpl(false, false, true);
// ExtractionStage es = new ExtractionStage();
// // VerificationFilter vf = new VerificationFilter();
// List signature_holders = null;
//
// String extension = extractExtension(file_name);
//
// String raw_text = null;
// if (file_name == null || (extension != null && extension.equals("txt")))
// //$NON-NLS-1$
// {
// raw_text = new String(data, "UTF-8"); //$NON-NLS-1$
//
// signature_holders = es.extractSignatureHolders(new
// TextDataSourceImpl(raw_text), parameters);
// // signature_holders = vf.extractSignaturesFromPlainText(raw_text);
// }
// else
// {
// signature_holders = es.extractSignatureHolders(new
// ByteArrayPdfDataSourceImpl(data), parameters);
//
// // signature_holders = vf.extractSignaturesFromPdf(data);
// }
//
// if (signature_holders.size() == 0)
// {
// throw new PDFDocumentException(206, "PDF document not signed.");
// //$NON-NLS-1$
// }
//
// return signature_holders;
// }
/**
* Extracts the extension from a file name string.
*
*
* The extension of a file name is whatever text follows the last '.'.
*
*
* @param file_name
* The file name.
* @return Returns the extension. If the file name ends with the '.', then an
* empty string is returned. If the file name doesn't contain any '.'
* or file_name is null, null is returned.
*/
public static String extractExtension(String file_name)
{
if (file_name == null)
{
return null;
}
int dot_index = file_name.lastIndexOf('.');
if (dot_index < 0)
{
return null;
}
return file_name.substring(dot_index + 1);
}
protected static class UploadedData
{
protected boolean preview = false;
protected String sig_app = null;
protected String file_name = null;
protected DataSource dataSource = null;
// protected byte[] file_data = null;
}
/**
* Formats the verification results for debugging. Returns 0 if no error occurs or the sum of all error-codes.
*
* @param results
*
* @param writer
* The output sink to write the formatted text to.
* @throws SettingNotFoundException
* Forwarded exception.
*/
protected static int debugVerifyResults(List results) throws SettingNotFoundException
{
int toreturn = 0;
Iterator it = results.iterator();
while (it.hasNext())
{
SignatureResponse result = (SignatureResponse) it.next();
toreturn += Integer.valueOf(result.getSignatureCheckCode()).intValue();
}
return toreturn;
}
public boolean isPDF(byte[] data) {
final byte[] PDF_MAGIC_NUMBER = { (byte) 0x25, (byte) 0x50, (byte)
0x44, (byte) 0x46 }; // %PDF
if (data == null || data.length < PDF_MAGIC_NUMBER.length) {
return false;
}
byte[] documentHeader = new byte[PDF_MAGIC_NUMBER.length];
System.arraycopy(data, 0, documentHeader, 0, documentHeader.length);
return Arrays.equals(documentHeader, PDF_MAGIC_NUMBER);
}
}