/**
* 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: Sign.java,v 1.7 2006/10/11 07:39:13 wprinz Exp $
*/
package at.knowcenter.wag.egov.egiz.web.servlets;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
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 org.apache.log4j.Logger;
import at.knowcenter.wag.egov.egiz.PdfAS;
import at.knowcenter.wag.egov.egiz.PdfASID;
import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger;
import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
import at.knowcenter.wag.egov.egiz.exceptions.ErrorCodeException;
import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException;
import at.knowcenter.wag.egov.egiz.exceptions.PlaceholderException;
import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
import at.knowcenter.wag.egov.egiz.framework.SignResult;
import at.knowcenter.wag.egov.egiz.framework.Signator;
import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
import at.knowcenter.wag.egov.egiz.framework.signators.DetachedSignator_1_0_0;
import at.knowcenter.wag.egov.egiz.pdf.TablePos;
import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory;
import at.knowcenter.wag.egov.egiz.sig.SignatureData;
import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl;
import at.knowcenter.wag.egov.egiz.sig.connectors.Connector;
import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorChooser;
import at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector;
import at.knowcenter.wag.egov.egiz.sig.connectors.bku.DetachedBKUConnector;
import at.knowcenter.wag.egov.egiz.sig.connectors.bku.EnvelopedBase64BKUConnector;
import at.knowcenter.wag.egov.egiz.sig.connectors.bku.LocRefDetachedBKUConnector;
import at.knowcenter.wag.egov.egiz.sig.connectors.moa.DetachedLocRefMOAConnector;
import at.knowcenter.wag.egov.egiz.tools.CodingHelper;
import at.knowcenter.wag.egov.egiz.web.ExternAppInformation;
import at.knowcenter.wag.egov.egiz.web.FormFields;
import at.knowcenter.wag.egov.egiz.web.LocalRequest;
import at.knowcenter.wag.egov.egiz.web.LocalRequestHelper;
import at.knowcenter.wag.egov.egiz.web.PDFContainer;
import at.knowcenter.wag.egov.egiz.web.SessionAttributes;
import at.knowcenter.wag.egov.egiz.web.SessionInformation;
/**
* This method is the sign 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 sign process
*
* @author wlackner
* @author wprinz
*/
public class SignServlet extends HttpServlet
{
/**
* SVUID.
*/
private static final long serialVersionUID = -4156938216903740438L;
/**
* The log.
*/
private static Log log = LogFactory.getLog(SignServlet.class);
protected void dispatch(HttpServletRequest request,
HttpServletResponse response, String resource) throws ServletException, IOException
{
dispatch(request, response, resource, getServletContext());
}
protected static void dispatch(HttpServletRequest request,
HttpServletResponse response, String resource, ServletContext context) throws ServletException, IOException
{
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
RequestDispatcher disp = context.getRequestDispatcher(resource);
disp.forward(request, response);
}
// The sign servlet is used for processing the upload only.
// Authentication is deactivated. if required - make an own servlet.
// /**
// * @author modified by tknall
// */
// public void doGet(HttpServletRequest request, HttpServletResponse response)
// throws ServletException, IOException
// {
// String authenticate = request.getHeader(AUTH);
// if (authenticate != null)
// {
// logger_.info("authenticate:" + authenticate);
// if (authenticate.indexOf(AUTH_BASIC) == 0)
// {
// authenticate = authenticate.substring(AUTH_BASIC.length() + 1);
// logger_.info("authenticate:" + authenticate);
// authenticate = new String(CodingHelper.decodeBase64(authenticate),
// "UTF-8");
// logger_.info("authenticate:" + authenticate);
//
// String[] auth_value = authenticate.split(":");
// String user_name = auth_value[0];
// String user_password = auth_value[1];
// logger_.info("username:" + user_name);
// // start modification tknall
// // logger_.info("password:" + user_password);
// logger_.info("password:XXXXXXXXXXXX");
// // stop modification tknall
//
// HttpSession session = request.getSession();
// session.setAttribute(SessionAttributes.ATTRIBUTE_USER_NAME, user_name);
// session.setAttribute(SessionAttributes.ATTRIBUTE_USER_PASSWORD,
// user_password);
//
// dispatch(request, response, "/jsp/signupload.jsp");
// return;
// }
// // start modification tknall
// } else {
// String user_name = "";
// String user_password = "";
// logger_.info("authenticate:User has not been authenticated!");
// logger_.info("username: UNKNOWN");
// logger_.info("password: XXXXXXXXXXXX");
// HttpSession session = request.getSession();
// session.setAttribute("uname", user_name);
// session.setAttribute("upass", user_password);
// dispatch(request, response, "/jsp/signupload.jsp");
// }
// request.setAttribute("error", "Falsche Authentifikation");
// request.setAttribute("cause", "Passwort oder Benutzername ist falsch");
// dispatch(request, response, "/jsp/error.jsp");
// // stop modification tknall
// }
/**
* Processes the sign 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
{
UploadedData ud = null;
ExternAppInformation exappinf = null;
TablePos pos = null;
// check if pdf-as has been called by external webapp
if(request.getParameter(FormFields.FIELD_PDF_URL) != null) {
String preview = (String) request.getParameter(FormFields.FIELD_PREVIEW);
String sig_type = (String) request.getParameter(FormFields.FIELD_SIGNATURE_TYPE);
String sig_app = (String) request.getParameter(FormFields.FIELD_CONNECTOR);
String sig_mode = (String) request.getParameter(FormFields.FIELD_MODE);
String filename = (String) request.getParameter(FormFields.FIELD_FILENAME);
String pdf_url = (String) request.getParameter(FormFields.FIELD_PDF_URL);
String pdf_id = (String) request.getParameter(FormFields.FIELD_PDF_ID);
String pdf_length = (String) request.getParameter(FormFields.FIELD_FILE_LENGTH);
String invoke_url = (String) request.getParameter(FormFields.FIELD_INVOKE_APP_URL);
String session_id = (String) request.getParameter(FormFields.FIELD_SESSION_ID);
String sig_pos_y = (String) request.getParameter(FormFields.FIELD_SIGPOS_Y);
String sig_pos_p = (String) request.getParameter(FormFields.FIELD_SIGPOS_P);
try {
pos = new TablePos("y:" + sig_pos_y +";p:" + sig_pos_p);
} catch (PDFDocumentException e) {
log.warn("Uanable to create signature position object: " + e.getMessage());
}
String query = pdf_url + "&" + FormFields.FIELD_PDF_ID + "=" + pdf_id;
byte[] extern_pdf = new byte[Integer.parseInt(pdf_length)];
URL source_url = new URL(query);
InputStream is = source_url.openStream();
extern_pdf = toByteArray(is);
// set UploadedData object...
UploadedData ud_extern = new UploadedData();
ud_extern.file_name = filename;
ud_extern.pdf = extern_pdf;
ud_extern.preview = preview.equalsIgnoreCase("true") ? true : false;
ud_extern.sig_app = sig_app;
ud_extern.sig_mode = sig_mode;
ud_extern.sig_type = sig_type;
ud = ud_extern;
exappinf = new ExternAppInformation(invoke_url,pdf_id, session_id);
}
else {
try
{
// tzefferer: modified
//UploadedData ud = retrieveUploadedDataFromRequest(request);
UploadedData ud_form = retrieveUploadedDataFromRequest(request);
ud = ud_form;
// end modify
} catch(Exception e) {
// Error retrieving data
request.setAttribute("error", "Fehler beim Upload der Daten");
request.setAttribute("cause", "Beim Upload der Daten ist ein Fehler aufgetreten.");
dispatch(request, response, "/jsp/error.jsp");
}
}
try {
PdfAS.applyStrictMode(ud.pdf);
SessionInformation si = new SessionInformation(); // SessionTable.generateSessionInformationObject();
si.connector = ud.sig_app;
si.application = "sign";
si.mode = ud.sig_mode;
si.pdf = ud.pdf;
si.type = ud.sig_type;
si.filename = formatFileName(ud.file_name);
si.download_inline = ud.download_inline;
// added tzefferer:
si.exappinf = exappinf;
si.pos = pos;
// end add
request.getSession().setAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION, si);
// String user_name = (String)
// request.getSession().getAttribute(SessionAttributes.ATTRIBUTE_USER_NAME);
// String user_password = (String)
// request.getSession().getAttribute(SessionAttributes.ATTRIBUTE_USER_PASSWORD);
// si.user_name = user_name;
// si.user_password = user_password;
prepareSign(si);
if (ud.preview)
{
String submit_url = response.encodeURL(request.getContextPath() + "/SignPreview");
String signature_data_url = response.encodeURL(request.getContextPath() + "/RetrieveSignatureData");
request.setAttribute("submit_url", submit_url);
request.setAttribute("signature_data_url", signature_data_url);
dispatch(request, response, "/jsp/signpreview.jsp");
return;
}
finishSign(si, request, response, getServletContext());
}
catch (PresentableException e)
{
e.printStackTrace();
prepareDispatchToErrorPage(e, request);
dispatch(request, response, "/jsp/error.jsp");
}
}
// tzefferer:added
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
// end add
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 preview_fi = null;
FileItem sig_type_fi = null;
FileItem sig_app_fi = null;
FileItem mode_fi = null;
FileItem file_upload_fi = null;
FileItem download_fi = null;
Iterator it = items.iterator();
while (it.hasNext())
{
FileItem item = (FileItem) it.next();
log.debug("item = " + item.getFieldName()); //$NON-NLS-1$
if (log.isDebugEnabled())
{
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_PREVIEW))
{
preview_fi = item;
continue;
}
if (item.getFieldName().equals(FormFields.FIELD_SIGNATURE_TYPE))
{
sig_type_fi = item;
continue;
}
if (item.getFieldName().equals(FormFields.FIELD_CONNECTOR))
{
sig_app_fi = item;
continue;
}
if (item.getFieldName().equals(FormFields.FIELD_MODE))
{
mode_fi = item;
continue;
}
if (item.getFieldName().equals(FormFields.FIELD_UPLOAD))
{
file_upload_fi = item;
continue;
}
if (item.getFieldName().equals(FormFields.FIELD_DOWNLOAD))
{
download_fi = item;
continue;
}
throw new ServletException("unrecognized POST data."); //$NON-NLS-1$
}
if (preview_fi == null || sig_type_fi == null || sig_app_fi == null || file_upload_fi == null || download_fi == null)
{
throw new ServletException("Insufficient data provided in request"); //$NON-NLS-1$
}
String mode = mode_fi.getString("UTF-8"); //$NON-NLS-1$
if (!mode.equals(FormFields.VALUE_MODE_BINARY) && !mode.equals(FormFields.VALUE_MODE_TEXTUAL) && !mode.equals(FormFields.VALUE_MODE_DETACHED))
{
throw new ServletException("The mode '" + mode + "' is unrecognized."); //$NON-NLS-1$ //$NON-NLS-2$
}
String preview_str = preview_fi.getString("UTF-8"); //$NON-NLS-1$
boolean preview = false;
if (preview_str.equals("true")) //$NON-NLS-1$
{
preview = true;
}
boolean download_inline = true;
if (download_fi.getString("UTF-8").equals(FormFields.VALUE_DOWNLOAD_ATTACHMENT)) //$NON-NLS-1$
{
download_inline = false;
}
String sig_type = sig_type_fi.getString("UTF-8"); //$NON-NLS-1$
String sig_app = sig_app_fi.getString("UTF-8"); //$NON-NLS-1$
String doc_file_name = file_upload_fi.getName();
log.debug("file content type =" + file_upload_fi.getContentType()); //$NON-NLS-1$
String extension = VerifyServlet.extractExtension(doc_file_name);
if (extension != null && !extension.equals("pdf")) //$NON-NLS-1$
{
throw new PDFDocumentException(201, "The provided file '" + doc_file_name + "' doesn't have the PDF extension (.pdf)."); //$NON-NLS-1$//$NON-NLS-2$
}
byte[] pdf = file_upload_fi.get();
if (file_upload_fi.getSize() <= 0)
{
throw new PDFDocumentException(250, "The document is empty."); //$NON-NLS-1$
}
UploadedData ud = new UploadedData();
ud.preview = preview;
ud.download_inline = download_inline;
ud.sig_type = sig_type;
ud.sig_app = sig_app;
ud.sig_mode = mode;
ud.file_name = doc_file_name;
ud.pdf = pdf;
return ud;
}
/**
* Prepares the sign.
*
*
* This prepares the data for both being signed or being previewed.
*
*
* @param si
* The SessionInformation to be prepared.
* @throws PresentableException
* f.e.
*/
public static void prepareSign(SessionInformation si) throws PresentableException
{
log.debug("prepareSign:"); //$NON-NLS-1$
PdfASID algorithm = FormFields.translateSignatureModeToPdfASID(si.mode);
Signator signator = SignatorFactory.createSignator(algorithm);
//tzefferer: modified
//si.iui = signator.prepareSign(si.pdf, si.type, null, ConnectorFactory.needsSIG_ID(si.connector));
si.iui = signator.prepareSign(si.pdf, si.type, si.pos, ConnectorFactory.needsSIG_ID(si.connector));
// end modify
log.debug("prepareSign finished."); //$NON-NLS-1$
}
/**
* Finishes the sign.
*
*
* For non local connectors this concludes the sign process, signs the
* document and returns the result. For local connectors this initializes the
* local sign process and redirects to following servlets.
*
*
* @param si
* The SessionInformation.
* @param request
* The servlet request for dispatching.
* @param response
* The servlet response for dispatching.
* @param context
* The servlet context for dispatching.
* @throws PresentableException
* f.e.
* @throws IOException
* f. e.
* @throws ServletException
* f. e.
*/
public static void finishSign(SessionInformation si,
HttpServletRequest request, HttpServletResponse response,
ServletContext context) throws PresentableException, IOException, ServletException
{
log.debug("finishSign:"); //$NON-NLS-1$
log.debug("connector = " + si.connector); //$NON-NLS-1$
if (ConnectorFactory.isConnectorLocal(si.connector))
{
log.debug("Connector is local -> dispatching to local processing."); //$NON-NLS-1$
String dispatch_to = LocalRequestHelper.processLocalSign(si, request, response);
dispatch(request, response, dispatch_to, context);
return;
}
log.debug("Connector is not local -> finishing the sign."); //$NON-NLS-1$
PdfASID algorithm = FormFields.translateSignatureModeToPdfASID(si.mode);
Signator signator = SignatorFactory.createSignator(algorithm);
log.debug("RequestURL = " + request.getRequestURL());
log.debug("ContextPath = " + request.getContextPath());
String host = request.getServerName();
URL signature_data_URL = new URL(request.getScheme(), host, request.getServerPort(), request.getContextPath() + "/RetrieveSignatureData");
String signature_data_url = response.encodeURL(signature_data_URL.toString());
Connector c = ConnectorChooser.chooseWebConnectorForSign(si.connector, si.type, signature_data_url);
si.iui.signed_signature_object = c.doSign(si.iui.signature_data);
si.sign_result = signator.finishSign(si.iui);
returnSignResponse(si, response);
log.debug("finishSign finished."); //$NON-NLS-1$
}
public static void prepareDispatchToErrorPage(PresentableException pe,
HttpServletRequest request)
{
if (pe instanceof ErrorCodeException)
{
ErrorCodeException ece = (ErrorCodeException) pe;
request.setAttribute("error", "Fehler " + ece.getErrorCode());
String cause = ece.getErrorCodeMessage();
if (ece.hasExternalErrorMessage())
{
cause = ece.getExternalErrorCode() + ": " + ece.getExternalErrorMessage();
}
request.setAttribute("cause", cause);
if (pe instanceof PlaceholderException)
{
PlaceholderException phe = (PlaceholderException) ece;
request.setAttribute("cause", "Der Platzhalter des Feldes " + phe.getField() + " ist um " + phe.getMissing() + " Bytes zu kurz. " + ece.getErrorCodeMessage());
}
}
else
{
request.setAttribute("error", "PresentableException");
request.setAttribute("cause", pe.toString());
}
}
public void dispatchToPreview(String document_text, String connector,
String mode, String signature_type, String submit_url,
HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
request.setAttribute("document_text", document_text);
request.setAttribute("connector", connector);
request.setAttribute("mode", mode);
request.setAttribute("signature_type", signature_type);
request.setAttribute("submit_url", submit_url);
dispatch(request, response, "/jsp/signpreview.jsp");
}
/**
* Formats the file name so that it is suitable for content disposition.
*
* @param file_name
* The file name.
* @return Returns the formatted file name.
*/
public static String formatFileName(String file_name)
{
File file = new File(file_name);
String file_name_only = file.getName();
// the file_name contains \\ ==> remove them so Internet Explorer works
// correctly.
return file_name_only;
}
/**
* Formats the file name according to the SignResult.
*
* @param file_name
* The file name.
* @param sign_result
* The sign result.
* @return Returns the formatted file name.
*/
public static String formatFileNameForSignResult(String file_name,
SignResult sign_result)
{
String output = file_name + "_signed";
if (sign_result.getMimeType().equals(DetachedSignator_1_0_0.MIME_TYPE))
{
output += ".xml";
}
else
{
output += ".pdf";
}
return output;
}
/**
* Returns the data in the SignResult with proper content disposition.
*
* @param si
* SessionInformation.
* @param response
* The servlet response.
* @throws IOException
* The IO Exception.
*/
public static void returnSignResponse(SessionInformation si,
HttpServletResponse response) throws IOException
{
SignResult sign_result = si.sign_result;
String file_name = formatFileNameForSignResult(si.filename, sign_result);
// tzefferer: added condition
if (si.exappinf == null) {
// The name parameter is actually deprecated in favour of
// Content-Disposition filename
// Unfortunately Acrobat reader does recognize neither of these parameters
// with its inline save-as. It always takes the page name.
response.setContentType(sign_result.getMimeType() + "; name=\"" + file_name + "\"");
if (si.download_inline)
{
response.addHeader("Content-Disposition", "inline; filename=\"" + file_name + "\"");
}
else
{
response.addHeader("Content-Disposition", "attachment; filename=\"" + file_name + "\"");
}
response.getOutputStream().write(sign_result.getData());
// tzefferer: added else-block
} else {
SignResult sr = si.sign_result;
byte[] signed_pdf = sr.getData();
PDFContainer entry = new PDFContainer(signed_pdf, si.exappinf.pdf_id);
ProvidePDFServlet.signedDocuments.add(entry);
// notify webapp...
String invoke_url = si.exappinf.invoke_url;
String providePDFServlet = "ProvidePDF";
String pdf_id = String.valueOf(si.exappinf.pdf_id);
String session_id = si.exappinf.session_id;
// build URL
int ind = invoke_url.indexOf("?");
String query = invoke_url.substring(0, ind) + ";jsessionid=" + session_id + invoke_url.substring(ind) + "&" + FormFields.FIELD_PDF_URL + "=" + providePDFServlet + "&" + FormFields.FIELD_PDF_ID + "=" + pdf_id + "&" + FormFields.FIELD_FILE_LENGTH + "=" + signed_pdf.length;
response.sendRedirect(query);
}
}
// tzefferer: added
public static byte[] toByteArray(InputStream inputStream) throws IOException {
if(inputStream == null) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream(8192);
int n;
byte[] buffer = new byte[2048];
BufferedInputStream bufIn = new BufferedInputStream(inputStream);
try {
while ((n = bufIn.read(buffer)) != -1) {
out.write(buffer, 0, n);
}
} finally {
if(bufIn != null) {
bufIn.close();
}
}
return out.toByteArray();
}
// end add
protected static class UploadedData
{
protected boolean preview = false;
protected boolean download_inline = false;
protected String sig_type = null;
protected String sig_app = null;
protected String sig_mode = null;
protected String file_name = null;
protected byte[] pdf = null;
}
}