From c4efec1daeb50b30d363bb9fb83aec5435dbf2ad Mon Sep 17 00:00:00 2001
From: tknall <tknall@7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c>
Date: Mon, 27 Apr 2009 08:16:42 +0000
Subject: New signature layout for new MOCCA bku integrated (etsi-moc-1.1). New
 architecture implemented that allows different signature layouts for single
 types of BKUs.

git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@337 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c
---
 .../at/gv/egiz/pdfas/api/commons/Constants.java    |   2 +
 .../at/gv/egiz/pdfas/exceptions/ErrorCode.java     |   5 +-
 .../egiz/pdfas/framework/ConnectorParameters.java  | 147 ++++++++++-----------
 .../java/at/knowcenter/wag/egov/egiz/PdfAS.java    |   2 +-
 .../egov/egiz/sig/connectors/bku/BKUHelper.java    |  71 ++++++++++
 .../egiz/sig/connectors/bku/BKUPostConnection.java |  11 ++
 .../sig/connectors/bku/DetachedBKUConnector.java   |  44 +++---
 .../bku/EnvelopedBase64BKUConnector.java           |   9 +-
 .../connectors/moa/DetachedLocRefMOAConnector.java |   8 --
 .../moa/EnvelopingBase64MOAConnector.java          |   8 --
 .../moa/MOASoapWithAttachmentConnector.java        |  23 ++--
 .../mocca/LocRefDetachedMOCCAConnector.java        |  61 ++++++---
 .../egiz/sig/connectors/mocca/MOCCAHelper.java     |  19 ---
 .../egiz/sig/sigid/DetachedMOCIdFormatter.java     |  12 +-
 .../wag/egov/egiz/sig/sigkz/SigKZIDHelper.java     |  62 ++++++++-
 .../signaturelayout/SignatureLayoutHandler.java    |  21 +++
 .../SignatureLayoutHandlerFactory.java             | 121 +++++++++++++++++
 .../mocca/MOCCASignatureLayout10Handler.java       |  24 ++++
 .../mocca/OldMOCCASignatureLayoutHandler.java      |  24 ++++
 .../td/TrustDeskSignatureLayoutHandler.java        |  22 +++
 .../wag/egov/egiz/web/servlets/DataURLServlet.java |  28 ++--
 21 files changed, 532 insertions(+), 192 deletions(-)
 create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java
 create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java
 create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java
 create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java
 create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java

(limited to 'src/main/java')

diff --git a/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java b/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java
index 19f7613..4fec0a1 100644
--- a/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java
+++ b/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java
@@ -110,6 +110,8 @@ public final class Constants
    * The name of the directory, where temporary files are stored.
    */
   public static final String TEMP_DIR_NAME = "pdfastmp";
+  
+  public static final String BKU_HEADER_SIGNATURE_LAYOUT = "SignatureLayout";
 
 }
 
diff --git a/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java b/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java
index f6b5602..c51d10a 100644
--- a/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java
+++ b/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java
@@ -20,6 +20,7 @@ public final class ErrorCode
   public static final int SETTINGS_EXCEPTION = 101;
   public static final int KZ_SETTING_NOT_FOUND = 102;
   public static final int NO_EMBEDABLE_TTF_CONFIGURED_FOR_PDFA = 103;
+  public static final int INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED = 104;
 
   public static final int DOCUMENT_CANNOT_BE_READ = 201;
   public static final int TEXT_EXTRACTION_EXCEPTION = 202;
@@ -44,7 +45,9 @@ public final class ErrorCode
   public static final int NON_BINARY_SIGNATURES_PRESENT = 317;  
 
   public static final int SIGNATURE_VERIFICATION_NOT_SUPPORTED = 371;  
-  public static final int INVALID_SIGNING_TIME = 372;  
+  public static final int INVALID_SIGNING_TIME = 372;
+
+  public static final int BKU_NOT_SUPPORTED = 373;
   
   public static final int WEB_EXCEPTION = 330;
 
diff --git a/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java b/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java
index a7c5d7a..235a03e 100644
--- a/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java
+++ b/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java
@@ -15,93 +15,84 @@ import java.util.Date;
  * 
  * @author wprinz
  */
