/** * 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; } }