From 29ad090c29567ff1a4d3a2ec9b8ad0b5d80ee24d Mon Sep 17 00:00:00 2001 From: pdanner Date: Mon, 6 Dec 2010 16:34:52 +0000 Subject: git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@671 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../at/gv/egiz/pdfas/web/helper/ApiHelper.java | 73 +++++ .../egiz/pdfas/web/helper/LocalRequestHelper.java | 331 ++++++++++++++++++++ .../at/gv/egiz/pdfas/web/helper/SessionHelper.java | 47 +++ .../egiz/pdfas/web/helper/SignServletHelper.java | 342 +++++++++++++++++++++ .../egiz/pdfas/web/helper/SigningTimeHelper.java | 71 +++++ .../egiz/pdfas/web/helper/WebSettingsReader.java | 210 +++++++++++++ .../java/at/gv/egiz/pdfas/web/helper/WebUtils.java | 92 ++++++ 7 files changed, 1166 insertions(+) create mode 100644 pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/ApiHelper.java create mode 100644 pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/LocalRequestHelper.java create mode 100644 pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java create mode 100644 pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java create mode 100644 pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SigningTimeHelper.java create mode 100644 pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/WebSettingsReader.java create mode 100644 pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/WebUtils.java (limited to 'pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper') diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/ApiHelper.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/ApiHelper.java new file mode 100644 index 0000000..a0f22fd --- /dev/null +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/ApiHelper.java @@ -0,0 +1,73 @@ +package at.gv.egiz.pdfas.web.helper; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import javax.servlet.ServletContext; + +import at.gv.egiz.pdfas.api.PdfAs; +import at.gv.egiz.pdfas.api.internal.PdfAsInternal; +import at.knowcenter.wag.egov.egiz.exceptions.WebException; + +/** + * Utility methods for easier handling of {@link PdfAs} API object. + * + * @author exthex + * + */ +public class ApiHelper { + + public static final String PDF_AS_OBJECT = "PDF_AS_OBJECT"; + + public static final String INTERNAL_PDF_AS_OBJECT = "INTERNAL_PDF_AS_OBJECT"; + + public static PdfAs createApiObject(File file) throws WebException { + try { + Class pdfAsClass = Class.forName("at.gv.egiz.pdfas.impl.api.PdfAsObject"); + Constructor constructor = pdfAsClass.getConstructor(new Class[]{File.class}); + PdfAs pdfAs = (PdfAs)constructor.newInstance(new Object[]{ + new File(WebSettingsReader.RESOURCES_PATH)}); + return pdfAs; + } catch (ClassNotFoundException e) { + throw new WebException(e); + } catch (SecurityException e) { + throw new WebException(e); + } catch (NoSuchMethodException e) { + throw new WebException(e); + } catch (IllegalArgumentException e) { + throw new WebException(e); + } catch (InstantiationException e) { + throw new WebException(e); + } catch (IllegalAccessException e) { + throw new WebException(e); + } catch (InvocationTargetException e) { + throw new WebException(e); + } + } + + public static PdfAsInternal createInternalApiObject() throws WebException { + try { + Class pdfAsClass = Class.forName("at.gv.egiz.pdfas.impl.api.internal.PdfAsInternalObject"); + PdfAsInternal pdfAsinternal = (PdfAsInternal)pdfAsClass.newInstance(); + return pdfAsinternal; + } catch (ClassNotFoundException e) { + throw new WebException(e); + } catch (SecurityException e) { + throw new WebException(e); + } catch (InstantiationException e) { + throw new WebException(e); + } catch (IllegalAccessException e) { + throw new WebException(e); + } + } + + public static PdfAs getPdfAsFromContext(ServletContext servletContext) { + return (PdfAs)servletContext.getAttribute(PDF_AS_OBJECT); + } + + public static PdfAsInternal getPdfAsInternalFromContext(ServletContext servletContext) { + return (PdfAsInternal)servletContext.getAttribute(INTERNAL_PDF_AS_OBJECT); + } + +} diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/LocalRequestHelper.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/LocalRequestHelper.java new file mode 100644 index 0000000..82b3983 --- /dev/null +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/LocalRequestHelper.java @@ -0,0 +1,331 @@ +/** + * 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: LocalRequestHelper.java,v 1.6 2006/10/31 08:22:04 wprinz Exp $ + */ +package at.gv.egiz.pdfas.web.helper; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Properties; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.commons.SignatureInformation; +import at.gv.egiz.pdfas.api.internal.PdfAsInternal; +import at.gv.egiz.pdfas.web.CurrentLocalOperation; +import at.gv.egiz.pdfas.web.LocalRequest; +import at.gv.egiz.pdfas.web.session.SignSessionInformation; +import at.gv.egiz.pdfas.web.session.VerifySessionInformation; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * Contains commonly used helper functions for the local request procedure. + * + * @author wprinz + */ +public abstract class LocalRequestHelper +{ + + /** + * The logger. + */ + protected static Log logger = LogFactory.getLog(LocalRequestHelper.class); + + /** + * The resource of the null request page jsp. + */ + public static final String NULL_REQUEST_PAGE_JSP = "/jsp/null_request_page.jsp"; + + /** + * The resource of the local connection page jsp. + */ + public static final String LOCAL_CONNECTION_PAGE_JSP = "/jsp/local_connection_page.jsp"; + + /** + * The resource of the redirect refresh page jsp. + */ + public static final String REDIRECT_REFRESH_PAGE_JSP = "/jsp/redirect_refresh_page.jsp"; + + /** + * Sets up the local sign procedure. + * + * @param response + * The HttpServletResponse the local request page is written to. + * @throws IOException + * Forwarded exception. + * @throws PresentableException + * Forwarded exception. + */ + public static String processLocalSign(PdfAsInternal pdfAsInternal, SignSessionInformation si, HttpServletRequest request, HttpServletResponse response) throws IOException, PresentableException + { + String host = request.getServerName(); +// URL loc_ref_URL = new URL(WebUtils.addJSessionID(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()); + + String sign_request = pdfAsInternal.prepareLocalSignRequest(si.signParameters, loc_ref_url, si.sdi); +// LocalConnector c = ConnectorChooser.chooseLocalConnectorForSign(si.connector, si.type, loc_ref_url); +// String sign_request = c.prepareSignRequest(si.si.getSignatureData()); + + String local_request_url = pdfAsInternal.getLocalServiceAddress(si.type, si.connector); +// String local_request_url = getLocalServiceAddress(si.type, si.connector); + si.localRequest = new LocalRequest(local_request_url, sign_request); + si.outputAvailable = false; +// si.response_properties = null; + + URL data_URL = new URL(request.getScheme(), host, request.getServerPort(), WebUtils.addJSessionID(request.getContextPath() + "/DataURL", request)); + String data_url = response.encodeURL(data_URL.toString()); + logger.debug("data_url = " + data_url); + + request.setAttribute("local_request_url", local_request_url); + request.setAttribute("data_url", data_url); + + return NULL_REQUEST_PAGE_JSP; + + // TODO old code - remove + // + // LocalConnector local_conn = (LocalConnector) + // ConnectorFactory.createConnector(si.connector); + // + // + // // refactor WEB + // String document_text = "fixme"; //si.iui.document_text; + // String request_string = local_conn.prepareSignRequest(si.user_name, + // document_text, si.type); + // String request_url = local_conn.getSignURL(si.type); + // + // LocalRequest local_request = new LocalRequest(request_url, + // request_string); + // List local_requests = new ArrayList(); + // local_requests.add(local_request); + // + // // ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // // ObjectOutputStream oos = new ObjectOutputStream(baos); + // // oos.writeObject(local_requests); + // // oos.close(); + // // baos.close(); + // + // si.requests = new LocalRequest[1]; + // si.requests[0] = new LocalRequest(local_conn.getSignURL(si.type), + // request_string); + // si.current_operation = 0; + // si.response_properties = new Properties[1]; + // si.response_properties[0] = null; + // + // // SessionTable.put(si); + // request.getSession().setAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION, + // si); + // + // // byte [] requests_bytes = baos.toByteArray(); + // // String base64 = CodingHelper.encodeBase64(requests_bytes); + // + // LocalRequestHelper.prepareDispatchToLocalConnectionPage(si.requests[0], + // request, response); + } + + /** + * Sets up the local verify procedure. + * @param list + * + * @param response + * The HttpServletResponse the local request page is written to. + * @return Returns the JSP location where the calling servlet should dispatch + * to. + * @throws SignatureException + * Forwarded exception. + * @throws NormalizeException + * Forwarded exception. + * @throws IOException + * Forwarded exception. + * @throws ConnectorFactoryException + * Forwarded exception. + * @throws SettingsException + * @throws ConnectorException + */ + public static String processLocalVerify(PdfAsInternal pdfAsInternal, VerifySessionInformation si, List signaturesToBeverified, HttpServletRequest request, HttpServletResponse response) throws SignatureException, NormalizeException, + IOException, ConnectorFactoryException, SettingsException, ConnectorException + { + si.currentLocalOperation = new CurrentLocalOperation(); + si.currentLocalOperation.signaturesToBeverified = signaturesToBeverified; // SignatureInformation + + si.currentLocalOperation.requests = new LocalRequest[signaturesToBeverified.size()]; + si.currentLocalOperation.response_xmls = new String[si.currentLocalOperation.requests.length]; + + si.currentLocalOperation.current_operation = 0; +// si.finished = false; + + String host = request.getServerName(); +// URL loc_ref_URL = new URL(WebUtils.addJSessionID(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()); + + for (int i = 0; i < si.currentLocalOperation.requests.length; i++) + { + SignatureInformation sigInfo = (SignatureInformation) signaturesToBeverified.get(i); + String request_string = pdfAsInternal.prepareLocalVerifyRequest(sigInfo, si.connector, si.type, loc_ref_url); + + LocalRequest local_request = new LocalRequest("not-needed", request_string); + si.currentLocalOperation.requests[i] = local_request; + si.currentLocalOperation.response_xmls[i] = null; + } + + String local_request_url = pdfAsInternal.getLocalServiceAddress(si.type, si.connector); + + URL data_URL = new URL(request.getScheme(), host, request.getServerPort(), WebUtils.addJSessionID(request.getContextPath() + "/DataURL", request)); + String data_url = response.encodeURL(data_URL.toString()); + + request.setAttribute("local_request_url", local_request_url); + request.setAttribute("data_url", data_url); + + return NULL_REQUEST_PAGE_JSP; + + } + + /** + * Formats the OK response from the web application back to the local BKU. + * + *

+ * As stated in the BKU tutorial, this response must be plain text "". + * Otherwise BKU will assume a failure. + *

+ * + * @param response + * The HttpServletResponse to answer to. + * @throws IOException + * Forwarded exception. + */ + protected static void formatBKUOkResponse(HttpServletResponse response) throws IOException + { + response.setContentType("text/plain"); + response.setCharacterEncoding("ISO-8859-1"); + + response.getWriter().println(""); + } + + /** + * Prepares the dispatch to the local data connection page. + * + *

+ * The calling servlet just has to dispatch to the jsp after calling this + * method. + *

+ * + * @param local_request + * The local request. Basically this contains the local service's + * target URL and the XML request string. + * @param response + * The HttpServletResponse to write this page to. + * @throws IOException + * Forwarded exception. + * @throws SignatureException + * Forwarded exception. + * @throws NormalizeException + * Forwarded exception. + */ + public static void prepareDispatchToLocalConnectionPage(LocalRequest local_request, HttpServletRequest request, HttpServletResponse response) throws IOException, SignatureException, + NormalizeException + { + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + + String local_request_url = local_request.getUrl(); + + String quoted_request = makeStringHTMLReady(local_request.getRequestString()); + + String host = request.getServerName(); // "129.27.153.77" + URL data_URL = new URL(request.getScheme(), host, request.getServerPort(), request.getContextPath() + "/AsynchronousDataResponder"); + String data_url = response.encodeURL(data_URL.toString()); + URL redirect_URL = new URL(request.getScheme(), host, request.getServerPort(), request.getContextPath() + "/AsynchronousRedirectResponder"); + String redirect_url = response.encodeURL(redirect_URL.toString()); + + request.setAttribute("local_request_url", local_request_url); + request.setAttribute("quoted_request", quoted_request); + request.setAttribute("data_url", data_url); + request.setAttribute("redirect_url", redirect_url); + } + + public static String makeStringHTMLReady(String input) + { + String output = input; + + output = output.replaceAll("&", "&"); + output = output.replaceAll("\"", """); + output = output.replaceAll("<", "<"); + output = output.replaceAll(">", ">"); + return output; + } + + public static String getLocalServerAddress(HttpServletRequest request, HttpServletResponse response) + { + String host = request.getServerName(); + URL local_server = null; + try + { + String scheme = request.getScheme(); + int port = request.getServerPort(); + if ("http".equalsIgnoreCase(scheme) && port == 80) { + local_server = new URL(scheme, host, "/"); + } else if ("https".equalsIgnoreCase(scheme) && port == 443) { + local_server = new URL(scheme, host, "/"); + } else { + local_server = new URL(scheme, host, port, "/"); + } + } + catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } + String loc_server = response.encodeURL(local_server.toString()); + + return loc_server; + } + + public static String getLocalContextAddress(HttpServletRequest request, HttpServletResponse response) { + String serverURL = getLocalServerAddress(request, response); + String context = request.getContextPath(); + if (serverURL.endsWith("/") && context.startsWith("/")) { + context = context.substring(1); + } + return serverURL + context; + } + +/** + * Tells, if the given connector is local. + * + * @param connector_identifier + * The connector. + * @return Returns true, if the given connector is local, false otherwise. + * @throws ConnectorFactoryException + * F.e. + */ + public static boolean isConnectorLocal(String connector_identifier) throws ConnectorFactoryException + { + return connector_identifier.equals(Constants.SIGNATURE_DEVICE_BKU) || connector_identifier.equals(Constants.SIGNATURE_DEVICE_A1) || connector_identifier.equals(Constants.SIGNATURE_DEVICE_MOC); + } + +} diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java new file mode 100644 index 0000000..e3c8269 --- /dev/null +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java @@ -0,0 +1,47 @@ +/** + * + */ +package at.gv.egiz.pdfas.web.helper; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.web.SessionExpiredException; +import at.gv.egiz.pdfas.web.session.SessionAttributes; + +/** + * @author wprinz + * + */ +public class SessionHelper +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(SessionHelper.class); + + public static Object getSession(HttpServletRequest request) throws SessionExpiredException + { + + HttpSession session = request.getSession(false); + if (session == null) + { + String msg = "There is no session associated with this request."; //$NON-NLS-1$ + log.error(msg); + throw new SessionExpiredException(msg); + } + + Object sessionObject = session.getAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION); + if (sessionObject == null) + { + String msg = "Unable to find session data in session " + session.getId(); + log.error(msg); + throw new SessionExpiredException(msg); + } + + return sessionObject; + } +} diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java new file mode 100644 index 0000000..779b37b --- /dev/null +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java @@ -0,0 +1,342 @@ +/** + * + */ +package at.gv.egiz.pdfas.web.helper; + +import java.io.IOException; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.PdfAs; +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; +import at.gv.egiz.pdfas.api.internal.PdfAsInternal; +import at.gv.egiz.pdfas.api.io.DataSink; +import at.gv.egiz.pdfas.api.sign.SignParameters; +import at.gv.egiz.pdfas.api.sign.SignResult; +import at.gv.egiz.pdfas.api.sign.SignatureDetailInformation; +import at.gv.egiz.pdfas.web.FormFields; +import at.gv.egiz.pdfas.web.PDFContainer; +import at.gv.egiz.pdfas.web.io.ByteArrayDataSink; +import at.gv.egiz.pdfas.web.servlets.ProvidePDFServlet; +import at.gv.egiz.pdfas.web.session.SessionAttributes; +import at.gv.egiz.pdfas.web.session.SignSessionInformation; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; + +/** + * @author wprinz + * + */ +public class SignServletHelper +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(SignServletHelper.class); + + public 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); + } + + + /** + * Prepares the sign. + * + *

+ * This prepares the data for both being signed or being previewed. + *

+ * + * @param si + * The SessionInformation to be prepared. + * @throws PdfAsException + */ + public static SignatureDetailInformation prepareSign(PdfAs pdfAs, SignSessionInformation si) throws PdfAsException + { + log.debug("prepareSign:"); //$NON-NLS-1$ + + SignParameters signParameters = new SignParameters(); + signParameters.setDocument(si.pdfDataSource); + signParameters.setSignatureDevice(si.connector); + signParameters.setSignaturePositioning(si.pos); + signParameters.setSignatureProfileId(si.type); + signParameters.setSignatureType(si.mode); + DataSink sink = new ByteArrayDataSink(); + signParameters.setOutput(sink); + + SignatureDetailInformation signatureDetail = pdfAs.prepareSign(signParameters); + si.sdi = signatureDetail; + si.signParameters = signParameters; +// 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.si = signator.prepareSign(si.pdfDataSource, si.type, si.pos, null); + // end modify + log.debug("prepareSign finished."); //$NON-NLS-1$ + return signatureDetail; + } + + /** + * 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 IOException + * f. e. + * @throws ServletException + * f. e. + * @throws PdfAsException + */ + public static void finishSign(SignSessionInformation si, HttpServletRequest request, HttpServletResponse response, ServletContext context) throws IOException, ServletException, PdfAsException + { + log.debug("finishSign:"); //$NON-NLS-1$ + PdfAs pdfAs = ApiHelper.getPdfAsFromContext(context); + PdfAsInternal pdfAsInternal = ApiHelper.getPdfAsInternalFromContext(context); + + // check if document is empty + if (si.sdi.getSignatureData() == null || si.sdi.getSignatureData().getLength() == 0) { + throw new PDFDocumentException(251, "Unable to extract and textual content."); + } + + log.debug("connector = " + si.connector); //$NON-NLS-1$ + if (LocalRequestHelper.isConnectorLocal(si.connector)) + { + log.debug("Connector is local -> dispatching to local processing."); //$NON-NLS-1$ + + String dispatch_to = LocalRequestHelper.processLocalSign(pdfAsInternal, si, request, response); + dispatch(request, response, dispatch_to, context); + return; + } + log.debug("Connector is not local -> finishing the sign."); //$NON-NLS-1$ + + ByteArrayDataSink data = new ByteArrayDataSink(); + si.signParameters.setOutput(data); + SignResult signResult = pdfAs.sign(si.signParameters, si.sdi); + si.signResult = signResult; + si.signedPdf = data.getData(); + +// 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(); + + // TODO TR: Web-Applikation verwendet in Loc-Ref-Variante ext. Referenz, um performanter zu sein; + // nachfolend auskommentieren, wenn anstatt SwA-Connector LocRef-Connector verwendet wird +// URL signature_data_URL = new URL(WebUtils.addJSessionID(LocalRequestHelper.getLocalContextAddress(request, response) + "/RetrieveSignatureData", request)); +// URL signature_data_URL = new URL(WebUtils.buildRetrieveSignatureDataURL(request, response)); +// String signature_data_url = response.encodeURL(signature_data_URL.toString()); +// +// Connector c = ConnectorChooser.chooseWebConnectorForSign(si.connector, si.type, signature_data_url); +// SignSignatureObject signSignatureObject = c.doSign(si.si.getSignatureData()); +// +// si.si.setSignSignatureObject(signSignatureObject); + +// si.output = TempDirHelper.createTempDataSink(si.filename + "_signed.pdf"); +// signator.finishSign(si.si, si.output); + + returnSignResponse(si, request, response); + log.debug("finishSign finished."); //$NON-NLS-1$ + + } + + /** + * Returns the data in the SignResult with proper content disposition. + * + * @param si + * SessionInformation. + * @param bs + * @parem request The servlet request. + * @param response + * The servlet response. + * @throws IOException + * The IO Exception. + */ + public static void returnSignResponse(SignSessionInformation si, HttpServletRequest request, HttpServletResponse response) throws IOException + { +// SignResult sign_result = si.sign_result; + + String file_name = formatFileNameForSignResult(si.filename, si.output.getMimeType()); + + // 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(si.output.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 + "\""); + } + + IOUtils.write(si.signedPdf, response.getOutputStream()); +// TempDirHelper.writeDataSinkToHttpResponse(si.output, response); + //response.getOutputStream().write(sign_result.getData()); + + // tzefferer: added else-block + } + else + { + /** + * The following code handles an external invocation of pdf-as. External invocation is done by + * redirecting the user to the Sign-Servlet using the parameters defined in class + * at.knowcenter.wag.egov.egiz.web.FormFields. + * e.g. http://localhost:48080/pdf-as/Sign?preview=false&connector=bku&mode=textual&sig_type=SIGNATURBLOCK_DE&inline=false&filename=test.pdf&num-bytes=45916&pdf-url=http%3A%2F%2Flocalhost%3A8080%2Fmyapp%2FProvidePDF&pdf-id=1956507909008215134&invoke-app-url=https%3A%2F%2Flocalhost%3A8443%2Fmyapp%2FReturnSignedPDF&invoke-app-error-url=https%3A%2F%2Flocalhost%3A8443%2Fmyapp%2Fpdfaserror.do&session-id=9085B85B364BEC31E7D38047FE54577D&locale=de + */ + log.debug("External webapp invocation detected."); + byte [] signed_pdf = si.signedPdf; +// byte [] signed_pdf = null; +// if (si.output instanceof FileBasedDataSink) +// { +// FileBasedDataSink fbds = (FileBasedDataSink)si.output; +// signed_pdf = new byte [(int)fbds.getFile().length()]; +// FileInputStream fis = new FileInputStream(fbds.getFile()); +// fis.read(signed_pdf); +// fis.close(); +// } +// else +// { +// ByteArrayDataSink bads = (ByteArrayDataSink)si.output; +// signed_pdf = bads.getByteArray(); +// } + HttpSession session = request.getSession(); + + 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; + + log.debug("External application has to be notified. Building url from callback url \"" + invoke_url + "\"."); + + // build URL + int ind = invoke_url.indexOf("?"); + + // fixed by tknall: must not presume that invoke_url contains "?" + String sep = "&"; + if (ind == -1) { + ind = invoke_url.length(); + sep = "?"; + } + + String query = invoke_url.substring(0, ind) + ";jsessionid=" + session_id + invoke_url.substring(ind) + + sep + FormFields.FIELD_PDF_URL + "=" + providePDFServlet + "&" + FormFields.FIELD_PDF_ID + + "=" + pdf_id + "&" + FormFields.FIELD_FILE_LENGTH + "=" + signed_pdf.length + + "&" + FormFields.FIELD_PDFAS_SESSION_ID + "=" + session.getId(); + + /* + * Using the external web-interface of pdf-as (as described above) pdf-as should be run within + * an iframe. In case of a signature performed with a local citizen card software or with the + * server bku the result has to be provided outside the iframe. To break out of the iframe a + * helper jsp (redirect_to_parent) has to be used that redirects the user to the parent + * window. + */ + disableBrowserCacheForResponse(response); + if (Constants.SIGNATURE_DEVICE_BKU.equals(si.connector) || Constants.SIGNATURE_DEVICE_MOC.equals(si.connector)) { + log.debug("Pdf-as is supposed to run within an iframe."); + log.debug("Putting external application notify url (\"" + query + "\") in session (" + session.getId() + ") for later use."); + session.setAttribute(SessionAttributes.PARENT_WEBAPP_REDIRECT_URL, query); + String redirectHelper = response.encodeRedirectURL(request.getContextPath() + "/jsp/redirect_to_parent.jsp"); + + log.debug("Redirecting to " + redirectHelper); + log.debug("The browser will finally be redirected outside the iframe to " + query + " in order to notify the external application."); + + response.sendRedirect(redirectHelper); + + } else { + log.debug("Notifying external application by redirecting to \"" + query + "\"."); + response.sendRedirect(query); + } + + } + + } + + public static void disableBrowserCacheForResponse(HttpServletResponse response) { + log.debug("Disabling browser cache for HttpServletResponse."); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Pragma","no-cache"); + response.setDateHeader("Expires", -1); + } + + /** + * The Mime Type for XML. + */ + public static final String XML_MIME_TYPE = "text/xml"; //$NON-NLS-1$ + + /** + * 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, String mimeType) + { + String output = file_name + "_signed"; + if (mimeType.equals(XML_MIME_TYPE)) + { + output += ".xml"; + } + else + { + output += ".pdf"; + } + + return output; + } + + + public static void finishLocalSign(PdfAs pdfAs, PdfAsInternal pdfAsInternal, SignSessionInformation si) throws PdfAsException { + ByteArrayDataSink data = new ByteArrayDataSink(); + si.signParameters.setOutput(data); + + SignResult signResult = pdfAsInternal.finishLocalSign(pdfAs, si.signParameters, si.sdi, si.localBKUParams, si.xmlResponse); + si.signResult = signResult; + si.output = data; + si.outputAvailable = true; + si.signedPdf = data.getData(); + } +} diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SigningTimeHelper.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SigningTimeHelper.java new file mode 100644 index 0000000..4837a70 --- /dev/null +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/SigningTimeHelper.java @@ -0,0 +1,71 @@ +package at.gv.egiz.pdfas.web.helper; + +import java.util.Date; + +import org.apache.commons.lang.time.DateFormatUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * This class deals with invalid signing times. + * @author tknall + */ +public final class SigningTimeHelper { + + private SigningTimeHelper() { + } + + private static Integer tolerance = null; + + /** + * The log. + */ + private final static Log LOG = LogFactory.getLog(SigningTimeHelper.class); + + private final static String FORMAT_UTC_DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + + public static synchronized void checkSigningTimeAgainstHostTime(Date signingTime) throws SignatureException { + if (tolerance == null) { + try { + String toleranceString = WebSettingsReader.getInstance().getSigningTimeTolerance(); + tolerance = new Integer(Integer.parseInt(toleranceString)); + } catch (NumberFormatException e) { + LOG.warn("Invalid configuration key signingtimetolerance. Disabling signing time check."); + tolerance = new Integer(-1); + } catch (SettingsException e) { + LOG.warn("Invalid configuration key signingtimetolerance. Disabling signing time check."); + tolerance = new Integer(-1); + } + } + if (tolerance.intValue() == -1) { + return; + } + + // current time + Date currentTime = new Date(); + + // lower limit + Date lowerLimit = new Date(currentTime.getTime() - tolerance.intValue()*1000); + + // upper limit + Date upperLimit = new Date(currentTime.getTime() + tolerance.intValue()*1000); + + String signingTimeString = DateFormatUtils.formatUTC(signingTime, FORMAT_UTC_DATE_PATTERN); + + if (LOG.isDebugEnabled()) { + String lower = DateFormatUtils.formatUTC(lowerLimit, FORMAT_UTC_DATE_PATTERN); + String upper = DateFormatUtils.formatUTC(upperLimit, FORMAT_UTC_DATE_PATTERN); + LOG.debug("Checking if signing time " + signingTimeString + " is valid according to the given time frame [ " + lower + ", " + upper + " ]."); + } + + if (signingTime.before(lowerLimit) || signingTime.after(upperLimit)) { + throw new SignatureException(ErrorCode.INVALID_SIGNING_TIME, "The signing time " + signingTimeString + " is out of the given tolerance of " + tolerance.intValue() + " seconds."); + } + + } + +} diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/WebSettingsReader.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/WebSettingsReader.java new file mode 100644 index 0000000..c7f6b7e --- /dev/null +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/WebSettingsReader.java @@ -0,0 +1,210 @@ +package at.gv.egiz.pdfas.web.helper; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import org.apache.commons.lang.text.StrSubstitutor; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.exceptions.ConfigUtilsException; +import at.gv.egiz.pdfas.utils.ConfigUtils; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * + * @author exthex + * + */ +public class WebSettingsReader { + + /** + * The configuration key that replaces a dynamically generated retrieve signature data url. + */ + private final static String RETRIEVE_SIGNATURE_DATA_URL_OVERRIDE_KEY = "retrieve_signature_data_url_override"; + + private final static String SIGNING_TIME_TOLERANCE_KEY = "signing_time_tolerance"; + + private static final Log logger_ = LogFactory.getLog(WebSettingsReader.class); + + public static String RESOURCES_PATH = null; + + private static String TMP_PATH = null; + + private static String CONFIG_PATH; + + private static String CFG = "cfg"; + + private String WEB_CONFIG_FILE_DEFAULT_NAME = "pdf-as-web.properties"; + + public static synchronized void initialize(String work_dir) { + + String tmpDir = null; + + String defaultConfigDeployedTo = null; + // resolve work directory + // configuration explicitely given ? + if (work_dir == null) { + + // configuration via system property ? + logger_.debug("No configuration directory given. Looking for system property \"" + + Constants.CONFIG_DIR_SYSTEM_PROPERTY + "\"."); + work_dir = System.getProperty(Constants.CONFIG_DIR_SYSTEM_PROPERTY); + if (work_dir == null) { + + // configuration via user's home directory ? + logger_ + .debug("System property not set. Trying to locate configuration within the user's home directory."); + String userHome = System.getProperty("user.home"); + if (userHome == null || userHome.length() == 0) { + throw new RuntimeException("Unable to resolve user's home directory."); + } + work_dir = ConfigUtils.assertFileSeparator(userHome) + Constants.USERHOME_CONFIG_FOLDER; + try { + defaultConfigDeployedTo = ConfigUtils.deployDefaultConfiguration(work_dir, false); + } catch (ConfigUtilsException e) { + throw new RuntimeException(e); + } + if (defaultConfigDeployedTo != null) { + logger_.info("** Default configuration successfully deployed to \"" + + defaultConfigDeployedTo + "\" **"); + } else { + logger_ + .debug("Default configuration has NOT been deployed. Maybe the configuration already exists."); + } + } else { + logger_.debug("Configuration set by system property."); + tmpDir = work_dir; + } + } else { + logger_.debug("Configuration path explicitely set."); + } + File configdirFile = new File(StrSubstitutor.replaceSystemProperties(work_dir)); + try { + work_dir = ConfigUtils.assertFileSeparator(configdirFile.getCanonicalPath()); + } catch (IOException e) { + work_dir = ConfigUtils.assertFileSeparator(configdirFile.getPath()); + } + if (!configdirFile.isDirectory()) { + throw new IllegalArgumentException("The config directory \"" + work_dir + + "\" does not exist or is not a directory."); + } + + // resolve temporary dir + if (tmpDir == null) { + logger_ + .debug("Temporary directory not explicitely set. Looking for user's temp directory."); + tmpDir = System.getProperty("java.io.tmpdir"); + if (tmpDir == null) { + logger_ + .debug("Unable to resolve user's temporary directory. Assuming temporary directory located within config dir."); + tmpDir = work_dir; + } + } else { + logger_.debug("Temporary directory explicitely set."); + } + File tmpdirFile = new File(StrSubstitutor.replaceSystemProperties(ConfigUtils + .assertFileSeparator(tmpDir) + Constants.TEMP_DIR_NAME)); + try { + tmpDir = ConfigUtils.assertFileSeparator(tmpdirFile.getCanonicalPath()); + } catch (IOException e) { + tmpDir = ConfigUtils.assertFileSeparator(tmpdirFile.getPath()); + } + + RESOURCES_PATH = work_dir; + TMP_PATH = tmpDir; + File tmpFile = new File(TMP_PATH); + if (!tmpFile.exists()) + tmpFile.mkdirs(); + CONFIG_PATH = RESOURCES_PATH + CFG + System.getProperty("file.separator"); + + if (defaultConfigDeployedTo != null) { + logger_.debug("** Default configuration successfully deployed to \"" + + defaultConfigDeployedTo + "\" **"); + } + logger_.debug("Setting system property \"" + Constants.CONFIG_DIR_SYSTEM_PROPERTY + + "\" to \"" + configdirFile.getPath() + "\"."); + System.setProperty(Constants.CONFIG_DIR_SYSTEM_PROPERTY, configdirFile.getPath()); + } + + private static WebSettingsReader instance; + + /** + * + * @return + * @throws SettingsException + */ + public static synchronized WebSettingsReader getInstance() throws SettingsException { + if (instance == null) + instance = new WebSettingsReader(); + return instance; + } + + /** + * + */ + public static void clearTemporaryDirectory() { + File temp_dir = new File(TMP_PATH); + logger_.debug("Clearing temporary directory: " + temp_dir); + + if (!temp_dir.exists()) + { + return; + } + + File[] files = temp_dir.listFiles(); + for (int i = 0; i < files.length; i++) + { + // added by tknall: do not try to remove svn-metadata + if (files[i].getName().endsWith(".svn")) { + continue; + } + logger_.debug(" Clearing temporary file: " + files[i]); + boolean delete_success = files[i].delete(); + if (!delete_success) + { + logger_.error("Couldn't delete the temporary file: " + files[i]); + } + } + } + + /** + * + * @return + */ + public static File getTemporaryDirectory() { + return new File(TMP_PATH); + } + + private Properties props; + + private WebSettingsReader() throws SettingsException { + String settingsFile = CONFIG_PATH + WEB_CONFIG_FILE_DEFAULT_NAME; + props = new Properties(); + try { + props.load(new FileInputStream(settingsFile)); + }catch(IOException ioe){ + throw new SettingsException("", ioe); + } + } + + /** + * + * @return + */ + public String getSigningTimeTolerance() { + return props.getProperty(SIGNING_TIME_TOLERANCE_KEY); + } + + /** + * + * @return + */ + public String getRetrieveSignatureDataURLOverride() { + return props.getProperty(RETRIEVE_SIGNATURE_DATA_URL_OVERRIDE_KEY); + } + +} diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/WebUtils.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/WebUtils.java new file mode 100644 index 0000000..61d694c --- /dev/null +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/WebUtils.java @@ -0,0 +1,92 @@ +package at.gv.egiz.pdfas.web.helper; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * @author tknall + */ +public final class WebUtils { + + private WebUtils() { + } + + /** + * The log. + */ + private final static Log LOG = LogFactory.getLog(WebUtils.class); + + /** + * Unlike {@link HttpServletResponse#encodeURL(String)} that adds only a + * {@code JSESSIONID} entry to the given url if needed, this method always + * adds the session id (except if already present within the url. + * + * @param url + * The given url. + * @param session + * The {@link HttpSession}. + * @return The given url plus a session id. + */ + public static String addJSessionID(String url, HttpSession session) { + if (url == null) { + return null; + } + if (!StringUtils.containsIgnoreCase(url, ";jsessionid=")) { + url = url + ";jsessionid=" + session.getId(); + LOG.debug("Adding jsessionid " + session.getId()); + } else { + LOG.debug("No need to add a jsessionid."); + } + LOG.debug("Returning url " + url); + return url; + } + + /** + * Unlike {@link HttpServletResponse#encodeURL(String)} that adds only a + * {@code JSESSIONID} entry to the given url if needed, this method always + * adds the session id (except if already present within the url. + * + * @param url + * The given url. + * @param request + * The {@link HttpServletRequest}. + * @return The given url plus a session id. + */ + public static String addJSessionID(String url, HttpServletRequest request) { + return addJSessionID(url, request.getSession()); + } + + /** + * Either dynamically creates locref content url or uses a url provides by the pdf-as + * configuration (key {@code retrieve_signature_data_url_override}). + * @param request The {@link HttpServletRequest}. + * @param response The {@link HttpServletResponse}. + * @return The retrieve signature data url. + */ + public static String buildRetrieveSignatureDataURL(HttpServletRequest request, HttpServletResponse response) { + String override = null; + LOG.debug("Building retrieve signature data url."); + try { + override = WebSettingsReader.getInstance().getRetrieveSignatureDataURLOverride(); + } catch (SettingsException e) { + LOG.info(e); + } + String result; + if (override == null) { + result = WebUtils.addJSessionID(LocalRequestHelper.getLocalContextAddress(request, response) + "/RetrieveSignatureData", request); + } else { + LOG.debug("Override url found: " + override); + result = WebUtils.addJSessionID(override, request); + } + LOG.debug("RetrieveSignatureDataURL = " + result); + return result; + } + +} -- cgit v1.2.3