-public class ConnectorParameters
-{
-  /**
-   * The profile Id to get the connector parameters from.
-   * 
-   * <p>
-   * The there are no explicit parameters for the connector in the profile, the
-   * default parameters are used.
-   * </p>
-   */
-  protected String profileId = null;
+public class ConnectorParameters {
+   /**
+    * The profile Id to get the connector parameters from.
+    * 
+    * <p>
+    * The there are no explicit parameters for the connector in the profile, the
+    * default parameters are used.
+    * </p>
+    */
+   protected String profileId = null;
 
-  /**
-   * The signature key identifier to be used or null if it should be read from
-   * the profile.
-   * 
-   * <p>
-   * Currently this is only used by MOA connectors and identifies the MOA key
-   * group to be used when signing. If null, the MOA connector reads the key
-   * from the profile.
-   * </p>
-   */
-  protected String signatureKeyIdentifier = null;
+   /**
+    * The signature key identifier to be used or null if it should be read from
+    * the profile.
+    * 
+    * <p>
+    * Currently this is only used by MOA connectors and identifies the MOA key
+    * group to be used when signing. If null, the MOA connector reads the key
+    * from the profile.
+    * </p>
+    */
+   protected String signatureKeyIdentifier = null;
 
-  /**
-   * Tells, if the connector should ask the device to return the hash input
-   * data.
-   * 
-   * <p>
-   * Note that not all connectors support to return the hash input data - so
-   * there is no guarantee that the hash value will actually be returned.
-   * </p>
-   */
-  protected boolean returnHashInputData = false;
+   /**
+    * Tells, if the connector should ask the device to return the hash input
+    * data.
+    * 
+    * <p>
+    * Note that not all connectors support to return the hash input data - so
+    * there is no guarantee that the hash value will actually be returned.
+    * </p>
+    */
+   protected boolean returnHashInputData = false;
 
-  /**
-   * Allows to specify an explicit time of verification.
-   * 
-   * <p>
-   * If null, the device's default behaviour determines the time of
-   * verification, which is usually the current time.
-   * </p>
-   * <p>
-   * The time of verification usually influences the certificate check. E.g. the
-   * certificate may not be valid at the time of verification.
-   * </p>
-   */
-  protected Date verificationTime = null;
+   /**
+    * Allows to specify an explicit time of verification.
+    * 
+    * <p>
+    * If null, the device's default behaviour determines the time of
+    * verification, which is usually the current time.
+    * </p>
+    * <p>
+    * The time of verification usually influences the certificate check. E.g.
+    * the certificate may not be valid at the time of verification.
+    * </p>
+    */
+   protected Date verificationTime = null;
 
-  public String getProfileId()
-  {
-    return this.profileId;
-  }
+   public String getProfileId() {
+      return this.profileId;
+   }
 
-  public void setProfileId(String profileId)
-  {
-    this.profileId = profileId;
-  }
-  
-  public String getSignatureKeyIdentifier()
-  {
-    return this.signatureKeyIdentifier;
-  }
+   public void setProfileId(String profileId) {
+      this.profileId = profileId;
+   }
 
-  public void setSignatureKeyIdentifier(String signatureKeyIdentifier)
-  {
-    this.signatureKeyIdentifier = signatureKeyIdentifier;
-  }
+   public String getSignatureKeyIdentifier() {
+      return this.signatureKeyIdentifier;
+   }
 
-  public boolean isReturnHashInputData()
-  {
-    return this.returnHashInputData;
-  }
+   public void setSignatureKeyIdentifier(String signatureKeyIdentifier) {
+      this.signatureKeyIdentifier = signatureKeyIdentifier;
+   }
 
-  public void setReturnHashInputData(boolean returnHashInputData)
-  {
-    this.returnHashInputData = returnHashInputData;
-  }
+   public boolean isReturnHashInputData() {
+      return this.returnHashInputData;
+   }
 
-  public Date getVerificationTime()
-  {
-    return this.verificationTime;
-  }
+   public void setReturnHashInputData(boolean returnHashInputData) {
+      this.returnHashInputData = returnHashInputData;
+   }
 
-  public void setVerificationTime(Date verificationTime)
-  {
-    this.verificationTime = verificationTime;
-  }
+   public Date getVerificationTime() {
+      return this.verificationTime;
+   }
+
+   public void setVerificationTime(Date verificationTime) {
+      this.verificationTime = verificationTime;
+   }
 
 }
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java b/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java
index c56a03e..2073714 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java
@@ -96,7 +96,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.0.9-20090319";
+  public static final String PDFAS_VERSION = "3.0.9-20090417";
   
   /**
    * The key of the strict mode setting.
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java
index af155a1..43c9649 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java
@@ -9,14 +9,18 @@ import java.security.cert.X509Certificate;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.Properties;
 import java.util.TimeZone;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import at.gv.egiz.pdfas.api.commons.Constants;
 import at.gv.egiz.pdfas.exceptions.external.ExternalErrorException;
 import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper;
 import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
@@ -582,4 +586,71 @@ public final class BKUHelper
     };
     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);
+
+     log.debug("BKU response header \"user-agent\":  " + bkuUserAgentHeader);
+     log.debug("BKU response header \"server\":  " + bkuServerHeader);
+     log.trace("BKU response header \"" + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "\":  " + bkuSignatureLayout);
+
+     String result = null;
+     
+     if (bkuServerHeader != null) {
+        result = bkuServerHeader;
+     } else if (bkuUserAgentHeader != null) {
+        result = bkuUserAgentHeader;
+     } else {
+        log.warn("Unable to find any BKU identifier (neither header value \"user-agent\" nor \"server\".)");
+     }
+     
+     if (bkuSignatureLayout != null && result != null) {
+        log.info("BKU response header \"" + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "\" found.");
+        String signatureLayoutData = " " + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "/" + bkuSignatureLayout;
+        if (!result.endsWith(signatureLayoutData)) {
+           log.debug("Appending signature layout value \"" + bkuSignatureLayout + "\" to bku identifier.");
+           result += signatureLayoutData;
+        } else {
+           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(HttpServletRequest request) {
+     return getBKUIdentifier(getBKUProperties(request));
+  }
+  
+  public static Properties getBKUProperties(HttpServletRequest request) {
+     Properties props = new Properties();
+     String server = request.getHeader("server");
+     String userAgent = request.getHeader("user-agent");
+     String signatureLayout = request.getHeader(Constants.BKU_HEADER_SIGNATURE_LAYOUT);
+     if (server != null) {
+        props.setProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY, server);
+     }
+     if (userAgent != null) {
+        props.setProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY, userAgent);
+     }
+     if (signatureLayout != null) {
+        props.setProperty(BKUPostConnection.BKU_SIGNATURE_LAYOUT_HEADER_KEY, signatureLayout);
+     }
+     return props;
+  }
+  
+  
 }
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java
index b582715..d2cffe8 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java
@@ -20,6 +20,7 @@ import org.apache.commons.httpclient.params.HttpMethodParams;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import at.gv.egiz.pdfas.api.commons.Constants;
 import at.knowcenter.wag.egov.egiz.sig.SignatureData;
 
 /**
@@ -39,6 +40,11 @@ public final class BKUPostConnection
    * The response Properties key that identifies the BKU Server header.
    */
   public static final String BKU_SERVER_HEADER_KEY = "BKU-Server-Header"; //$NON-NLS-1$
+  
+  /**
+   * The response property that declares the signature layout being applied.
+   */
+  public static final String BKU_SIGNATURE_LAYOUT_HEADER_KEY = "BKU-Signature-Layout"; //$NON-NLS-1$
 
   /**
    * The response Properties key that identifies the BKU User-Agent header.
@@ -130,6 +136,11 @@ public final class BKUPostConnection
        log.warn("BKU response header \"Server\" is empty.");
     }
 
+    Header signatureLayoutHeader = post_method.getResponseHeader(Constants.BKU_HEADER_SIGNATURE_LAYOUT); //$NON-NLS-1$
+    if (signatureLayoutHeader != null) {
+       response_properties.setProperty(BKU_SIGNATURE_LAYOUT_HEADER_KEY, signatureLayoutHeader.getValue());
+    }
+
     log.debug(post_method.getResponseCharSet());
     if (!post_method.getResponseCharSet().equals("UTF-8")) //$NON-NLS-1$
     {
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java
index 5164771..100f054 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java
@@ -21,10 +21,10 @@ import at.knowcenter.wag.egov.egiz.sig.connectors.Connector;
 import at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector;
 import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces;
 import at.knowcenter.wag.egov.egiz.sig.connectors.moa.DetachedLocRefMOAConnector;
-import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.MOCCAHelper;
-import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedIdFormatter;
-import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedMOCIdFormatter;
+import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.LocRefDetachedMOCCAConnector;
 import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper;
+import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler;
+import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandlerFactory;
 import at.knowcenter.wag.egov.egiz.tools.CodingHelper;
 import at.knowcenter.wag.egov.egiz.tools.FileHelper;
 
@@ -125,24 +125,20 @@ public class DetachedBKUConnector implements Connector, LocalConnector
     log.debug("analyzeSignResponse:"); //$NON-NLS-1$
 
     String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY);
-    String bkuServerHeader = response_properties.getProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY);
-    String bkuUserAgentHeader = response_properties.getProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY);
 
     BKUHelper.checkResponseForError(response_string);
 
-    // TODO[tknall] Parse server type and version in order to prevent unsupported cces from signing pdfs
-    // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.dataurl
-    log.debug("BKU response header \"user-agent\" header:  " + bkuUserAgentHeader);
-    // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.browser
-    log.debug("BKU response header \"server\"     header:  " + bkuServerHeader);
+    String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties);
+    log.debug("BKU identifier: \"" + bkuIdentifier + "\"");
     
-    SignSignatureObject so;
-    if (MOCCAHelper.isMOCCACCEId(bkuServerHeader == null ? bkuUserAgentHeader : bkuServerHeader)) {
-       log.debug("Evaluating response as MOCCA response.");
-       so = MOCCAHelper.parseCreateXMLResponse(response_string, new DetachedMOCIdFormatter());
-    } else {
-       so = BKUHelper.parseCreateXMLResponse(response_string, new DetachedIdFormatter());
+    SignatureLayoutHandler sigLayout;
+    try {
+       sigLayout = SignatureLayoutHandlerFactory.getSignatureLayoutHandlerInstance(bkuIdentifier);
+    } catch (SettingsException e) {
+       throw new ConnectorException(e.getErrorCode(), e.getMessage());
     }
+    
+    SignSignatureObject so = sigLayout.parseCreateXMLSignatureResponse(response_string);
 
     so.response_properties = response_properties;
 
@@ -322,17 +318,29 @@ public class DetachedBKUConnector implements Connector, LocalConnector
     String verify_request_template = this.environment.getVerifyRequestTemplate();
 
     String xml_content = null;
+
+    // MOA
     if (SigKZIDHelper.isMOASigned(so))
     {
       log.debug("The signature is MOA signed -> getting XML content from DetachedLocRefMOA connector.");
       DetachedLocRefMOAConnector moa_conn = new DetachedLocRefMOAConnector(this.environment.getProfile(), "loc ref not needed here");
       xml_content = moa_conn.prepareXMLContent(data, so);
-    }
+
+      // MOCCA
+  } else if (SigKZIDHelper.isMOCCASigned(so)) {
+     log.debug("MOCCA signature detected.");
+     String algorithmId = SigKZIDHelper.parseAlgorithmId(so.id);
+     log.debug("Algorithm = " + algorithmId);
+     LocRefDetachedMOCCAConnector mocca_connector = new LocRefDetachedMOCCAConnector(this.params, "not needed here", algorithmId);
+     xml_content = mocca_connector.prepareXMLContent(data, so);
+  }
+  // TD
     else
     {
+      log.debug("TD signature signature detected.");
       xml_content = prepareXMLContent(data, so);
     }
-
+    
     String verify_request_xml = verify_request_template.replaceFirst(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"));
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java
index f30b4b7..e415e98 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java
@@ -360,13 +360,8 @@ public class EnvelopedBase64BKUConnector implements Connector, LocalConnector
 
     BKUHelper.checkResponseForError(response_string);
 
-    // TODO[tknall] Parse server type and version in order to prevent unsupported cces from signing pdfs
-    String bkuServerHeader = response_properties.getProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY);
-    String bkuUserAgentHeader = response_properties.getProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY);
-    // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.dataurl
-    log.debug("BKU response header \"user-agent\" header:  " + bkuUserAgentHeader);
-    // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.browser
-    log.debug("BKU response header \"server\"     header:  " + bkuServerHeader);
+    String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties);
+    log.debug("BKU identifier: \"" + bkuIdentifier + "\"");
     
     SignSignatureObject so = BKUHelper.parseCreateXMLResponse(response_string, new HotfixIdFormatter());
 
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java
index 6ad5b94..b31d1ec 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java
@@ -107,14 +107,6 @@ public class DetachedLocRefMOAConnector implements Connector
 
     BKUHelper.checkResponseForError(response_string);
 
-    // TODO[tknall] Parse server type and version in order to prevent unsupported cces from signing pdfs
-    String bkuServerHeader = response_properties.getProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY);
-    String bkuUserAgentHeader = response_properties.getProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY);
-    // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.dataurl
-    log.debug("BKU response header \"user-agent\" header:  " + bkuUserAgentHeader);
-    // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.browser
-    log.debug("BKU response header \"server\"     header:  " + bkuServerHeader);
-    
     SignSignatureObject so = MOAHelper.parseCreateXMLResponse(response_string, new DetachedLocRefMOAIdFormatter());
 
     log.debug("analyzeSignResponse finished."); //$NON-NLS-1$
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java
index b309432..a6db63c 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java
@@ -218,14 +218,6 @@ public class EnvelopingBase64MOAConnector implements Connector
 
     BKUHelper.checkResponseForError(response_string);
 
-    // TODO[tknall] Parse server type and version in order to prevent unsupported cces from signing pdfs
-    String bkuServerHeader = response_properties.getProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY);
-    String bkuUserAgentHeader = response_properties.getProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY);
-    // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.dataurl
-    log.debug("BKU response header \"user-agent\" header:  " + bkuUserAgentHeader);
-    // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.browser
-    log.debug("BKU response header \"server\"     header:  " + bkuServerHeader);
-
     SignSignatureObject so = MOAHelper.parseCreateXMLResponse(response_string, new OldMOAIdFormatter());
 
     log.debug("analyzeSignResponse finished."); //$NON-NLS-1$
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java
index abd2b09..4636e20 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java
@@ -115,14 +115,6 @@ public class MOASoapWithAttachmentConnector implements Connector
 
     BKUHelper.checkResponseForError(response_string);
 
-    // TODO[tknall] Parse server type and version in order to prevent unsupported cces from signing pdfs
-    String bkuServerHeader = response_properties.getProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY);
-    String bkuUserAgentHeader = response_properties.getProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY);
-    // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.dataurl
-    log.debug("BKU response header \"user-agent\" header:  " + bkuUserAgentHeader);
-    // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.browser
-    log.debug("BKU response header \"server\"     header:  " + bkuServerHeader);
-    
     SignSignatureObject so = MOAHelper.parseCreateXMLResponse(response_string, new DetachedLocRefMOAIdFormatter());
 
     log.debug("analyzeSignResponse finished."); //$NON-NLS-1$
@@ -189,17 +181,24 @@ public class MOASoapWithAttachmentConnector implements Connector
 
     String xml_content = null;
     
+    // MOA
     if (SigKZIDHelper.isMOASigned(so)) {
        log.debug("MOA signature detected.");
        xml_content = prepareXMLContent(data, so);
+       
+    // MOCCA
     } else if (SigKZIDHelper.isMOCCASigned(so)) {
        log.debug("MOCCA signature detected.");
-       LocRefDetachedMOCCAConnector mocca_connector = new LocRefDetachedMOCCAConnector(this.params, "not needed here");
+       String algorithmId = SigKZIDHelper.parseAlgorithmId(so.id);
+       log.debug("Algorithm = " + algorithmId);
+       LocRefDetachedMOCCAConnector mocca_connector = new LocRefDetachedMOCCAConnector(this.params, "not needed here", algorithmId);
        xml_content = mocca_connector.prepareXMLContent(data, so);
+    
+    // TD
     } else {
-       log.debug("Generic signature (not MOA/MOCCA) signature detected.");
-      DetachedBKUConnector bku_connector = new DetachedBKUConnector(this.params, "not needed here");
-      xml_content = bku_connector.prepareXMLContent(data, so);
+       log.debug("TD signature signature detected.");
+       DetachedBKUConnector bku_connector = new DetachedBKUConnector(this.params, "not needed here");
+       xml_content = bku_connector.prepareXMLContent(data, so);
     }
 
     String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content);
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java
index c44f34b..b27edde 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java
@@ -12,6 +12,7 @@ import at.gv.egiz.pdfas.exceptions.ErrorCode;
 import at.gv.egiz.pdfas.framework.ConnectorParameters;
 import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
 import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
+import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException;
 import at.knowcenter.wag.egov.egiz.exceptions.SettingsException;
 import at.knowcenter.wag.egov.egiz.sig.SignatureData;
 import at.knowcenter.wag.egov.egiz.sig.SignatureResponse;
@@ -22,6 +23,9 @@ import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper;
 import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection;
 import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject;
 import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedMOCIdFormatter;
+import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper;
+import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler;
+import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandlerFactory;
 import at.knowcenter.wag.egov.egiz.tools.CodingHelper;
 import at.knowcenter.wag.egov.egiz.tools.FileHelper;
 
@@ -50,8 +54,19 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector {
     * @throws ConnectorException Thrown in case of error.
     */
    public LocRefDetachedMOCCAConnector(ConnectorParameters connectorParameters, String loc_ref_content) throws ConnectorException {
+      this(connectorParameters, loc_ref_content, null);
+   }
+
+   /**
+    * Constructor that builds the configuration environment for this connector according to the
+    * given profile.
+    * @param connectorParameters The connectot parameters.
+    * @param algorithmId The algorithm idenifier.
+    * @throws ConnectorException Thrown in case of error.
+    */
+   public LocRefDetachedMOCCAConnector(ConnectorParameters connectorParameters, String loc_ref_content, String algorithmId) throws ConnectorException {
       this.params = connectorParameters;
-      this.environment = new Environment(this.params.getProfileId(), loc_ref_content);
+      this.environment = new Environment(this.params.getProfileId(), loc_ref_content, algorithmId);
    }
 
    /**
@@ -116,15 +131,17 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector {
       String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY);
       BKUHelper.checkResponseForError(response_string);
       
-      // TODO[tknall] Parse server type and version in order to prevent unsupported cces from signing pdfs
-      String bkuServerHeader = response_properties.getProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY);
-      String bkuUserAgentHeader = response_properties.getProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY);
-      // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.dataurl
-      log.debug("BKU response header \"user-agent\" header:  " + bkuUserAgentHeader);
-      // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.browser
-      log.debug("BKU response header \"server\"     header:  " + bkuServerHeader);
-
-      SignSignatureObject so = MOCCAHelper.parseCreateXMLResponse(response_string, new DetachedMOCIdFormatter());
+      String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties);
+      log.debug("BKU identifier: \"" + bkuIdentifier + "\"");
+      SignatureLayoutHandler sigLayout;
+      try {
+         sigLayout = SignatureLayoutHandlerFactory.getSignatureLayoutHandlerInstance(bkuIdentifier);
+      } catch (SettingsException e) {
+         throw new ConnectorException(e.getErrorCode(), e.getMessage());
+      }
+      
+//      SignSignatureObject so = MOCCAHelper.parseCreateXMLResponse(response_string, new DetachedMOCIdFormatter());
+      SignSignatureObject so = sigLayout.parseCreateXMLSignatureResponse(response_string);
       so.response_properties = response_properties;
       log.debug("analyzeSignResponse finished."); 
       return so;
@@ -275,21 +292,21 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector {
       protected static final String TEMPLATE_FILE_PREFIX = "./templates/moc.";
 
       /**
-       * signing file template sufix
+       * signing file template suffix
        */
-      protected static final String SIGN_TEMPLATE_FILE_SUFIX = ".sign.request.xml";
+      protected static final String SIGN_TEMPLATE_FILE_SUFFIX = ".sign.request.xml";
 
       /**
-       * verifing template file sufix
+       * verifing template file suffix
        */
       /* signature verification is not supported by mocca
       protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml";
        */
 
       /**
-       * verifing file template key sufix
+       * verifing file template key suffix
        */
-      protected static final String VERIFY_TEMPLATE_SUFIX = ".verify.template.xml";
+      protected static final String VERIFY_TEMPLATE_SUFFIX = ".verify.template.xml";
 
       /**
        * The configuration key of the verify request template.
@@ -343,13 +360,16 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector {
       protected String cert_alg_ecdsa = null;
 
       protected String cert_alg_rsa = null;
+      
+      protected String algorithmId = null;
 
       /**
        * Initializes the environment with a given profile.
        * @param profile The configuration profile.
+       * @param algorithmId The algorithm identifer.
        * @throws ConnectorException Thrown in case of an error.
        */
-      public Environment(String profile, String loc_ref_content) throws ConnectorException {
+      public Environment(String profile, String loc_ref_content, String algorithmId) throws ConnectorException {
          this.profile = profile;
 
          this.loc_ref_content = loc_ref_content;
@@ -363,11 +383,16 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector {
 
          this.sign_keybox_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEYBOX_IDENTIFIER_KEY);
 
+         if (algorithmId == null) {
+            this.algorithmId = settings.getValueFromKey("default.moc.algorithm.id");
+         } else {
+            this.algorithmId = algorithmId;
+         }
 
          // SIGN REQUEST
          
          // try specific file
-         String sign_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moc.algorithm.id") + SIGN_TEMPLATE_FILE_SUFIX;
+         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);
          this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename));
 
