From db52e4d66d60184d53a27ba4d6772461daacc03d Mon Sep 17 00:00:00 2001 From: tknall Date: Fri, 22 Mar 2013 08:57:51 +0000 Subject: Maintenance update (bugfixes, new features, cleanup...) Refer to /dok/RELEASE_NOTES-3.3.txt for further information. git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/pdf-as/trunk@931 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../java/at/knowcenter/wag/egov/egiz/PdfAS.java | 245 ++++++++++---------- .../egov/egiz/cfg/CircularIncludeException.java | 44 ++++ .../wag/egov/egiz/cfg/NestedProperties.java | 255 +++++++++++++++++++++ .../knowcenter/wag/egov/egiz/cfg/PropertyTree.java | 82 +++++-- .../wag/egov/egiz/cfg/SettingsReader.java | 207 +++++++++-------- .../knowcenter/wag/egov/egiz/commandline/Main.java | 116 ++++------ .../framework/signators/BinarySignator_1_0_0.java | 29 +-- .../signators/DetachedSignator_1_0_0.java | 11 +- .../signators/DetachedfTextualSignator_1_0_0.java | 15 +- .../wag/egov/egiz/pdf/AbsoluteTextSignature.java | 4 +- .../wag/egov/egiz/pdf/BinarySignature.java | 215 +++++++++-------- .../at/knowcenter/wag/egov/egiz/pdf/PDFPage.java | 249 +++++++++++++++----- .../wag/egov/egiz/pdf/PDFSignatureObjectIText.java | 70 ++---- .../knowcenter/wag/egov/egiz/pdf/PDFUtilities.java | 25 +- .../wag/egov/egiz/pdf/StructContentHelper.java | 47 ++-- .../wag/egov/egiz/pdf/TextualSignature.java | 56 +++-- .../path/PathConstructionOperatorProcessor.java | 62 +++++ .../path/PathPaintingOperatorProcessor.java | 43 ++++ .../pdf/operator/path/construction/ClosePath.java | 68 ++++++ .../pdf/operator/path/construction/CurveTo.java | 85 +++++++ .../construction/CurveToReplicateFinalPoint.java | 82 +++++++ .../construction/CurveToReplicateInitialPoint.java | 84 +++++++ .../pdf/operator/path/construction/LineTo.java | 71 ++++++ .../pdf/operator/path/construction/MoveTo.java | 73 ++++++ .../operator/path/painting/CloseAndStrokePath.java | 59 +++++ .../painting/CloseFillEvenOddAndStrokePath.java | 60 +++++ .../painting/CloseFillNonZeroAndStrokePath.java | 60 +++++ .../egiz/pdf/operator/path/painting/EndPath.java | 68 ++++++ .../path/painting/FillEvenOddAndStrokePath.java | 72 ++++++ .../path/painting/FillNonZeroAndStrokePath.java | 72 ++++++ .../path/painting/FillPathEvenOddRule.java | 71 ++++++ .../painting/FillPathNonZeroWindingNumberRule.java | 72 ++++++ .../pdf/operator/path/painting/StrokePath.java | 70 ++++++ .../wag/egov/egiz/sig/SignatureObject.java | 171 +++++++------- .../wag/egov/egiz/sig/SignatureTypes.java | 167 +++++++++++++- .../at/knowcenter/wag/egov/egiz/sig/X509Cert.java | 32 ++- .../wag/egov/egiz/sig/connectors/BKUConnector.java | 81 ++++--- .../wag/egov/egiz/sig/connectors/MOAConnector.java | 47 ++-- .../egov/egiz/sig/connectors/bku/BKUHelper.java | 75 +++--- .../sig/connectors/bku/DetachedBKUConnector.java | 122 +++++----- .../bku/EnvelopedBase64BKUConnector.java | 68 +++--- .../connectors/moa/DetachedLocRefMOAConnector.java | 48 ++-- .../moa/EnvelopingBase64MOAConnector.java | 72 +++--- .../moa/MOASoapWithAttachmentConnector.java | 104 ++++----- .../mocca/LocRefDetachedMOCCAConnector.java | 108 ++++----- .../wag/egov/egiz/sig/sigkz/SigKZIDHelper.java | 53 +++-- .../mocca/MoccaXades14SignatureLayoutHandler.java | 53 +++++ .../wag/egov/egiz/tools/CodingHelper.java | 34 ++- 48 files changed, 2989 insertions(+), 1088 deletions(-) create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/CircularIncludeException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/NestedProperties.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathConstructionOperatorProcessor.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathPaintingOperatorProcessor.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/ClosePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveTo.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateFinalPoint.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateInitialPoint.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/LineTo.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/MoveTo.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseAndStrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillEvenOddAndStrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillNonZeroAndStrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/EndPath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillEvenOddAndStrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillNonZeroAndStrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathEvenOddRule.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathNonZeroWindingNumberRule.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/StrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MoccaXades14SignatureLayoutHandler.java (limited to 'pdf-as-lib/src/main/java/at/knowcenter') diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java index fa9d4c1..2681f80 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java @@ -115,7 +115,7 @@ public abstract class PdfAS * The current version of the pdf-as library. This version string is logged on every invocation * of the api or the web application. */ - public static final String PDFAS_VERSION = "3.3-SNAPSHOT"; + public static final String PDFAS_VERSION = "3.3"; /** * The key of the strict mode setting. @@ -1306,122 +1306,135 @@ public abstract class PdfAS */ public static PositioningInstruction adjustSignatureTableandCalculatePosition(final PdfDataSource pdfDataSource, PdfPTable pdf_table, TablePos pos) throws PDFDocumentException { - // first check pageinstruction in TablePos-object - // new,auto,absolut - PdfReader reader = readInPdfDocument(pdfDataSource); - PDFASUtils.checkReaderPermissions(reader); - // get pages of currentdocument - int doc_pages = reader.getNumberOfPages(); - int page = doc_pages; - boolean make_new_page = pos.isNewPage(); - if (!(pos.isNewPage() || pos.isPauto())) - { - // we should posit signaturtable on this page - - page = pos.getPage(); - // System.out.println("XXXXPAGE="+page+" doc_pages="+doc_pages); - if (page > doc_pages) - { - make_new_page = true; - page = doc_pages; - // throw new PDFDocumentException(227, "Page number is to big(=" + page+ - // ") cannot be parsed."); - } - } - - // getPagedimensions - Rectangle psize = reader.getPageSizeWithRotation(page); - int page_rotation = reader.getPageRotation(page); - - float page_width = psize.getWidth(); - float page_height = psize.getHeight(); - // now we can calculate x-position - float pre_pos_x = SIGNATURE_MARGIN_HORIZONTAL; - if (!pos.isXauto()) - { - // we do have absolute x - pre_pos_x = pos.getPosX(); - } - // calculate width - // center - float pre_width = page_width - 2*pre_pos_x; - if (!pos.isWauto()) - { - // we do have absolute width - pre_width = pos.getWidth(); - if (pos.isXauto()) - { // center x - pre_pos_x = (page_width - pre_width) / 2; - } - } - final float pos_x = pre_pos_x; - final float width = pre_width; - // Signatur table dimensions are complete - pdf_table.setTotalWidth(width); - pdf_table.setLockedWidth(true); - - final float table_height = pdf_table.getTotalHeight(); - // now check pos_y - float pos_y = pos.getPosY(); - if (!pos.isYauto()) - { - // we do have y-position too --> all parameters but page ok - if (make_new_page) - { - page++; - } - return new PositioningInstruction(make_new_page, page, pos_x, pos_y); - } - // pos_y is auto - if (make_new_page) - { - // ignore footer in new page - page++; - pos_y = page_height - SIGNATURE_MARGIN_VERTICAL; - return new PositioningInstruction(make_new_page, page, pos_x, pos_y); - } - // up to here no checks have to be made if Tablesize and Pagesize are fit - // Now we have to getfreespace in page and reguard footerline - float footer_line = pos.getFooterLine(); - float pre_page_length = PDFUtilities.calculatePageLength(pdfDataSource, page - 1, page_height - footer_line, page_rotation); - if (pre_page_length == Float.NEGATIVE_INFINITY) - { - // we do have an empty page or nothing in area above footerline - pre_page_length = page_height; - // no text --> SIGNATURE_BORDER - pos_y = page_height - SIGNATURE_MARGIN_VERTICAL; - if (pos_y - footer_line <= table_height) - { - make_new_page = true; - if (!pos.isPauto()) - { - // we have to correct pagenumber - page = reader.getNumberOfPages(); - } - page++; - // no text --> SIGNATURE_BORDER - pos_y = page_height - SIGNATURE_MARGIN_VERTICAL; - } - return new PositioningInstruction(make_new_page, page, pos_x, pos_y); - } - final float page_length = pre_page_length; - // we do have text take SIGNATURE_MARGIN - pos_y = page_height - page_length - SIGNATURE_MARGIN_VERTICAL; - if (pos_y - footer_line <= table_height) - { - make_new_page = true; - if (!pos.isPauto()) - { - // we have to correct pagenumber in case of absolute page and not enough - // space - page = reader.getNumberOfPages(); - } - page++; - // no text --> SIGNATURE_BORDER - pos_y = page_height - SIGNATURE_MARGIN_VERTICAL; - } - return new PositioningInstruction(make_new_page, page, pos_x, pos_y); + PdfReader reader = null; + try { + reader = PDFASUtils.createPdfReaderCheckingPermissions(pdfDataSource); + // get pages of currentdocument + int doc_pages = reader.getNumberOfPages(); + int page = doc_pages; + boolean make_new_page = pos.isNewPage(); + if (!(pos.isNewPage() || pos.isPauto())) + { + // we should posit signaturtable on this page + + page = pos.getPage(); + // System.out.println("XXXXPAGE="+page+" doc_pages="+doc_pages); + if (page > doc_pages) + { + make_new_page = true; + page = doc_pages; + // throw new PDFDocumentException(227, "Page number is to big(=" + page+ + // ") cannot be parsed."); + } + } + + // getPagedimensions + Rectangle psize = reader.getPageSizeWithRotation(page); + int page_rotation = reader.getPageRotation(page); + + float page_width = psize.getWidth(); + float page_height = psize.getHeight(); + + // now we can calculate x-position + float pre_pos_x = SIGNATURE_MARGIN_HORIZONTAL; + if (!pos.isXauto()) + { + // we do have absolute x + pre_pos_x = pos.getPosX(); + } + // calculate width + // center + float pre_width = page_width - 2*pre_pos_x; + if (!pos.isWauto()) + { + // we do have absolute width + pre_width = pos.getWidth(); + if (pos.isXauto()) + { // center x + pre_pos_x = (page_width - pre_width) / 2; + } + } + final float pos_x = pre_pos_x; + final float width = pre_width; + // Signatur table dimensions are complete + pdf_table.setTotalWidth(width); + pdf_table.setLockedWidth(true); + + final float table_height = pdf_table.getTotalHeight(); + // now check pos_y + float pos_y = pos.getPosY(); + + // in case an absolute y position is already given OR + // if the table is related to an invisible signature + // there is no need for further calculations + // (fixed adding new page in case of invisible signatures) + if (!pos.isYauto() || table_height == 0) + { + // we do have y-position too --> all parameters but page ok + if (make_new_page) + { + page++; + } + return new PositioningInstruction(make_new_page, page, pos_x, pos_y); + } + // pos_y is auto + if (make_new_page) + { + // ignore footer in new page + page++; + pos_y = page_height - SIGNATURE_MARGIN_VERTICAL; + return new PositioningInstruction(make_new_page, page, pos_x, pos_y); + } + // up to here no checks have to be made if Tablesize and Pagesize are fit + // Now we have to getfreespace in page and reguard footerline + float footer_line = pos.getFooterLine(); + float pre_page_length = PDFUtilities.calculatePageLength(pdfDataSource, page - 1, page_height - footer_line, page_rotation); + if (pre_page_length == Float.NEGATIVE_INFINITY) + { + // we do have an empty page or nothing in area above footerline + pre_page_length = page_height; + // no text --> SIGNATURE_BORDER + pos_y = page_height - SIGNATURE_MARGIN_VERTICAL; + if (pos_y - footer_line <= table_height) + { + make_new_page = true; + if (!pos.isPauto()) + { + // we have to correct pagenumber + page = reader.getNumberOfPages(); + } + page++; + // no text --> SIGNATURE_BORDER + pos_y = page_height - SIGNATURE_MARGIN_VERTICAL; + } + return new PositioningInstruction(make_new_page, page, pos_x, pos_y); + } + final float page_length = pre_page_length; + // we do have text take SIGNATURE_MARGIN + pos_y = page_height - page_length - SIGNATURE_MARGIN_VERTICAL; + if (pos_y - footer_line <= table_height) + { + make_new_page = true; + if (!pos.isPauto()) + { + // we have to correct pagenumber in case of absolute page and not enough + // space + page = reader.getNumberOfPages(); + } + page++; + // no text --> SIGNATURE_BORDER + pos_y = page_height - SIGNATURE_MARGIN_VERTICAL; + } + return new PositioningInstruction(make_new_page, page, pos_x, pos_y); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (Exception e) { + } + } + } } // /** diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/CircularIncludeException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/CircularIncludeException.java new file mode 100644 index 0000000..6ff7d3a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/CircularIncludeException.java @@ -0,0 +1,44 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.cfg; + +/** + * Exception indicating that circular includes were detected. + * + * @author Datentechnik Innovation GmbH + * + */ +public class CircularIncludeException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public CircularIncludeException() { + super(); + } + + public CircularIncludeException(String message) { + super(message); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/NestedProperties.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/NestedProperties.java new file mode 100644 index 0000000..259a1dc --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/NestedProperties.java @@ -0,0 +1,255 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.cfg; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.Enumeration; +import java.util.InvalidPropertiesFormatException; +import java.util.Iterator; +import java.util.Properties; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOCase; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.filefilter.WildcardFileFilter; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Enhanced Java Properties allowing nested include instructions.
+ * In order to include further Properties use the following instruction: + *

+ * include = [path/to/]foo.properties + *

+ * Note that wildcard imports are allowed, e.g. + *

+ * include = [path/to/]profile.*.properties + *

+ * In order to use more than one include instruction within a file append an arbitary postfix to include. + * in order to make each include key unique within a properties file, e.g. + *

+ * include = profile.SIGNATURBLOCK*.properties
+ * include.amtssignaturen = profile.AMTSSIGNATURBLOCK*.properties
+ * include.1 = myProfiles1/*.properties
+ * include.2 = myProfiles2/*.properties + *

+ * Note that + *

+ *

+ * Mind creating circular includes! + * + * @author Datentechnik Innovation GmbH + */ +public class NestedProperties extends Properties { + + private static final long serialVersionUID = 1L; + + private Log log = LogFactory.getLog(getClass()); + + /** + * Creates an empty property list with no default values. + */ + public NestedProperties() { + super(); + } + + /** + * Creates an empty property list with the specified defaults. + * @param defaults The defaults. + */ + public NestedProperties(Properties defaults) { + super(defaults); + } + + /** + * The name of the key that triggers including of other properties. + */ + private final String INCLUDE_KEY_NAME = "include"; + + /** + * Defines the default behaviour of the file matching filter. + */ + private final IOCase DEFAULT_IOCASE = IOCase.SENSITIVE; + + /** + * The maximum depth of includes before being regarded as circular (throwing a {@link CircularIncludeException}). + */ + private final int MAX_NESTED_INCLUDE_DEPTH = 25; + + @Override + /** + * Warning: When Properties are loaded using InputStreams include instructions are not supported. + */ + public synchronized void load(InputStream inStream) throws IOException { + log.debug("Loading properties from input stream. Include instructions are not supported."); + super.load(inStream); + } + + @Override + public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException { + // Loading from InputStream is not supported since including further property files that have been declared + // using relative paths need a context directory which cannot be retrieved from InputStreams. + throw new UnsupportedOperationException("Imports from XML files are not supported."); + } + + /** + * Reads a property list from a certain file including other properties files if include instructions are present. + * Note that include instructions that do not match any files do not result in an exception. A respective message at + * WARN level is logged. + * + * @param file + * The file to be read. + * @throws IOException + * Thrown in case of an I/O error. + * @throws CircularIncludeException + * Thrown if circular includes have been detected (@link {@link RuntimeException}). + */ + public synchronized void load(File file) throws IOException, CircularIncludeException { + load(file, 0); + } + + /** + * Reads a property list from a certain file including other properties files if include instructions are present. + * Note that include instructions that do not match any files do not result in an exception. A respective message at + * WARN level is logged. + * + * @param file + * The file to be read. + * @param currentDepth + * The current include depth. + * @throws IOException + * Thrown in case of an I/O error. + * @throws CircularIncludeException + * Thrown if circular includes have been detected (@link {@link RuntimeException}). + */ + private synchronized void load(File file, int currentDepth) throws IOException, CircularIncludeException { + if (currentDepth > MAX_NESTED_INCLUDE_DEPTH) { + throw new CircularIncludeException("Circular include instruction(s) detected."); + } + InputStream in = null; + try { + in = new FileInputStream(file); + log.debug("Loading '" + file.getCanonicalPath() + "'."); + super.load(in); + } finally { + IOUtils.closeQuietly(in); + } + // Properties have been loaded. Apply preprocessing step in order to process include instructions. + // Provide a context directory in order to be able to resolve relative path instructions. + processIncludes(file.getParentFile(), currentDepth); + } + + /** + * Resolves all include instructions as part of a postprocessing step. + * + * @param contextFolder + * The folder that should be assumed as starting folder for relative include instructions. + * @param currentDepth + * The current include depth. + * @throws IOException + * Thrown in case of error. + */ + private void processIncludes(File contextFolder, int currentDepth) throws IOException { + SortedMap sortedIncludeInstructions = new TreeMap(); + + // Walk through properties, collecting include instructions. + // Since the backing Hashtable does not guarantee any order, import instructions need to be sorted according to + // their keys (natural order -> alphabetically). + // This allows for defining a pseudo load order: include.1=path/to/settings.propertes, + // include.2=other/path/to/settings.properties + @SuppressWarnings("unchecked") + Enumeration propertyNames = (Enumeration) propertyNames(); + while (propertyNames.hasMoreElements()) { + String key = propertyNames.nextElement(); + // valid include instructions: include=xxx, include.foo=xxx, include.foo.foo=xxx... (keys are case + // insensitive) + if (INCLUDE_KEY_NAME.equalsIgnoreCase(key) || StringUtils.startsWithIgnoreCase(key, INCLUDE_KEY_NAME + ".")) { + String includeValue = StringUtils.trimToNull(getProperty(key)); + if (includeValue != null) { + sortedIncludeInstructions.put(key, includeValue); + } + } + } + + // performing imports + Iterator includeIt = sortedIncludeInstructions.keySet().iterator(); + while (includeIt.hasNext()) { + String includeInstructionKey = includeIt.next(); + String includePath = getProperty(includeInstructionKey); + processInclude(contextFolder, includePath, currentDepth); + // remove import instruction from properties + remove(includeInstructionKey); + } + } + + /** + * Processes a single include instruction (which may lead to several imports due to wildcard support). + * + * @param contextFolder + * The folder that should be assumed as starting folder for relative include instructions. + * @param includePath + * The include path instruction. + * @param currentDepth + * The current include depth. + * @throws IOException + * Thrown in case of error. + */ + private void processInclude(File contextFolder, String includePath, int currentDepth) throws IOException { + // Combine contextFolder with relative path instructions from includePath. + File includeInstruction = new File(contextFolder, includePath); + contextFolder = includeInstruction.getParentFile(); + String includeName = includeInstruction.getName(); + + WildcardFileFilter fileFilter = new WildcardFileFilter(includeName, DEFAULT_IOCASE); + Collection includeFiles = null; + if (contextFolder != null && contextFolder.exists() && contextFolder.isDirectory()) { + includeFiles = FileUtils.listFiles(contextFolder, fileFilter, null); + } + if (includeFiles != null && !includeFiles.isEmpty()) { + log.info("Including '" + includePath + "'."); + for (File includeFile : includeFiles) { + NestedProperties includeProperties = new NestedProperties(); + includeProperties.load(includeFile, currentDepth + 1); + putAll(includeProperties); + } + } else { + log.warn("Unable to find '" + includeName + "' in folder '" + contextFolder.getCanonicalPath() + "'."); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java index 49ba003..e9276b8 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java @@ -38,7 +38,7 @@ import java.util.Vector; * the values of a configuration is stored in nested hashes. The keys in an area are stored in a * HashMap. The values of a key are stored in a Vector to overload some keys. The property tree can * be used to extract sub nodes and sub keys of different tree levels. - * + * * @author wlackner * @see java.util.HashMap * @see java.util.Vector @@ -49,7 +49,7 @@ public class PropertyTree implements Serializable { * SVUID. */ private static final long serialVersionUID = -1686170519955886222L; - + /** * The key split string. A key can be a complex key. Sub keys are separated from each other with * the split string. This string is used to devide the complex key. @@ -77,7 +77,7 @@ public class PropertyTree implements Serializable { * the tree will be created. The last part of the key (last splitted element) adds the value to * there own value data structure (Vector).
* Example: setKeyValue("key.1_level.2_level","the value for k_1_2")null if the key is not a subtree referece */ @@ -129,7 +129,7 @@ public class PropertyTree implements Serializable { * This method return the subtree that corresponds to a particular key. The key does not split. * Therefore the key must be a children of the current node. Search only in the key map of the * current node. - * + * * @param key the key that has to be a sub node * @return a sub tree (PropertyTree) or null if the key is not a children of the * current node @@ -142,7 +142,7 @@ public class PropertyTree implements Serializable { * Returns the last value (keys can be overloaded) of a key. The key are splitted into subnodes * and the last node of the key is the current value holder. If a key or subnode is not in the sub * tree the return value is null. - * + * * @param key the key that holds the value (can be a nested key like "key.1.2.3") * @return the value of the key (last node of the key) or null otherwise */ @@ -162,7 +162,7 @@ public class PropertyTree implements Serializable { * Returns the first value (keys can be overloaded) of a key. The key are splitted into subnodes * and the last node of the key is the current value holder. If a key or subnode is not in the sub * tree the return value is null. - * + * * @param key the key that holds the value (can be a nested key like "key.1.2.3") * @return the value of the key (last node of the key) or null otherwise */ @@ -180,7 +180,7 @@ public class PropertyTree implements Serializable { /** * This method return all values of the current node. The values are stored as String values. - * + * * @return the values (type String) of the current node * @see Vector */ @@ -191,7 +191,7 @@ public class PropertyTree implements Serializable { /** * This method return all keys (sub tree references) of the current node as a Map. The keys are * stored as String values. - * + * * @return the keys (type String) of the current node * @see Map */ @@ -202,7 +202,7 @@ public class PropertyTree implements Serializable { /** * This method return all keys (sub tree references) of the current node as an ArrayList. The keys * are stored as String values. - * + * * @return the keys (type String) of the current node * @see ArrayList */ @@ -219,10 +219,10 @@ public class PropertyTree implements Serializable { } /** - * + * * This method return all sub tree references of a key as an ArrayList. The keys are stored as * String values. - * + * * @param key (can be a nested key like "key.1.2.3") * @return the keys (type String) of the current node * @see ArrayList @@ -237,7 +237,7 @@ public class PropertyTree implements Serializable { /** * This method return all values of a key. The values are stored as String values. - * + * * @param key (can be a nested key like "key.1.2.3") * @return the values (type Vector) of the key or null if the key is not in the sub * tree of the current node @@ -254,7 +254,7 @@ public class PropertyTree implements Serializable { /** * Store a sub tree (type PropertyTree) in the current node. The key and it's sub tree are stored * in a HashMap. - * + * * @param key the reference of the sub tree * @param tree the sub tree of the key * @see HashMap @@ -270,7 +270,7 @@ public class PropertyTree implements Serializable { * Extracts a sub tree of a nested key. The Method returns the last sub tree of the nested key. * Example: if the key is like: key.1.2.3 the sub tree of the last * node 3 is returned. - * + * * @param key the reference of the sub tree * @return a sub tree of the key or null if the key can not be found */ @@ -280,7 +280,7 @@ public class PropertyTree implements Serializable { /** * This method checks if a key is a reference to a sub tree in the current node. - * + * * @param key a simple key that is a parent reference of a sub tree * @return true if the key is found, false otherwise */ @@ -291,7 +291,7 @@ public class PropertyTree implements Serializable { /** * The default toString method. It starts with the current node recursively downwards and return * the String representation of the node. - * + * * @return the string representation of the node */ public String toString() { @@ -300,9 +300,9 @@ public class PropertyTree implements Serializable { /** * This is a helper function to define the prefix for different levels in the toString method, not - * realy nice ;-). - * It replaces all "." chars with " ". - * + * realy nice ;-).

+ * In other words: Fills {@code key} with spaces (of same length). + * * @param key * @return a replaces prefix string */ @@ -312,7 +312,7 @@ public class PropertyTree implements Serializable { /** * This method concatenates all values of the current node and return them as a combinded string. - * + * * @param prefix * @param tree * @return the string representation of the node values @@ -330,7 +330,7 @@ public class PropertyTree implements Serializable { /** * The toString method. It starts with a special level prefix, sub tree and recursively adds all * sub trees. - * + * * @param prefix the prefix for this node * @param tree the current node * @return the string representation of the node @@ -351,8 +351,40 @@ public class PropertyTree implements Serializable { } return os; } - + public void removeEntry(String key) { - this.keys_.remove(key); + this.keys_.remove(key); } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((keys_ == null) ? 0 : keys_.hashCode()); + result = prime * result + ((values_ == null) ? 0 : values_.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PropertyTree other = (PropertyTree) obj; + if (keys_ == null) { + if (other.keys_ != null) + return false; + } else if (!keys_.equals(other.keys_)) + return false; + if (values_ == null) { + if (other.values_ != null) + return false; + } else if (!values_.equals(other.values_)) + return false; + return true; + } + } \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java index 352c594..832f952 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java @@ -32,7 +32,6 @@ import iaik.security.provider.IAIK; import iaik.utils.RFC2253NameParser; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; @@ -42,6 +41,7 @@ import java.util.Enumeration; import java.util.Properties; import java.util.Vector; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.text.StrSubstitutor; import org.apache.commons.logging.Log; @@ -49,6 +49,7 @@ 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.exceptions.ErrorCode; import at.gv.egiz.pdfas.utils.ConfigUtils; import at.gv.egiz.pdfas.utils.TempDirHelper; import at.knowcenter.wag.egov.egiz.PdfAS; @@ -61,36 +62,36 @@ import at.knowcenter.wag.egov.egiz.tools.FileHelper; * The SettingsReader reads the settings.txt file. The * settings.txt is a simple java property file that collects all * parameters used in different modules. - * + * * The SettingsReader provides methods to get the property keys and the * corresponding values. The keys could be defined as combinations of single * keys. Therefore it is possible to combine differen classes of keys. An * example could be: - * + * *

- *     
+ *
  *                        #SettingNotFoundException
  *                        error.code.100=Interner Fehler
  *                        error.code.101=Die Konfigurationsdatei konnte nicht geladen werden
- *                        
+ *
  *                        #PDFDocumentException
  *                        error.code.200=Das Dokument konnte nicht geladen werden
- *                        
+ *
  *                        #SignatureException
  *                        error.code.300=Die Signatur ist ungültig
- *                        
+ *
  *                        #NormalizeException
  *                        error.code.400=Die angegebene Version ist nicht bekannt
- *                       
+ *
  *                        normalizer.version=V01
 
- *      
+ *
  * 
- * + * * The internal representation of the example above is: - * + * *
- *     
+ *
 
  *                        .error|
  *                              |.code|
@@ -100,10 +101,10 @@ import at.knowcenter.wag.egov.egiz.tools.FileHelper;
  *                              |     |.101=Die Konfigurationsdatei konnte nicht geladen werden
  *                              |     |.300=Die Signatur ist ungueltig
  *                       .normalizer|
- *                                  |.version=V01      
- *      
+ *                                  |.version=V01
+ *
  * 
- * + * * @author wlackner */ public class SettingsReader implements Serializable @@ -145,17 +146,22 @@ public class SettingsReader implements Serializable * The file path postfix where certificates are stored */ private static final String CERT = "certificates"; - + /** * pdf-as internal properties resource path */ private static final String PDF_AS_PROP_RESOURCE = "/config/pdf-as.properties"; - + + /** + * The default configuration properties. These settings can be overridden by any local configuration. + */ + private static final String DEFAULT_CFG_PROPERTIES_RESOURCE = "/config/defaultconfig.properties"; + /** * internal help file */ private static final String HELP_TEXT_PROP_RESOURCE = "/config/help_text.properties"; - + public static final boolean REGISTER_IAIK_PROVIDERS_ON_DEFAULT = true; // /** @@ -165,14 +171,14 @@ public class SettingsReader implements Serializable /** * The path of the resources repository. - * + * *

* This usually contains sub directories for the templates, the configuration * files, etc. *

*/ public static String RESOURCES_PATH = null; - + /** * The path for temporary files. */ @@ -237,7 +243,7 @@ public class SettingsReader implements Serializable /** * The reference to the settings file. */ - private static String settingsFile_ = null; + private static File settingsFile_ = null; /** * The reference to the property representation of the settings file. @@ -258,7 +264,7 @@ public class SettingsReader implements Serializable * The only cause to do this is that the definition file should only be read * once while getting often this instance. The method throws an IOException if * the settings file could not be read. - * + * * @param settingsFile * load this file, if the settingsFile == null the * default settings ({@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}) @@ -271,39 +277,45 @@ public class SettingsReader implements Serializable try { String cfg_path = CONFIG_PATH; - properties_ = new Properties(); if (settingsFile == null) { settingsFile = cfg_path + CONFIG_FILE_DEFAULT_NAME; } - settingsFile_ = settingsFile; - if (logger_.isInfoEnabled()) - { - File file = new File(settingsFile_); - logger_.debug("load Settings:" + file.getAbsolutePath()); - // Properties sys_prop = System.getProperties(); - // Enumeration prop_keys = sys_prop.propertyNames(); - // while (prop_keys.hasMoreElements()) { - // String key = (String) prop_keys.nextElement(); - // String value = sys_prop.getProperty(key); - // logger_.info(key + "=" + value); - // } - } - FileInputStream sfs = new FileInputStream(settingsFile_); - properties_.load(sfs); - + settingsFile_ = new File(settingsFile); + logger_.debug("load Settings:" + settingsFile_.getAbsolutePath()); + + // DTI + // (1) first load default properties which may be overloaded by local configurations + Properties defaultConfiguration = new Properties(); + InputStream in = null; + try { + defaultConfiguration.load(in = getClass().getResourceAsStream(DEFAULT_CFG_PROPERTIES_RESOURCE)); + } catch (Exception e) { + throw new SettingsException(ErrorCode.UNABLE_TO_LOAD_DEFAULT_CONFIG, + "Unable to load default configuration.", e); + } finally { + IOUtils.closeQuietly(in); + } + + // (2) then load main configuration (considers include instructions) + NestedProperties includeAwareProperties = new NestedProperties(defaultConfiguration); + try { + includeAwareProperties.load(settingsFile_); + properties_ = includeAwareProperties; + } catch (CircularIncludeException e) { + throw new SettingsException(ErrorCode.CIRCULAR_INCLUDE_INSTRUCTION_DETECTED, e); + } + + // (3) then forcedly overwrite some system settings // dferbas override with system props properties_.load(SettingsReader.class.getResourceAsStream(PDF_AS_PROP_RESOURCE)); + // (4) and finally add help texts. Properties help_prop = new Properties(); -// FileInputStream hfs = new FileInputStream(cfg_path + HELP_TEXT_FILE_DEFAULT_NAME); -// help_prop.load(hfs); help_prop.load(SettingsReader.class.getResourceAsStream(HELP_TEXT_PROP_RESOURCE)); - // load properties from current package! - // properties_.load(getClass().getResourceAsStream(settingsFile_)); + // (5) Build PropertyTree configuration. Enumeration prop_keys = properties_.propertyNames(); - while (prop_keys.hasMoreElements()) { String key = (String) prop_keys.nextElement(); @@ -319,10 +331,12 @@ public class SettingsReader implements Serializable pTree_.setKeyValue(key, value); } } + catch (IOException e) { throw new SettingsException("Couldn't load settings from file " + settingsFile, e); } + } /** @@ -331,7 +345,7 @@ public class SettingsReader implements Serializable * holding the definitions of the default settings file. Default file: * {@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}: "settings.txt". * Note: IAIK JCE and IAIK ECC security providers are automatically registered. - * + * * @return an instance of the SettingsReader * @throws SettingsException * if the default settings file could not be read @@ -340,15 +354,15 @@ public class SettingsReader implements Serializable { return getInstance(null); } - + /** * Reloads the Settings file. - * + * *

* Subsequent calls to getInstance will return the new settings. * Note: IAIK JCE and IAIK ECC security providers are automatically registered. *

- * + * * @throws SettingsException f.e. */ public synchronized static void createInstance() throws SettingsException @@ -356,16 +370,16 @@ public class SettingsReader implements Serializable instance_ = null; getInstance(); } - + /** * Reloads the Settings file. - * + * *

* Subsequent calls to getInstance will return the new settings. *

* @param registerProvider true: automatically registers IAIK JCE and ECC Provider; * false: providers will NOT be automatically registered, providers - * needed have to be registered by the API user + * needed have to be registered by the API user * @throws SettingsException f.e. */ public synchronized static void createInstance(boolean registerProvider) throws SettingsException @@ -381,18 +395,18 @@ public class SettingsReader implements Serializable * settingsFile == null the default settings file will be load. * Default file: {@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}: * "settings.txt" - * + * * If an instance of this class exist, the input param is ignored! The * SettingsReader is singleton and therefore the first * {@link SettingsReader#getInstance()}defines the settings file that has to * be loaded. This means changes between a application lifecyle can not be * done! - * + * * @param settingsFile * the settings file that should be load. * @param registerProvider true: automatically registers IAIK JCE and ECC Provider; * false: providers will NOT be automatically registered, providers - * needed have to be registered by the API user + * needed have to be registered by the API user * @return an instance of the SettingsReader * @throws SettingsException * if the settings file could not be read @@ -402,7 +416,7 @@ public class SettingsReader implements Serializable if (instance_ == null) { int length = Utils.max(new int[] { RESOURCES_PATH.length(), TMP_PATH.length(), CONFIG_PATH.length(), CERT_PATH.length() }); - + logger_.info(StringUtils.repeat("*", length + 25)); logger_.info(" resources path = \"" + RESOURCES_PATH + "\""); logger_.info(" configuration path = \"" + CONFIG_PATH + "\""); @@ -410,7 +424,7 @@ public class SettingsReader implements Serializable logger_.info(" temporary path = \"" + TMP_PATH + "\""); logger_.debug(" file.encoding = \"" + System.getProperty("file.encoding") + "\""); logger_.info(StringUtils.repeat("*", length + 25)); - + if (registerProvider) { IAIK.addAsProvider(); ECCProvider.addAsProvider(); @@ -429,12 +443,12 @@ public class SettingsReader implements Serializable // Does not conform with PKIX, but is used by belgium citizen card // log.info("Registering RDN \"SERIALNUMBER\" as " + ObjectID.serialNumber + "."); RFC2253NameParser.register("SERIALNUMBER", ObjectID.serialNumber); - + instance_ = new SettingsReader(settingsFile); } return instance_; } - + /** * This method returns an synchronized instance of this class. The settings * file is read only once using this class. This method returns the instance @@ -443,13 +457,13 @@ public class SettingsReader implements Serializable * Default file: {@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}: * "settings.txt". * Note: IAIK JCE and IAIK ECC security providers are automatically registered. - * + * * If an instance of this class exist, the input param is ignored! The * SettingsReader is singleton and therefore the first * {@link SettingsReader#getInstance()}defines the settings file that has to * be loaded. This means changes between a application lifecyle can not be * done! - * + * * @param settingsFile * the settings file that should be load. * @return an instance of the SettingsReader @@ -464,7 +478,7 @@ public class SettingsReader implements Serializable /** * This method returns a property value to the corresponding key. If the key * is not found in the property file a SettingNotFoundException is thrown. - * + * * @param key * get the value for that key in the property file * @return the value of the property key. @@ -490,17 +504,10 @@ public class SettingsReader implements Serializable return result; } - - // TODO in the next change request, the Setting system will be refactored - // this is just for testing purposes. - public void setSetting(String key, String value) - { - properties_.setProperty(key, value); - } /** * Relocates the relative file. - * + * * @param file * The relative file. * @return Returns the usable file. @@ -519,7 +526,7 @@ public class SettingsReader implements Serializable /** * This method returns a property value to the corresponding key. If the key * is not found in the property file the input param defaultValue is returned. - * + * * @param key * get the value for that key in the property file * @param defaultValue @@ -545,7 +552,7 @@ public class SettingsReader implements Serializable * This method returns a property value to the corresponding key. If the key * is not found in the property file the input param defaultKey is searched. * If the default key is not found the input param defaultValue is returned. - * + * * @param primaryKey * get the value for that key in the property file * @param defaultKey @@ -580,7 +587,7 @@ public class SettingsReader implements Serializable * keyPrefix. The method search all keys in the property file that has the * keyPrefix as leading substring. The Object[] collects all * sub keys without the keyPrefix. - * + * * @param keyPrefix * to search for sub keys * @return alls keys starting with the keyPrefix @@ -604,7 +611,7 @@ public class SettingsReader implements Serializable * If a property value is number (interger) this method extracts the value and * convert it to an int. If the key ist not found or the conversion fails, the * defaultValue is returned. - * + * * @param key * get the value for that key in the property file * @param defaultValue @@ -641,7 +648,7 @@ public class SettingsReader implements Serializable * This method returns an array of sub keys (children references) of the key. * The method is a wrapper calling the method * {@link PropertyTree#getKeys(String key)}. - * + * * @param key * get all sub keys for that key in the property file * @return an list of sub keys (type String) @@ -659,7 +666,7 @@ public class SettingsReader implements Serializable * not overload keys. If a key is defined more than one times the last * definition is stored it the property list. The method is a wrapper calling * the method {@link PropertyTree#getFirstValue(String key)}. - * + * * @param key * get the value for that key in the property file * @return the value of the property key @@ -678,7 +685,7 @@ public class SettingsReader implements Serializable /** * This method returns the PropertyTree representation of the configuration * file. - * + * * @return Returns the pTree. * @see PropertyTree */ @@ -686,20 +693,20 @@ public class SettingsReader implements Serializable { return pTree_; } - + /** * Reads internal resource as string. * @param relativePath * @return null in case of error */ public String readInternalResourceAsString(String relativePath) { -// return readAsString(getInternalResource(relativePath)); - return FileHelper.readFromInputStream(getInternalResource(relativePath)); +// return readAsString(getInternalResource(relativePath)); + return FileHelper.readFromInputStream(getInternalResource(relativePath)); } - + /** * Get resource as stream, relative to internal resource path {@value #INTERNAL_RESOURCE_PATH} - * + * * @param relativePath * @return */ @@ -717,9 +724,9 @@ public class SettingsReader implements Serializable } return stream; } - + /** - * Read resource as utf8 string. + * Read resource as utf8 string. * @param is * @return null in case of error */ @@ -730,7 +737,7 @@ public class SettingsReader implements Serializable return IOUtils.toString(is, "utf-8"); } catch (IOException e) { logger_.info("error reading stream to string ", e); - } + } return null; } */ @@ -758,11 +765,11 @@ public class SettingsReader implements Serializable /** * Returns the directory where temporary files should be stored. - * + * *

* If the directory doesn't exist, it is created. *

- * + * * @return Returns the directory where temporary files should be stored. * @see TempDirHelper#getTemporaryDirectory() */ @@ -773,7 +780,7 @@ public class SettingsReader implements Serializable /** * Deletes all files in the temporary directory, if it exists. - * + * *

* This should be used to clear temporary files when the application shuts * down. @@ -784,19 +791,19 @@ public class SettingsReader implements Serializable { TempDirHelper.clearTemporaryDirectory(); } - + public static synchronized void initialize(String configdir, String tmpdir) { - + String defaultConfigDeployedTo = null; // resolve work directory // configuration explicitely given ? if (configdir == null) { - + // configuration via system property ? logger_.debug("No configuration directory given. Looking for system property \"" + Constants.CONFIG_DIR_SYSTEM_PROPERTY + "\"."); configdir = System.getProperty(Constants.CONFIG_DIR_SYSTEM_PROPERTY); if (configdir == 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"); @@ -808,7 +815,7 @@ public class SettingsReader implements Serializable defaultConfigDeployedTo = ConfigUtils.deployDefaultConfiguration(configdir, false); } catch (ConfigUtilsException e) { throw new RuntimeException(e); - } + } if (defaultConfigDeployedTo != null) { logger_.info("** Default configuration successfully deployed to \"" + defaultConfigDeployedTo + "\" **"); } else { @@ -833,7 +840,7 @@ public class SettingsReader implements Serializable { throw new IllegalArgumentException("The config directory \"" + configdir + "\" 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."); @@ -851,14 +858,14 @@ public class SettingsReader implements Serializable } catch (IOException e) { tmpdir = ConfigUtils.assertFileSeparator(tmpdirFile.getPath()); } - + RESOURCES_PATH = configdir; TMP_PATH = tmpdir; CONFIG_PATH = RESOURCES_PATH + CFG + FILE_SEP; CERT_PATH = RESOURCES_PATH + CERT + FILE_SEP; // ConfigUtils.printConfigInfo(logger_); - + if (defaultConfigDeployedTo != null) { logger_.debug("** Default configuration successfully deployed to \"" + defaultConfigDeployedTo + "\" **"); } @@ -870,10 +877,10 @@ public class SettingsReader implements Serializable { initialize(base_dir, null); } - + /** * Initializes the paths of the SettingsReader for web application usage. - * + * * @param base_dir * The base directory of this web application. E.g. * TOMCAT_HOME/webapps/pdf-as @@ -890,14 +897,14 @@ public class SettingsReader implements Serializable { initialize(null); } - + static { - + String versionString = "* PDF-AS library version " + PdfAS.PDFAS_VERSION + " *"; String paddingString = StringUtils.repeat("*", versionString.length()); logger_.info("PDF-AS info\n" + paddingString + "\n" + versionString + "\n" + paddingString); } - + public Properties getProperties() { return this.properties_; } diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java index 1b66f53..0468160 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java @@ -73,7 +73,7 @@ import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; /** * The main program entry point of the commandline tool. - * + * * @author wprinz */ public abstract class Main @@ -156,18 +156,18 @@ public abstract class Main /** * Main program entry point. - * + * * @param args * The commandline arguments. * @throws IOException - * + * * @deprecated use {@link at.gv.egiz.pdfas.commandline.Main} instead */ public static void main(String[] args) throws IOException { System.out.println("\nWarning: The entry point at.knowcenter.wag.egov.egiz.commandline.Main is deprecated. Use at.gv.egiz.pdfas.commandline.Main instead.\n"); at.gv.egiz.pdfas.commandline.Main.main(args); } - + /* public static void main(String[] args) throws IOException { @@ -413,7 +413,7 @@ public abstract class Main catch (PresentableException e) { printPresentableException(e); - + if (output != null) { logger_.debug("Deleting output file on error."); @@ -451,10 +451,10 @@ public abstract class Main // } PrintWriter messageOutput = new PrintWriter(System.out); - - + + if (mode.equals(VALUE_MODE_SIGN)) - { + { carryOutSign(input, connector, signature_mode, signature_type, pos_string, user_name, user_password, output, messageOutput); } else @@ -468,22 +468,12 @@ public abstract class Main PrintWriter messageOutput) throws PresentableException { messageOutput.println("Signing..."); - - // for performance measurement - long startTime = 0; - long fileSize = 0; - if (logger_.isInfoEnabled()) { - startTime = System.currentTimeMillis(); - } PdfDataSource pdfDataSource; try { File file = new File(input); pdfDataSource = new FileBasedPdfDataSourceImpl(file, (int)file.length()); - if (logger_.isDebugEnabled()) - fileSize = file.length(); - } catch (IOException e) { @@ -495,7 +485,7 @@ public abstract class Main try { outputFile = new File(output); - + dataSink = new FileBasedDataSink(outputFile); } catch (IOException e) @@ -523,39 +513,23 @@ public abstract class Main } } - // for performance measurement - if (logger_.isInfoEnabled()) { - long endTime = System.currentTimeMillis(); - String toReport = "SIGN;" + signature_mode + ";" + input + ";"+ fileSize + ";" + (endTime - startTime); - logger_.info(toReport); - } - messageOutput.println("Signing was successful."); } public static void carryOutVerify(String input, String connector, int verify_which, PrintWriter messageOutput) throws PresentableException { messageOutput.println("Verifying..."); - - // for performance measurement - long startTime = 0; - long fileSize = 0; - if (logger_.isInfoEnabled()) { - startTime = System.currentTimeMillis(); - } - + DataSource dataSource = null; try { File file = new File(input); - if (logger_.isDebugEnabled()) - fileSize = file.length(); String extension = extractExtension(input); if (extension != null && extension.equals("txt")) { try { - FileInputStream fis = new FileInputStream(file); + FileInputStream fis = new FileInputStream(file); byte[] input_bytes = new byte[(int) file.length()]; fis.read(input_bytes); fis.close(); @@ -582,24 +556,16 @@ public abstract class Main messageOutput.println("Verification results:"); formatVerifyResults(results, messageOutput); - - // for performance measurement - if (logger_.isInfoEnabled()) { - long endTime = System.currentTimeMillis(); - String toReport = "VERIFY;"+ input + ";"+ fileSize + ";" + (endTime - startTime) + ";" + debugVerifyResults(results); - logger_.info(toReport); - } - - + } /** * 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 @@ -664,14 +630,14 @@ public abstract class Main // } } // logger_.debug("Finally used sign algorithm = " + signatorId); - + String connectorId = CommandlineConnectorChooser.chooseCommandlineConnectorForSign(connector); PdfAS.signCommandline(pdfDataSource, dataSink, signatorId, connectorId, signature_type, null, pos, null, null); // PdfAS.sign(algorithm, pdfDataSource, dataSink, signature_type, connector, pos); } - + public static List processVerify(DataSourceHolder dataSource, String connector, int verify_which) throws PresentableException { VerificationFilterParameters parameters = SettingsHelper.readVerificationFilterParametersFromSettings(); @@ -698,7 +664,7 @@ public abstract class Main holders_to_verify = new ArrayList(); holders_to_verify.add(holder); } - + List results = PdfAS.verifySignatureHolders(holders_to_verify, connector, false, null); return results; @@ -749,7 +715,7 @@ public abstract class Main /** * Prints that the provided option was unrecognized. - * + * * @param option * The unrecognized option. * @throws PresentableException @@ -763,7 +729,7 @@ public abstract class Main /** * Prints that the provided value was unrecognized. - * + * * @param parameter * The parameter, which is missing a value. * @throws PresentableException @@ -777,7 +743,7 @@ public abstract class Main /** * Prints that the provided value was unrecognized. - * + * * @param value * The unrecognized value. * @throws PresentableException @@ -791,7 +757,7 @@ public abstract class Main /** * Prints that the provided additional commandline argument was unrecognized. - * + * * @param argument * The unrecognized argument. * @throws PresentableException @@ -805,7 +771,7 @@ public abstract class Main /** * Prints that a certain parameter was missing. - * + * * @param missing_term * A description of the missing parameter ("e.g. a mode"). * @param parameter @@ -820,7 +786,7 @@ public abstract class Main /** * Prints that something is missing. - * + * * @param missing_term * A descriptive message of the missing thing. * @throws PresentableException @@ -834,7 +800,7 @@ public abstract class Main /** * Prints out the ErrorCodeException in a descriptive form. - * + * * @param ece * The ErrorCodeException to be printed. */ @@ -868,7 +834,7 @@ public abstract class Main /** * Prints the usage text. - * + * * @param writer * The writer to print the text to. * @throws PresentableException @@ -920,7 +886,9 @@ public abstract class Main writer.print(" " + PARAMETER_SIGNATURE_TYPE + " <"); SignatureTypes sig_types = SignatureTypes.getInstance(); SettingsReader settings = SettingsReader.getInstance(); - Set types_array = sig_types.getSignatureTypes(); + // show only signature profiles that can be used for signature +// Set types_array = sig_types.getSignatureTypes(); + Set types_array = sig_types.getSignatureTypesForSignature(); Iterator it = types_array.iterator(); while (it.hasNext()) { @@ -973,7 +941,7 @@ public abstract class Main /** * Checks the value for correctness. - * + * * @param mode * The parameter's value. * @return Returns true, if the value is correct, false otherwise. @@ -985,7 +953,7 @@ public abstract class Main /** * Checks the value for correctness. - * + * * @param signature_mode * The parameter's value. * @return Returns true, if the value is correct, false otherwise. @@ -998,7 +966,7 @@ public abstract class Main /** * Checks the value for correctness. - * + * * @param connector * The parameter's value. * @return Returns true, if the value is correct, false otherwise. @@ -1012,7 +980,7 @@ public abstract class Main /** * Checks the value for correctness. - * + * * @param signature_type * The parameter's value. * @return Returns true, if the value is correct, false otherwise. @@ -1020,8 +988,8 @@ public abstract class Main protected static boolean checkSignatureType(String signature_type) throws SignatureTypesException { return SignatureTypes.getInstance().getSignatureTypes().contains(signature_type); - - // exthex: uuuaaaahhhhh WHY??? wprinz again?, dont do that. Use List.contains(o), please + + // exthex: uuuaaaahhhhh WHY??? wprinz again?, dont do that. Use List.contains(o), please // take a java course and read: http://www.amazon.de/Java-f%C3%BCr-Dummies-Barry-Burd/dp/382662999X // List types_array = sig_types.getSignatureTypes(); // Iterator it = types_array.iterator(); @@ -1038,7 +1006,7 @@ public abstract class Main /** * Translates the commandline argument to a PDF-AS-ID. - * + * * @param signature_mode * The signator mode commandline argument. * @return Returns the corresponding PDFASID. @@ -1066,7 +1034,7 @@ public abstract class Main /** * Formats the verification results. - * + * * @param results * The List of SignatureResponse verification results. * @param writer @@ -1088,12 +1056,12 @@ public abstract class Main } } } - + /** * 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 @@ -1106,16 +1074,16 @@ public abstract class Main while (it.hasNext()) { SignatureResponse result = (SignatureResponse) it.next(); - + toreturn += Integer.valueOf(result.getSignatureCheckCode()).intValue(); } return toreturn; } - + /** * Formats the SignatureResponse. - * + * * @param result * The SignatureResponse to be printed. * @param writer diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java index 46245d2..de94527 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java @@ -60,7 +60,7 @@ import com.lowagie.text.pdf.PdfPTable; /** * Signs the document binary. - * + * *

* In prepareSign, an Incremental Update is created that contains the Signature * block and the egiz dictionary. For formatting the layout, variable values are @@ -72,9 +72,9 @@ import com.lowagie.text.pdf.PdfPTable; * In finishSign, the variable fields (values, /Cert) are replaced with the * values according to the encoding. *

- * + * * @deprecated moved to new-framework - * + * * @author wprinz */ public class BinarySignator_1_0_0 implements Signator @@ -131,18 +131,6 @@ public class BinarySignator_1_0_0 implements Signator variable_field_definitions.add(sfd); } } - - //check if signature block is invisible, and if so and if also signature block is positioned - //on a new page, prevent pdf-as to do that, because why should make a new page just for an invisible block - //added by rpiazzi - if (signature_object.getSignatureTypeDefinition().getInvisibleFieldDefinitions().size()==SignatureTypes.REQUIRED_SIG_KEYS.length) { - if (pi.isMakeNewPage()) { - int pageNumber = pi.getPage(); - pi = new PositioningInstruction(false, pageNumber-1, 0, 0); - } - } - //end added - IncrementalUpdateInformation iui = IncrementalUpdateHelper.writeIncrementalUpdate(pdf, pdf_table, signature_type, pi, variable_field_definitions, all_field_definitions, null, null, null); String temp_string = iui.temp_ir_number + " " + iui.temp_ir_generation + " obj"; //$NON-NLS-1$//$NON-NLS-2$ @@ -187,7 +175,6 @@ public class BinarySignator_1_0_0 implements Signator } catch (UnsupportedEncodingException e) { - e.printStackTrace(); throw new PDFDocumentException(201, e); } } @@ -198,10 +185,10 @@ public class BinarySignator_1_0_0 implements Signator public SignResult finishSign(IncrementalUpdateInformation iui) throws PresentableException { restoreSignedPdf(iui); - + // PdfAS.prefixID(iui.signed_signature_object, PdfAS.BINARY_ID); fillReplacesWithValues(iui); - + BinarySignature.replaceCertificate(iui); BinarySignature.replacePlaceholders(iui); @@ -212,7 +199,7 @@ public class BinarySignator_1_0_0 implements Signator /** * Reads the signature values from the signed signature object and fills the * corresponding value in the Replaces array. - * + * * @param iui * The IncrementalUpdateInformation. */ @@ -222,7 +209,7 @@ public class BinarySignator_1_0_0 implements Signator while (it.hasNext()) { ReplaceInfo ri = (ReplaceInfo) it.next(); - + ri.value = iui.signed_signature_object.retrieveStringValue(ri.sfd.field_name); } } @@ -256,7 +243,7 @@ public class BinarySignator_1_0_0 implements Signator /** * Forms the SignatureData to be used for signing. - * + * * @param iui * The IncrementalUpdateInformation. * @return Returns the SignatureData to be used for signing. diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java index 9ffeefe..492c5f1 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java @@ -44,12 +44,12 @@ import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; /** * This signator is just for testing purposes. - * + * *

* It doesn't modify the original document, but simply returns the XML signature * response as the signed document. *

- * + * * @author wprinz */ public class DetachedSignator_1_0_0 implements Signator @@ -58,7 +58,7 @@ public class DetachedSignator_1_0_0 implements Signator * The Pdf-AS ID of this Signator. */ public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEST, SignatorFactory.VERSION_1_0_0); - + /** * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() */ @@ -90,12 +90,12 @@ public class DetachedSignator_1_0_0 implements Signator IncrementalUpdateInformation iui = new IncrementalUpdateInformation(); iui.original_document = pdf; iui.signature_type = signature_type; - iui.pos = pos; + iui.pos = pos; String document_text = PdfAS.extractNormalizedTextTextual(pdf); iui.nonTextObjectInfos = PdfAS.extractNonTextualObjects(pdf); // logger_.debug("signed_text = " + document_text); - + DataSource ds = new TextDataSourceImpl(document_text); iui.signature_data = new SignatureDataImpl(ds, MIME_TYPE, "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -117,7 +117,6 @@ public class DetachedSignator_1_0_0 implements Signator } catch (UnsupportedEncodingException e) { - e.printStackTrace(); throw new PDFDocumentException(300, e); } } diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedfTextualSignator_1_0_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedfTextualSignator_1_0_0.java index 1559246..73e6afb 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedfTextualSignator_1_0_0.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedfTextualSignator_1_0_0.java @@ -44,7 +44,7 @@ import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; /** * Signs a document textually. - * + * *

* In prepareSign, the document text is extracted and normalized. *

@@ -52,7 +52,7 @@ import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; * In finishSign, the signed SignatureObject is transformed into a Signature * block, which is then written as an Incremental Update. *

- * + * * @author wprinz */ public class DetachedfTextualSignator_1_0_0 implements Signator @@ -61,12 +61,12 @@ public class DetachedfTextualSignator_1_0_0 implements Signator * The Mime Type. */ public static final String MIME_TYPE = "text/xml"; //$NON-NLS-1$ - + /** * The Pdf-AS ID of this Signator. */ public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_DETACHED_TEXTUAL, SignatorFactory.VERSION_1_0_0); - + /** * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() */ @@ -88,7 +88,7 @@ public class DetachedfTextualSignator_1_0_0 implements Signator * The parameter has_SIG_ID is not used by this Signator because it doesn't * pre-format the signature block. *

- * + * * @see at.knowcenter.wag.egov.egiz.framework.Signator#prepareSign(byte[], * String, TablePos, boolean) */ @@ -98,12 +98,12 @@ public class DetachedfTextualSignator_1_0_0 implements Signator IncrementalUpdateInformation iui = new IncrementalUpdateInformation(); iui.original_document = pdf; iui.signature_type = signature_type; - iui.pos = pos; + iui.pos = pos; String document_text = PdfAS.extractNormalizedTextTextual(pdf, "cp1252"); iui.nonTextObjectInfos = PdfAS.extractNonTextualObjects(pdf); // logger_.debug("signed_text = " + document_text); - + DataSource ds = new TextDataSourceImpl(document_text); iui.signature_data = new SignatureDataImpl(ds, MIME_TYPE, "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -125,7 +125,6 @@ public class DetachedfTextualSignator_1_0_0 implements Signator } catch (UnsupportedEncodingException e) { - e.printStackTrace(); throw new PDFDocumentException(300, e); } } diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java index fd59d34..7b5a968 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java @@ -73,7 +73,9 @@ public class AbsoluteTextSignature public static List getSignatureTypesForTextAnalysis() throws SignatureTypesException { SignatureTypes sig_types = SignatureTypes.getInstance(); - List allSignatureTypes = sig_types.getSignatureTypeDefinitions(); + // use only those profiles that are allowed to be used for verification +// List allSignatureTypes = sig_types.getSignatureTypeDefinitions(); + List allSignatureTypes = sig_types.getSignatureTypeDefinitionsForVerification(); List textSignatureTypes = new ArrayList(allSignatureTypes.size()); Iterator it = allSignatureTypes.iterator(); diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java index ece9525..75a64f1 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java @@ -40,6 +40,7 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -89,25 +90,46 @@ import com.lowagie.text.pdf.PdfStamper; import com.lowagie.text.pdf.PdfStamperImp; import com.lowagie.text.pdf.PdfString; import com.lowagie.text.pdf.PdfTemplate; +import com.lowagie.text.pdf.PdfWriter; /** * Contains various extension functions to digitally sign documents. - * + * *

* These functions are used to replace parts of the original Egiz plain text * signature mechanism. *

- * + * * @author wprinz */ public abstract class BinarySignature { //23.11.2010 changed by exthex - added replacePlaceholder(PdfStamper stamper, int pageNr, String placeholderName) method - + protected static Log logger = LogFactory.getLog(BinarySignature.class); + + /** + * The resource path of the srgb profile to be embedded in case of PDF/A-1b. + */ + private static final String srgbProfileResource = "/at/gv/egiz/pdfas/itext/srgb.profile"; + + /** + * The color profile to be embedded in case of PDF/A-1b. + */ + private static final byte[] SRGB_PROFILE; + + static { + try { + logger.debug("Preloading srgb color profile '" + srgbProfileResource + "."); + SRGB_PROFILE = IOUtils.toByteArray(BinarySignature.class.getResourceAsStream(srgbProfileResource)); + } catch (IOException e) { + throw new RuntimeException("Unable to preload srgb color profile.", e); + } + } + /** * The tolerance area of the line break algorithm. - * + * * @see Placeholder#replacePlaceholderWithTolerance(byte[], List, byte[], int) */ public static final int LINE_BREAK_TOLERANCE = 10; @@ -116,11 +138,11 @@ public abstract class BinarySignature * The number of bytes left out for the certificate placeholder. */ public static final int CERTIFICATE_PLACEHOLDER_LENGTH = 10000; - + /** * The number of bytes left out for the timestamp placeholder. */ - public static final int TIMESTAMP_PLACEHOLDER_LENGTH = 5000; + public static final int TIMESTAMP_PLACEHOLDER_LENGTH = 5000; /** * The placeholder character used to fill out Strings in the layout process. @@ -162,11 +184,11 @@ public abstract class BinarySignature * The SIG_ID brev. */ public static final byte[] BREV_SID = { 's', 'i', 'd' }; - + /** * The SIG_ALG brev. */ - public static final byte[] BREV_ALG = { 'a', 'l', 'g' }; + public static final byte[] BREV_ALG = { 'a', 'l', 'g' }; /** * No explicit encoding. @@ -185,7 +207,7 @@ public abstract class BinarySignature /** * The PDFName of the Egiz Dictionary. - * + * *

* Used to locate and identify the Egiz Dictionary in the document. *

@@ -195,7 +217,7 @@ public abstract class BinarySignature /** * The PDFName of the Original Document Size (ODS) field in an Egiz * Dictionary. - * + * *

* The ODS must be a positive integral number. *

@@ -226,7 +248,7 @@ public abstract class BinarySignature * The PdfName of the certificate array. */ public static final PdfName EGIZ_CERTIFICATE_NAME = new PdfName("Cert"); - + /** * The PdfName of the Timestamp */ @@ -239,7 +261,7 @@ public abstract class BinarySignature /** * The PDFName of the Signature XObject field in an Egiz Dictionary. - * + * *

* This must be an indirect reference to the XObject containing the Signature * table. @@ -251,17 +273,17 @@ public abstract class BinarySignature * The number placeholder that is used to give numbers a fixed length. */ protected static final PdfNumber NUMBER_PLACEHOLDER = new PdfNumber(999999999); - + /** * Extracts the signature text only. - * + * *

* The signature text is the text of the Signature XObject. *

- * + * * @param egiz_dict * The Egiz Dictionary. - * + * * @return Returns the signature text. */ public static String extractSignatureTextOnly(PdfDictionary egiz_dict) throws IOException @@ -276,7 +298,7 @@ public abstract class BinarySignature /** * Retrieves the size of the original document from the Egiz Dictionary. - * + * * @param egiz_dict * The Egiz Dictionary. * @return Returns the size (in bytes) of the original document. @@ -292,7 +314,7 @@ public abstract class BinarySignature /** * Retrieves the previous Egiz dictionary from the given one, if a previous * dictionary exists. - * + * * @param egiz_dict * The Egiz Dictionary. * @return Returns the previous Egiz Dictionary, or null if there is none. @@ -306,7 +328,7 @@ public abstract class BinarySignature /** * Retrieves the Egiz Dictionary from the document if present. - * + * * @param reader * The reader to retrieve the dictionary from. * @return Returns the Egiz Dictionary, if present, or returns null, if no @@ -327,7 +349,7 @@ public abstract class BinarySignature /** * Retrieves the Egiz Dictionary's indirect reference from the reader. - * + * * @param reader * The reader. * @return Returns the indirect reference of the Egiz Dictionary, or null, if @@ -342,14 +364,14 @@ public abstract class BinarySignature /** * Retrieves the chain of Egiz Dictionaries from the reader. - * + * *

* The first element in the List will be the top most (oldest) Egiz * Dictionary. The last element in the List will be the bottom most (latest) * Egiz Dictionary. If the list is empty, no dictionary could be found at all, * which means that the document is not digitally signed. *

- * + * * @param reader * The reader. * @return Returns the List of PdfDictionaries from the document. @@ -374,7 +396,7 @@ public abstract class BinarySignature /** * Builds a digest of the given data. - * + * * @param data * The data to be digested. * @param length @@ -393,7 +415,6 @@ public abstract class BinarySignature } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); throw new PDFDocumentException(202, "Digest algorithm not supported - NoSuchAlgorithmException", e); } @@ -406,7 +427,7 @@ public abstract class BinarySignature /** * Retrieves the signable text from the given document. - * + * * @param data * The data. * @param ods @@ -423,7 +444,7 @@ public abstract class BinarySignature /** * Fills the holes in the byte ranges with the SIGN_PLACEHOLDER. - * + * * @param data * The given byte ranged data. * @param byte_ranges @@ -697,7 +718,7 @@ public abstract class BinarySignature // throw new PresentableException(e); // } // } - + protected static int getLineBreakTolerance(IncrementalUpdateInformation iui) throws PDFDocumentException { SettingsReader settings; @@ -717,7 +738,7 @@ public abstract class BinarySignature } return lineBreakTolerance; } - + protected static int getCertificatePlaceholderLength(IncrementalUpdateInformation iui) throws SettingNotFoundException { SettingsReader settings; @@ -737,7 +758,7 @@ public abstract class BinarySignature } return certLen; } - + protected static int getTimestampPlaceholderLength(IncrementalUpdateInformation iui) throws SettingNotFoundException { SettingsReader settings; @@ -761,7 +782,7 @@ public abstract class BinarySignature /** * Signs a document with the given signature table using the Incremental * Update method. - * + * *

* The table containing the signature text will be appended. As specified by * the parameters, the signature will be appended to the last page, or a plain @@ -777,7 +798,7 @@ public abstract class BinarySignature * information about the signature. Basically the size of the original * document and the reference of the signature table. *

- * + * * @param original_document * The original document. * @param pdf_table @@ -811,10 +832,7 @@ public abstract class BinarySignature // System.out.println("wprinz: STAMPING PDF"); // InputStream is = original_document.createInputStream(); - byte[] pdf_data = original_document.getAsByteArray(); - PdfReader reader = new PdfReader(pdf_data); - PDFASUtils.checkReaderPermissions(reader); - // is.close(); + PdfReader reader = PDFASUtils.createPdfReaderCheckingPermissions(original_document); OutputStream baos = written_pdf.createOutputStream("application/pdf"); // ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -823,7 +841,7 @@ public abstract class BinarySignature // incremental updated // The stamper allows this by setting append = true boolean adobeSigField = AdobeSignatureHelper.isAdobeSignatureFieldEnabled(so.getSignatureTypeDefinition().getType()); - PdfStamper stamper = null; + PdfStamper stamper = null; if (adobeSigField) { stamper = PdfStamper.createSignature(reader, baos, '\0', null, true); } else { @@ -843,13 +861,13 @@ public abstract class BinarySignature { throw new PDFDocumentException(224, "The provided page (=" + pi.getPage() + ") is out of range."); } - + if (SignaturePlaceholderContext.isSignaturePlaceholderDataSet() && SignaturePlaceholderContext.getSignaturePlaceholderData().getPlaceholderName() != null) { replacePlaceholder(stamper, pi.getPage(), SignaturePlaceholderContext.getSignaturePlaceholderData().getPlaceholderName()); } - + PdfContentByte content = stamper.getOverContent(pi.getPage()); // content = StampContent einer PageStamp. @@ -857,12 +875,12 @@ public abstract class BinarySignature // table_height = " + pdf_table.getTotalHeight()); PdfTemplate table_template = content.createTemplate(pdf_table.getTotalWidth(), pdf_table.getTotalHeight()); - table_template.setCompress(Boolean.FALSE); // do not compress sigblock because we rewrite it afterwards for bin sig + table_template.setCompress(Boolean.FALSE); // do not compress sigblock because we rewrite it afterwards for bin sig // exthex StructContentHelper structHelper = new StructContentHelper(stamper, content, pi.getPage()); structHelper.prepareStructData(table_template); - + pdf_table.writeSelectedRows(0, -1, 0, pdf_table.getTotalHeight(), table_template); // table_template.moveTo(0, 0); @@ -876,13 +894,13 @@ public abstract class BinarySignature // pdf_table.writeSelectedRows(0, -1, SIGNATURE_BORDER / 2, // table_position, content); - + structHelper.beginSigBlockContent(); - + content.addTemplate(table_template, pi.getX(), pi.getY() - pdf_table.getTotalHeight()); - - structHelper.endSigBlockContent(); - + + structHelper.endSigBlockContent(); + ActualTablePos atp = new ActualTablePos(); atp.page = pi.getPage(); @@ -891,13 +909,13 @@ public abstract class BinarySignature atp.width = pdf_table.getTotalWidth(); atp.height = pdf_table.getTotalHeight(); iui.actualTablePos = atp; - + structHelper.buildFigureStructData(so, table_template); structHelper.buildSigBlockStructData(); structHelper.finishMainStructData(); - + structHelper.buildVerifyLinkStructData(table_template, atp); - + // For debugging print a 100x100 grid // { // Rectangle psize = reader.getPageSizeWithRotation(pos.page); @@ -940,7 +958,22 @@ public abstract class BinarySignature // PdfObject value = resources.get(key); // System.out.println(" " + key + " = " + value); // } - + + // added by dti: fixing PDF/A-1b + if (PDFASUtils.isPdfAEnabled(profile)) { + logger.debug("Adding sRGB IEC61966-2.1 color profile (output intent) in order to satisfy PDF/A-1b requirements."); + PdfWriter writer = stamper.getWriter(); + writer.setOutputIntents("Custom", "sRGB", "", "sRGB IEC61966-2.1", SRGB_PROFILE); + PdfArray a = writer.getExtraCatalog().getAsArray(PdfName.OUTPUTINTENTS); + if (a != null) { + PdfDictionary d = a.getAsDict(0); + if (d != null) { + // overwrite PDF/X entry with PDF/A entry + d.put(PdfName.S, PdfName.GTS_PDFA1); + } + } + } + // add the EGIZ dict: if (variable_field_definitions != null) { @@ -964,22 +997,20 @@ public abstract class BinarySignature } catch (IOException e) { - e.printStackTrace(); throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, e); } catch (DocumentException e) { - e.printStackTrace(); throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, e); } } - + private static void replacePlaceholder(PdfStamper stamper, int pageNr, String placeholderName) throws BadElementException, MalformedURLException, IOException, BadPdfFormatException, PresentableException { Image img = Image.getInstance(SignaturePlaceholderData.class.getResource("empty.jpg")); PdfImage pImg = new PdfImage(img, "Imwurscht", null); PdfStamperImp stamperImp = (PdfStamperImp)stamper.getWriter(); PdfIndirectObject ind = stamperImp.addToBody(pImg); - + PdfDictionary resources = stamper.getReader().getPageN(pageNr).getAsDict(PdfName.RESOURCES); if (ind != null && resources != null) { @@ -999,11 +1030,11 @@ public abstract class BinarySignature throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, new NullPointerException("Resource dictionary not found in document structure!")); } } - + /** * Creates the EGIZ Dictionary and adds it to the document. - * + * * @param stamper * The PdfStamper. * @param table_template @@ -1092,11 +1123,11 @@ public abstract class BinarySignature // /encodings replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the // /Cert - + if (iui.timeStamper != null) { encodings_array.add(new PdfName(new String(ENCODING_NIL))); // the /Timestamp replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the /timestamp - + } // hidden replaces @@ -1153,9 +1184,9 @@ public abstract class BinarySignature } PdfString cert_placeholder = new PdfString(cert_bytes); cert_array.add(cert_placeholder); - egiz_dict.put(EGIZ_CERTIFICATE_NAME, cert_array); - - // Timestamp + egiz_dict.put(EGIZ_CERTIFICATE_NAME, cert_array); + + // Timestamp if (iui.timeStamper != null) { // only if handler is available PdfArray timestamp_array = new PdfArray(); @@ -1167,10 +1198,10 @@ public abstract class BinarySignature } PdfString timestamp_placeholder = new PdfString(timestamp_bytes); timestamp_array.add(timestamp_placeholder); - egiz_dict.put(EGIZ_TIMESTAMP_NAME, timestamp_array); + egiz_dict.put(EGIZ_TIMESTAMP_NAME, timestamp_array); } - + // /Data array with hidden information if (has_hidden_variable_fields || invisibleKZString != null) { @@ -1221,7 +1252,7 @@ public abstract class BinarySignature /** * Converts a field name (type) to the corresponding BREV. - * + * * @param type * The field name (type). * @return Returns the corresponding BREV, or BREV_NIL if the type is not @@ -1261,12 +1292,12 @@ public abstract class BinarySignature /** * Updates the information in the egiz dictionary to reflect the real offsets * of the byte ranges. - * + * *

* This replaces the "dummy numbers" in the egiz dictionary with the correct * values. *

- * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException @@ -1309,7 +1340,7 @@ public abstract class BinarySignature byte[] cert_bytes = cert_str.getBytes("US-ASCII"); int cert_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, cert_bytes); int cert_start = cert_index + cert_bytes.length; - + //Timestamp int timestamp_index = 0; int timestamp_start = 0; @@ -1325,14 +1356,14 @@ public abstract class BinarySignature int cur_pos = array_start; int cur_br_start = 0; - + // write the /encodings byte range { int num_replaces = calcNumReps(iui.replaces); - int num_holes = num_replaces + 1 + 1; + int num_holes = num_replaces + 1 + 1; // +1 = the /encodings hole - // +1 = the /Cert + // +1 = the /Cert // +1 = the /Timestamp if (iui.timeStamper != null) { num_holes += 1; @@ -1376,7 +1407,7 @@ public abstract class BinarySignature iui.cert_start = cert_start; } - + // write the /Timestamp byte range if (iui.timeStamper != null) { StringInfo byte_range = new StringInfo(); @@ -1394,7 +1425,7 @@ public abstract class BinarySignature cur_br_start = timestamp_start + iui.timestamp_length; iui.timestamp_start = timestamp_start; - } + } // determine the /Data byte ranges if any List ifd = iui.invisible_field_definitions; @@ -1411,7 +1442,7 @@ public abstract class BinarySignature { StringInfo si = (StringInfo) iui.kz_list.get(0); si.string_start = hole_start; - + hole_start += si.string_length + 2; } @@ -1468,7 +1499,7 @@ public abstract class BinarySignature cur_pos += num_digits; cur_pos += 1; - + // update the Kennzeichnung byte ranges cur_pos = kz_start; for (int i = 0; i < iui.kz_list.size(); i++) @@ -1494,7 +1525,7 @@ public abstract class BinarySignature /** * Replaces the certificate placeholder with the certificate from the signed * Signature Object. - * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException @@ -1550,7 +1581,7 @@ public abstract class BinarySignature /** * Replaces the timestam placeholder with the timestamp from the signed * Signature Object. - * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException @@ -1558,27 +1589,27 @@ public abstract class BinarySignature public static void replaceTimestamp(IncrementalUpdateInformation iui) throws PDFDocumentException { String timestamp = iui.signed_signature_object.getSigTimeStamp(); - if (timestamp != null) { + if (timestamp != null) { byte[] escaped = Placeholder.escapePDFString(timestamp.getBytes()); if (escaped.length > iui.timestamp_length) { throw new PlaceholderException("timestamp", escaped.length - iui.timestamp_length); } - System.arraycopy(escaped, 0, iui.signed_pdf, iui.timestamp_start, escaped.length); + System.arraycopy(escaped, 0, iui.signed_pdf, iui.timestamp_start, escaped.length); } } - + /** * Replaces the placeholders with values from the signed SignatureObject. - * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException */ public static void replacePlaceholders(IncrementalUpdateInformation iui) throws PDFDocumentException { - final int lineBreakTolerance = getLineBreakTolerance(iui); - + final int lineBreakTolerance = getLineBreakTolerance(iui); + final byte[] signed_pdf = iui.signed_pdf; // int num_replaces = calcNumReps(iui.replaces); @@ -1661,7 +1692,7 @@ public abstract class BinarySignature * carried out. Accordingly to this number, entries in the dictionary are * created. *

- * + * * @param replaces * The ReplaceInfo list. * @return Returns the number of string replaces. @@ -1681,12 +1712,12 @@ public abstract class BinarySignature /** * Determines the List of ReplaceInfo objects of replaces in the content * stream regarding the given field definitions. - * + * *

* This method collects all variable String fields in a content stream and * orders them according to their start offset. *

- * + * * @param pdf * The PDF. * @param begin @@ -1760,7 +1791,7 @@ public abstract class BinarySignature /** * Determines the Kennzeichnug in the content stream. - * + * * @param pdf * The PDF. * @param begin @@ -1819,7 +1850,7 @@ public abstract class BinarySignature /** * Finds the index of the StringInfo within the StringInfo list that has the * given content (caption). - * + * * @param strings * The list of StringInfos. * @param caption @@ -1886,7 +1917,7 @@ public abstract class BinarySignature /** * Tells, if the given StringInfo contains only placeholder characters. - * + * * @param si * The StringInfo. * @param placeholder @@ -1935,7 +1966,7 @@ public abstract class BinarySignature /** * Finds the first string after and at the given index not being a placeholder * string. - * + * * @param strings * The list of StringInfos. * @param start @@ -1958,7 +1989,7 @@ public abstract class BinarySignature /** * Restores the given String to its placeholder. - * + * * @param pdf * The PDF. * @param si @@ -1978,7 +2009,7 @@ public abstract class BinarySignature /** * Reconstructs the replaces from the PDF and forms suitable value strings. - * + * * @param pdf * The PDF. * @param brevs @@ -2044,7 +2075,7 @@ public abstract class BinarySignature /** * Reads an unsigned integer number. - * + * * @param pdf * The PDF. * @param start_index @@ -2073,7 +2104,7 @@ public abstract class BinarySignature /** * Replaces a number by the new value. - * + * * @param pdf * The PDF. * @param start_index diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java index 7de89d2..1a89b7b 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java @@ -25,15 +25,19 @@ */ package at.knowcenter.wag.egov.egiz.pdf; +import java.awt.Rectangle; +import java.awt.geom.GeneralPath; import java.io.IOException; import java.util.List; import java.util.Map; +import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; import org.pdfbox.cos.COSName; import org.pdfbox.cos.COSStream; import org.pdfbox.pdmodel.PDPage; import org.pdfbox.pdmodel.PDResources; +import org.pdfbox.pdmodel.common.PDRectangle; import org.pdfbox.pdmodel.common.PDStream; import org.pdfbox.pdmodel.graphics.xobject.PDXObject; import org.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; @@ -44,6 +48,21 @@ import org.pdfbox.util.TextPosition; import org.pdfbox.util.operator.OperatorProcessor; import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.ClosePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.CurveTo; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.CurveToReplicateFinalPoint; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.CurveToReplicateInitialPoint; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.LineTo; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.MoveTo; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.CloseAndStrokePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.CloseFillEvenOddAndStrokePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.CloseFillNonZeroAndStrokePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.EndPath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.FillEvenOddAndStrokePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.FillNonZeroAndStrokePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.FillPathEvenOddRule; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.FillPathNonZeroWindingNumberRule; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.StrokePath; /** * PDFPage is an inner class that is used to calculate the page length of a PDF @@ -52,7 +71,7 @@ import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; * This method is called when processing the FileStream. By calling the method * {@link org.pdfbox.util.PDFStreamEngine#processStream(org.pdfbox.pdmodel.PDPage, org.pdfbox.pdmodel.PDResources, org.pdfbox.cos.COSStream)} * the implemented method showCharacter is called. - * + * * @author wlackner * @see PDFTextStripper */ @@ -67,41 +86,167 @@ public class PDFPage extends PDFTextStripper * The maximum (lowest) y position of a character. */ protected float max_character_ypos = Float.NEGATIVE_INFINITY; - + /** * The maximum (lowest y position of an image. */ protected float max_image_ypos = Float.NEGATIVE_INFINITY; - + /** * The effective page height. */ protected float effectivePageHeight; - + + /** + * The path currently being constructed. + */ + private GeneralPath currentPath = new GeneralPath(); + + /** + * The lowest position of a drawn path (originating from top). + */ + private float maxPathRelatedYPositionFromTop = Float.NEGATIVE_INFINITY; + /** * Constructor. - * + * * @param effectivePageHeight The height of the page to be evaluated. PDF elements outside this height will not be considered. - * + * * @throws IOException */ public PDFPage(float effectivePageHeight) throws IOException { super(); - + this.effectivePageHeight = effectivePageHeight; - + OperatorProcessor newInvoke = new MyInvoke(); newInvoke.setContext(this); operators.put("Do", newInvoke); + + registerCustomPathOperators(); } + /** + * Registers operators responsible for path construction and painting in order to fix auto positioning on pages with + * path elements. + * + * @author Datentechnik Innovation GmbH + */ + @SuppressWarnings("unchecked") + private void registerCustomPathOperators() { + + // *** path construction + + operators.put("m", new MoveTo(this)); + operators.put("l", new LineTo(this)); + operators.put("c", new CurveTo(this)); + operators.put("y", new CurveToReplicateFinalPoint(this)); + operators.put("v", new CurveToReplicateInitialPoint(this)); + operators.put("h", new ClosePath(this)); + + // *** path painting + + // "S": stroke path + operators.put("S", new StrokePath(this)); + operators.put("s", new CloseAndStrokePath(this)); + operators.put("f", new FillPathNonZeroWindingNumberRule(this)); + operators.put("F", new FillPathNonZeroWindingNumberRule(this)); + operators.put("f*", new FillPathEvenOddRule(this)); + operators.put("b", new CloseFillNonZeroAndStrokePath(this)); + operators.put("B", new FillNonZeroAndStrokePath(this)); + operators.put("b*", new CloseFillEvenOddAndStrokePath(this)); + operators.put("B*", new FillEvenOddAndStrokePath(this)); + operators.put("n", new EndPath(this)); + + // Note: The graphic context (org.pdfbox.pdmodel.graphics.PDGraphicsState) of the underlying pdfbox library does + // not yet support clipping. This prevents feasible usage of clipping operators (W, W*). +// operators.put("W", new ...(this)); +// operators.put("W*", new ...(this)); + + } + + /** + * Returns the path currently being constructed. + * + * @return The path currently being constructed. + */ + public GeneralPath getCurrentPath() { + return currentPath; + } + + /** + * Sets the current path. + * @param currentPath The new current path. + */ + public void setCurrentPath(GeneralPath currentPath) { + this.currentPath = currentPath; + } + + /** + * Registers a rectangle that bounds the path currently being drawn. + * + * @param bounds + * A rectangle depicting the bounds (coordinates originating from bottom left). + * @author Datentechnik Innovation GmbH + */ + public void registerPathBounds(Rectangle bounds) { + if (!bounds.isEmpty()) { + logger_.trace("Registering path bounds: " + bounds); + + // vertical start of rectangle (counting from top of page) + float upperBoundYPositionFromTop; + + // vertical end of rectangle (counting from top of page) + // this depicts the current end of path-related page content + float lowerBoundYPositionFromTop; + + PDRectangle boundaryBox = page.findMediaBox(); + float pageHeight; + + switch (page.findRotation()) { + case 90: // CW + pageHeight = boundaryBox.getWidth(); + upperBoundYPositionFromTop = (float) bounds.getMinX(); + lowerBoundYPositionFromTop = (float) bounds.getMaxX(); + break; + case 180: + pageHeight = boundaryBox.getHeight(); + upperBoundYPositionFromTop = (float) bounds.getMinY(); + lowerBoundYPositionFromTop = (float) bounds.getMaxY(); + break; + case 270: // CCW + pageHeight = boundaryBox.getWidth(); + upperBoundYPositionFromTop = pageHeight - (float) bounds.getMaxX(); + lowerBoundYPositionFromTop = pageHeight - (float) bounds.getMinX(); + break; + default: + pageHeight = boundaryBox.getHeight(); + upperBoundYPositionFromTop = pageHeight - (float) bounds.getMaxY(); + lowerBoundYPositionFromTop = pageHeight - (float) bounds.getMinY(); + break; + } + + // new maximum ? + if (lowerBoundYPositionFromTop > maxPathRelatedYPositionFromTop) { + // Is the rectangle (at least partly) located above the footer line? + // (effective page height := page height - footer line) + if (upperBoundYPositionFromTop <= effectivePageHeight) { + // yes: update current end of path-related page content + maxPathRelatedYPositionFromTop = lowerBoundYPositionFromTop; + logger_.trace("New max path related y position (from top): " + maxPathRelatedYPositionFromTop); + } else { + // no: rectangle is fully located below the footer line -> ignore + logger_.trace("Ignoring path bound below the footer line."); + } + } + } + } protected void processOperator(PDFOperator operator, List arguments) throws IOException { - //logger_.debug("operator = " + operator); - - super.processOperator(operator, arguments); +// logger_.debug("operator = " + operator); + super.processOperator(operator, arguments); } // exthex @@ -111,7 +256,7 @@ public class PDFPage extends PDFTextStripper * is used to calculate the latest position of a text in the page. Sorry for * this missinterpretation of the method, but it is the only way to do this * (provided by PDFBox)!!! - * + * * @param text * the character to be displayed -> calculate there y position. */ @@ -119,7 +264,7 @@ public class PDFPage extends PDFTextStripper { float current_y = text.getY(); final String character = text.getCharacter(); - + int pageRotation = page.findRotation(); //logger_.debug("PageRotation = " + pageRotation); if (pageRotation == 0) @@ -146,7 +291,7 @@ public class PDFPage extends PDFTextStripper //logger_.debug("character is below footer_line. footer_line = " + this.footer_line + ", text.character=" + character + ", y=" + current_y); return; } - + // store ypos of the char if it is not empty if (!character.equals(" ") && current_y > this.max_character_ypos) { @@ -160,26 +305,18 @@ public class PDFPage extends PDFTextStripper // logger_.debug(new String(string)); // } - /** - * Returns the calculated page length. - * - * @return the max page length value - */ - public float getMaxPageLength() - { - float max_ypos = Float.NEGATIVE_INFINITY; - - if (this.max_character_ypos > this.max_image_ypos) - { - max_ypos = this.max_character_ypos; - } - else - { - max_ypos = this.max_image_ypos; - } - - return max_ypos; - } + /** + * Returns the calculated page length. + * + * @return the max page length value + */ + public float getMaxPageLength() { + if (logger_.isDebugEnabled()) { + logger_.debug("Determining page content length: text=" + max_character_ypos + ", image=" + max_image_ypos + + ", path=" + maxPathRelatedYPositionFromTop); + } + return NumberUtils.max(max_character_ypos, max_image_ypos, maxPathRelatedYPositionFromTop); + } public class MyInvoke extends OperatorProcessor { @@ -192,26 +329,26 @@ public class PDFPage extends PDFTextStripper Map xobjects = context.getXObjects(); PDXObject xobject = (PDXObject) xobjects.get(name.getName()); - + PDStream stream = xobject.getPDStream(); COSStream cos_stream = stream.getStream(); - + COSName subtype = (COSName) cos_stream.getDictionaryObject(COSName.SUBTYPE); if (subtype.equals(COSName.IMAGE)) { logger_.debug("XObject Image"); - + Matrix ctm = context.getGraphicsState().getCurrentTransformationMatrix(); logger_.debug("ctm = " + ctm); - + Pos [] coordinates = new Pos [] { new Pos(0, 0, 1), new Pos(1, 0, 1), new Pos(0, 1, 1), new Pos(1, 1, 1) }; - + Pos [] transformed_coordinates = transtormCoordinates(coordinates, ctm); - + /********************************************************** * pdf-as fix: * calculating min and max point of an image to look where @@ -219,10 +356,10 @@ public class PDFPage extends PDFTextStripper * fix solves problems with footer and images and * placement of the signature in an image only pdf document **********************************************************/ - + float actual_lowest_point = Float.NaN; float actual_starting_point = Float.NaN; - + int pageRotation = page.findRotation(); logger_.debug("PageRotation = " + pageRotation); if (pageRotation == 0) @@ -231,7 +368,7 @@ public class PDFPage extends PDFTextStripper logger_.debug("min_y = " + min_y); float page_height = page.findMediaBox().getHeight(); logger_.debug("page_height = " + page_height); - + actual_lowest_point = page_height - min_y; actual_starting_point = page_height - findMaxY(transformed_coordinates); } @@ -243,7 +380,7 @@ public class PDFPage extends PDFTextStripper logger_.debug("page_width = " + page_width); actual_lowest_point = max_x; - actual_starting_point = findMinX(transformed_coordinates); + actual_starting_point = findMinX(transformed_coordinates); } if (pageRotation == 180) { @@ -257,17 +394,17 @@ public class PDFPage extends PDFTextStripper { float min_x = findMinX(transformed_coordinates); logger_.debug("min_x = " + min_x); - + float page_width = page.findMediaBox().getWidth(); logger_.debug("page_width = " + page_width); - + actual_lowest_point = page_width - min_x; - actual_starting_point = page_width - findMaxX(transformed_coordinates); + actual_starting_point = page_width - findMaxX(transformed_coordinates); } - + logger_.debug("actual_lowest_point = " + actual_lowest_point); - + if (actual_lowest_point > PDFPage.this.effectivePageHeight && actual_starting_point > PDFPage.this.effectivePageHeight) { logger_.debug("image is below footer_line"); @@ -278,7 +415,7 @@ public class PDFPage extends PDFTextStripper { PDFPage.this.max_image_ypos = actual_lowest_point; } - + return; } @@ -297,7 +434,7 @@ public class PDFPage extends PDFTextStripper } } } - + public static Pos [] transtormCoordinates (Pos [] coordinates, Matrix m) { Pos [] transformed = new Pos [coordinates.length]; @@ -307,18 +444,18 @@ public class PDFPage extends PDFTextStripper } return transformed; } - + public static Pos transtormCoordinate (Pos pos, Matrix m) { Pos transformed = new Pos(); transformed.x = pos.x * m.getValue(0, 0) + pos.y * m.getValue(1, 0) + pos.z * m.getValue(2, 0); transformed.y = pos.x * m.getValue(0, 1) + pos.y * m.getValue(1, 1) + pos.z * m.getValue(2, 1); transformed.z = pos.x * m.getValue(0, 2) + pos.y * m.getValue(1, 2) + pos.z * m.getValue(2, 2); - + logger_.debug(" transformed " + pos + " --> " + transformed); return transformed; } - + public static float findMinY (Pos [] coordinates) { float min = Float.POSITIVE_INFINITY; @@ -331,7 +468,7 @@ public class PDFPage extends PDFTextStripper } return min; } - + public static float findMaxY(Pos[] coordinates) { float max = 0; for (int i = 0; i < coordinates.length; i++) { @@ -341,7 +478,7 @@ public class PDFPage extends PDFTextStripper } return max; } - + public static float findMaxX (Pos [] coordinates) { float max = Float.NEGATIVE_INFINITY; diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java index a8a150e..3b9909f 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java @@ -35,6 +35,7 @@ import org.apache.log4j.Level; import org.apache.log4j.Logger; import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.utils.PDFASUtils; import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; @@ -59,7 +60,7 @@ import com.lowagie.text.pdf.SubsetLocal; * This class is the IText implementation of the PDFSignatureObject interface. * The class takes an abstract definition of a signature object and convert them * into a pdf table that is used to sign a pdf document. - * + * * @author wlackner * @see at.knowcenter.wag.egov.egiz.sig.SignatureObject * @see at.knowcenter.wag.egov.egiz.table.Table @@ -76,8 +77,6 @@ public class PDFSignatureObjectIText implements PDFSignatureObject // Also fixed a minor bug which prevented proper style inheritment (Bug Nr. #534). // 04.11.2010 changed by exthex - allow setting separate hAlign and vAlign for image cells analog to value cells. - private static final String SIG_PDFA1_B_VALID = "SIG_PDFA1B_VALID"; - /** * The default font definition */ @@ -116,7 +115,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * The empty constructor. It loads the ui definitions from signature tables * and init the align map. - * + * * @throws PDFDocumentException */ public PDFSignatureObjectIText() throws PDFDocumentException @@ -127,7 +126,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * load the class settings - * + * * @throws PDFDocumentException * @see SettingsReader */ @@ -174,7 +173,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * Set the abstract signature definition. - * + * * @param signatorObject * the abstract signator object * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#setSignatorObject(at.knowcenter.wag.egov.egiz.sig.SignatureObject) @@ -186,7 +185,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * This method maps the table cell definitions to the pdfCell element. - * + * * @param pdfCell * the pdf cell to be styled * @param cellStyle @@ -226,7 +225,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject align = ((Integer) alignMap_.get(cellStyle.getVAlign())).intValue(); if (align != -1) pdfCell.setVerticalAlignment(align); - + align = -1; if (type == Entry.TYPE_VALUE && cellStyle.getValueHAlign() != null) align = ((Integer) alignMap_.get(cellStyle.getValueHAlign())).intValue(); @@ -242,7 +241,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * This method maps the cell font definition to the iText Font Object - * + * * @param fontString * @return the corresponding iText Font Object * @see com.lowagie.text.Font @@ -277,12 +276,12 @@ public class PDFSignatureObjectIText implements PDFSignatureObject int face = ((Integer) font_face).intValue(); float height = Float.parseFloat(font_arr[1]); int weight = ((Integer) font_weight).intValue(); - + font = new Font(face, height, weight); fontMap_.put(fontString, font); return font; } - + /** * Creates a custom * @param fontString @@ -305,15 +304,15 @@ public class PDFSignatureObjectIText implements PDFSignatureObject } } logger_.debug("TrueType Font detected:"+fontName +" ("+fontSize+")"); - + try { Font font = (Font) fontMap_.get(fontString); - + if (font == null) { logger_.debug("Font \"" + fontString + "\" not in cache. Instantiating font."); String fontPath = SettingsReader.RESOURCES_PATH + "fonts" + File.separator + fontName; logger_.debug("Instantiating \"" + fontPath + "\"."); - + font = new Font(BaseFont.createFont(fontPath, BaseFont.WINANSI, true), fontSize); fontMap_.put(fontString, font); } @@ -334,7 +333,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject *
  • images
  • *
  • tables
  • * - * + * * @param abstractCell * the abstract cell definition * @return the new redererd pdf table cell @@ -345,27 +344,8 @@ public class PDFSignatureObjectIText implements PDFSignatureObject */ private PdfPCell renderCell(Entry abstractCell) throws PDFDocumentException { - boolean pdfaValid =false; - try - { - String profileid = sigObject_.getSignatureTypeDefinition().getType(); - String pdfa = SettingsReader.getInstance().getSetting("sig_obj." +profileid+".key."+SIG_PDFA1_B_VALID, "default."+SIG_PDFA1_B_VALID, "false"); - pdfaValid= "true".equalsIgnoreCase(pdfa); - -// exthex test - //SubsetLocal.set(!pdfaValid); - -// boolean forceSubset = true; // get this from config, default to false - //String - - //SubsetLocal.set(true); // exthex - - logger_.trace("Sign PDF/A compliant:"+pdfa); - } catch (SettingsException e1) - { - logger_.error(e1); - } - + boolean pdfaValid = PDFASUtils.isPdfAEnabled(sigObject_.getSignatureTypeDefinition().getType()); + PdfPCell pdf_cell = null; Style cell_style = abstractCell.getStyle(); boolean isValue = true; @@ -384,7 +364,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject { font_string = cell_style.getValueFont(); } - + logger_.trace("using cell font: "+font_string); Font cell_font; @@ -402,7 +382,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject } // exthex if (pdfaValid && abstractCell.getType() == Entry.TYPE_VALUE) { - SubsetLocal.addNonSubsetFont(cell_font.getBaseFont()); + SubsetLocal.addNonSubsetFont(cell_font.getBaseFont()); } Phrase text_phrase = new Phrase(text, cell_font); pdf_cell = new PdfPCell(text_phrase); @@ -429,9 +409,9 @@ public class PDFSignatureObjectIText implements PDFSignatureObject } Image image = Image.getInstance(img_file.getCanonicalPath()); logger_.debug("Using image file \"" + img_file.getCanonicalPath() + "\"."); - + image.scaleToFit(80.0f, 80.0f); - boolean fit = true; + boolean fit = true; Style.ImageScaleToFit istf = cell_style.getImageScaleToFit(); if (istf != null) { @@ -490,7 +470,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject * This method visualize an abstract table into a corresponding pdf table. The * new pdf table is redered and get the style information from the abstract * cell. - * + * * @param abstractTable * the abstract table definition * @return the new redererd pdf table cell @@ -558,7 +538,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * This method creates the pdf table object. It takes the abstract table * definition from the signature object and render the abstract table. - * + * * @param sigObject * the signature object, the base for the abstract table definition * @return R @@ -587,7 +567,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * Converts the current abstract signature object in a pdf signature object * implementation - * + * * @return the converted pdf signature object * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#getSignatureObject() */ @@ -603,11 +583,11 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * Converts a abstract signature object in a pdf signature object * implementation - * + * * @param sigObject * the abstract signatorObject to convert * @return the converted pdf signature object - * @throws PDFDocumentException + * @throws PDFDocumentException * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#getSignatureObject(at.knowcenter.wag.egov.egiz.sig.SignatureObject) */ public Object getSignatureObject(SignatureObject sigObject) throws PDFDocumentException diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java index bdc1078..b3adb71 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java @@ -32,6 +32,7 @@ import java.util.List; import at.gv.egiz.pdfas.framework.input.PdfDataSource; import at.gv.egiz.pdfas.impl.input.ByteArrayPdfDataSourceImpl; +import at.gv.egiz.pdfas.utils.PDFASUtils; import org.pdfbox.pdfparser.PDFParser; import org.pdfbox.pdmodel.PDDocument; @@ -44,7 +45,7 @@ import com.lowagie.text.DocumentException; /** * Contains useful helpers for accessing PDF documents. - * + * * @author wprinz * @author mruhmer */ @@ -52,12 +53,13 @@ public abstract class PDFUtilities { public static float calculatePageLength(final PdfDataSource pdfDataSource, int page, float effectivePageHeight, int pagerotation) throws PDFDocumentException { + PDDocument pdfDocument_ = null; try { //ByteArrayInputStream original_bais = new ByteArrayInputStream(pdf); //byte [] normalized_pdf = TextualSignature.normalizePDF(original_bais); byte [] normalized_pdf = TextualSignature.normalizePDF(pdfDataSource); - + // PERF: The whole PDF normalization process is costy ByteArrayInputStream bais = new ByteArrayInputStream(normalized_pdf); @@ -66,9 +68,8 @@ public abstract class PDFUtilities parser.setTempDirectory(temporary_dir); parser.parse(); - PDDocument pdfDocument_ = parser.getPDDocument(); + pdfDocument_ = parser.getPDDocument(); float page_length = calculatePageLength(pdfDocument_, page, effectivePageHeight, pagerotation); - pdfDocument_.close(); return page_length; } catch (IOException e) @@ -78,8 +79,10 @@ public abstract class PDFUtilities catch (DocumentException e) { throw new PDFDocumentException(201, e); + } finally { + PDFASUtils.closeQuietly(pdfDocument_); } - } + } public static float calculatePageLength(PDDocument document, int page, float effectivePageHeight, int pagerotation) throws IOException { //int last_page_id = document.getNumberOfPages(); @@ -87,8 +90,8 @@ public abstract class PDFUtilities PDPage pdpage = (PDPage) allPages.get(page); pdpage.setRotation(pagerotation); return calculatePageLength(pdpage, effectivePageHeight); - } - + } + /** * @deprecated * @param pdf @@ -98,12 +101,13 @@ public abstract class PDFUtilities */ public static float calculateLastPageLength(final byte[] pdf, float effectivePageHeight) throws PDFDocumentException { + PDDocument pdfDocument_ = null; try { //ByteArrayInputStream original_bais = new ByteArrayInputStream(pdf); PdfDataSource dataSource = new ByteArrayPdfDataSourceImpl(pdf); byte [] normalized_pdf = TextualSignature.normalizePDF(dataSource); - + ByteArrayInputStream bais = new ByteArrayInputStream(normalized_pdf); PDFParser parser = new PDFParser(bais); @@ -111,9 +115,8 @@ public abstract class PDFUtilities parser.setTempDirectory(temporary_dir); parser.parse(); - PDDocument pdfDocument_ = parser.getPDDocument(); + pdfDocument_ = parser.getPDDocument(); float last_page_length = calculateLastPageLength(pdfDocument_, effectivePageHeight); - pdfDocument_.close(); return last_page_length; } @@ -124,6 +127,8 @@ public abstract class PDFUtilities catch (DocumentException e) { throw new PDFDocumentException(201, e); + } finally { + PDFASUtils.closeQuietly(pdfDocument_); } } diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java index a9c1c54..deb5fed 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java @@ -173,9 +173,8 @@ public class StructContentHelper implements StructContentWriter { } } catch (Exception ex) { - logger.error("error", ex); - throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, - "error writing structured signature content", ex); + logger.warn("Unable to process structured document data. Going to write untagged signature block.", ex); + isTagged = false; } } @@ -471,16 +470,38 @@ public class StructContentHelper implements StructContentWriter { } } - private void checkTagging() { - PdfDictionary markDict = stamper.getReader().getCatalog().getAsDict(PdfName.MARKINFO); - if (markDict != null) { - isTagged = markDict.getAsBoolean(PdfName.MARKED).booleanValue(); - } - if (!isTagged) { - logger.debug("input document is not tagged. no structure/wai information is written"); - } - logger.debug("Input is tagged. Writing structure/WAI data."); - } + private void checkTagging() { + PdfDictionary markDict = stamper.getReader().getCatalog().getAsDict(PdfName.MARKINFO); + if (markDict != null) { + isTagged = markDict.getAsBoolean(PdfName.MARKED).booleanValue(); + } + if (!isTagged) { + logger.debug("Input document is not tagged. No structure data will be attached to signature block."); + } else { + logger.trace("Document claims to be tagged. Checking availability of structured tree root."); + PdfDictionary structTreeRoot; + if ((structTreeRoot = getStructTreeRoot()) == null) { + // document claimed to be tagged but document does not contain structural information + isTagged = false; + logger.debug("Document claims to be tagged structured tree root was not found."); + } else if (getParentTreeNums() == null) { + // document claimed to be tagged but document does not contain structural information + isTagged = false; + logger.debug("Document claims to be tagged but required information is missing."); + } else if (structTreeRoot.getDirectObject(PdfName.K) == null) { + // structured content + isTagged = false; + logger.debug("Document claims to be tagged but required information is missing."); + } else { + logger.debug("Input is tagged and required structure data seems to be available. Going to write structured signature block."); + } + if (!isTagged) { + logger.info("Unable to process structured document data. Going to write untagged signature block."); + } + } + } + + diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java index 35a0768..3ce690b 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java @@ -53,7 +53,7 @@ import com.lowagie.text.pdf.PdfWriter; /** * Contains helper function for textual signatures. - * + * * @author wprinz */ public class TextualSignature @@ -62,21 +62,22 @@ public class TextualSignature * The logger definition. */ private static final Logger logger_ = ConfigLogger.getLogger(TextualSignature.class); - + /** * Extracts the document text from a given pdf. - * + * * @param pdf_stream * The pdf_input stream. * @return Returns the extracted document text. - * @throws PDFDocumentException + * @throws PDFDocumentException * @throws TextExtractionException * Forwarded exception. */ - public static String extractTextTextual(PdfDataSource pdfDataSource, String encoding) throws PDFDocumentException + public static String extractTextTextual(PdfDataSource pdfDataSource, String encoding) throws PDFDocumentException { PerformanceCounters.textExtractions.increment(); - + PDDocument doc = null; + Document document = null; try { int first_page_rotation = 0; @@ -90,12 +91,8 @@ public class TextualSignature // byte[] bytes = normalizePDF(pdf_stream); - //iText - - byte [] pdf_data = pdfDataSource.getAsByteArray(); - PdfReader reader = new PdfReader(pdf_data); - PDFASUtils.checkReaderPermissions(reader); - //pdf_stream.close(); + + PdfReader reader = PDFASUtils.createPdfReaderCheckingPermissions(pdfDataSource); // PERF: PDF normalization needs byte array - this is costy ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); @@ -108,7 +105,7 @@ public class TextualSignature // this method (although it works when a Table is appended)... very // fragile. - Document document = new Document(); + document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, baos); document.open(); @@ -126,7 +123,7 @@ public class TextualSignature first_page_rotation = new_size_withrot.getRotation(); //logger_.info("iText first_page_rotation="+new_size_withrot.getRotation()); } - //logger_.info("iText set PageSize of page:"+page_num+" to: "+new_size_withrot); + //logger_.info("iText set PageSize of page:"+page_num+" to: "+new_size_withrot); //document.setPageSize(new_size); document.setPageSize(new_size_withrot); document.newPage(); @@ -163,15 +160,15 @@ public class TextualSignature //logger_.info("temporary_dir="+temporary_dir.getAbsolutePath()); parser.setTempDirectory(temporary_dir); parser.parse(); - - PDDocument doc = parser.getPDDocument(); + + doc = parser.getPDDocument(); //System.out.println("pdfBox.getNumberOfPages()"+doc.getNumberOfPages()); - + PDFTextStripper stripper = new PDFTextStripper(); stripper.setSortByPosition(false); stripper.setGetFirstPageRotationFromThis(true); stripper.setFirstPageRotation(first_page_rotation); - + // stripper.setStartPage(4); // stripper.setEndPage(4); logger_.debug("TextualSignator extractTextTextual: Begin stripping text"); @@ -182,8 +179,7 @@ public class TextualSignature throw new PDFDocumentException(ErrorCode.TEXT_EXTRACTION_EXCEPTION, "Unable to extract textual content.", e); } logger_.debug("TextualSignator extractTextTextual: Stripping text ended"); - - doc.close(); + //logger_.debug("TextualSignator extractTextTextual="+text); return text; @@ -199,39 +195,39 @@ public class TextualSignature catch (DocumentException e) { throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); + } finally { + PDFASUtils.closeQuietly(doc); + PDFASUtils.closeQuietly(document); } } - + /** * Normalizes a given binary PDF to a version PDFbox can handle correctly. - * + * *

    * PDFbox has serious problems with documents that use incremental updates or * XObject forms. Therefor use this to remove incremental updates and create a * streamlined document. *

    - * + * *

    * Note that this has nothing to do with text normalization. It just unifies * the PDF documents that are fed into PDFbox for text extraction and page * length determination. *

    - * + * * @param input_pdf * The input pdf to be normalized. * @return Returns the normalized pdf. * @throws IOException * @throws DocumentException - * @throws PDFDocumentException + * @throws PDFDocumentException */ public static byte[] normalizePDF(PdfDataSource pdfDataSource) throws IOException, DocumentException, PDFDocumentException { //iText - byte [] pdf_data = pdfDataSource.getAsByteArray(); - PdfReader reader = new PdfReader(pdf_data); - PDFASUtils.checkReaderPermissions(reader); - //input_pdf.close(); - + PdfReader reader = PDFASUtils.createPdfReaderCheckingPermissions(pdfDataSource); + // PERF: PDF Normalization needs byte array ByteArrayOutputStream baos = new ByteArrayOutputStream(); // For some reason the Reader -> ImportPage -> Writer mechanism produces diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathConstructionOperatorProcessor.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathConstructionOperatorProcessor.java new file mode 100644 index 0000000..143a6b6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathConstructionOperatorProcessor.java @@ -0,0 +1,62 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path; + +import java.awt.geom.Point2D; + +import org.pdfbox.util.operator.OperatorProcessor; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; + +/** + * Provides functions for path construction operators. + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author Datentechnik Innovation GmbH + * + */ +public abstract class PathConstructionOperatorProcessor extends OperatorProcessor { + + public PathConstructionOperatorProcessor(PDFPage context) { + setContext(context); + } + + /** + * Transforms the given point from user space coordinates to device space coordinates based on the current + * transition matrix. + * + * @param x + * The x axis value of the user space coordinates. + * @param y + * The y axis value of the user space coordinates. + * @return The transformed point. + */ + public Point2D transform(double x, double y) { + double[] position = { x, y }; + context.getGraphicsState().getCurrentTransformationMatrix().createAffineTransform() + .transform(position, 0, position, 0, 1); + return new Point2D.Double(position[0], position[1]); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathPaintingOperatorProcessor.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathPaintingOperatorProcessor.java new file mode 100644 index 0000000..9a76f87 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathPaintingOperatorProcessor.java @@ -0,0 +1,43 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path; + +import org.pdfbox.util.operator.OperatorProcessor; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; + +/** + * Provides functions for path painting operators. + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author Datentechnik Innovation GmbH + * + */ +public abstract class PathPaintingOperatorProcessor extends OperatorProcessor { + + public PathPaintingOperatorProcessor(PDFPage context) { + setContext(context); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/ClosePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/ClosePath.java new file mode 100644 index 0000000..ea87887 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/ClosePath.java @@ -0,0 +1,68 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Close the current subpath by appending a straight line segment from the current point to the starting point of the + * subpath. If the current subpath is already closed, h shall donothing. This operator terminates the current subpath. + * Appending another segment to the current path shall begin a new subpath, even if the new segment begins at the + * endpoint reached by the h operation. + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class ClosePath extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public ClosePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + pdfPage.getCurrentPath().closePath(); + + if (log.isTraceEnabled()) { + log.trace("Closing current path."); + } + } catch (Exception e) { + log.warn("Error processing operator 'h'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveTo.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveTo.java new file mode 100644 index 0000000..a2fc8de --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveTo.java @@ -0,0 +1,85 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.cos.COSNumber; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), + * using (x1, y1) and (x2, y2) as the Bezier control points (see 8.5.2.2, "Cubic Bezier Curves"). The new current point + * shall be (x3, y3). + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CurveTo extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CurveTo(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + COSNumber x1 = (COSNumber) operands.get(0); + COSNumber y1 = (COSNumber) operands.get(1); + COSNumber x2 = (COSNumber) operands.get(2); + COSNumber y2 = (COSNumber) operands.get(3); + COSNumber x3 = (COSNumber) operands.get(4); + COSNumber y3 = (COSNumber) operands.get(5); + + Point2D p1 = transform(x1.doubleValue(), y1.doubleValue()); + Point2D p2 = transform(x2.doubleValue(), y2.doubleValue()); + Point2D p3 = transform(x3.doubleValue(), y3.doubleValue()); + + pdfPage.getCurrentPath().curveTo( + (float) p1.getX(), (float) p1.getY(), + (float) p2.getX(), (float) p2.getY(), + (float) p3.getX(), (float) p3.getY() + ); + + if (log.isTraceEnabled()) { + log.trace("Appending cubic Bezier curve with x1:" + p1.getX() + ",y1:" + p1.getY() + ", x2:" + + p2.getX() + ",y2:" + p2.getY() + ", x3:" + p3.getX() + ",y3:" + p3.getY()); + } + } catch (Exception e) { + log.warn("Error processing operator 'c'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateFinalPoint.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateFinalPoint.java new file mode 100644 index 0000000..bb5c86c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateFinalPoint.java @@ -0,0 +1,82 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.cos.COSNumber; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), + * using (x1, y1) and (x3, y3) as the Bezier control points (see 8.5.2.2, "Cubic Bezier Curves"). The new current point + * shall be (x3, y3). + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CurveToReplicateFinalPoint extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CurveToReplicateFinalPoint(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + COSNumber x1 = (COSNumber) operands.get(0); + COSNumber y1 = (COSNumber) operands.get(1); + COSNumber x3 = (COSNumber) operands.get(2); + COSNumber y3 = (COSNumber) operands.get(3); + + Point2D p1 = transform(x1.doubleValue(), y1.doubleValue()); + Point2D p3 = transform(x3.doubleValue(), y3.doubleValue()); + + pdfPage.getCurrentPath().curveTo( + (float) p1.getX(), (float) p1.getY(), + (float) p3.getX(), (float) p3.getY(), + (float) p3.getX(), (float) p3.getY() + ); + + if (log.isTraceEnabled()) { + log.trace("Appending cubic Bezier curve with x1:" + p1.getX() + ",y1:" + p1.getY() + ", x3:" + + p3.getX() + ",y3:" + p3.getY()); + } + } catch (Exception e) { + log.warn("Error processing operator 'y'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateInitialPoint.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateInitialPoint.java new file mode 100644 index 0000000..b35bcaf --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateInitialPoint.java @@ -0,0 +1,84 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.cos.COSNumber; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), + * using the current point and (x2, y2) as the Bezier control points (see 8.5.2.2, "Cubic Bezier Curves"). The new + * current point shall be (x3, y3). + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CurveToReplicateInitialPoint extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CurveToReplicateInitialPoint(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + COSNumber x2 = (COSNumber) operands.get(0); + COSNumber y2 = (COSNumber) operands.get(1); + COSNumber x3 = (COSNumber) operands.get(2); + COSNumber y3 = (COSNumber) operands.get(3); + + Point2D currentPoint = pdfPage.getCurrentPath().getCurrentPoint(); + Point2D p2 = transform(x2.doubleValue(), y2.doubleValue()); + Point2D p3 = transform(x3.doubleValue(), y3.doubleValue()); + + pdfPage.getCurrentPath().curveTo( + (float)currentPoint.getX(), (float)currentPoint.getY(), + (float) p2.getX(), (float) p2.getY(), + (float) p3.getX(), (float) p3.getY() + ); + + if (log.isTraceEnabled()) { + log.trace("Appending cubic Bezier curve with x2:" + p2.getX() + ",y2:" + p2.getY() + ", x3:" + + p3.getX() + ",y3:" + p3.getY() + ", using current point x:" + currentPoint.getX() + ",y:" + + currentPoint.getY()); + } + } catch (Exception e) { + log.warn("Error processing operator 'v'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/LineTo.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/LineTo.java new file mode 100644 index 0000000..ae5894d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/LineTo.java @@ -0,0 +1,71 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.cos.COSNumber; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Append a straight line segment from the current point to the point (x, y). The new current point shall be (x, y). + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class LineTo extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public LineTo(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + COSNumber x = (COSNumber) operands.get(0); + COSNumber y = (COSNumber) operands.get(1); + Point2D p = transform(x.doubleValue(), y.doubleValue()); + + pdfPage.getCurrentPath().lineTo((float) p.getX(), (float) p.getY()); + + if (log.isTraceEnabled()) { + log.trace("Adding line to x:" + p.getX() + ",y:" + p.getY()); + } + } catch (Exception e) { + log.warn("Error processing operator 'l'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/MoveTo.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/MoveTo.java new file mode 100644 index 0000000..b43de2e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/MoveTo.java @@ -0,0 +1,73 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.cos.COSNumber; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Begin a new subpath by moving the current point to coordinates (x, y), omitting any connecting line segment. If the + * previous path construction operator in the current path was also m, the new m overrides it; no vestige of the + * previous m operation remains in the path. + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class MoveTo extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public MoveTo(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + COSNumber x = (COSNumber) operands.get(0); + COSNumber y = (COSNumber) operands.get(1); + Point2D p = transform(x.doubleValue(), y.doubleValue()); + + pdfPage.getCurrentPath().moveTo((float) p.getX(), (float) p.getY()); + + if (log.isTraceEnabled()) { + log.trace("Moving current path to x:" + p.getX() + ",y:" + p.getY()); + } + } catch (Exception e) { + log.warn("Error processing operator 'm'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseAndStrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseAndStrokePath.java new file mode 100644 index 0000000..54f4af8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseAndStrokePath.java @@ -0,0 +1,59 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Close and stroke the path. This operator shall have the same effect as the sequence h S. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CloseAndStrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CloseAndStrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + if (log.isTraceEnabled()) { + log.trace("Closing and stroking path."); + } + context.processOperator("h", operands); + context.processOperator("S", operands); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillEvenOddAndStrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillEvenOddAndStrokePath.java new file mode 100644 index 0000000..6a84cf4 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillEvenOddAndStrokePath.java @@ -0,0 +1,60 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Close, fill, and then stroke the path, using the even-odd rule to determine the region to fill. This operator shall + * have the same effect as the sequence h B*. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CloseFillEvenOddAndStrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CloseFillEvenOddAndStrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + if (log.isTraceEnabled()) { + log.trace("Closing, filling (even odd rule) and stroking path."); + } + context.processOperator("h", operands); + context.processOperator("B*", operands); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillNonZeroAndStrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillNonZeroAndStrokePath.java new file mode 100644 index 0000000..f8db567 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillNonZeroAndStrokePath.java @@ -0,0 +1,60 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Close, fill, and then stroke the path, using the nonzero winding number rule to determine the region to fill. This + * operator shall have the same effect as the sequence h B. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CloseFillNonZeroAndStrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CloseFillNonZeroAndStrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + if (log.isTraceEnabled()) { + log.trace("Closing, filling (non zero rule) and stroking path."); + } + context.processOperator("h", operands); + context.processOperator("B", operands); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/EndPath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/EndPath.java new file mode 100644 index 0000000..4448a1e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/EndPath.java @@ -0,0 +1,68 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * End the path object without filling or stroking it. This operator shall be a path-painting no-op, used primarily for + * the side effect of changing the current clipping path. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class EndPath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public EndPath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + log.debug("Ending path " + pdfPage.getCurrentPath()); + pdfPage.getCurrentPath().reset(); + + if (log.isTraceEnabled()) { + log.trace("End path without filling or stroking."); + } + + } catch (Exception e) { + log.warn("Error processing operator 'n'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillEvenOddAndStrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillEvenOddAndStrokePath.java new file mode 100644 index 0000000..8a42dff --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillEvenOddAndStrokePath.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.awt.geom.GeneralPath; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Fill and then stroke the path, using the even-odd rule to determine the region to fill. This operator shall produce + * the same result as B, except that the path is filled as if with f* instead of + * f. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class FillEvenOddAndStrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public FillEvenOddAndStrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + if (log.isTraceEnabled()) { + log.trace("Filling (even odd rule) and stroking path."); + } + + GeneralPath currentPath = (GeneralPath) pdfPage.getCurrentPath().clone(); + context.processOperator("f*", operands); + pdfPage.setCurrentPath(currentPath); + context.processOperator("S", operands); + + } catch (Exception e) { + log.warn("Error processing operator 'B*'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillNonZeroAndStrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillNonZeroAndStrokePath.java new file mode 100644 index 0000000..96025ed --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillNonZeroAndStrokePath.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.awt.geom.GeneralPath; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Fill and then stroke the path, using the nonzero winding number rule to determine the region to fill. This operator + * shall produce the same result as constructing two identical path objects, painting the first with f and + * the second with S. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class FillNonZeroAndStrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public FillNonZeroAndStrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + if (log.isTraceEnabled()) { + log.trace("Filling (non zero rule) and stroking path."); + } + + GeneralPath currentPath = (GeneralPath) pdfPage.getCurrentPath().clone(); + context.processOperator("f", operands); + pdfPage.setCurrentPath(currentPath); + context.processOperator("S", operands); + + } catch (Exception e) { + log.warn("Error processing operator 'B'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathEvenOddRule.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathEvenOddRule.java new file mode 100644 index 0000000..c6417ea --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathEvenOddRule.java @@ -0,0 +1,71 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.awt.Rectangle; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Fill the path, using the even-odd rule to determine the region to fill. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class FillPathEvenOddRule extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public FillPathEvenOddRule(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + pdfPage.getCurrentPath().setWindingRule(java.awt.geom.GeneralPath.WIND_EVEN_ODD); + Rectangle bounds = pdfPage.getCurrentPath().getBounds(); + pdfPage.getCurrentPath().reset(); + + if (log.isTraceEnabled()) { + log.trace("Filling path, using even-odd rule."); + } + + pdfPage.registerPathBounds(bounds); + + } catch (Exception e) { + log.warn("Error processing operator 'f*'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathNonZeroWindingNumberRule.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathNonZeroWindingNumberRule.java new file mode 100644 index 0000000..b350009 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathNonZeroWindingNumberRule.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.awt.Rectangle; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Fill the path, using the nonzero winding number rule to determine the region to fill. Any subpaths that are open + * shall be implicitly closed before being filled. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class FillPathNonZeroWindingNumberRule extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public FillPathNonZeroWindingNumberRule(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + pdfPage.getCurrentPath().setWindingRule(java.awt.geom.GeneralPath.WIND_NON_ZERO); + Rectangle bounds = pdfPage.getCurrentPath().getBounds(); + pdfPage.getCurrentPath().reset(); + + if (log.isTraceEnabled()) { + log.trace("Filling path, using nonzero winding number rule."); + } + + pdfPage.registerPathBounds(bounds); + + } catch (Exception e) { + log.warn("Error processing operator 'f/F'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/StrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/StrokePath.java new file mode 100644 index 0000000..9dfce7e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/StrokePath.java @@ -0,0 +1,70 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.awt.Rectangle; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Strokes the path. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class StrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public StrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + Rectangle bounds = pdfPage.getCurrentPath().getBounds(); + pdfPage.getCurrentPath().reset(); + + if (log.isTraceEnabled()) { + log.trace("Stroking path."); + } + + pdfPage.registerPathBounds(bounds); + + } catch (Exception e) { + log.warn("Error processing operator 'S'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java index 9e28213..b5a05ed 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java @@ -77,7 +77,7 @@ import at.knowcenter.wag.egov.egiz.tools.Normalizer; * All values that build or used by the signation creation process, call the * external services, can read or set separately. All other values are defined * in the settings file. - * + * * @author wlackner * @author modified by Thomas Knall */ @@ -138,7 +138,7 @@ public class SignatureObject implements Serializable public static final String SIG_CER_DIG = "SIG_CER_DIG"; private X509Cert x509Cert_ = null; - + private String timeStamp = null; // public static final String SIG_RES = "SIG_RES"; @@ -194,7 +194,7 @@ public class SignatureObject implements Serializable /** * The raw xml response from the connector that was used to set the values in * this SignatureObject. - * + * *

    * This is set by the Connector so that signing Applications can use the * returned XML values. @@ -222,7 +222,7 @@ public class SignatureObject implements Serializable /** * The empty constructor. It initilize the normlizer, load the settings and * set the default styles. - * + * * @throws SignatureException * ErrorCode:101, 400 */ @@ -235,7 +235,7 @@ public class SignatureObject implements Serializable /** * This method initialize the normalizer - * + * * @throws SignatureException * ErrorCode:400 */ @@ -254,7 +254,7 @@ public class SignatureObject implements Serializable /** * This method load the signature definitions - * + * * @throws SignatureException * ErrorCode:101 */ @@ -296,7 +296,7 @@ public class SignatureObject implements Serializable /** * Dummy getter Method for debugging only - * + * * @return response string */ public String getSigResponse() @@ -306,7 +306,7 @@ public class SignatureObject implements Serializable /** * Dummy setter Method for debugging only - * + * * @param sigRespone * store the response string */ @@ -317,7 +317,7 @@ public class SignatureObject implements Serializable /** * This method set the signature type. - * + * * @param sigType * the signature type to be set * @throws SignatureTypesException @@ -331,7 +331,7 @@ public class SignatureObject implements Serializable /** * Returns the default signation type - * + * * @return the key for the default signature definition, if the key is not * found it returns null */ @@ -343,7 +343,7 @@ public class SignatureObject implements Serializable /** * This method checks if a given signature key is realy a defined signature * key. - * + * * @param sigKey * the key to check * @return true if the key is correct, false if the given key is not defined @@ -360,7 +360,7 @@ public class SignatureObject implements Serializable * The value that has to be set would be normalized!
    * If the key equals to SIG_VALUE all whitespaces are * removed!
    - * + * * @param key * the key to be set * @param value @@ -371,7 +371,7 @@ public class SignatureObject implements Serializable public boolean setSigValue(String key, String value) { return setSigValue(key, value, false); } - + public boolean setSigValue(String key, String value, boolean placeholder) { SignatureEntry sig_entry = null; @@ -416,7 +416,7 @@ public class SignatureObject implements Serializable /** * Set the value and the caption to given key. - * + * * @param key * the key of the signature object * @param value @@ -435,14 +435,14 @@ public class SignatureObject implements Serializable * This method returns a value for a given signature key. If the key equals to * SIG_NORM and the value is null the version * string of the current normalizer is returned! - * + * * @param key * the key to get the value for * @return a value for the given key */ public String getSigValue(String key) { - + String value = null; SignatureEntry sigEntry = null; if (sigEntries_.containsKey(key)) @@ -462,13 +462,13 @@ public class SignatureObject implements Serializable logger_.debug("Using override property for key '" + key + "' = " + value); } } - + return value; } /** * Sets the "Kennzeichnung". - * + * * @param kz * The "Kennzeichnung" to be set. */ @@ -479,7 +479,7 @@ public class SignatureObject implements Serializable /** * Returns the "Kennzeichnung" of this signature. - * + * * @return Returns the "Kennzeichnung" of this signature. Returns null if * there is no "Kennzeichnung" or it is not recognized by this * application. @@ -508,14 +508,14 @@ public class SignatureObject implements Serializable * and the coresponding value is null the key itself is * returned as caption! If the key does not exist the method returns * null. - * + * * @param key * the key to get the caption for * @return a caption for the given key */ private String getSigCaption(String key) { - + String caption = null; if (sigEntries_.containsKey(key)) { @@ -667,15 +667,15 @@ public class SignatureObject implements Serializable if (StringUtils.equals(nameFromText, nameFromCertificate)) { return nameFromText; } - + logger_.debug("Checking RFC2253 name."); - + // if we do not have a name from certificate just return the name from text if (nameFromCertificate == null) { logger_.debug("No certificate RFC2253 name provided. Applying less sophisticated workaround (does not cover all cases) without certificate usage."); return prepareRFC2253Name(nameFromText); } - + // no name from text extraction available, just return name from certificate if (nameFromText == null) { logger_.debug("No extracted/reconstructed name available. Just returning the name from certificate: \"" + nameFromCertificate + "\"."); @@ -762,13 +762,13 @@ public class SignatureObject implements Serializable result.append(rdnVP.getValue()); } else { // no BER encoding -> take value from certificate - // also take RDN from certificate if possible + // also take RDN from certificate if possible String certValue = values[values.length - 1 - i].getAVA() .getValueAsString(); String rdn = resolveRDN(nameFromCertificate, certValue, rdnVP.getRdn()); result.append(rdn + "=").append(certValue); } - + } String merged = result.toString(); if (logger_.isDebugEnabled()) { @@ -785,15 +785,15 @@ public class SignatureObject implements Serializable } return merged; } - + /** * This method tries to resolve the RDN corresponding to a given value from the certificate String. - * As values might occur multiple times for different RDNs, an unambiguous resolving cannot be assured. + * As values might occur multiple times for different RDNs, an unambiguous resolving cannot be assured. * In case of ambiguity, the RDN extracted from text is returned by default. - * + * * This method is a bug fix for a problem that caused the verification of ZID documents to fail as the RDN * from the extracted text ("EMAILADDRESS") was different to the RDN in the certificate ("EMAIL") - * + * * @param certString * The String obtained from the certificate * @param value @@ -804,42 +804,42 @@ public class SignatureObject implements Serializable * The resolved RDN from the certificate, or the RDN from text extraction */ private static String resolveRDN(String certString, String value, String extractedRDN) { - + if (!certString.contains(value)) { - + // given value cannot be found in certificate string return extractedRDN; } - + if (certString.indexOf(value) != certString.lastIndexOf(value)) { - + // given value is ambiguous - cannot resolve RDN from certificate string return extractedRDN; } - + String[] parts = certString.split(",|;"); String val = value.trim(); - + for (int i = 0; i < parts.length; i++) { - + String part = parts[i].trim(); - + if (part.endsWith(val)) { - + // found entry - extract RDN - String[] components = part.split("="); + String[] components = part.split("="); if (components.length != 2) { // unexpected format - return default - return extractedRDN; - } + return extractedRDN; + } String rdn = components[0].trim(); - return rdn; - } - } + return rdn; + } + } // default return extractedRDN; } - + /** * @return Returns the SignationIssuer. */ @@ -920,10 +920,10 @@ public class SignatureObject implements Serializable } // dferbas baik - + /** * signature algorithm if embedded - * @param sigAlg + * @param sigAlg */ public void setSigAlg(String sigAlg) { @@ -937,7 +937,7 @@ public class SignatureObject implements Serializable public String getSigAlg() { return getSigValue(SignatureTypes.SIG_ALG); - } + } /** * @param certDigest @@ -1016,7 +1016,7 @@ public class SignatureObject implements Serializable setSigValue(SIG_CER, x509Certificate); storeCertificate(getSignationSerialNumber(), getSignationIssuer(), x509Certificate); } - + public void setX509Certificate(X509Certificate cert) { try @@ -1037,7 +1037,7 @@ public class SignatureObject implements Serializable /** * return the 509v3 certificate of the given serialNumber and the given issuer * string - * + * * @param serialNumber * the serialNumber which the certificates should load * @param issuer @@ -1070,7 +1070,7 @@ public class SignatureObject implements Serializable /** * Set the signation id's build by a BKU signated SignatureObject. - * + * * @param sigIds * the string to store. */ @@ -1152,7 +1152,7 @@ public class SignatureObject implements Serializable String productVersion = response_properties.getProperty("productVersion"); logger_.debug("productVersion = " + productVersion); - boolean new_etsi = decideNewEtsiByBKUVersion(productVersion); + boolean new_etsi = decideNewEtsiByBKUVersion(productVersion); logger_.debug("verwende neue etsi properties = " + new_etsi); String etsi_prefix = ""; @@ -1183,7 +1183,7 @@ public class SignatureObject implements Serializable /** * Checks if the current SignatureObject is siganted by MOA. It checks if the * current SignatureObject has a signation id value. - * + * * @return true if no signation id value is found, false otherwise */ public boolean isMOASigned() @@ -1204,7 +1204,7 @@ public class SignatureObject implements Serializable /** * Tells if this SignatureObject is textual. - * + * * @return Returns true, if it is textual. */ public boolean isTextual() @@ -1223,7 +1223,7 @@ public class SignatureObject implements Serializable /** * Tells, if this SignatureObject is binary. - * + * * @return Returns true, if it is binary. */ public boolean isBinary() @@ -1237,14 +1237,14 @@ public class SignatureObject implements Serializable { logger_.error(e.getMessage(), e); } - + return SigKZIDHelper.isBinary(kz); } /** * Takes the signation id value of the current SignatureObject and split them * into the corresponding id array added with the id-base. - * + * * @return the id array */ // TODO hotifx @@ -1328,7 +1328,7 @@ public class SignatureObject implements Serializable real_ids[3] = "0-" + base + "-" + ids[3]; real_ids[4] = "0-" + base + "-" + ids[4]; real_ids[5] = etsi_string; - + if (logger_.isDebugEnabled()) { for (int id_idx = 0; id_idx < real_ids.length; id_idx++) @@ -1345,7 +1345,7 @@ public class SignatureObject implements Serializable * for equition. Used to store and find corresponting certificates. * Normalzing: normalizing the string using the normalizer, remove all white * spaces, encode as base64 and replace all "/" chars with "_". - * + * * @param issuer * the issuer string to normalize * @return the normalized issuer string @@ -1357,7 +1357,7 @@ public class SignatureObject implements Serializable { if (issuer != null) { - // use explicit method for normalization + // use explicit method for normalization issuer = normalizeIssuer(issuer); /* this block may be used to enhance normalization (tknall) try { @@ -1375,7 +1375,6 @@ public class SignatureObject implements Serializable } catch (UnsupportedEncodingException e) { - e.printStackTrace(); throw new RuntimeException(e); } } @@ -1443,7 +1442,7 @@ public class SignatureObject implements Serializable } } } - + private X509Cert loadCertificateFromCertstore(String serialNumber, String issuer) { String iss_hash = getIssuerFileHash(issuer); String cert_store_path = certPath_ + iss_hash; @@ -1476,10 +1475,10 @@ public class SignatureObject implements Serializable *

  • add the .txt extension to get the meta information of * the certificate
  • * - * + * * The certificate meta file is build by the base64 coded issuer string and * the cert digest value devided by the @ char. - * + * * @param serialNumber * the file name of the certificate .der|.txt * @param issuer @@ -1541,7 +1540,7 @@ public class SignatureObject implements Serializable /** * Writes the certificate data to a file and stores the file in the local * certificate store. - * + * * @param cert_data * The binary certificate data. */ @@ -1580,17 +1579,17 @@ public class SignatureObject implements Serializable /** * Connects to the LDAP server to look for the certificate. - * + * * @param serialNumber * The serial number String of the certificate being sought. E.g. * "123455676744123432". * @param issuer * The issuer String of the certificate being sought. - * + * * @return Returns the DER certificate file as can be stored in the local * repository. Returns null, if the document wasn't found on the * server. - * @throws ClassNotFoundException + * @throws ClassNotFoundException */ protected byte[] loadCertificateFromLDAP(String serialNumber, String issuer) { // START modification by TK @@ -1629,10 +1628,10 @@ public class SignatureObject implements Serializable *
  • add the .txt extension to get the meta information of * the certificate
  • * - * + * * The certificate meta file is build by the base64 coded issuer string and * the cert digest value devided by the @ char. - * + * * @param serialNumber * the file name of the certificate .der|.txt * @param issuer @@ -1650,7 +1649,7 @@ public class SignatureObject implements Serializable { return storeCertificate(serialNumber, issuer, x509Certificate); } - + /** * This method stores a X509v3 certificate to the filesystem. The reference to * the stored certificate is build by the serialNumber and the issuer string. @@ -1673,10 +1672,10 @@ public class SignatureObject implements Serializable *
  • add the .txt extension to get the meta information of * the certificate
  • * - * + * * The certificate meta file is build by the base64 coded issuer string and * the cert digest value devided by the @ char. - * + * * @param serialNumber * the file name of the certificate .der|.txt * @param issuer @@ -1723,7 +1722,7 @@ public class SignatureObject implements Serializable } return store_complete; } - + /** * @return Returns the AbstractTable. * @see at.knowcenter.wag.egov.egiz.table.Table @@ -1739,7 +1738,7 @@ public class SignatureObject implements Serializable /** * This method read the style definitions from the settings file. - * + * * @param styleKey * the key to read the style definitions * @return the defined style informations @@ -1762,7 +1761,7 @@ public class SignatureObject implements Serializable * This method creates an abstract signature table object. It takes all keys * and values set by the signature object to create the corresponding abstract * table object. The table definition is read from the settings file. - * + * * @param tableKey * is the name of the table definition in the settings file * @return a new abstract signature table @@ -1964,7 +1963,7 @@ public class SignatureObject implements Serializable /** * This method returns a signature entry object. - * + * * @param key * the corresponding key * @return the signature entry object of the given key, null if the key does @@ -1977,7 +1976,7 @@ public class SignatureObject implements Serializable /** * This method is a helper function to remove all white spaces from a text. - * + * * @param text * the white spaces should remove from * @return a text without white spaces @@ -1993,7 +1992,7 @@ public class SignatureObject implements Serializable } /** - * + * * @param placeholder * @return Returns the list of SignatureFieldDefinitions that's values in the * SignatureObject have been filled out with placeholders. @@ -2015,7 +2014,7 @@ public class SignatureObject implements Serializable setValueBruteForce(SignatureTypes.SIG_ID, null); continue; } - + if (sfd.field_name.equals(SignatureTypes.SIG_ALG) && !baikEnabled) { setValueBruteForce(SignatureTypes.SIG_ID, null); continue; @@ -2040,7 +2039,7 @@ public class SignatureObject implements Serializable /** * Returns the raw signature response XML string as set by the signing * Connector. - * + * * @return Returns the XML response String. */ public String getRawSignatureResponse() @@ -2050,12 +2049,12 @@ public class SignatureObject implements Serializable /** * Sets the raw signature response XML string. - * + * *

    * This should be used by the Connector to pass the response String to the * signer. *

    - * + * * @param raw_response_string * The new raw signature response string. */ @@ -2063,8 +2062,8 @@ public class SignatureObject implements Serializable { this.raw_signature_response = raw_response_string; } - - + + /** * get timestamp if available diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java index 783512c..a4d71fd 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java @@ -26,7 +26,9 @@ package at.knowcenter.wag.egov.egiz.sig; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -45,6 +47,118 @@ import at.knowcenter.wag.exactparser.ByteArrayUtils; public class SignatureTypes { + /** + * Defines all supported states for {@link SignatureTypes} (signature profiles). Signature types can be enabled + * ("on"), can be set to support signature only ("sign_only"), to verification only ("verify_only") or can be + * disabled ("off" or any other value not covered by other enum values). + * + * @author Datentechnik Innovation GmbH + */ + public enum State { + + /** + * Enables a signature profile. + */ + ON ("on", "yes", "true", "enabled"), + + /** + * Disables a signature profile. + */ + OFF (), + + /** + * Restricts the signature profile so that is can only be used for verification purposes and not for signature. + */ + VERIFY_ONLY ("verify_only", "verify-only", "verifyonly", "verify only", "verify"), + + /** + * Allows the signature profile to be used for signature but not for verification. + */ + SIGN_ONLY ("sign_only", "sign-only", "signonly", "sign only", "sign"); + + /** + * Sets the default state when no valid value was provided. + */ + private static final State DEFAULT = OFF; + + /** + * States that allow signatures. + */ + private static final State[] CAN_SIGN = { ON, SIGN_ONLY }; + + /** + * States that allow verification. + */ + private static final State[] CAN_VERIFY = { ON, VERIFY_ONLY }; + + private String[] keyWords; + + private State(String... keyWords) { + this.keyWords = keyWords; + } + + /** + * Returns a valid State from a given {@code keyWord}. If the {@code keyWord} cannot be matched to a certain + * state, the default State {@link #OFF} is returned. + * + * @param keyWord + * A valid keyword like "on", "sign_only"... + * @return The enum State. + */ + public static State fromString(String keyWord) { + if (keyWord == null) { + return DEFAULT; + } + try { + return valueOf(keyWord.toUpperCase()); + } catch (IllegalArgumentException e) { + for (State candidate : values()) { + for (String candidateKeyWord : candidate.keyWords) { + if (keyWord.equalsIgnoreCase(candidateKeyWord)) { + return candidate; + } + } + } + return DEFAULT; + } + } + + /** + * Returns {@code true} when the current state is one of the given candidate {@code states}. + * + * @param states + * The candidate states. + * @return {@code true} when the current state is one of the given candidate states, {@code false} if not. + */ + public boolean in(State... states) { + if (states != null) { + for (State state : states) { + if (this == state) { + return true; + } + } + } + return false; + } + + /** + * Returns if the respective state allows signatures. + * @return {@code true} if signatures are allowed, {@code false} if not. + */ + public boolean canSign() { + return in(CAN_SIGN); + } + + /** + * Returns if the respective state allows verification. + * @return {@code true} if verification is allowed, {@code false} if not. + */ + public boolean canVerify() { + return in(CAN_VERIFY); + } + + } + // 03.11.2010 changed by exthex - commented unneeded setDefaultStyles method to reduce confusion /** @@ -70,8 +184,8 @@ public class SignatureTypes /** * The state value activating an signature definition */ - private static final String STATE_ON = "on"; - +// public static final String STATE_ON = "on"; + // /** // * The state value de activating an signature definition // */ @@ -403,10 +517,12 @@ public class SignatureTypes if (settings_ != null) { ArrayList types = settings_.getKeys(TYPES); - for (int type_idx = 0; type_idx < types.size(); type_idx++) - { - String type = (String) types.get(type_idx); - addSignatureType(type); + if (types != null) { + for (int type_idx = 0; type_idx < types.size(); type_idx++) + { + String type = (String) types.get(type_idx); + addSignatureType(type); + } } } } @@ -420,8 +536,9 @@ public class SignatureTypes * @param typeName */ public void addSignatureType(String typeName) { - - if (STATE_ON.equals(settings_.getSetting(TYPES + "." + typeName, null))) + +// if (STATE_ON.equals(settings_.getSetting(TYPES + "." + typeName, null))) + if (State.fromString(settings_.getSetting(TYPES + "." + typeName, null)) != State.OFF) { SignatureTypeDefinition sig_type_def; try @@ -446,6 +563,23 @@ public class SignatureTypes return this.typeDefMap_.keySet(); } + /** + * Returns a set of identifiers for profiles than can be used for signature, i.e. profiles that are either enabled + * ("on") or set to "sign_only"). + * + * @return A set of signature profile/type identifiers. + */ + @SuppressWarnings("unchecked") + public Set getSignatureTypesForSignature() { + Set filteredResult = new HashSet(); + for (String signatureProfileId : (Set) typeDefMap_.keySet()) { + if (State.fromString(settings_.getSetting(TYPES + "." + signatureProfileId, null)).canSign()) { + filteredResult.add(signatureProfileId); + } + } + return filteredResult; + } + /** * @return a list of signature type definitions */ @@ -453,6 +587,23 @@ public class SignatureTypes { return new ArrayList(this.typeDefMap_.values()); } + + /** + * Returns a (filtered) list of signature type definitions useable for verification. Those definitions for profiles + * that are not allowed to be used for verification are filtered. + * + * @return A filtered list of signature type definitions. + */ + @SuppressWarnings("unchecked") + public List getSignatureTypeDefinitionsForVerification() { + List filteredResult = new ArrayList(typeDefMap_.size()); + for (String signatureProfileId : (Set) typeDefMap_.keySet()) { + if (State.fromString(settings_.getSetting(TYPES + "." + signatureProfileId, null)).canVerify()) { + filteredResult.add((SignatureTypeDefinition) typeDefMap_.get(signatureProfileId)); + } + } + return filteredResult; + } /** * This method returns the corresponding signature type definition to a given diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java index 7b4e463..e11a38c 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java @@ -99,7 +99,7 @@ public class X509Cert implements Serializable * statement and remove all whitespaces in the string. The result string * (base64) is used by reconstructing the certiface sign by the verification * process. - * + * * @param certString * the string to normalize * @return the normalized cert string @@ -115,7 +115,7 @@ public class X509Cert implements Serializable /** * This method initialzes a X509Certificate by a string value. It must be * coded Base64 or as plain binary stream. - * + * * @param certString * the certificate string to analyse * @return the X509Cert object @@ -150,7 +150,9 @@ public class X509Cert implements Serializable String serial_num = cert.getSerialNumber().toString(); String issuer = cert.getIssuerDN().getName(); - issuer = issuer.replaceAll(", ", ","); + // fixed by dti: commas within issuer rdns are escapted by "\,". These escapted commas must not be replaced. +// issuer = issuer.replaceAll(", ", ","); + issuer = issuer.replaceAll("[^\\\\], ", ","); String subject_name = cert.getSubjectDN().toString(); x509_cert.setSerialNumber(serial_num); x509_cert.setIssuerName(issuer); @@ -174,7 +176,7 @@ public class X509Cert implements Serializable } return x509_cert; } - + public static X509Cert initByX509Certificate(X509Certificate cert) throws CertificateEncodingException { X509Cert x509_cert = new X509Cert(); x509_cert.setX509Cert(cert); @@ -182,7 +184,9 @@ public class X509Cert implements Serializable String serial_num = cert.getSerialNumber().toString(); String issuer = cert.getIssuerDN().getName(); - issuer = issuer.replaceAll(", ", ","); + // fixed by dti: commas within issuer rdns are escapted by "\,". These escapted commas must not be replaced. +// issuer = issuer.replaceAll(", ", ","); + issuer = issuer.replaceAll("[^\\\\], ", ","); String subject_name = cert.getSubjectDN().toString(); x509_cert.setSerialNumber(serial_num); x509_cert.setIssuerName(issuer); @@ -210,7 +214,9 @@ public class X509Cert implements Serializable String serial_num = cert.getSerialNumber().toString(); String issuer = cert.getIssuerDN().getName(); - issuer = issuer.replaceAll(", ", ","); + // fixed by dti: commas within issuer rdns are escapted by "\,". These escapted commas must not be replaced. +// issuer = issuer.replaceAll(", ", ","); + issuer = issuer.replaceAll("[^\\\\], ", ","); String subject_name = cert.getSubjectDN().toString(); x509_cert.setSerialNumber(serial_num); x509_cert.setIssuerName(issuer); @@ -226,7 +232,7 @@ public class X509Cert implements Serializable { // nothing to do, cause certString is not X509 conformc logger_.error(ce.getMessage(), ce); - + } catch (IOException ioe) { @@ -240,7 +246,7 @@ public class X509Cert implements Serializable /** * This method initialzes a X509Certificate by a file path value. The file * must be a plain binary file like .cer format. - * + * * @param filePath * the certificate file to analyse * @return the X509Cert object @@ -276,7 +282,9 @@ public class X509Cert implements Serializable String serial_num = cert.getSerialNumber().toString(); String issuer = cert.getIssuerDN().getName(); - issuer = issuer.replaceAll(", ", ","); + // fixed by dti: commas within issuer rdns are escapted by "\,". These escapted commas must not be replaced. +// issuer = issuer.replaceAll(", ", ","); + issuer = issuer.replaceAll("[^\\\\], ", ","); String subject_name = cert.getSubjectDN().toString(); x509_cert.setSerialNumber(serial_num); x509_cert.setIssuerName(issuer); @@ -300,7 +308,7 @@ public class X509Cert implements Serializable /** * This method initialzes a X509Certificate by a file value. The file must be * a plain binary file like .cer format. - * + * * @param certFile * the certificate file to analyse * @return the X509Cert object @@ -314,7 +322,7 @@ public class X509Cert implements Serializable /** * This method checks if a certificate file is X509 conform. - * + * * @return true if a certificate file is X509 conform, false otherwise */ public boolean isX509Cert() @@ -480,7 +488,7 @@ public class X509Cert implements Serializable /** * This method checks, if a X509Certificate has a public key with the rsa * algorithm. - * + * * @return true if the public key is produced with rsa, false otherwise */ public boolean isRSA() diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java index c3b6421..e4d78c3 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java @@ -49,9 +49,9 @@ import at.knowcenter.wag.egov.egiz.tools.CodingHelper; /** * Connector for communicating with BKU. - * + * * @deprecated use the new connectors. - * + * * @author wlackner * @author wprinz */ @@ -59,7 +59,7 @@ public class BKUConnector implements LocalConnector { /** * ConnectorInformation that identifies this Connector to the system. - * + * * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory * @see ConnectorInformation */ @@ -85,7 +85,7 @@ public class BKUConnector implements LocalConnector /** * load the inital signature settings - * + * * @see SettingsReader */ public void loadSettings() throws SignatureException @@ -111,7 +111,7 @@ public class BKUConnector implements LocalConnector * SignatureObject is filled out by the parsed BKU-Response.
    * If an error request is send back from BKU, an error message is generated an * an exception is thrown. - * + * * @param sigType * the type of the SignatureObject that should be returned * @param userName @@ -137,7 +137,7 @@ public class BKUConnector implements LocalConnector * This method generates the BKU verify prozess. It checks if the given * SignatureObject is signed by MOA or BKU. The verify template string is * filled out by the corresponding method. - * + * * @param normalizedText * the normalized text to verify * @param sigObject @@ -163,7 +163,7 @@ public class BKUConnector implements LocalConnector * X509Certificate, CertDigest, DigestValue and the signation id-s. If the * X509Certificate is extracted it would be stored in the certificates * directory. - * + * * @param xmlResponse * the response string from the BKU sign-request * @param sigObj @@ -177,7 +177,7 @@ public class BKUConnector implements LocalConnector private void parseCreateXMLResponse(Properties response_properties, SignatureObject sigObj) throws SignatureException { String xmlResponse = response_properties.getProperty("response_string"); - + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); Pattern sig_val_p_e = Pattern.compile(""); Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); @@ -280,7 +280,7 @@ public class BKUConnector implements LocalConnector ids[2] = extractId(xmlResponse, "signed-data-object-"); ids[3] = extractId(xmlResponse, "etsi-data-reference-"); ids[4] = extractId(xmlResponse, "etsi-data-object-"); - + //TODO hotfix - already deprecated String final_ids =SignatureObject.formatSigIds(response_properties, ids); //sigObj.setSignationIDs(ids); @@ -289,7 +289,7 @@ public class BKUConnector implements LocalConnector /** * This emthod extracts id-values from a text. The id is given by the name. - * + * * @param text * the id-value that should extract from * @param name @@ -301,13 +301,13 @@ public class BKUConnector implements LocalConnector String id = null; int start_idx = text.indexOf(name) + name.length(); int end_idx = text.indexOf("\"", start_idx); - + // TODO hotfix! - already deprecated - final int quot_end_idx = end_idx; + final int quot_end_idx = end_idx; final int squot_end_idx = text.indexOf("'", start_idx); end_idx = Math.min(quot_end_idx, squot_end_idx); // TODO hotfix end! - already deprecated - + id = text.substring(start_idx, end_idx); if (logger_.isDebugEnabled()) { @@ -319,7 +319,7 @@ public class BKUConnector implements LocalConnector /** * This method reads the verify template from the file system and fills out * the template with the SignatureObject values. - * + * * @param normalizedText * the normalized text to veryfied * @param sigObject @@ -362,7 +362,7 @@ public class BKUConnector implements LocalConnector verify_template = getConnectorValueFromProfile(sigObject.getSignationType(), "bku.verify.template2"); //"./templates/BKUVerifyTemplateB64_neueBKU.xml"; sig_prop_filename = getConnectorValueFromProfile(sigObject.getSignationType(), "bku.verify.template2.SP"); //"./templates/BKUVerifyTemplateSP_neueBKU.xml"; } - + //String ver_temp_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_template)); String ver_temp_str = this.settings_.readInternalResourceAsString(verify_template); @@ -388,13 +388,18 @@ public class BKUConnector implements LocalConnector } sig_prop_str = sig_prop_str.replaceFirst("SigningTimeReplace", sigObject.getSignationDate()); - + String issuer_name = sigObject.getSignationIssuer(); // The issuer is already unicode, so it mustn't be encoded again. //byte[] issuer_name = CodingHelper.encodeUTF8(sigObject.getSignationIssuer()); // new String(issuer_name); // this would double encode the String, not to mention the missing encoding - sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", issuer_name); - + + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", issuer_name); + sig_prop_str = sig_prop_str.replace("X509IssuerNameReplace", issuer_name); + sig_prop_str = sig_prop_str.replaceFirst("X509SerialNumberReplace", sigObject.getSignationSerialNumber()); sig_prop_str = sig_prop_str.replaceFirst("DigestValueX509CertificateReplace", sigObject.getX509CertificateDigest()); sig_prop_str = sig_prop_str.replaceFirst("SigIdReplace", ids[0]); @@ -403,30 +408,30 @@ public class BKUConnector implements LocalConnector ver_temp_str = ver_temp_str.replaceFirst("CertAlgReplace", cert_alg); ver_temp_str = ver_temp_str.replaceFirst("TemplateQualifyingPropertiesReplace", sig_prop_str); byte[] sig_prop_code = CodingHelper.buildDigest(sig_prop_str.getBytes("UTF-8"), "sha1"); - + // TODO hotfix - already deprecated if (neue_bku) { final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; final int hash_end = sig_prop_str.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; assert hash_end > hash_start; - + final String string_to_be_hashed = sig_prop_str.substring(hash_start, hash_end); logger_.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); - + logger_.debug("\n--------------------- ETSI properties string to be hashed: start ---------------------"); logger_.debug(string_to_be_hashed); logger_.debug("\n--------------------- ETSI properties string to be hashed: stop ---------------------"); - + final byte [] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, "sha1"); } - + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedPropertiesReplace", sig_prop_hash); if (logger_.isDebugEnabled()) @@ -453,7 +458,7 @@ public class BKUConnector implements LocalConnector //String raw_b64 = CodingHelper.encodeUTF8AsBase64(normalizedText); String raw_b64 = CodingHelper.encodeBase64(data_value); - + ver_temp_str = ver_temp_str.replaceFirst("Base64ContentReplace", raw_b64); ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedDataReplace", object_data_hash); @@ -479,7 +484,7 @@ public class BKUConnector implements LocalConnector * This method parses the verify response string and return a * SignatureResponse object. The SignatureResponse object is filled out by the * response values from the BKU-response. - * + * * @param xmlResponse * the response values from the BKU-verify request * @return SignatureResponse object @@ -621,8 +626,8 @@ public class BKUConnector implements LocalConnector return sig_res; } - - + + public String prepareSignRequest(String userName, String signText, String signType) throws SignatureException @@ -636,7 +641,7 @@ public class BKUConnector implements LocalConnector //String sign_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); String sign_req_str = this.settings_.readInternalResourceAsString(sign_request_filename); - //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); if (logger_.isDebugEnabled()) { //logger_.debug(sign_request_filename + "_signText.xml :" + signText); @@ -660,7 +665,7 @@ public class BKUConnector implements LocalConnector SignatureObject sigObject) throws SignatureException { String verify_request = getVerifyRequestTemplateFileName(sigObject.getSignationType()); - + //String verify_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request)); String verify_req_str = this.settings_.readInternalResourceAsString(verify_request); @@ -681,7 +686,11 @@ public class BKUConnector implements LocalConnector // get the BKU-template verify_template_str = getVerifyTemplate(normalizedText, sigObject); } - verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str); + verify_req_str = verify_req_str.replace("XMLContentReplace", verify_template_str); if (logger_.isDebugEnabled()) { logger_.debug("verify_req_str.xml : " + verify_req_str); @@ -692,7 +701,7 @@ public class BKUConnector implements LocalConnector /** * Sends the request to the given URL. - * + * * @param url * The URL. * @param request_string @@ -722,7 +731,7 @@ public class BKUConnector implements LocalConnector // TODO hotfix - already deprecated String response_string = response_properties.getProperty("response_string"); - + SignatureObject sig_obj = new SignatureObject(); sig_obj.setRawSignatureResponse(response_string); try @@ -783,7 +792,7 @@ public class BKUConnector implements LocalConnector public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws SignatureException { String response_string = response_properties.getProperty("response_string"); - + if (!response_string.equals("")) { Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); @@ -880,13 +889,13 @@ public class BKUConnector implements LocalConnector /** * Returns the type of this BKU-like connector. - * + * *

    * All settings keys will be prefixed by this type. So to reuse the BKU * connector, a deriving class has to implement this method specifying an own * type. *

    - * + * * @return Returns the type of this BKU-like connector. */ protected String getType() diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java index ef355a0..d413a29 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java @@ -63,7 +63,7 @@ import at.knowcenter.wag.egov.egiz.tools.CodingHelper; /** * Connector to access the MOA service. - * + * * @deprecated * @author wlackner * @author wprinz @@ -72,7 +72,7 @@ public class MOAConnector implements Connector { /** * ConnectorInformation that identifies this Connector to the system. - * + * * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory * @see ConnectorInformation */ @@ -80,7 +80,7 @@ public class MOAConnector implements Connector /** * The class type value. - * + * *

    * Just for convenience. *

    @@ -122,7 +122,7 @@ public class MOAConnector implements Connector /** * load the inital signature settings - * + * * @see SettingsReader */ private void loadSettings() throws SignatureException @@ -148,7 +148,7 @@ public class MOAConnector implements Connector * SignatureObject is filled out by the parsed MOA-Response.
    * If an error request is send back from MOA, an error message is generated an * an exception is thrown. - * + * * @param sigType * the type of the SignatureObject that should be returned * @param userName @@ -282,7 +282,7 @@ public class MOAConnector implements Connector * SignatureValue, X509IssuerName, SigningTime, X509SerialNumber, * X509Certificate, CertDigest and DigestValues. If the X509Certificate is * extracted it would be stored in the certificates directory. - * + * * @param xmlResponse * the response string from the MOA sign-request * @param sigObj @@ -393,7 +393,7 @@ public class MOAConnector implements Connector /** * This method reads the verify template from the file system and fills out * the template with the SignatureObject values. - * + * * @param normalizedText * the normalized text to veryfied * @param sigObject @@ -453,12 +453,18 @@ public class MOAConnector implements Connector // byte[] issuer_name = // CodingHelper.encodeUTF8(sigObject.getSignationIssuer()); // new String(issuer_name) - sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", sigObject.getSignationIssuer()); + + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", sigObject.getSignationIssuer()); + sig_prop_str = sig_prop_str.replace("X509IssuerNameReplace", sigObject.getSignationIssuer()); sig_prop_str = sig_prop_str.replaceFirst("X509SerialNumberReplace", sigObject.getSignationSerialNumber()); sig_prop_str = sig_prop_str.replaceFirst("DigestValueX509CertificateReplace", sigObject.getX509CertificateDigest()); verify_req_str = verify_req_str.replaceFirst("CertAlgReplace", cert_alg); - verify_req_str = verify_req_str.replaceFirst("TemplateSignedPropertiesReplace", sig_prop_str); +// verify_req_str = verify_req_str.replaceFirst("TemplateSignedPropertiesReplace", sig_prop_str); + verify_req_str = verify_req_str.replace("TemplateSignedPropertiesReplace", sig_prop_str); byte[] sig_prop_code = CodingHelper.buildDigest(sig_prop_str.getBytes("UTF-8"), "sha1"); // added // the // ("UTF-8") @@ -509,7 +515,7 @@ public class MOAConnector implements Connector * This method generates the MOA verify prozess. It checks if the given * SignatureObject is signed by MOA or BKU. The verify template string is * filled out by the corresponding method. - * + * * @param normalizedText * the normalized text to verify * @param sigObject @@ -548,7 +554,12 @@ public class MOAConnector implements Connector BKUConnector bku_conn = new BKUConnector(); verify_template_str = bku_conn.getVerifyTemplate(normalizedText, sigObject); } - verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str); + + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str); + verify_req_str = verify_req_str.replace("XMLContentReplace", verify_template_str); verify_req_str = verify_req_str.replaceFirst("TrustProfileIDReplace", trust_profile); if (logger_.isDebugEnabled()) @@ -564,10 +575,6 @@ public class MOAConnector implements Connector } catch (WebException we) { - if (logger_.isDebugEnabled()) - { - we.printStackTrace(); - } SignatureException se = new SignatureException(we.getErrorCode(), we); throw se; } @@ -616,7 +623,7 @@ public class MOAConnector implements Connector * This method parses the verify response string and return a * SignatureResponse object. The SignatureResponse object is filled out by the * response values from the BKU-response. - * + * * @param xmlResponse * the response values from the MOA-verify request * @return SignatureResponse object @@ -639,7 +646,7 @@ public class MOAConnector implements Connector Pattern cert_qualified_p = Pattern.compile(""); Matcher cert_qualified_m = cert_qualified_p.matcher(xmlResponse); // [tknall] stop qualified certificate - + Pattern sig_chk_p_s = Pattern.compile(""); Pattern sig_chk_p_e = Pattern.compile(""); Pattern man_chk_p_s = Pattern.compile(""); @@ -671,11 +678,11 @@ public class MOAConnector implements Connector Matcher cert_m_e = cert_p_e.matcher(xmlResponse); SignatureResponse sig_res = new SignatureResponse(); - + // [tknall] start qualified certificate sig_res.setQualifiedCertificate(cert_qualified_m.find()); // [tknall] stop qualified certificate - + // public authority Pattern publicAuthority_p = Pattern.compile(""); Matcher publicAuthority_m = publicAuthority_p.matcher(xmlResponse); @@ -821,7 +828,7 @@ public class MOAConnector implements Connector * SOAP Message send and recieve by the AXIS module. The Response SOAP message * of the MOA server is parsed by AXIS and the message envelope is send back * to the calling method. - * + * * @param requestString * the request string (XML) to send. * @param serviceMode diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java index ee250ff..908ed57 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java @@ -60,14 +60,14 @@ import at.knowcenter.wag.egov.egiz.tools.CodingHelper; /** * Contains static helper methods used by the BKU Connectors. - * + * * @author wprinz */ public final class BKUHelper { private static final Pattern ALLOWED_SL_RESPONSE_PATTERN = Pattern.compile("^.*<[\\w]*:?(CreateXMLSignatureResponse|VerifyXMLSignatureResponse)[^>]*>(.*).*$", Pattern.DOTALL); - + /** * The log. */ @@ -75,21 +75,21 @@ public final class BKUHelper /** * Encodes the given SignatureData to a valid Base64Content. - * + * *

    * The data is Base64 encoded. If the mime-type suggests that the data is * binary, it is Base64 encoded for a second time. *

    - * + * * @param data * The data to be converted to a valid Base64 content. * @return Returns the Base64 content. */ public static String prepareBase64Content(SignatureData data) { - // PERF: base64 encoding needs byte array + // PERF: base64 encoding needs byte array byte [] d = DataSourceHelper.convertDataSourceToByteArray(data.getDataSource()); - + String base64 = CodingHelper.encodeBase64(d); if (data.getMimeType().equals("application/pdf")) //$NON-NLS-1$ { @@ -105,7 +105,7 @@ public final class BKUHelper *

    * This is useful for building the hash. *

    - * + * * @param data * The data to be prepared. * @return Returns the prepared data. @@ -114,7 +114,7 @@ public final class BKUHelper { // PERF: prepareEnvelopingData needs byte array byte[] enc = DataSourceHelper.convertDataSourceToByteArray(data.getDataSource()); - + if (data.getMimeType().equals("application/pdf")) //$NON-NLS-1$ { log.debug("The data is application/pdf - so the binary data is Base64 encoded."); //$NON-NLS-1$ @@ -125,7 +125,6 @@ public final class BKUHelper } catch (UnsupportedEncodingException e) { - e.printStackTrace(); throw new RuntimeException("Very Strange: US-ASCII encoding not supported???", e); //$NON-NLS-1$ } } @@ -135,7 +134,7 @@ public final class BKUHelper /** * Checks the response xml for an error description and if found throws an * appropriate exception. - * + * * @param response_string * The response xml. * @throws ConnectorException @@ -169,29 +168,29 @@ public final class BKUHelper throw new ExternalErrorException(error_code, error_mess); } log.debug("No error found. Assuring that CreateXMLSignatureResponse or VerifyXMLSignatureResponse elements are available."); - + // assure that a CreateXMLSignatureResponse or a VerifyXMLSignatureResponse is available Matcher slMatcher = ALLOWED_SL_RESPONSE_PATTERN.matcher(response_string); if (!slMatcher.matches()) { throw new ConnectorException(ErrorCode.UNABLE_TO_RECEIVE_SUITABLE_RESPONSE, "No suitable response received: " + response_string); } - + } /** * This method parses the BKU-Response string. - * + * *

    * It separates the SignatureValue, X509IssuerName, SigningTime, * X509SerialNumber, X509Certificate, CertDigest, DigestValue and the * signation id-s. If the X509Certificate is extracted it would be stored in * the certificates directory. *

    - * + * * @param xmlResponse * The response string. * @return Returns the parsed signature object holding the data. - * + * * @throws ConnectorException * ErrorCode (303, 304) * @see SignatureObject @@ -355,7 +354,7 @@ public final class BKUHelper ids[2] = extractId(xmlResponse, "signed-data-object-"); //$NON-NLS-1$ ids[3] = extractId(xmlResponse, "etsi-data-reference-"); //$NON-NLS-1$ ids[4] = extractId(xmlResponse, "etsi-data-object-"); //$NON-NLS-1$ - + String algs = AlgorithmSuiteUtil.extractAlgorithmSuiteString(xmlResponse); SignSignatureObject so = new SignSignatureObject(); @@ -363,26 +362,26 @@ public final class BKUHelper so.issuer = iss_nam; so.signatureValue = sig_val; so.x509Certificate = cert; - + AlgorithmSuiteObject suite = new AlgorithmSuiteObject(algs, false); so.sigAlgorithm = AlgorithmMapper.getUri(suite.getSignatureMethod()); - + String defaultCertAlg = environment.getDefaultAlgForCert(cert); if (AlgorithmSuiteUtil.isDefaultCertAlg(algs, defaultCertAlg)) { // do not embed default alg algs = null; - } + } String final_ids = id_formatter.formatIds(ids, algs); so.id = final_ids; - + return so; } /** * Removes all whitespaces ("\\s") from the String. - * + * * @param str * The String. * @return The String with all whitespaces removed. @@ -394,7 +393,7 @@ public final class BKUHelper /** * This emthod extracts id-values from a text. The id is given by the name. - * + * * @param text * the id-value that should extract from * @param name @@ -411,7 +410,7 @@ public final class BKUHelper return ""; } // stop - + int start_idx = startOfName + name.length(); int end_idx = text.indexOf("\"", start_idx); //$NON-NLS-1$ @@ -430,7 +429,7 @@ public final class BKUHelper * This method parses the verify response string and return a * SignatureResponse object. The SignatureResponse object is filled out by the * response values from the BKU-response. - * + * * @param xmlResponse * the response values from the BKU-verify request * @return SignatureResponse object @@ -521,14 +520,14 @@ public final class BKUHelper if (hash_data_m_s.find() && hash_data_m_e.find()) { String hashInputData = xmlResponse.substring(hash_data_m_s.end(), hash_data_m_e.start()); - + Pattern b64_p_s = Pattern.compile(""); //$NON-NLS-1$ Pattern b64_p_e = Pattern.compile(""); //$NON-NLS-1$ Matcher b64_m_s = b64_p_s.matcher(hashInputData); Matcher b64_m_e = b64_p_e.matcher(hashInputData); boolean hashInputDataFound = b64_m_s.find() && b64_m_e.find(); - + String b64 = hashInputDataFound ? hashInputData.substring(b64_m_s.end(), b64_m_e.start()) : ""; sig_res.setHashInputData(b64); @@ -623,7 +622,7 @@ public final class BKUHelper public static String formDateTimeElement(Date verificationTime, String namespace) { String nsPrefix = StringUtils.isBlank(namespace) ? "" : (namespace + ":"); - + String dateTimeElement = ""; if (verificationTime != null) { @@ -633,25 +632,25 @@ public final class BKUHelper df.setTimeZone(TimeZone.getTimeZone("UTC")); String dateTime = df.format(verificationTime) + "Z"; log.debug("DateTime (VerificationTime in UTC) = " + dateTime); - + dateTimeElement = "<" + nsPrefix + "DateTime>" + dateTime + ""; }; return dateTimeElement; } - + public static String getBKUIdentifier(Properties parsedResponseProperties) { - + // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.browser String bkuServerHeader = parsedResponseProperties.getProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY); // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.dataurl String bkuUserAgentHeader = parsedResponseProperties.getProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY); - + String bkuSignatureLayout = parsedResponseProperties.getProperty(BKUPostConnection.BKU_SIGNATURE_LAYOUT_HEADER_KEY); - + return getBKUIdentifier(bkuServerHeader, bkuUserAgentHeader, bkuSignatureLayout); } - + public static String getBKUIdentifier(String bkuServerHeader, String bkuUserAgentHeader, String bkuSignatureLayout) { log.debug("BKU response header \"user-agent\": " + bkuUserAgentHeader); @@ -659,7 +658,7 @@ public final class BKUHelper log.trace("BKU response header \"" + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "\": " + bkuSignatureLayout); String result = null; - + if (bkuServerHeader != null) { result = bkuServerHeader; } else if (bkuUserAgentHeader != null) { @@ -667,7 +666,7 @@ public final class BKUHelper } else { log.warn("Unable to find any BKU identifier (neither header value \"user-agent\" nor \"server\".)"); } - + if (bkuSignatureLayout != null && result != null) { log.debug("BKU response header \"" + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "\" found."); String signatureLayoutData = " " + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "/" + bkuSignatureLayout; @@ -678,18 +677,18 @@ public final class BKUHelper log.debug("Signature layout already encoded in server/user-agent header."); } } - + if (result != null) { log.debug("Returning BKU identifier \"" + result + "\""); } else { log.debug("Returning null BKU identifier."); } - + return result; } public static String getBKUIdentifier(LocalBKUParams bkuParams) { return getBKUIdentifier(bkuParams.getServer(), bkuParams.getUserAgent(), bkuParams.getSignatureLayout()); } - + } diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java index a8de41e..6926d2b 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java @@ -55,11 +55,11 @@ import at.knowcenter.wag.egov.egiz.tools.CodingHelper; /** * Connects to the BKU using the detached multipart/formdata requests. - * + * *

    * This feature is available since BKU version 2.7.4. *

    - * + * * @author wprinz */ public class DetachedBKUConnector implements Connector, LocalConnector @@ -85,12 +85,12 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Constructor that builds the configuration environment for this connector * according to the given profile. - * + * *

    * If confuguration parameters are not defined on that profile, the default * parameters defined in the configuration are used. *

    - * + * * @param connectorParameters * The connectot parameters. * @throws ConnectorException @@ -101,10 +101,10 @@ public class DetachedBKUConnector implements Connector, LocalConnector this.params = connectorParameters; this.environment = new Environment(this.params.getProfileId(), loc_ref_content); } - + /** * Prepares the sign request xml to be sent using the sign request template. - * + * * @param data * The SignatureData. * @return Returns the sign request xml to be sent. @@ -120,7 +120,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector String sign_keybox_identifier = this.environment.getSignKeyboxIdentifier(); String mime_type = data.getMimeType(); String loc_ref_content = this.environment.getLocRefContent(); - + if (log.isDebugEnabled()) { log.debug("sign keybox identifier = " + sign_keybox_identifier); //$NON-NLS-1$ @@ -139,7 +139,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Analyzes the sign response xml and extracts the signature data. - * + * * @param response_properties * The response properties containing the response String and * transport related information. @@ -155,14 +155,14 @@ public class DetachedBKUConnector implements Connector, LocalConnector String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties); log.debug("BKU identifier: " + (bkuIdentifier != null ? ("\"" + bkuIdentifier + "\"") : "n/a")); - + SignatureLayoutHandler sigLayout; try { sigLayout = SignatureLayoutHandlerFactory.getSignatureLayoutHandlerInstance(bkuIdentifier); } catch (SettingsException e) { throw new ConnectorException(e.getErrorCode(), e.getMessage()); } - + BKUHelper.checkResponseForError(response_string); SignSignatureObject so = sigLayout.parseCreateXMLSignatureResponse(response_string, this.environment); @@ -225,15 +225,15 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Sends the request and data to the given URL. - * + * *

    * This method mainly handles communication exceptions. The actual send work * is done by doPostRequestMultipart. *

    - * + * * @see BKUPostConnection#doPostRequestMultipart(String, String, * SignatureData) - * + * * @param url * The URL to send the request to. * @param request_string @@ -262,7 +262,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Performs a sign. - * + * * @param data * The data to be signed. * @return Returns the signature object containing the signature data. @@ -289,7 +289,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Performs a verification. - * + * * @param data * The data to be verified. * @param so @@ -331,7 +331,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Prepares the verify request xml to be sent using the verify request * template. - * + * * @param data * The SignatureData. * @param so @@ -345,7 +345,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector String verify_request_template = this.environment.getVerifyRequestTemplate(); String xml_content = null; - + if (dsigData != null && dsigData.getXmlDsig() != null) { xml_content = dsigData.getXmlDsig(); @@ -355,16 +355,18 @@ public class DetachedBKUConnector implements Connector, LocalConnector xml_content = chooseAndCreateXMLDsig(data, so); } - - - String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + String verify_request_xml = verify_request_template.replace(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, this.environment.getLocRefContent()); verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.DATE_TIME_REPLACE, BKUHelper.formDateTimeElement(this.params.getVerificationTime(), "sl")); return verify_request_xml; } - - private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { // MOA if (SigKZIDHelper.isMOASigned(so)) { @@ -379,7 +381,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector log.debug("Algorithm = " + algorithmId); LocRefDetachedMOCCAConnector mocca_connector = new LocRefDetachedMOCCAConnector(this.params, "not needed here", algorithmId); return mocca_connector.prepareXMLContent(data, so); - + // ATRUST } else if (SigKZIDHelper.isATrustSigned(so)) { log.debug("ATrust signature detected"); @@ -391,20 +393,20 @@ public class DetachedBKUConnector implements Connector, LocalConnector else if (SigKZIDHelper.isBKUSigned(so)) { log.debug("TD signature signature detected."); return prepareXMLContent(data, so); - } + } // unknown else { throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "Unsupported signature (" + so.id + ", " +so.kz + "). Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); } - } + } /** * Prepares the XML content the holds the actual signature data. - * + * *

    * This strongly rebuilds the XML content as retuned from a sign request. *

    - * + * * @param data * The data. * @param so @@ -421,13 +423,13 @@ public class DetachedBKUConnector implements Connector, LocalConnector String ids_string = so.getSigID(); String[] ids = SignatureObject.parseSigIds(ids_string); - + X509Certificate cert = so.getX509Certificate(); - + // dferbas AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); - + // data digest replace { // byte[] data_value = data.getData(); @@ -457,7 +459,11 @@ public class DetachedBKUConnector implements Connector, LocalConnector verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_ID_REPLACE, ids[0]); verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); - verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replace(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); // SigDataRefReplace already done above verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); @@ -495,7 +501,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Analyzes the verify response string. - * + * * @param response_properties * The response properties containing the response XML. * @return Returns the SignatureResponse containing the verification result. @@ -518,7 +524,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Holds environment configuration information like templates. - * + * * @author wprinz */ public static class Environment extends ConnectorEnvironment @@ -537,27 +543,27 @@ public class DetachedBKUConnector implements Connector, LocalConnector * The configuration key of the sign URL. */ protected static final String SIGN_URL_KEY = "bku.sign.url"; //$NON-NLS-1$ - + /** * BKU template file prefix */ protected static final String TEMPLATE_FILE_PREFIX = "/templates/bku."; - + /** * signing file template sufix */ protected static final String SIGN_TEMPLATE_FILE_SUFIX = ".sign.xml"; - + /** * verifing template file sufix */ - protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml"; + protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml"; /** * verifing file template key sufix */ protected static final String VERIFY_TEMPLATE_SUFIX = ".verify.template.xml"; - + /** * The configuration key of the verify request template. */ @@ -605,7 +611,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Initializes the environment with a given profile. - * + * * @param profile * The configuration profile. * @throws ConnectorException @@ -614,7 +620,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector public Environment(String profile, String loc_ref_content) throws ConnectorException { this.profile = profile; - + this.loc_ref_content = loc_ref_content; SettingsReader settings = null; @@ -626,7 +632,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector { throw new ConnectorException(300, e); } - + this.sign_keybox_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEYBOX_IDENTIFIER_KEY); String sign_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.bku.algorithm.id") + SIGN_TEMPLATE_FILE_SUFIX; @@ -634,7 +640,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector // try to load template from file //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); - + // when first load failed (the template file does'nt exist), load it from default template file if(this.sign_request_template == null) { @@ -642,7 +648,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); } - + if (this.sign_request_template == null) { throw new ConnectorException(300, "Can not read the create xml request template"); //$NON-NLS-1$ @@ -651,20 +657,20 @@ public class DetachedBKUConnector implements Connector, LocalConnector this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); // verify - + String verify_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.bku.algorithm.id") + VERIFY_REQUEST_TEMPLATE_FILE_SUFIX; - + // try to load template file for verifing //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); - + if(this.verify_request_template == null) { verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); } - + if (this.verify_request_template == null) { throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); //$NON-NLS-1$ @@ -674,7 +680,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector String verify_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.bku.algorithm.id") + VERIFY_TEMPLATE_SUFIX; //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); this.verify_template = settings.readInternalResourceAsString(verify_filename); - + if(this.verify_template == null) { verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); @@ -702,7 +708,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Returns the LocRef content. - * + * * @return Returns the LocRef content. */ public String getLocRefContent() @@ -712,7 +718,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Returns the sign keybox identifier. - * + * * @return Returns the sign keybox identifier. */ public String getSignKeyboxIdentifier() @@ -722,7 +728,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Returns the sign request template. - * + * * @return Returns the sign request template. */ public String getSignRequestTemplate() @@ -732,7 +738,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Returns the sign URL. - * + * * @return Returns the sign URL. */ public String getSignURL() @@ -742,7 +748,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Returns the verify request template. - * + * * @return Returns the verify request template. */ public String getVerifyRequestTemplate() @@ -752,7 +758,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Returns the verify template. - * + * * @return Returns the verify template. */ public String getVerifyTemplate() @@ -762,7 +768,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Returns the verify URL. - * + * * @return Returns the verify URL. */ public String getVerifyURL() @@ -772,7 +778,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Returns the ecdsa cert alg property. - * + * * @return Returns the ecdsa cert alg property. */ public String getCertAlgEcdsa() @@ -782,7 +788,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Returns the rsa cert alg property. - * + * * @return Returns the rsa cert alg property. */ public String getCertAlgRsa() @@ -793,7 +799,7 @@ public class DetachedBKUConnector implements Connector, LocalConnector /** * Reads the configuration entry given by the key, first from the given * profile, if not found from the defaults. - * + * * @param settings * The settings. * @param profile diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java index 170cc45..22318a2 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java @@ -52,7 +52,7 @@ import at.knowcenter.wag.egov.egiz.tools.CodingHelper; /** * @author wprinz - * + * */ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector { @@ -72,16 +72,16 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Constructor that builds the configuration environment for this connector * according to the given profile. - * + * *

    * If confuguration parameters are not defined on that profile, the default * parameters defined in the configuration are used. *

    - * + * *

    * This is the new "hotfix" base64 connector. *

    - * + * * @param profile * The profile from which the Environment should be assembled. * @throws ConnectorException @@ -137,7 +137,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector // /** // * This emthod extracts id-values from a text. The id is given by the name. -// * +// * // * @param text // * the id-value that should extract from // * @param name @@ -166,11 +166,11 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Prepares the XML content the holds the actual signature data. - * + * *

    * This strongly rebuilds the XML content as retuned from a sign request. *

    - * + * * @param data * The data. * @param so @@ -186,13 +186,13 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector { String ids_string = so.getSigID(); String[] ids = SignatureObject.parseSigIds(ids_string); - + X509Certificate cert = so.getX509Certificate(); - + // dferbas AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); - + // data digest replace byte[] data_value = BKUHelper.prepareEnvelopingData(data); { @@ -225,7 +225,11 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_ID_REPLACE, ids[0]); verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); - verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replace(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); // SigDataRefReplace already done above @@ -276,7 +280,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Prepares the sign request xml to be sent using the sign request template. - * + * * @param data * The SignatureData. * @return Returns the sign request xml to be sent. @@ -302,7 +306,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Prepares the verify request xml to be sent using the verify request * template. - * + * * @param data * The SignatureData. * @param so @@ -325,7 +329,11 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector xml_content = chooseAndCreateXMLDsig(data, so); } - String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + String verify_request_xml = verify_request_template.replace(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); // log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); @@ -349,7 +357,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Sends the request to the given URL. - * + * * @param url * The URL. * @param request_string @@ -373,7 +381,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Analyzes the sign response xml and extracts the signature data. - * + * * @param response_properties * The response properties containing the response String and * transport related information. @@ -391,7 +399,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties); log.debug("BKU identifier: \"" + bkuIdentifier + "\""); - + SignSignatureObject so = BKUHelper.parseCreateXMLResponse(response_string, new HotfixIdFormatter(), this.environment); log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ @@ -400,7 +408,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Analyzes the verify response string. - * + * * @param response_properties * The response properties containing the response XML. * @return Returns the SignatureResponse containing the verification result. @@ -423,7 +431,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Holds environment configuration information like templates. - * + * * @author wprinz */ public static class Environment extends ConnectorEnvironment @@ -488,7 +496,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Initializes the environment with a given profile. - * + * * @param profile * The configuration profile. * @throws ConnectorException @@ -524,7 +532,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); log.debug("Verify request template filename = " + verify_request_filename); - + if (this.verify_request_template == null) { throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); //$NON-NLS-1$ @@ -555,7 +563,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Returns the sign keybox identifier. - * + * * @return Returns the sign keybox identifier. */ public String getSignKeyboxIdentifier() @@ -565,7 +573,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Returns the sign request template. - * + * * @return Returns the sign request template. */ public String getSignRequestTemplate() @@ -575,7 +583,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Returns the sign URL. - * + * * @return Returns the sign URL. */ public String getSignURL() @@ -585,7 +593,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Returns the verify request template. - * + * * @return Returns the verify request template. */ public String getVerifyRequestTemplate() @@ -595,7 +603,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Returns the verify template. - * + * * @return Returns the verify template. */ public String getVerifyTemplate() @@ -605,7 +613,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Returns the verify URL. - * + * * @return Returns the verify URL. */ public String getVerifyURL() @@ -615,7 +623,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Returns the ecdsa cert alg property. - * + * * @return Returns the ecdsa cert alg property. */ public String getCertAlgEcdsa() @@ -625,7 +633,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Returns the rsa cert alg property. - * + * * @return Returns the rsa cert alg property. */ public String getCertAlgRsa() @@ -636,7 +644,7 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector /** * Reads the configuration entry given by the key, first from the given * profile, if not found from the defaults. - * + * * @param settings * The settings. * @param profile diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java index ea90841..07e9ccd 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java @@ -55,7 +55,7 @@ import at.knowcenter.wag.egov.egiz.tools.FileHelper; /** * Connects to MOA providing the Data detached as LocRef on a local resource. - * + * * @author wprinz */ public class DetachedLocRefMOAConnector implements Connector @@ -79,12 +79,12 @@ public class DetachedLocRefMOAConnector implements Connector /** * Constructor that builds the configuration environment for this connector * according to the given profile. - * + * *

    * If confuguration parameters are not defined on that profile, the default * parameters defined in the configuration are used. *

    - * + * * @param profile * The profile from which the Environment should be assembled. * @throws SettingsException @@ -183,7 +183,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Prepares the verify request xml to be sent using the verify request * template. - * + * * @param data * The SignatureData. * @param so @@ -206,7 +206,11 @@ public class DetachedLocRefMOAConnector implements Connector xml_content = chooseAndCreateXMLDsig(data, so); } - String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + String verify_request_xml = verify_request_template.replace(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.TRUST_PROFILE_ID_REPLACE, this.environment.getVerifyTrustProfileId()); verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, this.environment.getSignatureDataUrl()); @@ -217,7 +221,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Analyzes the verify response string. - * + * * @param response_properties * The response properties containing the response XML. * @return Returns the SignatureResponse containing the verification result. @@ -272,7 +276,11 @@ public class DetachedLocRefMOAConnector implements Connector // Qualified Properties replaces verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); - verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replace(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); // SigDataRefReplace already done above verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); @@ -323,7 +331,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Holds environment configuration information like templates. - * + * * @author wprinz */ public static class Environment extends ConnectorEnvironment @@ -417,7 +425,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Initializes the environment with a given profile. - * + * * @param profile * The configuration profile. * @throws SettingsException @@ -516,7 +524,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Returns the URL where to load the detached data from. - * + * * @return Returns the URL where to load the detached data from. */ public String getSignatureDataUrl() @@ -526,7 +534,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Returns the sign key identifier. - * + * * @return Returns the sign key identifier. */ public String getSignKeyIdentifier() @@ -536,7 +544,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Returns the sign request template. - * + * * @return Returns the sign request template. */ public String getSignRequestTemplate() @@ -546,7 +554,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Returns the sign URL. - * + * * @return Returns the sign URL. */ public String getSignURL() @@ -556,7 +564,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Returns the verify request template. - * + * * @return Returns the verify request template. */ public String getVerifyRequestTemplate() @@ -566,7 +574,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Returns the verify template. - * + * * @return Returns the verify template. */ public String getVerifyTemplate() @@ -576,7 +584,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Returns the verify URL. - * + * * @return Returns the verify URL. */ public String getVerifyURL() @@ -586,7 +594,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Returns the verify trust profile id. - * + * * @return Returns the verify trust profile id. */ public String getVerifyTrustProfileId() @@ -596,7 +604,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Returns the ecdsa cert alg property. - * + * * @return Returns the ecdsa cert alg property. */ public String getCertAlgEcdsa() @@ -606,7 +614,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Returns the rsa cert alg property. - * + * * @return Returns the rsa cert alg property. */ public String getCertAlgRsa() @@ -617,7 +625,7 @@ public class DetachedLocRefMOAConnector implements Connector /** * Reads the configuration entry given by the key, first from the given * profile, if not found from the defaults. - * + * * @param settings * The settings. * @param profile diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java index 6f2d171..4a33fc8 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java @@ -54,7 +54,7 @@ import at.knowcenter.wag.egov.egiz.tools.FileHelper; /** * @author wprinz - * + * */ public class EnvelopingBase64MOAConnector implements Connector { @@ -69,18 +69,18 @@ public class EnvelopingBase64MOAConnector implements Connector * other configurable elements. */ protected Environment environment = null; - + protected ConnectorParameters params = null; /** * Constructor that builds the configuration environment for this connector * according to the given profile. - * + * *

    * If confuguration parameters are not defined on that profile, the default * parameters defined in the configuration are used. *

    - * + * * @param profile * The profile from which the Environment should be assembled. * @throws ConnectorException @@ -150,7 +150,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Prepares the sign request xml to be sent using the sign request template. - * + * * @param data * The SignatureData. * @return Returns the sign request xml to be sent. @@ -176,7 +176,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Prepares the verify request xml to be sent using the verify request * template. - * + * * @param data * The SignatureData. * @param so @@ -199,7 +199,11 @@ public class EnvelopingBase64MOAConnector implements Connector xml_content = chooseAndCreateXMLDsig(data, so); } - String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + String verify_request_xml = verify_request_template.replace(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.TRUST_PROFILE_ID_REPLACE, this.environment.getVerifyTrustProfileId()); String returnHashInputDataElement = ""; @@ -208,10 +212,10 @@ public class EnvelopingBase64MOAConnector implements Connector returnHashInputDataElement = MOASoapWithAttachmentConnector.RETURN_HASH_INPUT_DATA; } verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.RETURN_HASH_INPUT_DATA_REPLACE, returnHashInputDataElement); - + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.DATE_TIME_REPLACE, BKUHelper.formDateTimeElement(this.params.getVerificationTime())); - + log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); return verify_request_xml; @@ -219,7 +223,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Analyzes the sign response xml and extracts the signature data. - * + * * @param response_properties * The response properties containing the response String and * transport related information. @@ -243,7 +247,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Analyzes the verify response string. - * + * * @param response_properties * The response properties containing the response XML. * @return Returns the SignatureResponse containing the verification result. @@ -266,11 +270,11 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Prepares the XML content the holds the actual signature data. - * + * *

    * This strongly rebuilds the XML content as retuned from a sign request. *

    - * + * * @param data * The data. * @param so @@ -285,7 +289,7 @@ public class EnvelopingBase64MOAConnector implements Connector try { X509Certificate cert = so.getX509Certificate(); - + // dferbas AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); @@ -311,7 +315,11 @@ public class EnvelopingBase64MOAConnector implements Connector // Qualified Properties replaces verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); - verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replace(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); // SigDataRefReplace already done above @@ -339,7 +347,7 @@ public class EnvelopingBase64MOAConnector implements Connector // Base64 content replace -> do this at last for performance String base64 = CodingHelper.encodeBase64(data_value); verify_xml = verify_xml.replaceFirst(TemplateReplaces.BASE64_CONTENT_REPLACE, base64); - + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ return verify_xml; } @@ -352,7 +360,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Holds environment configuration information like templates. - * + * * @author wprinz */ public static class Environment extends ConnectorEnvironment @@ -401,7 +409,7 @@ public class EnvelopingBase64MOAConnector implements Connector * The configuration key for the RSA cert alg property. */ protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ - + protected String profile = null; protected String sign_key_identifier = null; @@ -424,7 +432,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Initializes the environment with a given profile. - * + * * @param profile * The configuration profile. * @throws ConnectorException @@ -433,7 +441,7 @@ public class EnvelopingBase64MOAConnector implements Connector public Environment(String profile, String signKeyIdentifier) throws ConnectorException { this.profile = profile; - + SettingsReader settings = null; try { @@ -449,7 +457,7 @@ public class EnvelopingBase64MOAConnector implements Connector this.sign_key_identifier = signKeyIdentifier; } else - { + { this.sign_key_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEY_IDENTIFIER_KEY); } @@ -488,7 +496,7 @@ public class EnvelopingBase64MOAConnector implements Connector this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); } - + public String getProfile() { return this.profile; @@ -496,7 +504,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Returns the sign key identifier. - * + * * @return Returns the sign key identifier. */ public String getSignKeyIdentifier() @@ -506,7 +514,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Returns the sign request template. - * + * * @return Returns the sign request template. */ public String getSignRequestTemplate() @@ -516,7 +524,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Returns the sign URL. - * + * * @return Returns the sign URL. */ public String getSignURL() @@ -526,7 +534,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Returns the verify request template. - * + * * @return Returns the verify request template. */ public String getVerifyRequestTemplate() @@ -536,7 +544,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Returns the verify template. - * + * * @return Returns the verify template. */ public String getVerifyTemplate() @@ -546,7 +554,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Returns the verify URL. - * + * * @return Returns the verify URL. */ public String getVerifyURL() @@ -556,7 +564,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Returns the verify trust profile id. - * + * * @return Returns the verify trust profile id. */ public String getVerifyTrustProfileId() @@ -566,7 +574,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Returns the ecdsa cert alg property. - * + * * @return Returns the ecdsa cert alg property. */ public String getCertAlgEcdsa() @@ -576,7 +584,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Returns the rsa cert alg property. - * + * * @return Returns the rsa cert alg property. */ public String getCertAlgRsa() @@ -587,7 +595,7 @@ public class EnvelopingBase64MOAConnector implements Connector /** * Reads the configuration entry given by the key, first from the given * profile, if not found from the defaults. - * + * * @param settings * The settings. * @param profile diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java index db0a04f..401921b 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java @@ -54,7 +54,7 @@ import at.knowcenter.wag.egov.egiz.tools.CodingHelper; /** * Connects to MOA providing the Data detached as LocRef on a local resource. - * + * * @author wprinz */ public class MOASoapWithAttachmentConnector implements Connector @@ -72,9 +72,9 @@ public class MOASoapWithAttachmentConnector implements Connector private static Log log = LogFactory.getLog(MOASoapWithAttachmentConnector.class); protected static final String MULTIPART_LOC_REF_CONTENT = "formdata:fileupload"; //$NON-NLS-1$ - + protected static final String RETURN_HASH_INPUT_DATA = ""; //$NON-NLS-1$ - + /** * The connector parameters. */ @@ -85,17 +85,17 @@ public class MOASoapWithAttachmentConnector implements Connector * other configurable elements. */ protected Environment environment = null; - - + + /** * Constructor that builds the configuration environment for this connector * according to the given profile. - * + * *

    * If confuguration parameters are not defined on that profile, the default * parameters defined in the configuration are used. *

    - * + * * @param connectorParameters * The parameters for this connector. * @throws ConnectorException @@ -193,7 +193,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Prepares the verify request xml to be sent using the verify request * template. - * + * * @param data * The SignatureData. * @param so @@ -216,32 +216,36 @@ public class MOASoapWithAttachmentConnector implements Connector xml_content = chooseAndCreateXMLDsig(data, so); } - String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + String verify_request_xml = verify_request_template.replace(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.TRUST_PROFILE_ID_REPLACE, this.environment.getVerifyTrustProfileId()); verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, this.environment.getSignatureDataUrl()); - + String returnHashInputDataElement = ""; if (this.params.isReturnHashInputData()) { returnHashInputDataElement = RETURN_HASH_INPUT_DATA; } verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.RETURN_HASH_INPUT_DATA_REPLACE, returnHashInputDataElement); - + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.DATE_TIME_REPLACE, BKUHelper.formDateTimeElement(this.params.getVerificationTime())); - + log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); return verify_request_xml; } - + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { - + // MOA if (SigKZIDHelper.isMOASigned(so)) { log.debug("MOA signature detected."); return prepareXMLContent(data, so); - + // MOCCA } else if (SigKZIDHelper.isMOCCASigned(so)) { log.debug("MOCCA signature detected."); @@ -255,7 +259,7 @@ public class MOASoapWithAttachmentConnector implements Connector log.debug("A-Trust signature detected."); this.environment.reInitVerifyTemplate(ATRUST_VERIFY_TEMPLATE_KEY); return prepareXMLContent(data, so); - + // TD bku } else if (SigKZIDHelper.isBKUSigned(so)) { log.debug("TD bku signature detected."); @@ -263,13 +267,13 @@ public class MOASoapWithAttachmentConnector implements Connector return bku_connector.prepareXMLContent(data, so); } else { throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "Unsupported signature (" + so.id + ", " +so.kz + "). Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); - + } } - + /** * Analyzes the verify response string. - * + * * @param response_properties * The response properties containing the response XML. * @return Returns the SignatureResponse containing the verification result. @@ -298,7 +302,7 @@ public class MOASoapWithAttachmentConnector implements Connector String verify_xml = null; X509Certificate cert = so.getX509Certificate(); - + // dferbas AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); @@ -326,7 +330,11 @@ public class MOASoapWithAttachmentConnector implements Connector // Qualified Properties replaces verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); - verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replace(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); // SigDataRefReplace already done above verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); @@ -367,23 +375,11 @@ public class MOASoapWithAttachmentConnector implements Connector { try { - // for performance measurement -// long startTime = 0; -// if (log.isInfoEnabled()) { -// startTime = System.currentTimeMillis(); -// } - + // Properties response_properties = MOASoapConnection.connectMOA(request_string, MOASoapConnection.SERVICE_SIGN, url); log.debug("Connecting to " + url); Properties response_properties = MOASoapConnection.doPostRequestMultipart(url,mode, request_string, data ); - - // for performance measurement -// if (log.isInfoEnabled()) { -// long endTime = System.currentTimeMillis(); -// String toReport = "MOA-PROCESSING;-;-;" + (endTime - startTime) + ";"; -// log.info(toReport); -// } - + return response_properties; } catch (Exception e) @@ -391,14 +387,14 @@ public class MOASoapWithAttachmentConnector implements Connector throw new ConnectorException(330, e); } } - + public void reInitVerifyTemplate(String templatePropKey) throws ConnectorException { this.environment.reInitVerifyTemplate(templatePropKey); } /** * Holds environment configuration information like templates. - * + * * @author wprinz */ public static class Environment extends ConnectorEnvironment @@ -490,7 +486,7 @@ public class MOASoapWithAttachmentConnector implements Connector protected String cert_alg_rsa = null; - + public void reInitVerifyTemplate(String templatePropKey) throws ConnectorException { SettingsReader settings = null; try @@ -501,14 +497,14 @@ public class MOASoapWithAttachmentConnector implements Connector { throw new ConnectorException(300, e); } - + String verify_request_filename = getConnectorValueFromProfile(settings, this.profile, templatePropKey); this.verify_template = settings.readInternalResourceAsString(verify_request_filename); - + } /** * Initializes the environment with a given profile. - * + * * @param profile * The configuration profile. * @throws SettingsException @@ -537,7 +533,7 @@ public class MOASoapWithAttachmentConnector implements Connector this.sign_key_identifier = signKeyIdentifier; } else - { + { this.sign_key_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEY_IDENTIFIER_KEY); } @@ -570,7 +566,7 @@ public class MOASoapWithAttachmentConnector implements Connector if (this.verify_request_template == null) { - verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); } @@ -614,7 +610,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Returns the URL where to load the detached data from. - * + * * @return Returns the URL where to load the detached data from. */ public String getSignatureDataUrl() @@ -624,7 +620,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Returns the sign key identifier. - * + * * @return Returns the sign key identifier. */ public String getSignKeyIdentifier() @@ -634,7 +630,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Returns the sign request template. - * + * * @return Returns the sign request template. */ public String getSignRequestTemplate() @@ -644,7 +640,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Returns the sign URL. - * + * * @return Returns the sign URL. */ public String getSignURL() @@ -654,7 +650,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Returns the verify request template. - * + * * @return Returns the verify request template. */ public String getVerifyRequestTemplate() @@ -664,7 +660,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Returns the verify template. - * + * * @return Returns the verify template. */ public String getVerifyTemplate() @@ -674,7 +670,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Returns the verify URL. - * + * * @return Returns the verify URL. */ public String getVerifyURL() @@ -684,7 +680,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Returns the verify trust profile id. - * + * * @return Returns the verify trust profile id. */ public String getVerifyTrustProfileId() @@ -694,7 +690,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Returns the ecdsa cert alg property. - * + * * @return Returns the ecdsa cert alg property. */ public String getCertAlgEcdsa() @@ -704,7 +700,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Returns the rsa cert alg property. - * + * * @return Returns the rsa cert alg property. */ public String getCertAlgRsa() @@ -715,7 +711,7 @@ public class MOASoapWithAttachmentConnector implements Connector /** * Reads the configuration entry given by the key, first from the given * profile, if not found from the defaults. - * + * * @param settings * The settings. * @param profile diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java index 12fc709..f9fe70b 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java @@ -120,10 +120,10 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { * @throws ConnectorException Thrown in case of an error. */ public SignSignatureObject doSign(SignatureData data) throws ConnectorException { - log.debug("doSign:"); + log.debug("doSign:"); String sign_request_xml = prepareSignRequest(data); - log.debug("sign_request_xml = " + sign_request_xml); + log.debug("sign_request_xml = " + sign_request_xml); String url = this.environment.getSignURL(); Properties response_properties = sendRequest(url, sign_request_xml, data); @@ -132,7 +132,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { sso.response_properties = response_properties; - log.debug("doSign finished."); + log.debug("doSign finished."); return sso; } @@ -148,12 +148,12 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { * This method analyzes a signature response of the signature device. * @param response_properties The response elements of the signature device. * @return The parsed signed signature object. - * @throws ConnectorException Thrown in case of an error. + * @throws ConnectorException Thrown in case of an error. */ public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException { - log.debug("analyzeSignResponse:"); + log.debug("analyzeSignResponse:"); String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); - + String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties); log.debug("BKU identifier: \"" + bkuIdentifier + "\""); SignatureLayoutHandler sigLayout; @@ -162,13 +162,13 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { } catch (SettingsException e) { throw new ConnectorException(e.getErrorCode(), e.getMessage()); } - + BKUHelper.checkResponseForError(response_string); - + // SignSignatureObject so = MOCCAHelper.parseCreateXMLResponse(response_string, new DetachedMOCIdFormatter()); SignSignatureObject so = sigLayout.parseCreateXMLSignatureResponse(response_string, this.environment); so.response_properties = response_properties; - log.debug("analyzeSignResponse finished."); + log.debug("analyzeSignResponse finished."); return so; } @@ -187,7 +187,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { * @throws ConnectorException Thrown in case of an error. */ public String prepareSignRequest(SignatureData data) throws ConnectorException { - log.debug("prepareSignRequestDetached:"); + log.debug("prepareSignRequestDetached:"); String sign_request_template = this.environment.getSignRequestTemplate(); @@ -196,9 +196,9 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { String loc_ref_content = this.environment.getLocRefContent(); if (log.isDebugEnabled()) { - log.debug("sign keybox identifier = " + sign_keybox_identifier); - log.debug("mime type = " + mime_type); - log.debug("loc_ref_content = " + loc_ref_content); + log.debug("sign keybox identifier = " + sign_keybox_identifier); + log.debug("mime type = " + mime_type); + log.debug("loc_ref_content = " + loc_ref_content); } String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEYBOX_IDENTIFIER_REPLACE, sign_keybox_identifier); @@ -206,7 +206,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, loc_ref_content); log.debug("sign_request_xml = " + sign_request_xml); - log.debug("prepareSignRequestDetached finished."); + log.debug("prepareSignRequestDetached finished."); return sign_request_xml; } @@ -226,15 +226,15 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { * @throws ConnectorException Thrown in case of an error. */ public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException { - log.debug("prepareXMLContent:"); + log.debug("prepareXMLContent:"); try { - + String ids_string = so.getSigID(); String sigId = this.parseSigId(ids_string); X509Certificate cert = so.getX509Certificate(); - - + + // dferbas AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); @@ -244,7 +244,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { String object_data_hash = CodingHelper.encodeBase64(data_value_hash); // template replacements - + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); @@ -259,7 +259,11 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_ID_REPLACE, sigId); verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); - verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + // fixed by dti: Issuer names may contain escapted commas ("\,"). As far as replaceFirst (and replaceAll) + // methods are regarded, backslashes in the replacement string may cause the results to be different than + // if it were being treated as a literal replacement string. +// verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replace(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); // SigDataRefReplace already done above verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); @@ -270,15 +274,15 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { if (matcher.find()) { log.debug("SignedProperties found."); String string_to_be_hashed = matcher.group(1); - log.debug("SignedProperties string to be hashed: " + string_to_be_hashed); - final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); + log.debug("SignedProperties string to be hashed: " + string_to_be_hashed); + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); } - log.debug("prepareXMLContent finished."); + log.debug("prepareXMLContent finished."); return verify_xml; } catch (Exception e) { log.debug(e); @@ -291,21 +295,21 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { * @author wprinz */ public static class Environment extends ConnectorEnvironment { - + /** * The configuration key of the sign keybox identifier. */ - protected static final String SIGN_KEYBOX_IDENTIFIER_KEY = "moc.sign.KeyboxIdentifier"; + protected static final String SIGN_KEYBOX_IDENTIFIER_KEY = "moc.sign.KeyboxIdentifier"; /** * The configuration key of the sign request template. */ - protected static final String SIGN_REQUEST_TEMPLATE_KEY = "moc.sign.request.detached"; + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "moc.sign.request.detached"; /** * The configuration key of the sign URL. */ - protected static final String SIGN_URL_KEY = "moc.sign.url"; + protected static final String SIGN_URL_KEY = "moc.sign.url"; /** * BKU template file prefix @@ -334,29 +338,29 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { */ /* signature verification is not supported by mocca protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "moc.verify.request.detached"; - */ + */ /** * The configuration key of the verify template. */ - protected static final String VERIFY_TEMPLATE_KEY = "moc.verify.template.detached"; + protected static final String VERIFY_TEMPLATE_KEY = "moc.verify.template.detached"; /** * The configuration key of the verify URL. */ /* signature verification is not supported by mocca protected static final String xxxVERIFY_URL_KEY = "moc.verify.url"; - */ + */ /** * The configuration key for the ECDSA cert alg property. */ - protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; /** * The configuration key for the RSA cert alg property. */ - protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; protected String profile = null; @@ -381,7 +385,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { protected String cert_alg_ecdsa = null; protected String cert_alg_rsa = null; - + protected String algorithmId = null; /** @@ -411,7 +415,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { } // SIGN REQUEST - + // try specific file String sign_request_filename = TEMPLATE_FILE_PREFIX + this.algorithmId + SIGN_TEMPLATE_FILE_SUFFIX; log.debug("Trying to load specific sign request file " + sign_request_filename); @@ -428,15 +432,15 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { // request file is needed !!! if (this.sign_request_template == null) { - throw new ConnectorException(300, "Can not read the create xml request template"); + throw new ConnectorException(300, "Can not read the create xml request template"); } this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); - + // VERIFY REQUEST /* signature verification is not supported by mocca - + // try specific file String verify_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moc.algorithm.id") + VERIFY_REQUEST_TEMPLATE_FILE_SUFIX; log.debug("Trying to load specific verify request file " + verify_request_filename); @@ -451,11 +455,11 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { // request file is needed !!! if (this.verify_request_template == null) { - throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); } - + */ - + // load template file // try specific file String verify_filename = TEMPLATE_FILE_PREFIX + this.algorithmId + VERIFY_TEMPLATE_SUFFIX; @@ -473,7 +477,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { // signature template is needed !!! if (this.verify_template == null) { - throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); } /* signature verification is not supported by mocca @@ -496,7 +500,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { /** * Returns the LocRef content. - * + * * @return Returns the LocRef content. */ public String getLocRefContent() { @@ -505,7 +509,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { /** * Returns the sign keybox identifier. - * + * * @return Returns the sign keybox identifier. */ public String getSignKeyboxIdentifier() { @@ -514,7 +518,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { /** * Returns the sign request template. - * + * * @return Returns the sign request template. */ public String getSignRequestTemplate() { @@ -523,7 +527,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { /** * Returns the sign URL. - * + * * @return Returns the sign URL. */ public String getSignURL() { @@ -532,7 +536,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { /** * Returns the verify request template. - * + * * @return Returns the verify request template. */ /* signature verification is not supported by mocca @@ -543,7 +547,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { /** * Returns the verify template. - * + * * @return Returns the verify template. */ public String getVerifyTemplate() { @@ -552,7 +556,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { /** * Returns the verify URL. - * + * * @return Returns the verify URL. */ /* signature verification is not supported by mocca @@ -563,7 +567,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { /** * Returns the ecdsa cert alg property. - * + * * @return Returns the ecdsa cert alg property. */ public String getCertAlgEcdsa() { @@ -572,7 +576,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { /** * Returns the rsa cert alg property. - * + * * @return Returns the rsa cert alg property. */ public String getCertAlgRsa() { @@ -582,7 +586,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { /** * Reads the configuration entry given by the key, first from the given * profile, if not found from the defaults. - * + * * @param settings * The settings. * @param profile @@ -599,7 +603,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { return value; } } - + /** * Parses the common part for all id attributes from a given signature parameter string. * @param sigIdString The given signature parameter string. diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java index 094880d..03bf931 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java @@ -50,49 +50,52 @@ import at.knowcenter.wag.egov.egiz.sig.sigid.HotfixIdFormatter; */ public final class SigKZIDHelper { - + /** * The Logger. */ protected static Log logger = LogFactory.getLog(SigKZIDHelper.class); - + public static boolean isTextual(PdfASID sig_kz) { if (sig_kz == null) { // Old signature -> must be textual. - + return true; } - + // new signauture -> sig_kz decides return sig_kz.getType().equals(SignatorFactory.TYPE_TEXTUAL); } - + public static boolean isBinary(PdfASID sig_kz) { return ! isTextual(sig_kz); } - - + + public static boolean isMOASigned(PdfASID sig_kz, String sig_id) { if (sig_kz == null || sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) { // old signature - if sig_id is null this means MOA - + return sig_id == null; } - - if(sig_id == null) + + // According to the specification no signature parameter means MOA signature. + // Fixed: empty ("") or blank (" "), non-null signature parameter should also be regarded as "no signature parameter" +// if (sig_id != null) + if (StringUtils.isBlank(sig_id)) return true; - + // new signature - sig_id decides String [] ids = sig_id.split("@"); // dferbas String prefix = (ids[0].split(":"))[0]; - - + + if (prefix.equals(DetachedLocRefMOAIdFormatter.SIG_ID_PREFIX)) { return true; @@ -116,10 +119,10 @@ public final class SigKZIDHelper logger.error(e.getMessage(), e); } } - + return isMOASigned(kz, sig_id); } - + /** * @author tknall */ @@ -128,7 +131,7 @@ public final class SigKZIDHelper if (StringUtils.isEmpty(sig_id)) { return false; } - String[] ids = sig_id.split("@"); + String[] ids = sig_id.split("@"); if (ArrayUtils.isEmpty(ids)) { return false; } @@ -136,7 +139,7 @@ public final class SigKZIDHelper if (algorithmId == null) { return false; } else { - return algorithmId.startsWith("etsi-moc-1.0") || algorithmId.startsWith("etsi-moc-1.1"); + return algorithmId.startsWith("etsi-moc-1.0") || algorithmId.startsWith("etsi-moc-1.1") || algorithmId.startsWith("etsi-moc-1.2"); } } @@ -203,16 +206,16 @@ public final class SigKZIDHelper logger.error(e.getMessage(), e); } } - + return isOldBKU(kz, sig_id); } - + public static String getAlgorithmId(String bkuIdentifier) throws SettingsException, SettingNotFoundException, ConnectorException { SettingsReader sr = SettingsReader.getInstance(); String base = "signaturelayout.pattern"; Vector v = sr.getSettingKeys(base); - + Iterator it = v.iterator(); while (it.hasNext()) { String subKey = (String) it.next(); @@ -225,7 +228,7 @@ public final class SigKZIDHelper return algValue; } } - + if ("true".equalsIgnoreCase(sr.getSetting("signaturelayout.strict", "false"))) { logger.debug("Enforcing bku support check."); throw new ConnectorException(ErrorCode.BKU_NOT_SUPPORTED, "Unsupported BKU: " + bkuIdentifier); @@ -233,7 +236,7 @@ public final class SigKZIDHelper logger.debug("bku support check disabled."); return null; } - + } public static boolean isATrustSigned(SignSignatureObject so) { @@ -241,7 +244,7 @@ public final class SigKZIDHelper if (sig_id == null && StringUtils.isEmpty(sig_id)) { return false; } - return sig_id.startsWith("etsi-bka-atrust-1.0"); + return sig_id.startsWith("etsi-bka-atrust-1.0"); } /** @@ -251,11 +254,11 @@ public final class SigKZIDHelper */ public static boolean isBKUSigned(SignSignatureObject so) throws ConnectorException { if (isOldBKU(so)) return true; - + if (so.id.startsWith("etsi-bka-1.0")) { return true; } - + return false; } diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MoccaXades14SignatureLayoutHandler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MoccaXades14SignatureLayoutHandler.java new file mode 100644 index 0000000..ed14315 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MoccaXades14SignatureLayoutHandler.java @@ -0,0 +1,53 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signaturelayout.mocca; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.MOCCAHelper; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedMOCIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; + +/** + * Layout handler for XAdES 1.4 based signature layouts. + * + * @author Datentechnik Innovation GmbH + */ +public class MoccaXades14SignatureLayoutHandler implements SignatureLayoutHandler { + + /** + * The signature parameter identifier for XAdES 1.4 signatures. + */ + private final static String ALGORITHM_ID = "etsi-moc-1.2"; + + /** + * Parses the given xmlResponse with respect to the specific signature layout of mocca. + */ + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, ConnectorEnvironment env) + throws ConnectorException { + return MOCCAHelper.parseCreateXMLResponse(xmlResponse, new DetachedMOCIdFormatter(ALGORITHM_ID), env); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java index 5132021..3546cd7 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java @@ -38,7 +38,7 @@ import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; /** * This class provides encoding and decoding methods and other coding methods. * All methods are static! - * + * * @author wlackner */ public class CodingHelper @@ -52,7 +52,7 @@ public class CodingHelper /** * This method encodes a given Unicode (Java) String to UTF-8 bytes and then * encodes these UTF-8 bytes to a Base64 US-ASCII (Java) String. - * + * * @param plain_string * to be encoded * @return the UTF-8 and Base64 encoded string @@ -68,7 +68,6 @@ public class CodingHelper } catch (UnsupportedEncodingException e) { - e.printStackTrace(); throw new RuntimeException(e); } } @@ -76,7 +75,7 @@ public class CodingHelper /** * This method decodes the UTF-8 bytes from a Base64 US-ASCII (Java) String * and decodes the UTF-8 bytes to a unicode (Java) String. - * + * * @param encoded_string * to be decoded * @return the Base64 and UTF-8 decoded string @@ -92,7 +91,6 @@ public class CodingHelper } catch (UnsupportedEncodingException e) { - e.printStackTrace(); throw new RuntimeException(e); } } @@ -108,7 +106,6 @@ public class CodingHelper // try { // utf8 = theString.getBytes("UTF-8"); // } catch (UnsupportedEncodingException e) { - // e.printStackTrace(); // } // return utf8; // } @@ -139,20 +136,19 @@ public class CodingHelper // try { // the_string = new String(ba, "UTF-8"); // } catch (UnsupportedEncodingException e) { - // e.printStackTrace(); // } // return the_string; // } /** * This method decodes a given Base64 string. - * + * *

    * Note that the given String must only contain Base64 characters. (The string * will be converted to a byte array of "US-ASCII" (7 bit) bytes and then this * byte array will be decoded using the Base64 algorithm. *

    - * + * * @param theString * to be decoded * @return a Base64 decoded byte array @@ -166,14 +162,13 @@ public class CodingHelper } catch (UnsupportedEncodingException e) { - e.printStackTrace(); throw new RuntimeException("Very Strange: US-ASCII encoding not supported???", e); } } /** * This method decodes a given Base64 byte array - * + * * @param ba * the byte array to be decoded * @return a Base64 decoded byte array @@ -185,7 +180,7 @@ public class CodingHelper /** * This method encodes a given byte array Base64 - * + * * @param plainString * the byte array to be encoded * @return the Base64 encoded string @@ -199,7 +194,6 @@ public class CodingHelper } catch (UnsupportedEncodingException e) { - e.printStackTrace(); throw new RuntimeException("Very Strange: US-ASCII encoding not supported???", e); } } @@ -207,15 +201,15 @@ public class CodingHelper // dferbas /** * This method builds an hash value of a given byte array. - * + * * @param data * the byte array to build the hash value for - * @param hashAlg hash algorithm for {@link MessageDigest} e.g. "SHA-1" + * @param hashAlg hash algorithm for {@link MessageDigest} e.g. "SHA-1" * @return the calculated hash value as a byte array * @see MessageDigest */ public static byte[] buildDigest(byte[] data, String hashAlg) - { + { MessageDigest digester = null; try { @@ -243,10 +237,10 @@ public class CodingHelper byte [] data = DataSourceHelper.convertDataSourceToByteArray(input); return buildDigest(data, hashAlg); } - + /** * This method escapes a given string with HTML entities. - * + * * @param rawString * the string to escaped * @return the HTML escaped string @@ -263,7 +257,7 @@ public class CodingHelper /** * This method checks, if a byte array contains chars that are not base64 * conform. - * + * * @param byteArray * the array to test * @return boolean, if a byte array is base64 conform, false otherwise @@ -282,7 +276,7 @@ public class CodingHelper /** * This method checks, if a string contains chars that are not base64 conform. - * + * * @param string * the chars to test * @return boolean, if the given string is base64 conform, false otherwise -- cgit v1.2.3