From c8abbd8bef5349ab892a2853a4e5e3d5ed16b670 Mon Sep 17 00:00:00 2001 From: Jakob Heher Date: Tue, 12 May 2026 15:33:19 +0200 Subject: Update docs & various fixes discovered in the process (#86) - update documentation for pdf-as 5 - document the v2 json api - fix a number of documentation quirks - document `keyId` parameter - px (pixels) -> pt (pdf page units) - document --verify_level - remove a number of documented features that were never implemented: - `adobeSignFieldValue` and `sigLogoAltText` from signature profiles - `UNDERLINE` and `STRIKETHRU` from fonts - `num-bytes` parameter - `verify_only`/`sign_only` enable states for profiles - update mobile BKU base URL - update pdfbox backend default to 3 in sample configurations - consistently made boolean parsing from configuration files case permissive - add moa verification timeout - add support for BOLDITALIC to all base fonts, and for ITALIC to helvetica and courier - fix a number of small quirks - hibernate properties are now reloaded properly - fix the signature block parameter key regex - v1 json api now correctly checks for onlinebku/mobilebku being enabled - pdfbox 2 module correctly compares for integer equality regardless of cached boxed ints - test operationcountwatcher no longer sometimes breaks due to spring context differences --- .../src/main/configuration/pdf-as-web.properties | 6 +- .../gv/egiz/pdfas/web/config/WebConfiguration.java | 142 ++++----------------- .../at/gv/egiz/pdfas/web/helper/PdfAsHelper.java | 33 +---- .../pdfas/web/helper/PdfAsParameterExtractor.java | 12 +- .../gv/egiz/pdfas/web/json_api/JacksonConfig.java | 8 ++ .../egiz/pdfas/web/servlets/ExternSignServlet.java | 5 +- .../gv/egiz/pdfas/web/servlets/JSONAPIServlet.java | 4 +- .../web/stats/impl/StatisticMicrometerBackend.java | 24 ++-- .../egiz/pdfas/web/ws/PDFASVerificationImpl.java | 6 +- pdf-as-web/src/main/webapp/egiz.jsp | 8 +- 10 files changed, 65 insertions(+), 183 deletions(-) (limited to 'pdf-as-web/src/main') diff --git a/pdf-as-web/src/main/configuration/pdf-as-web.properties b/pdf-as-web/src/main/configuration/pdf-as-web.properties index 98249adf..4b3102f9 100644 --- a/pdf-as-web/src/main/configuration/pdf-as-web.properties +++ b/pdf-as-web/src/main/configuration/pdf-as-web.properties @@ -20,7 +20,7 @@ ext.overwrite.wl.1=^$ ############################################################################## ## Signing by Security-Layer bku.local.url=http://127.0.0.1:3495/http-security-layer-request -bku.mobile.url=https://www.handy-signatur.at/mobile/https-security-layer-request/default.aspx +bku.mobile.url=https://service.a-trust.at/mobile/https-security-layer-request/default.aspx ############################################################################## @@ -58,13 +58,13 @@ moal.test.Certificate=KG_ECC_TEST.crt ############################################################################## ###### Enable SOAP Service # Enable signing endpoint -soap.sign.enabled=true +# soap.sign.enabled=true # Enable implicide signature-verification during WebService signing soap.sign.with.verify.enabled=true # Enable signature-verification endpoint -# soap.verify.enabled=false +# soap.verify.enabled=true ############################################################################## diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/config/WebConfiguration.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/config/WebConfiguration.java index 0b3fdf05..85e1b75d 100644 --- a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/config/WebConfiguration.java +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/config/WebConfiguration.java @@ -117,7 +117,7 @@ public class WebConfiguration implements IConfigurationConstants { public static final String UPLOAD_FILESIZE_THRESHOLD = "web.upload.filesizeThreshold"; public static final String UPLOAD_MAX_FILESIZE = "web.upload.filesizeMax"; - public static final String UPLOAD_MAX_REQUESTSIZE = "web.upload.RequestsizeMax"; + public static final String UPLOAD_MAX_REQUESTSIZE = "web.upload.requestsizeMax"; public static final String PLACEHOLDER_GENERATOR_ENABLED = "qr.placeholder.generator.enabled"; @@ -125,14 +125,14 @@ public class WebConfiguration implements IConfigurationConstants { private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB - private static Properties properties = new Properties(); - private static Properties hibernateProps = new Properties(); + private static final Properties properties = new Properties(); + private static final Properties hibernateProps = new Properties(); private static final Logger logger = LoggerFactory .getLogger(WebConfiguration.class); - private static List whiteListregEx = new ArrayList(); - private static List overwritewhiteListregEx = new ArrayList(); + private static final List whiteListregEx = new ArrayList(); + private static final List overwritewhiteListregEx = new ArrayList(); public static void configure(String configFile) { try (InputStream is = new FileInputStream(configFile)) { @@ -145,6 +145,7 @@ public class WebConfiguration implements IConfigurationConstants { public static void configure(InputStream config) { properties.clear(); + hibernateProps.clear(); whiteListregEx.clear(); overwritewhiteListregEx.clear(); @@ -324,12 +325,7 @@ public class WebConfiguration implements IConfigurationConstants { public static boolean isAllowExtOverwrite() { String value = properties.getProperty(ALLOW_EXT_OVERWRITE); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(value); } public static synchronized boolean isOverwriteAllowed(String key) { @@ -354,42 +350,22 @@ public class WebConfiguration implements IConfigurationConstants { public static boolean isJSONAPIEnabled() { String value = properties.getProperty(JSON_API_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(value); } public static boolean isKeepSignedDocument() { String value = properties.getProperty(KEEP_SIGNED_DOCUMENT); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(value); } public static boolean isMoaEnabled(String keyIdentifier) { String value = properties.getProperty(MOA_LIST + "." + keyIdentifier + ".enabled"); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(value); } public static boolean isQRPlaceholderGenerator() { String value = properties.getProperty(PLACEHOLDER_GENERATOR_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(value); } public static String getMoaURL(String keyIdentifier) { @@ -443,121 +419,57 @@ public class WebConfiguration implements IConfigurationConstants { public static boolean getMOASSEnabled() { String value = properties.getProperty(MOA_SS_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(value); } public static boolean getKeystoreDefaultEnabled() { String value = properties.getProperty(KEYSTORE_DEFAULT_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(value); } public static boolean getKeystoreEnabled(String keyIdentifier) { String value = properties.getProperty(KEYSTORE_LIST + "." + keyIdentifier + "." + KEYSTORE_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(value); } public static boolean getLocalBKUEnabled() { - String value = properties.getProperty(LOCAL_BKU_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(properties.getProperty(LOCAL_BKU_ENABLED)); } public static boolean getMobileBKUEnabled() { - String value = properties.getProperty(MOBILE_BKU_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(properties.getProperty(MOBILE_BKU_ENABLED)); } public static boolean getOnlineBKUEnabled() { - String value = properties.getProperty(ONLINE_BKU_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(properties.getProperty(ONLINE_BKU_ENABLED)); } public static boolean getSL20Enabled() { - String value = properties.getProperty(SL20_BKU_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(properties.getProperty(SL20_BKU_ENABLED)); } public static boolean getSoapSignEnabled() { - String value = properties.getProperty(SOAP_SIGN_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(properties.getProperty(SOAP_SIGN_ENABLED)); } public static boolean isSoapSignWithVerifyEnabled() { String value = properties.getProperty(SOAP_SIGN_WITH_VERIFY_ENABLED); if (value != null) { - return value.equals("true"); - + return Boolean.parseBoolean(value); } return getSoapSignEnabled(); } public static boolean getSoapVerifyEnabled() { - String value = properties.getProperty(SOAP_VERIFY_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(properties.getProperty(SOAP_VERIFY_ENABLED)); } public static boolean isShowErrorDetails() { - String value = properties.getProperty(ERROR_DETAILS); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(properties.getProperty(ERROR_DETAILS)); } public static boolean isWhiteListEnabled() { - String value = properties.getProperty(WHITELIST_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(properties.getProperty(WHITELIST_ENABLED)); } public static synchronized boolean isProvidePdfURLinWhitelist(String url) { @@ -612,13 +524,7 @@ public class WebConfiguration implements IConfigurationConstants { } public static boolean getReloadEnabled() { - String value = properties.getProperty(RELOAD_ENABLED); - if (value != null) { - if (value.equals("true")) { - return true; - } - } - return false; + return Boolean.parseBoolean(properties.getProperty(RELOAD_ENABLED)); } public static int getFilesizeThreshold() { diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/PdfAsHelper.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/PdfAsHelper.java index 95e9089f..4a4d15b2 100644 --- a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/PdfAsHelper.java +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/PdfAsHelper.java @@ -181,33 +181,6 @@ public class PdfAsHelper { return pdfAsConfig; } - private static void validatePdfSize(HttpServletRequest request, - HttpServletResponse response, byte[] pdfData) - throws PdfAsWebException { - // Try to check num-bytes - String pdfSizeString = PdfAsParameterExtractor.getNumBytes(request); - if (pdfSizeString != null) { - long pdfSize = -1; - try { - pdfSize = Long.parseLong(pdfSizeString); - } catch (NumberFormatException e) { - throw new PdfAsWebException( - PdfAsParameterExtractor.PARAM_NUM_BYTES - + " parameter has to be a positiv number!", e); - } - if (pdfSize <= 0) { - throw new PdfAsWebException( - "Invalid PDF Size! Has to bigger than zero!"); - } - - if (pdfData.length != pdfSize) { - throw new PdfAsWebException("Signature Data Size and " - + PdfAsParameterExtractor.PARAM_NUM_BYTES - + " missmatch!"); - } - } - } - public static String buildPosString(HttpServletRequest request, HttpServletResponse response) throws PdfAsWebException { String posP = PdfAsParameterExtractor.getSigPosP(request); @@ -270,19 +243,19 @@ public class PdfAsHelper { sb.append("w:auto;"); } } - sb.append("w:" + posW.trim() + ";"); + sb.append("w:").append(posW.trim()).append(";"); } else { sb.append("w:auto;"); } if (posP != null) { - if (!(posP.equals("auto") || posP.equals("new"))) { + if (!(posP.equals("auto") || posP.equals("new") || posP.equals("last"))) { try { Integer.parseInt(posP); } catch (NumberFormatException e) { throw new PdfAsWebException( PdfAsParameterExtractor.PARAM_SIG_POS_P - + " has invalid value! (auto | new )"); + + " has invalid value! (auto | new | last)"); } } sb.append("p:" + posP.trim() + ";"); diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/PdfAsParameterExtractor.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/PdfAsParameterExtractor.java index 0791e37e..ede5fdf5 100644 --- a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/PdfAsParameterExtractor.java +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/helper/PdfAsParameterExtractor.java @@ -41,7 +41,6 @@ public class PdfAsParameterExtractor { public static final String PARAM_CONNECTOR = "connector"; public static final String PARAM_TRANSACTION_ID = "transactionId"; - public static final String PARAM_CONNECTOR_DEFAULT = "bku"; public static final String PARAM_FORMAT = "format"; public static final String PARAM_HTML = "html"; @@ -63,7 +62,6 @@ public class PdfAsParameterExtractor { public static final String PARAM_VERIFY_LEVEL_OPTION_INT_ONLY = "intOnly"; public static final String PARAM_LOCALE = "locale"; - public static final String PARAM_NUM_BYTES = "num-bytes"; public static final String PARAM_PDF_URL = "pdf-url"; public static final String PARAM_SIG_TYPE = "sig-type"; public static final String PARAM_SIG_TYPE_ALIAS = "sig_type"; @@ -85,11 +83,7 @@ public class PdfAsParameterExtractor { .getLogger(PdfAsParameterExtractor.class); public static String getConnector(HttpServletRequest request) { - String connector = (String)request.getAttribute(PARAM_CONNECTOR); - if(connector != null) { - return connector; - } - return PARAM_CONNECTOR_DEFAULT; + return (String)request.getAttribute(PARAM_CONNECTOR); } public static Map getDynamicSignatureBlockParameters(HttpServletRequest request) throws Exception { @@ -234,10 +228,6 @@ public class PdfAsParameterExtractor { return null; } - public static String getNumBytes(HttpServletRequest request) { - return (String)request.getAttribute(PARAM_NUM_BYTES); - } - public static String getPdfUrl(HttpServletRequest request) { return (String)request.getAttribute(PARAM_PDF_URL); } diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/json_api/JacksonConfig.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/json_api/JacksonConfig.java index bd82f8ed..ffb02c5f 100644 --- a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/json_api/JacksonConfig.java +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/json_api/JacksonConfig.java @@ -2,6 +2,7 @@ package at.gv.egiz.pdfas.web.json_api; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationModule; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -16,4 +17,11 @@ public class JacksonConfig { DeserializationFeature.READ_ENUMS_USING_TO_STRING ); } + + @Bean + public Jackson2ObjectMapperBuilderCustomizer useJaxbJsonNames() { + return b -> b.modulesToInstall( + new JakartaXmlBindAnnotationModule() + ); + } } diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/servlets/ExternSignServlet.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/servlets/ExternSignServlet.java index a28a4835..18754288 100644 --- a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/servlets/ExternSignServlet.java +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/servlets/ExternSignServlet.java @@ -309,6 +309,9 @@ public class ExternSignServlet extends HttpServlet { // Get Connector String connector = PdfAsParameterExtractor.getConnector(request); + if (connector == null) { + throw new PdfAsException("No connector specified"); + } String transactionId = PdfAsParameterExtractor.getTransactionId(request); @@ -460,7 +463,7 @@ public class ExternSignServlet extends HttpServlet { return; } else { - throw new PdfAsWebException("Invalid connector (bku | moa | jks)"); + throw new PdfAsWebException("Invalid connector (bku | moa | jks | onlinebku | mobilebku)"); } } diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/servlets/JSONAPIServlet.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/servlets/JSONAPIServlet.java index b60fae06..f2c39a75 100644 --- a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/servlets/JSONAPIServlet.java +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/servlets/JSONAPIServlet.java @@ -243,14 +243,14 @@ public class JSONAPIServlet extends HttpServlet { } if (PDFASSignParameters.Connector.ONLINEBKU.equals(connectorEnum)) { - if (WebConfiguration.getLocalBKUURL() == null) { + if (WebConfiguration.getOnlineBKUURL() == null) { throw new PdfAsWebException( "Invalid connector onlinebku is not supported"); } } if (PDFASSignParameters.Connector.MOBILEBKU.equals(connectorEnum)) { - if (WebConfiguration.getLocalBKUURL() == null) { + if (WebConfiguration.getHandyBKUURL() == null) { throw new PdfAsWebException( "Invalid connector mobilebku is not supported"); } diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/stats/impl/StatisticMicrometerBackend.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/stats/impl/StatisticMicrometerBackend.java index 89127e6a..8b8fb489 100644 --- a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/stats/impl/StatisticMicrometerBackend.java +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/stats/impl/StatisticMicrometerBackend.java @@ -7,30 +7,25 @@ import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.Timer; import lombok.extern.slf4j.Slf4j; +import lombok.val; import org.jspecify.annotations.NonNull; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.DisposableBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; @Slf4j public class StatisticMicrometerBackend implements StatisticBackend { /** bridge between ServiceLoader component and Boot's beans */ @Component - public static class SpringContextProxy implements ApplicationContextAware { - private static volatile ApplicationContext applicationContext; - @Override public void setApplicationContext(@NonNull ApplicationContext ctx) { applicationContext = ctx; } - public static T getBean(Class type) { - try { - return (applicationContext != null) ? applicationContext.getBean(type) : null; - } catch (BeansException ex) { - log.warn("Spring MeterRegistry not available, skipped micrometer metric logging", ex); - return null; - } - } + public static class SpringContextProxy { + public static MeterRegistry meterRegistry; + SpringContextProxy(MeterRegistry registry) { meterRegistry = registry; } } public static final String NAME = "StatisticMicrometerBackend"; @Override public String getName() { return NAME; } @@ -39,8 +34,11 @@ public class StatisticMicrometerBackend implements StatisticBackend { public void storeEvent(StatisticEvent e) { if (e == null) return; - MeterRegistry registry = SpringContextProxy.getBean(MeterRegistry.class); - if (registry == null) return; + MeterRegistry registry = SpringContextProxy.meterRegistry; + if (registry == null) { + log.warn("Spring MeterRegistry not available, skipped micrometer metric logging"); + return; + } Tags baseTags = Tags.of( "operation", safeName(e.getOperation(), v -> v.getName()), diff --git a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/ws/PDFASVerificationImpl.java b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/ws/PDFASVerificationImpl.java index 68c5d227..1afd0c2d 100644 --- a/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/ws/PDFASVerificationImpl.java +++ b/pdf-as-web/src/main/java/at/gv/egiz/pdfas/web/ws/PDFASVerificationImpl.java @@ -69,7 +69,11 @@ public class PDFASVerificationImpl implements PDFASVerification { } statisticEvent.setFilesize(request.getInputData().length); statisticEvent.setProfileId(null); - statisticEvent.setDevice(request.getVerificationLevel().toString()); + statisticEvent.setDevice( + (lvl == SignatureVerificationLevel.FULL_VERIFICATION ? + VerificationLevel.FULL_CERT_PATH : + VerificationLevel.INTEGRITY_ONLY) + .toString()); List results = PdfAsHelper.synchronousVerify( request.getInputData(), sigIdx, lvl, preProcessor); diff --git a/pdf-as-web/src/main/webapp/egiz.jsp b/pdf-as-web/src/main/webapp/egiz.jsp index 7036697f..1050af43 100644 --- a/pdf-as-web/src/main/webapp/egiz.jsp +++ b/pdf-as-web/src/main/webapp/egiz.jsp @@ -207,16 +207,16 @@

Detailinformationen

Unter folgenden Links finden Sie detaillierte - Informationen wie Sie zu OpenID Connect, der Bürgerkarte und - der Handy-Signatur.

+ Informationen wie Sie zu OpenID Connect und + der ID Austria.

OpenID Connect

Bürgerkarte.at

- Handy-Signatur.at + ID Austria - Häufige Fragen
-- cgit v1.2.3