@@ -410,7 +435,7 @@ public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector {
          
          // load template file
          // try specific file
-         String verify_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moc.algorithm.id") + VERIFY_TEMPLATE_SUFIX;
+         String verify_filename = TEMPLATE_FILE_PREFIX + this.algorithmId + VERIFY_TEMPLATE_SUFFIX;
          log.debug("Trying to load specific signature template file " + verify_filename);
          this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename));
 
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java
index fe23584..7e32230 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java
@@ -38,25 +38,6 @@ public final class MOCCAHelper {
     */
    private final static Log log = LogFactory.getLog(MOCCAHelper.class);
    
-   /**
-    * The pattern that identifies a mocca response (that matches the header value "Server" or "User-Agent").
-    */
-   private final static Pattern MOCCA_PATTERN  = Pattern.compile("(citizen-card-environment/\\d+(\\.\\d+) MOCCA[ /].*)|(Jetty(.*))");
-
-   /**
-    * Checks if the given header value for "Server" or "User-Agent" respectively indicates that
-    * the response was from a mocca cce.
-    * @param cceId The value of the http header "Server" or "User-Agent".
-    * @see http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung
-    * @return <code>true</code> if the id points to a mocca response, <code>false</code> if not.
-    */
-   public final static boolean isMOCCACCEId(String cceId) {
-      if (cceId == null) {
-         return false;
-      }
-      return MOCCA_PATTERN.matcher(cceId).matches();
-   }
-
    /**
     * This method parses the signature creation response of the signature
     * device mocca.
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java
index ae46225..8b9b606 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java
@@ -16,17 +16,21 @@ import at.knowcenter.wag.egov.egiz.exceptions.SettingsException;
  */
 public class DetachedMOCIdFormatter implements IdFormatter {
 
-   public static final String SIG_ID_PREFIX = "etsi-moc-1.0";
-
    /**
     * Key value in property file
     */
-   public static final String SIG_ID_PROPERTY_KEY = "default.moc.algorithm.id";
+   private static final String SIG_ID_PROPERTY_KEY = "default.moc.algorithm.id";
 
    /**
     * The log.
     */
    private static Log log = LogFactory.getLog(DetachedIdFormatter.class);
+   
+   private String algorithmId;
+   
+   public DetachedMOCIdFormatter(String algorithmId) {
+      this.algorithmId = algorithmId;
+   }
 
    /**
     * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[])
@@ -39,7 +43,7 @@ public class DetachedMOCIdFormatter implements IdFormatter {
       } catch (SettingsException e) {
          log.error(e.getMessage(), e);
       }
-      prefix = StringUtils.defaultIfEmpty(prefix, SIG_ID_PREFIX);
+      prefix = StringUtils.defaultIfEmpty(this.algorithmId, prefix);
       
       StringBuffer formattedIds = new StringBuffer(prefix).append("@").append(ids[0]);
       return formattedIds.toString();
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java
index 67c5e15..5c3fc07 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java
@@ -3,14 +3,22 @@
  */
 package at.knowcenter.wag.egov.egiz.sig.sigkz;
 
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.regex.Pattern;
+
 import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import at.gv.egiz.pdfas.exceptions.ErrorCode;
 import at.knowcenter.wag.egov.egiz.PdfASID;
+import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
 import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
 import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException;
+import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException;
+import at.knowcenter.wag.egov.egiz.exceptions.SettingsException;
 import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
 import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject;
 import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedLocRefMOAIdFormatter;
@@ -95,17 +103,34 @@ public final class SigKZIDHelper
    * @author tknall
    */
   public static boolean isMOCCASigned(SignSignatureObject so) {
-     String sig_kz = so.kz;
      String sig_id = so.id;
-     if (StringUtils.isEmpty(sig_kz) || StringUtils.isEmpty(sig_id)) {
+     if (StringUtils.isEmpty(sig_id)) {
         return false;
      }
      String[] ids = sig_id.split("@");
      if (ArrayUtils.isEmpty(ids)) {
         return false;
      }
-     String prefix = ids[0];
-     return DetachedMOCIdFormatter.SIG_ID_PREFIX.equals(prefix);
+     String algorithmId = parseAlgorithmId(sig_id);
+     if (algorithmId == null) {
+        return false;
+     } else {
+        return algorithmId.startsWith("etsi-moc-");
+     }
+  }
+
+  /**
+   * @author tknall
+   */
+  public static String parseAlgorithmId(String algorithmParameter) {
+     if (StringUtils.isEmpty(algorithmParameter)) {
+        return null;
+     }
+     String[] ids = algorithmParameter.split("@");
+     if (ArrayUtils.isEmpty(ids)) {
+        return null;
+     }
+     return ids[0];
   }
 
   public static boolean isOldBKU(PdfASID sig_kz, String sig_id) throws ConnectorException
@@ -158,5 +183,34 @@ public final class SigKZIDHelper
     
     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();
+       String key = base + "." + subKey;
+       String value = sr.getSetting(key);
+       Pattern p = Pattern.compile(value);
+       if (p.matcher(bkuIdentifier).matches()) {
+          String algKey = "signaturelayout.algorithm.id." + subKey;
+          String algValue = sr.getSetting(algKey);
+          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);
+    } else {
+       logger.debug("bku support check disabled.");
+       return null;
+    }
+    
+  }
 
 }
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java
new file mode 100644
index 0000000..964908d
--- /dev/null
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java
@@ -0,0 +1,21 @@
+package at.knowcenter.wag.egov.egiz.sig.signaturelayout;
+
+import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
+import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject;
+
+/**
+ * Considers different signature layout characteristics among different versions of citizen card
+ * environments. 
+ * @author tknall
+ */
+public interface SignatureLayoutHandler {
+   
+   /**
+    * This method parses the CreateXMLSignatureResponse given from a certain signature device.
+    * 
+    * @param xmlResponse The response string.
+    * @return Returns the parsed signature object.
+    */
+   public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse) throws ConnectorException;
+
+}
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java
new file mode 100644
index 0000000..c56b5f6
--- /dev/null
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java
@@ -0,0 +1,121 @@
+package at.knowcenter.wag.egov.egiz.sig.signaturelayout;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.util.regex.Pattern;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.pdfas.exceptions.ErrorCode;
+import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
+import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
+import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException;
+import at.knowcenter.wag.egov.egiz.exceptions.SettingsException;
+
+/**
+ * Returns instances of signature layout handlers based on given bku
+ * identifiers.
+ * 
+ * @author tknall
+ */
+public class SignatureLayoutHandlerFactory {
+
+   /**
+    * Prefix of configuration keys defining bku identifiers for a signature layout.
+    */
+   private final static String SIGNATURE_LAYOUT_CONFIG_KEY_PATTERN = "signaturelayout.pattern";
+   
+   /**
+    * Prefix of configuration keys defining implementations of signature layout handlers.
+    * @see SignatureLayoutHandler
+    */
+   private final static String SIGNATURE_LAYOUT_CONFIG_KEY_IMPL = "signaturelayout.implementation";
+   
+   /**
+    * A map holding instantiated signature layout implementations (for performance reasons).
+    */
+   private final static Map instances = Collections.synchronizedMap(new HashMap());
+
+   /**
+    * The log.
+    */
+   private static Log log = LogFactory.getLog(SignatureLayoutHandlerFactory.class);
+   
+   /**
+    * Returns an instance of a signature layout handler based on the given bku identifier.
+    * @param bkuIdentifier The bku identifier (e.g. <code>citizen-card-environment/1.2 MOCCA/1.1.1</code>).
+    * @return An implementation of a signature layout handler.
+    * @throws ConnectorException Thrown in case of an error finding a match within the configuration with the given bku identifier.
+    * @throws SettingsException Thrown in case of an error within the configuration.
+    */
+   public static SignatureLayoutHandler getSignatureLayoutHandlerInstance(String bkuIdentifier) throws ConnectorException, SettingsException {
+      SignatureLayoutHandler signatureLayoutHandler = (SignatureLayoutHandler) instances.get(bkuIdentifier);
+      
+      if (signatureLayoutHandler == null) {
+         SettingsReader sr = SettingsReader.getInstance();
+
+         Vector v = sr.getSettingKeys(SIGNATURE_LAYOUT_CONFIG_KEY_PATTERN);
+         String implValue = null;
+
+         Iterator it = v.iterator();
+         try {
+            while (it.hasNext()) {
+               String subKey = (String) it.next();
+               String key = SIGNATURE_LAYOUT_CONFIG_KEY_PATTERN + "." + subKey;
+               String value = sr.getSetting(key);
+               Pattern p = Pattern.compile(value);
+               if (p.matcher(bkuIdentifier).matches()) {
+                  String implKey = SIGNATURE_LAYOUT_CONFIG_KEY_IMPL + "." + subKey;
+                  implValue = sr.getSetting(implKey);
+               }
+            }
+         } catch (SettingNotFoundException e) {
+            throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, e.getMessage());
+         }
+
+         if (implValue == null) {
+            throw new ConnectorException(ErrorCode.BKU_NOT_SUPPORTED, "Unsupported BKU: " + bkuIdentifier);
+         }
+         
+         log.debug("Trying to instantiate SignatureLayoutHandler \"" + implValue + "\".");
+
+         try {
+            Class clazz = Class.forName(implValue);
+            Object obj = clazz.newInstance();
+            if (!(obj instanceof SignatureLayoutHandler)) {
+               throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Invalid signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\".");
+            }
+            signatureLayoutHandler = (SignatureLayoutHandler) obj;
+         } catch (InstantiationException e) {
+            throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Error instantiating signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\".");
+         } catch (IllegalAccessException e) {
+            throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Illegal access instantiating signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\".");
+         } catch (ClassNotFoundException e) {
+            throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Unable to find signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\".");
+         }
+
+         log.debug("SignatureLayoutHandler successfully instantiated.");
+         instances.put(bkuIdentifier, signatureLayoutHandler);
+      } else {
+         log.trace("SignatureLayoutHandler has already been instantiated. Returning old instance.");
+      }
+      
+      return signatureLayoutHandler;
+
+   }
+
+   /**
+    * Verifies that the bku is supported trying to match the given bku identifier.
+    * @param bkuIdentifier The bku identifier (e.g. <code>citizen-card-environment/1.2 MOCCA/1.1.1</code>).
+    * @throws ConnectorException Thrown in case of an error (e.g. bku not supported).
+    * @throws SettingsException Thrown in case of an error within the configuration.
+    */
+   public static void verifyBKUSupport(String bkuIdentifier) throws ConnectorException, SettingsException {
+      getSignatureLayoutHandlerInstance(bkuIdentifier);
+   }
+
+}
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java
new file mode 100644
index 0000000..0913b49
--- /dev/null
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java
@@ -0,0 +1,24 @@
+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.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;
+
+/**
+ * Implementation of a signature layout handler for the first release of mocca.
+ * @author tknall
+ */
+public class MOCCASignatureLayout10Handler implements SignatureLayoutHandler {
+
+   private final static String ALGORITHM_ID = "etsi-moc-1.1";
+
+   /**
+    * Parses the given xmlResponse with respect to the specific signature layout of mocca.
+    */
+   public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse) throws ConnectorException {
+      return MOCCAHelper.parseCreateXMLResponse(xmlResponse, new DetachedMOCIdFormatter(ALGORITHM_ID));
+   }
+
+}
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java
new file mode 100644
index 0000000..958370e
--- /dev/null
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java
@@ -0,0 +1,24 @@
+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.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;
+
+/**
+ * Implementation of a signature layout handler for the beta version of mocca.
+ * @author tknall
+ */
+public class OldMOCCASignatureLayoutHandler implements SignatureLayoutHandler {
+   
+   private final static String ALGORITHM_ID = "etsi-moc-1.0";
+
+   /**
+    * Parses the given xmlResponse with respect to the specific signature layout of mocca.
+    */
+   public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse) throws ConnectorException {
+      return MOCCAHelper.parseCreateXMLResponse(xmlResponse, new DetachedMOCIdFormatter(ALGORITHM_ID));
+   }
+
+}
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java
new file mode 100644
index 0000000..5d6eb96
--- /dev/null
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java
@@ -0,0 +1,22 @@
+package at.knowcenter.wag.egov.egiz.sig.signaturelayout.td;
+
+import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
+import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper;
+import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject;
+import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedIdFormatter;
+import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler;
+
+/**
+ * Implementation of a signature layout handler for trustDesk basic.
+ * @author tknall
+ */
+public class TrustDeskSignatureLayoutHandler implements SignatureLayoutHandler {
+
+   /**
+    * Parses the given xmlResponse with respect to the specific signature layout of trustDesk basic.
+    */
+   public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse) throws ConnectorException {
+      return BKUHelper.parseCreateXMLResponse(xmlResponse, new DetachedIdFormatter());
+   }
+
+}
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/servlets/DataURLServlet.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/servlets/DataURLServlet.java
index 7947d90..7cf762e 100644
--- a/src/main/java/at/knowcenter/wag/egov/egiz/web/servlets/DataURLServlet.java
+++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/servlets/DataURLServlet.java
@@ -42,13 +42,17 @@ import at.knowcenter.wag.egov.egiz.PdfASID;
 import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
 import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException;
 import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
+import at.knowcenter.wag.egov.egiz.exceptions.SettingsException;
 import at.knowcenter.wag.egov.egiz.exceptions.SignatorFactoryException;
 import at.knowcenter.wag.egov.egiz.exceptions.SignatureException;
 import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder;
 import at.knowcenter.wag.egov.egiz.sig.SignatureResponse;
 import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorChooser;
 import at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector;
+import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper;
 import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection;
+import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler;
+import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandlerFactory;
 import at.knowcenter.wag.egov.egiz.web.FormFields;
 import at.knowcenter.wag.egov.egiz.web.LocalRequest;
 import at.knowcenter.wag.egov.egiz.web.LocalRequestHelper;
@@ -200,7 +204,17 @@ public class DataURLServlet extends HttpServlet
     log.trace("processSign");
     
     String xml_response = retrieveXMLResponse(request);
+    Properties response_properties = BKUHelper.getBKUProperties(request);
 
+    String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties);
+    log.debug("BKU identifier: \"" + bkuIdentifier + "\"");
+    
+    try {
+       SignatureLayoutHandlerFactory.verifyBKUSupport(bkuIdentifier);
+    } catch (SettingsException e) {
+       throw new ConnectorException(e.getErrorCode(), e.getMessage());
+    }
+    
     if (isNullResponse(xml_response))
     {
       log.debug("Received a NullOperationResponse -> answering with the first request."); //$NON-NLS-1$
@@ -210,12 +224,6 @@ public class DataURLServlet extends HttpServlet
       
       log.debug("There are still requests to be performed -> answering with request."); //$NON-NLS-1$
 
-      // TODO[tknall] Parse user agent's cce type and version in order to prevent unsupported cces from signing pdfs
-      // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.dataurl
-      log.debug("BKU response header \"user-agent\" header:  " + request.getHeader("User-Agent"));
-      // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.browser
-      log.debug("BKU response header \"server\"     header:  " + request.getHeader("Server"));
-      
       LocalRequest local_request = si.localRequest;
 
       String request_string = local_request.getRequestString();
@@ -229,16 +237,8 @@ public class DataURLServlet extends HttpServlet
     {
       log.debug("Received a normal response -> storing the response."); //$NON-NLS-1$
 
-      Properties response_properties = new Properties();
       response_properties.setProperty(BKUPostConnection.RESPONSE_STRING_KEY, xml_response);
       
-      String userAgent = request.getHeader("User-Agent");
-      if (userAgent != null) {
-         response_properties.setProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY, userAgent);
-      } else {
-         log.warn("BKU request/response header \"User-Agent\" is empty.");
-      }
-      
       si.response_properties = response_properties;
       
       log.debug("All requests have been processed -> processing the responses."); //$NON-NLS-1$
-- 
cgit v1.2.3