CAMEL-8129: XAdES BES/EPES for XML Signature Signer. Thanks to Franz Forsthofer 
for the patch.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/23688d3d
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/23688d3d
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/23688d3d

Branch: refs/heads/master
Commit: 23688d3d84886e9f6fab8d73bc72991484f5c151
Parents: 0866d13
Author: Claus Ibsen <[email protected]>
Authored: Wed Dec 17 08:18:59 2014 +0100
Committer: Claus Ibsen <[email protected]>
Committed: Wed Dec 17 08:18:59 2014 +0100

----------------------------------------------------------------------
 components/camel-xmlsecurity/pom.xml            |    6 +
 .../api/DefaultXAdESSignatureProperties.java    |   58 +
 .../api/XAdESEncapsulatedPKIData.java           |   83 ++
 .../api/XAdESSignatureProperties.java           | 1207 ++++++++++++++++++
 .../xmlsecurity/api/XmlSignatureConstants.java  |   49 +
 .../xmlsecurity/api/XmlSignatureProperties.java |   43 +-
 .../processor/XmlSignerProcessor.java           |   42 +-
 .../xmlsecurity/SpringXmlSignatureTest.java     |   28 +
 .../XAdESSignaturePropertiesTest.java           |  922 +++++++++++++
 .../component/xmlsecurity/XmlSignatureTest.java |    8 +-
 .../xmlsecurity/util/TestKeystore.java          |    2 +-
 .../xmlsecurity/SpringXmlSignatureTests.xml     |   33 +
 .../camel/component/xmlsecurity/xades/XAdES.xsd |  466 +++++++
 .../xmlsecurity/xades/xmldsig-core-schema.xsd   |  291 +++++
 .../features/src/main/resources/features.xml    |    1 +
 15 files changed, 3221 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/23688d3d/components/camel-xmlsecurity/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/pom.xml 
b/components/camel-xmlsecurity/pom.xml
index 142a71e..74d02ec 100755
--- a/components/camel-xmlsecurity/pom.xml
+++ b/components/camel-xmlsecurity/pom.xml
@@ -46,6 +46,12 @@
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-core</artifactId>
         </dependency>
+        <!-- for base 64 in XAdES -->
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>${commons-codec-version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.santuario</groupId>
             <artifactId>xmlsec</artifactId>

http://git-wip-us.apache.org/repos/asf/camel/blob/23688d3d/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/DefaultXAdESSignatureProperties.java
----------------------------------------------------------------------
diff --git 
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/DefaultXAdESSignatureProperties.java
 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/DefaultXAdESSignatureProperties.java
new file mode 100644
index 0000000..edfd757
--- /dev/null
+++ 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/DefaultXAdESSignatureProperties.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.xmlsecurity.api;
+
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+
+/**
+ * Default implementation for the XAdES signature properties which determines
+ * the Signing Certificate from a keystore and an alias.
+ * 
+ */
+public class DefaultXAdESSignatureProperties extends XAdESSignatureProperties {
+
+    private KeyStore keystore;
+
+    private String alias;
+
+    public DefaultXAdESSignatureProperties() {
+    }
+
+    public void setKeystore(KeyStore keystore) {
+        this.keystore = keystore;
+    }
+
+    public void setAlias(String alias) {
+        this.alias = alias;
+    }
+
+    @Override
+    protected X509Certificate getSigningCertificate() throws Exception { 
//NOPMD
+        X509Certificate cert = (X509Certificate) 
keystore.getCertificate(alias);
+        if (cert == null) {
+            throw new XmlSignatureException("No certificate found in keystore 
for alias '%s'");
+        }
+        return cert;
+    }
+
+    @Override
+    protected X509Certificate[] getSigningCertificateChain() throws Exception 
{ //NOPMD
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/23688d3d/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XAdESEncapsulatedPKIData.java
----------------------------------------------------------------------
diff --git 
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XAdESEncapsulatedPKIData.java
 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XAdESEncapsulatedPKIData.java
new file mode 100644
index 0000000..55b7c68
--- /dev/null
+++ 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XAdESEncapsulatedPKIData.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.xmlsecurity.api;
+
+/**
+ * Class representing the Encapsulated PKI Data of the XAdES specification.
+ * 
+ */
+public class XAdESEncapsulatedPKIData {
+
+    private final String base64Conent;
+
+    private final String encoding;
+
+    private final String id;
+
+    /**
+     * Constructor
+     * 
+     * @param base64Conent
+     *            base64 encoded content
+     * @param encoding
+     *            , can be <code>null</code> or empty; encoding
+     *            http://uri.etsi.org/01903/v1.2.2#DER for denoting that the
+     *            original PKI data were ASN.1 data encoded in DER.
+     *            http://uri.etsi.org/01903/v1.2.2#BER for denoting that the
+     *            original PKI data were ASN.1 data encoded in BER.
+     *            http://uri.etsi.org/01903/v1.2.2#CER for denoting that the
+     *            original PKI data were ASN.1 data encoded in CER.
+     *            http://uri.etsi.org/01903/v1.2.2#PER for denoting that the
+     *            original PKI data were ASN.1 data encoded in PER.
+     *            http://uri.etsi.org/01903/v1.2.2#XER for denoting that the
+     *            original PKI data were ASN.1 data encoded in XER.
+     * 
+     * @param id
+     *            ID for the Id attribute, can be <code>null</code>
+     * @throws IllegalArgumentException
+     *             if <tt>base64Conent</tt> is <code>null</code> or empty
+     */
+    public XAdESEncapsulatedPKIData(String base64Conent, String encoding, 
String id) {
+        if (base64Conent == null || base64Conent.isEmpty()) {
+            throw new IllegalArgumentException("Value for parameter 
'base64Conent' is null or empty");
+        }
+        this.base64Conent = base64Conent;
+        this.encoding = encoding;
+        this.id = id;
+    }
+
+    /**
+     * Returns the base 64 encoded content. Cannot be <code>null</code> or
+     * empty.
+     */
+    public String getBase64Conent() {
+        return base64Conent;
+    }
+
+    /**
+     * Returns the character encoding of the content. Cannot be
+     * <code>null</code> or empty.
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/23688d3d/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XAdESSignatureProperties.java
----------------------------------------------------------------------
diff --git 
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XAdESSignatureProperties.java
 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XAdESSignatureProperties.java
new file mode 100644
index 0000000..3daddf9
--- /dev/null
+++ 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XAdESSignatureProperties.java
@@ -0,0 +1,1207 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.xmlsecurity.api;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import javax.security.auth.x500.X500Principal;
+import javax.xml.crypto.dom.DOMStructure;
+import javax.xml.crypto.dsig.DigestMethod;
+import javax.xml.crypto.dsig.Reference;
+import javax.xml.crypto.dsig.XMLObject;
+import javax.xml.crypto.dsig.XMLSignature;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import org.apache.camel.Message;
+import org.apache.commons.codec.binary.Base64;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.util.ObjectHelper.isNotEmpty;
+
+/**
+ * Implementation of the XAdES-BES and XAdES-EPES properties defined in
+ * http://www.etsi.org/deliver/etsi_ts%5C101900_101999%5C101903%5C01.04
+ * .02_60%5Cts_101903v010402p.pdf. XAdES-T and XAdES-C is not implemented.
+ * <p>
+ * You have to overwrite the method {@link #getSigningCertificate()} or
+ * {@link #getSigningCertificateChain()} if you want to have a
+ * 'SigningCertificate' element in your XML Signature.
+ * <p>
+ * Further limitations:
+ * <ul>
+ * <li>No support for the 'QualifyingPropertiesReference' element (see section
+ * 6.3.2 of spec).</li>
+ * <li>No support for the 'Transforms' element contained in the
+ * 'SignaturePolicyId' element contained in 'SignaturePolicyIdentifier' 
element</li>
+ * <li>No support of the 'CounterSignature' element --> no support for the
+ * 'UnsignedProperties' element</li>
+ * <li>A 'CommitmentTypeIndication' element contains always the
+ * 'AllSignedDataObjects' element. The 'ObjectReference' element within the
+ * 'CommitmentTypeIndication' element is not supported.</li>
+ * <li>The 'AllDataObjectsTimeStamp' element is not supported (it requires a
+ * time authority)</li>
+ * <li>The 'IndividualDataObjectsTimeStamp' element is not supported (it
+ * requires a time authority)</li>
+ * </ul>
+ */
+public class XAdESSignatureProperties implements XmlSignatureProperties {
+
+    public static final String HTTP_URI_ETSI_ORG_01903_V1_3_2 = 
"http://uri.etsi.org/01903/v1.3.2#";;
+
+    public static final String HTTP_URI_ETSI_ORG_01903_V1_1_1 = 
"http://uri.etsi.org/01903/v1.1.1#";;
+
+    public static final String HTTP_URI_ETSI_ORG_01903_V1_2_2 = 
"http://uri.etsi.org/01903/v1.2.2#";;
+
+    public static final String SIG_POLICY_NONE = "None";
+
+    public static final String SIG_POLICY_IMPLIED = "Implied";
+
+    public static final String SIG_POLICY_EXPLICIT_ID = "ExplicitId";
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(XAdESSignatureProperties.class);
+
+    private static final Set<String> SIG_POLICY_VALUES = new TreeSet<String>();
+
+    private boolean addSigningTime = true;
+
+    private String namespace = HTTP_URI_ETSI_ORG_01903_V1_3_2;
+
+    private String prefix = "etsi";
+
+    private List<String> signingCertificateURIs = Collections.emptyList();
+
+    private String digestAlgorithmForSigningCertificate = DigestMethod.SHA256; 
//"http://www.w3.org/2000/09/xmldsig#sha1";;
+
+    private String signaturePolicy = SIG_POLICY_NONE;
+
+    private String sigPolicyId;
+
+    private String sigPolicyIdQualifier;
+
+    private String sigPolicyIdDescription;
+
+    private List<String> sigPolicyIdDocumentationReferences = 
Collections.emptyList();
+
+    private String signaturePolicyDigestAlgorithm = DigestMethod.SHA256; 
//"http://www.w3.org/2000/09/xmldsig#sha1";;
+
+    private String signaturePolicyDigestValue;
+
+    private List<String> sigPolicyQualifiers = Collections.emptyList();
+
+    private String dataObjectFormatDescription;
+
+    private String dataObjectFormatMimeType;
+
+    private String dataObjectFormatIdentifier;
+
+    private String dataObjectFormatIdentifierQualifier;
+
+    private String dataObjectFormatIdentifierDescription;
+
+    private List<String> dataObjectFormatIdentifierDocumentationReferences = 
Collections.emptyList();
+
+    private List<String> signerClaimedRoles = Collections.emptyList();
+
+    private List<XAdESEncapsulatedPKIData> signerCertifiedRoles = 
Collections.emptyList();
+
+    private String signatureProductionPlaceCity;
+
+    private String signatureProductionPlaceStateOrProvince;
+
+    private String signatureProductionPlacePostalCode;
+
+    private String signatureProductionPlaceCountryName;
+
+    private String commitmentTypeId;
+
+    private String commitmentTypeIdQualifier;
+
+    private String commitmentTypeIdDescription;
+
+    private List<String> commitmentTypeIdDocumentationReferences = 
Collections.emptyList();
+
+    private List<String> commitmentTypeQualifiers = Collections.emptyList();
+
+    static {
+        SIG_POLICY_VALUES.add(SIG_POLICY_NONE);
+        SIG_POLICY_VALUES.add(SIG_POLICY_IMPLIED);
+        SIG_POLICY_VALUES.add(SIG_POLICY_EXPLICIT_ID);
+    }
+
+    public XAdESSignatureProperties() {
+    }
+
+    public boolean isAddSigningTime() {
+        return addSigningTime;
+    }
+
+    public void setAddSigningTime(boolean addSigningTime) {
+        this.addSigningTime = addSigningTime;
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public void setNamespace(String namespace) {
+        if (namespace == null) {
+            throw new IllegalArgumentException("Parameter 'namespace' is 
null");
+        }
+        this.namespace = namespace;
+    }
+
+    protected String findNamespace(Message message) {
+        return message.getHeader(XmlSignatureConstants.HEADER_XADES_NAMESPACE, 
getNamespace(), String.class);
+    }
+
+    public String getPrefix() {
+        return prefix;
+    }
+
+    public void setPrefix(String prefix) {
+        this.prefix = prefix;
+    }
+
+    protected String findPrefix(Message message) {
+        return message.getHeader(XmlSignatureConstants.HEADER_XADES_PREFIX, 
getPrefix(), String.class);
+    }
+
+    /**
+     * URIs of the signing certificate or signing certificate chain. For the
+     * sining certificate the first URI is taken. If there is a signing
+     * certificate chain specified, then the URIs are assigned to the
+     * certificates in the chain in the order given in the provided list. You
+     * have to specify an empty entry (null or empty srting), if no URI should
+     * be assigned to a specific certificate in the list. If you specify an
+     * empty list, then no URIs are assigned.
+     * 
+     * @throws IllegalArgumentException
+     *             if the parameter is <code>null</code> or one of the URIs is
+     *             <code>null</code>
+     */
+    public void setSigningCertificateURIs(List<String> signingCertificateURIs) 
{
+        if (signingCertificateURIs == null) {
+            throw new IllegalArgumentException("Parameter 
'signingCertificateURIs' is null");
+        }
+        this.signingCertificateURIs = new 
ArrayList<String>(signingCertificateURIs);
+    }
+
+    public List<String> getSigningCertificateURIs() {
+        return signingCertificateURIs;
+    }
+
+    public String getDigestAlgorithmForSigningCertificate() {
+        return digestAlgorithmForSigningCertificate;
+    }
+
+    /**
+     * Digest Algorithm for creating the digest of the signing certificate.
+     * Possible values: "http://www.w3.org/2000/09/xmldsig#sha1";,
+     * "http://www.w3.org/2001/04/xmlenc#sha256";,
+     * "http://www.w3.org/2001/04/xmldsig-more#sha384";,
+     * "http://www.w3.org/2001/04/xmlenc#sha512";. Default value is
+     * "http://www.w3.org/2001/04/xmlenc#sha256";.
+     * 
+     */
+    public void setDigestAlgorithmForSigningCertificate(String 
digestAlgorithm) {
+        this.digestAlgorithmForSigningCertificate = digestAlgorithm;
+    }
+
+    public String getSignaturePolicy() {
+        return signaturePolicy;
+    }
+
+    /**
+     * Signature Policy. Possible values: {@link #SIG_POLICY_NONE},
+     * {@link #SIG_POLICY_IMPLIED}, {@link #SIG_POLICY_EXPLICIT_ID}. Default
+     * value is {@link #SIG_POLICY_NONE}.
+     * 
+     */
+    public void setSignaturePolicy(String signaturePolicy) {
+        if (!SIG_POLICY_VALUES.contains(signaturePolicy)) {
+            throw new IllegalArgumentException(String.format(
+                    "Signature policy '%s' is invalid. Possible values are 
'None', 'Implied', and 'ExplicitId'.", signaturePolicy));
+        }
+        this.signaturePolicy = signaturePolicy;
+    }
+
+    public String getSigPolicyId() {
+        return sigPolicyId;
+    }
+
+    /**
+     * Identifier must be specified if {@link #getSignaturePolicy()} equals
+     * "ExplicitId". Must be an URI
+     */
+    public void setSigPolicyId(String sigPolicyId) {
+        this.sigPolicyId = sigPolicyId;
+    }
+
+    public String getSigPolicyIdQualifier() {
+        return sigPolicyIdQualifier;
+    }
+
+    /**
+     * Qualifier for the Signature Policy Identifier. Possible values are
+     * <code>null</code> (which means no Qualifier element is created),
+     * "OIDAsURI", or "OIDAsURN". Default value is <code>null</code>. If the
+     * identifier is an OID then a qualifier must be set.
+     */
+    public void setSigPolicyIdQualifier(String sigPolicyIdQualifier) {
+        this.sigPolicyIdQualifier = sigPolicyIdQualifier;
+    }
+
+    public String getSigPolicyIdDescription() {
+        return sigPolicyIdDescription;
+    }
+
+    public void setSigPolicyIdDescription(String sigPolicyIdDescription) {
+        this.sigPolicyIdDescription = sigPolicyIdDescription;
+    }
+
+    public List<String> getSigPolicyIdDocumentationReferences() {
+        return sigPolicyIdDocumentationReferences;
+    }
+
+    /**
+     * 
+     * Sets the documentation references of the signature policy.
+     * 
+     * @throws IllegalArgumentException
+     *             if the parameter is <code>null</code> or one of the
+     *             documentation references is <code>null</code> or empty
+     */
+    public void setSigPolicyIdDocumentationReferences(List<String> 
sigPolicyIdDocumentationReferences) {
+        if (sigPolicyIdDocumentationReferences == null) {
+            throw new IllegalArgumentException("Parameter 
'sigPolicyIdDocumentationReferences' is null");
+        }
+        for (String ref : sigPolicyIdDocumentationReferences) {
+            if (ref == null || ref.isEmpty()) {
+                throw new IllegalArgumentException("At least one documentation 
reference of the signature policy is null or empty");
+            }
+        }
+        this.sigPolicyIdDocumentationReferences = 
sigPolicyIdDocumentationReferences;
+    }
+
+    public String getSignaturePolicyDigestAlgorithm() {
+        return signaturePolicyDigestAlgorithm;
+    }
+
+    /**
+     * Digest Algorithm for creating the digest of the signature policy
+     * document. Possible values: "http://www.w3.org/2000/09/xmldsig#sha1";,
+     * "http://www.w3.org/2001/04/xmlenc#sha256";,
+     * "http://www.w3.org/2001/04/xmldsig-more#sha384";,
+     * "http://www.w3.org/2001/04/xmlenc#sha512";. Default value is
+     * "http://www.w3.org/2001/04/xmlenc#sha256";.
+     * 
+     */
+    public void setSignaturePolicyDigestAlgorithm(String 
signaturePolicyDigestAlgorithm) {
+        this.signaturePolicyDigestAlgorithm = signaturePolicyDigestAlgorithm;
+    }
+
+    public String getSignaturePolicyDigestValue() {
+        return signaturePolicyDigestValue;
+    }
+
+    /** Digest value for the signature policy base 64 encoded. */
+    public void setSignaturePolicyDigestValue(String 
signaturePolicyDigestValue) {
+        this.signaturePolicyDigestValue = signaturePolicyDigestValue;
+    }
+
+    public List<String> getSigPolicyQualifiers() {
+        return sigPolicyQualifiers;
+    }
+
+    /**
+     * Sets the signature policy qualifiers. Each qualifier can be a text or a
+     * XML fragment with the root element 'SigPolicyQualifier' with the XAdES
+     * namespace.
+     * 
+     * @throws IllegalArgumentException
+     *             if the input parameter is <code>null</code>, or one of the
+     *             qualifiers is <code>null</code> or empty
+     * 
+     */
+    public void setSigPolicyQualifiers(List<String> sigPolicyQualifiers) {
+        if (sigPolicyQualifiers == null) {
+            throw new IllegalArgumentException("Parameter 
'sigPolicyQualifiers' is null");
+        }
+        for (String qualifier : sigPolicyQualifiers) {
+            if (qualifier == null || qualifier.isEmpty()) {
+                throw new IllegalArgumentException("At least one of the policy 
qualifiers is null or empty");
+            }
+        }
+        this.sigPolicyQualifiers = new ArrayList<String>(sigPolicyQualifiers);
+    }
+
+    public String getDataObjectFormatDescription() {
+        return dataObjectFormatDescription;
+    }
+
+    public void setDataObjectFormatDescription(String 
dataObjectFormatDescription) {
+        this.dataObjectFormatDescription = dataObjectFormatDescription;
+    }
+
+    public String getDataObjectFormatMimeType() {
+        return dataObjectFormatMimeType;
+    }
+
+    public void setDataObjectFormatMimeType(String dataObjectFormatMimeType) {
+        this.dataObjectFormatMimeType = dataObjectFormatMimeType;
+    }
+
+    public String getDataObjectFormatIdentifier() {
+        return dataObjectFormatIdentifier;
+    }
+
+    public void setDataObjectFormatIdentifier(String 
dataObjectFormatIdentifier) {
+        this.dataObjectFormatIdentifier = dataObjectFormatIdentifier;
+    }
+
+    public String getDataObjectFormatIdentifierQualifier() {
+        return dataObjectFormatIdentifierQualifier;
+    }
+
+    /**
+     * Qualifier for the Format Identifier. Possible values are
+     * <code>null</code> (which means no Qualifier element is created),
+     * "OIDAsURI", or "OIDAsURN". Default value is <code>null</code>. If the
+     * identifier is an OID then a qualifier must be set.
+     */
+    public void setDataObjectFormatIdentifierQualifier(String 
dataObjectFormatIdentifierQualifier) {
+        this.dataObjectFormatIdentifierQualifier = 
dataObjectFormatIdentifierQualifier;
+    }
+
+    public String getDataObjectFormatIdentifierDescription() {
+        return dataObjectFormatIdentifierDescription;
+    }
+
+    public void setDataObjectFormatIdentifierDescription(String 
dataObjectFormatIdentifierDescription) {
+        this.dataObjectFormatIdentifierDescription = 
dataObjectFormatIdentifierDescription;
+    }
+
+    public List<String> getDataObjectFormatIdentifierDocumentationReferences() 
{
+        return dataObjectFormatIdentifierDocumentationReferences;
+    }
+
+    /**
+     * 
+     * Sets the documentation references of the data object format identifier.
+     * 
+     * @throws IllegalArgumentException
+     *             if the parameter is <code>null</code> or one of the
+     *             documentation references is <code>null</code> or empty
+     */
+    public void 
setDataObjectFormatIdentifierDocumentationReferences(List<String> 
dataObjectFormatIdentifierDocumentationReferences) {
+        if (dataObjectFormatIdentifierDocumentationReferences == null) {
+            throw new IllegalArgumentException("Parameter 
'dataObjectFormatIdentifierDocumentationReferences' is null");
+        }
+        for (String ref : dataObjectFormatIdentifierDocumentationReferences) {
+            if (ref == null || ref.isEmpty()) {
+                throw new IllegalArgumentException("At least one reference of 
the identifier of the data object format is null or empty");
+            }
+        }
+        this.dataObjectFormatIdentifierDocumentationReferences = new 
ArrayList<String>(dataObjectFormatIdentifierDocumentationReferences);
+    }
+
+    public List<String> getSignerClaimedRoles() {
+        return signerClaimedRoles;
+    }
+
+    /**
+     * Sets the claimed roles list. A role can be either a text or a XML
+     * fragment with the root element 'ClaimedRole' with the XAdES namespace.
+     * 
+     * @throws IllegalArgumentException
+     *             if <tt>signerClaimedRoles</tt> is <code>null</code>, or if
+     *             one of the roles is <code>null</code> or empty
+     */
+    public void setSignerClaimedRoles(List<String> signerClaimedRoles) {
+        if (signerClaimedRoles == null) {
+            throw new IllegalArgumentException("Parameter 'signerClaimedRoles' 
is null");
+        }
+        for (String role : signerClaimedRoles) {
+            if (role == null || role.isEmpty()) {
+                throw new IllegalArgumentException("At least one of the signer 
claimed roles is null or empty");
+            }
+        }
+        this.signerClaimedRoles = new ArrayList<String>(signerClaimedRoles);
+    }
+
+    public List<XAdESEncapsulatedPKIData> getSignerCertifiedRoles() {
+        return signerCertifiedRoles;
+    }
+
+    /**
+     * Sets the certified roles.
+     * 
+     * @throws IllegalArgumentException
+     *             if <tt>signerCertifiedRoles</tt> is <code>null</code>
+     */
+    public void setSignerCertifiedRoles(List<XAdESEncapsulatedPKIData> 
signerCertifiedRoles) {
+        if (signerCertifiedRoles == null) {
+            throw new IllegalArgumentException("Parameter 
'signerCertifiedRoles' is null");
+        }
+        for (XAdESEncapsulatedPKIData role : signerCertifiedRoles) {
+            if (role == null) {
+                throw new IllegalArgumentException("At least one of the signer 
certified roles is null");
+            }
+        }
+        this.signerCertifiedRoles = new 
ArrayList<XAdESEncapsulatedPKIData>(signerCertifiedRoles);
+    }
+
+    public String getSignatureProductionPlaceCity() {
+        return signatureProductionPlaceCity;
+    }
+
+    public void setSignatureProductionPlaceCity(String 
signatureProductionPlaceCity) {
+        this.signatureProductionPlaceCity = signatureProductionPlaceCity;
+    }
+
+    public String getSignatureProductionPlaceStateOrProvince() {
+        return signatureProductionPlaceStateOrProvince;
+    }
+
+    public void setSignatureProductionPlaceStateOrProvince(String 
signatureProductionPlaceStateOrProvince) {
+        this.signatureProductionPlaceStateOrProvince = 
signatureProductionPlaceStateOrProvince;
+    }
+
+    public String getSignatureProductionPlacePostalCode() {
+        return signatureProductionPlacePostalCode;
+    }
+
+    public void setSignatureProductionPlacePostalCode(String 
signatureProductionPlacePostalCode) {
+        this.signatureProductionPlacePostalCode = 
signatureProductionPlacePostalCode;
+    }
+
+    public String getSignatureProductionPlaceCountryName() {
+        return signatureProductionPlaceCountryName;
+    }
+
+    public void setSignatureProductionPlaceCountryName(String 
signatureProductionPlaceCountryName) {
+        this.signatureProductionPlaceCountryName = 
signatureProductionPlaceCountryName;
+    }
+
+    public String getCommitmentTypeId() {
+        return commitmentTypeId;
+    }
+
+    public void setCommitmentTypeId(String commitmentTypeId) {
+        this.commitmentTypeId = commitmentTypeId;
+    }
+
+    public String getCommitmentTypeIdQualifier() {
+        return commitmentTypeIdQualifier;
+    }
+
+    /**
+     * Qualifier for the Commitment Type ID. Possible values are
+     * <code>null</code> (which means no Qualifier element is created),
+     * "OIDAsURI", or "OIDAsURN". Default value is <code>null</code>. If the
+     * identifier is an OID then a qualifier must be set.
+     */
+    public void setCommitmentTypeIdQualifier(String commitmentTypeIdQualifier) 
{
+        this.commitmentTypeIdQualifier = commitmentTypeIdQualifier;
+    }
+
+    public String getCommitmentTypeIdDescription() {
+        return commitmentTypeIdDescription;
+    }
+
+    public void setCommitmentTypeIdDescription(String 
commitmentTypeIdDescription) {
+        this.commitmentTypeIdDescription = commitmentTypeIdDescription;
+    }
+
+    public List<String> getCommitmentTypeIdDocumentationReferences() {
+        return commitmentTypeIdDocumentationReferences;
+    }
+
+    /**
+     * Sets the documentation references for the Commitment Type ID:
+     * 
+     * @throws IllegalArgumentException
+     *             if the parameter is <code>null</code> or a documentation
+     *             reference is <code>null</code> or empty
+     * 
+     */
+    public void setCommitmentTypeIdDocumentationReferences(List<String> 
commitmentTypeIdDocumentationReferences) {
+        if (commitmentTypeIdDocumentationReferences == null) {
+            throw new IllegalArgumentException("Parameter 
'commitmentTypeIdDocumentationReferences' is null");
+        }
+        for (String ref : commitmentTypeIdDocumentationReferences) {
+            if (ref == null || ref.isEmpty()) {
+                throw new IllegalArgumentException("At least one documentation 
reference of the commitment type is null or empty");
+            }
+        }
+        this.commitmentTypeIdDocumentationReferences = new 
ArrayList<String>(commitmentTypeIdDocumentationReferences);
+    }
+
+    public List<String> getCommitmentTypeQualifiers() {
+        return commitmentTypeQualifiers;
+    }
+
+    /**
+     * List of additional qualifying information on the commitment. Each list
+     * element can be a text or an XML fragment with the root element
+     * 'CommitmentTypeQualifier' with the XAdES namespace.
+     * 
+     * @throws IllegalArgumentException
+     *             if the input parameter is <code>null</code>, or one 
qualifier
+     *             is <code>null</code> or empty
+     */
+    public void setCommitmentTypeQualifiers(List<String> 
commitmentTypeQualifiers) {
+        if (commitmentTypeQualifiers == null) {
+            throw new IllegalArgumentException("Parameter 
'commitmentTypeQualifiers' is null");
+        }
+        for (String qualifier : commitmentTypeQualifiers) {
+            if (qualifier == null || qualifier.isEmpty()) {
+                throw new IllegalArgumentException("At least one qualifier of 
the commitment type is null or empty");
+            }
+        }
+        this.commitmentTypeQualifiers = new 
ArrayList<String>(commitmentTypeQualifiers);
+    }
+
+    @Override
+    public Output get(Input input) throws Exception { //NOPMD
+
+        XmlSignatureProperties.Output result = new Output();
+
+        if (!isAddSignedSignatureProperties() && 
!isAddSignedDataObjectPropeties()) {
+            LOG.debug("XAdES signature properties are empty. Therefore no 
XAdES element will be added to the signature.");
+            return result;
+        }
+        String signedPropertiesId = "_" + UUID.randomUUID().toString();
+        Reference ref = input.getSignatureFactory().newReference("#" + 
signedPropertiesId,
+                
input.getSignatureFactory().newDigestMethod(input.getContentDigestAlgorithm(), 
null), Collections.emptyList(),
+                "http://uri.etsi.org/01903#SignedProperties";, null);
+
+        Node parent = input.getParent();
+        Document doc;
+        if (Node.DOCUMENT_NODE == parent.getNodeType()) {
+            doc = (Document) parent; // enveloping
+        } else {
+            doc = parent.getOwnerDocument(); // enveloped
+        }
+
+        Element qualifyingProperties = createElement("QualifyingProperties", 
doc, input);
+        
setIdAttributeFromHeader(XmlSignatureConstants.HEADER_XADES_QUALIFYING_PROPERTIES_ID,
 qualifyingProperties, input);
+        String signatureId = input.getSignatureId();
+        if (signatureId == null || signatureId.isEmpty()) {
+            LOG.debug("No signature Id configured. Therefore a value is 
generated.");
+            // generate one
+            signatureId = "_" + UUID.randomUUID().toString();
+            // and set to output
+            result.setSignatureId(signatureId);
+        }
+        setAttribute(qualifyingProperties, "Target", "#" + signatureId);
+        Element signedProperties = createElement("SignedProperties", doc, 
input);
+        qualifyingProperties.appendChild(signedProperties);
+        setAttribute(signedProperties, "Id", signedPropertiesId);
+        signedProperties.setIdAttribute("Id", true);
+        addSignedSignatureProperties(doc, signedProperties, input);
+        String contentReferenceId = addSignedDataObjectProperties(doc, 
signedProperties, input);
+        result.setContentReferenceId(contentReferenceId);
+        DOMStructure structure = new DOMStructure(qualifyingProperties);
+
+        XMLObject propertiesObject = 
input.getSignatureFactory().newXMLObject(Collections.singletonList(structure), 
null, null, null);
+
+        result.setReferences(Collections.singletonList(ref));
+        result.setObjects(Collections.singletonList(propertiesObject));
+
+        return result;
+    }
+
+    protected void setAttribute(Element element, String attrName, String 
value) {
+        //  element.setAttribute(name, value); did cause NullPointerException 
in santuario 2.02
+        element.setAttributeNS("", attrName, value);
+    }
+
+    protected void setIdAttributeFromHeader(String header, Element element, 
Input input) {
+        String value = input.getMessage().getHeader(header, String.class);
+        if (value != null && !value.isEmpty()) {
+            setAttribute(element, "Id", value);
+            element.setIdAttribute("Id", true);
+        }
+    }
+
+    protected String addSignedDataObjectProperties(Document doc, Element 
signedProperties, Input input) throws XmlSignatureException,
+            SAXException, IOException, ParserConfigurationException {
+        if (isAddSignedDataObjectPropeties()) {
+            Element signedDataObjectProperties = 
createElement("SignedDataObjectProperties", doc, input);
+            
setIdAttributeFromHeader(XmlSignatureConstants.HEADER_XADES_SIGNED_DATA_OBJECT_PROPERTIES_ID,
 signedDataObjectProperties, input);
+            signedProperties.appendChild(signedDataObjectProperties);
+            String contentReferenceId = 
addDataObjectFormat(signedDataObjectProperties, doc, input);
+            addCommitmentTypeIndication(signedDataObjectProperties, doc, 
input);
+            return contentReferenceId;
+        } else {
+            return null;
+        }
+    }
+
+    protected boolean isAddSignedDataObjectPropeties() {
+        return isAddDataObjectFormat() || isAddCommitmentType();
+    }
+
+    protected void addCommitmentTypeIndication(Element 
signedDataObjectProperties, Document doc, Input input) throws SAXException,
+            IOException, ParserConfigurationException, XmlSignatureException {
+        if (!isAddCommitmentType()) {
+            return;
+        }
+        Element commitmentTypeIndication = 
createElement("CommitmentTypeIndication", doc, input);
+        signedDataObjectProperties.appendChild(commitmentTypeIndication);
+        Element commitmentTypeIdEl = createElement("CommitmentTypeId", doc, 
input);
+        commitmentTypeIndication.appendChild(commitmentTypeIdEl);
+        Element identifier = createElement("Identifier", doc, input);
+        commitmentTypeIdEl.appendChild(identifier);
+        identifier.setTextContent(getCommitmentTypeId());
+        if (getDataObjectFormatIdentifierQualifier() != null && 
!getDataObjectFormatIdentifierQualifier().isEmpty()) {
+            setAttribute(identifier, "Qualifier", 
getDataObjectFormatIdentifierQualifier());
+        }
+        if (getCommitmentTypeIdDescription() != null && 
!getCommitmentTypeIdDescription().isEmpty()) {
+            Element description = createElement("Description", doc, input);
+            commitmentTypeIdEl.appendChild(description);
+            description.setTextContent(getCommitmentTypeIdDescription());
+        }
+        if (!getCommitmentTypeIdDocumentationReferences().isEmpty()) {
+            Element documentationReferences = 
createElement("DocumentationReferences", doc, input);
+            commitmentTypeIdEl.appendChild(documentationReferences);
+            List<String> docReferences = 
getCommitmentTypeIdDocumentationReferences();
+            for (String documentationReferenceValue : docReferences) {
+                Element documentationReference = 
createElement("DocumentationReference", doc, input);
+                documentationReferences.appendChild(documentationReference);
+                
documentationReference.setTextContent(documentationReferenceValue);
+            }
+        }
+        Element allSignedDataObjects = createElement("AllSignedDataObjects", 
doc, input);
+        commitmentTypeIndication.appendChild(allSignedDataObjects);
+
+        List<String> qualifiers = getCommitmentTypeQualifiers();
+        if (!qualifiers.isEmpty()) {
+            Element qualifiersEl = createElement("CommitmentTypeQualifiers", 
doc, input);
+            commitmentTypeIndication.appendChild(qualifiersEl);
+            String errorMessage = "The XAdES confguration is invalid. The list 
of the commitment type qualifiers contains the invalid entry '%s'. An entry 
must either be a text or an XML fragment "
+                    + "with the root element '%s' with the namespace '%s'.";
+            for (String qualifier : getCommitmentTypeQualifiers()) {
+                Element qualifierEl = createChildFromXmlFragmentOrText(doc, 
input, "CommitmentTypeQualifier", errorMessage, qualifier);
+                qualifiersEl.appendChild(qualifierEl);
+            }
+        }
+    }
+
+    protected boolean isAddCommitmentType() {
+        return getCommitmentTypeId() != null && 
!getCommitmentTypeId().isEmpty();
+    }
+
+    protected String addDataObjectFormat(Element signedDataObjectProperties, 
Document doc, Input input) throws XmlSignatureException {
+        if (!isAddDataObjectFormat()) {
+            return null;
+        }
+        Element dataObjectFormat = createElement("DataObjectFormat", doc, 
input);
+        signedDataObjectProperties.appendChild(dataObjectFormat);
+        String contentReferenceId = "_" + UUID.randomUUID().toString();
+        setAttribute(dataObjectFormat, "ObjectReference", contentReferenceId);
+
+        if (getDataObjectFormatDescription() != null && 
!getDataObjectFormatDescription().isEmpty()) {
+            Element description = createElement("Description", doc, input);
+            dataObjectFormat.appendChild(description);
+            description.setTextContent(getDataObjectFormatDescription());
+        }
+        if (getDataObjectFormatIdentifier() != null && 
!getDataObjectFormatIdentifier().isEmpty()) {
+            Element objectIdentifier = createElement("ObjectIdentifier", doc, 
input);
+            dataObjectFormat.appendChild(objectIdentifier);
+            Element identifier = createElement("Identifier", doc, input);
+            objectIdentifier.appendChild(identifier);
+
+            identifier.setTextContent(getDataObjectFormatIdentifier());
+            if (getDataObjectFormatIdentifierQualifier() != null && 
!getDataObjectFormatIdentifierQualifier().isEmpty()) {
+                setAttribute(identifier, "Qualifier", 
getDataObjectFormatIdentifierQualifier());
+            }
+            if (getDataObjectFormatIdentifierDescription() != null && 
!getDataObjectFormatIdentifierDescription().isEmpty()) {
+                Element description = createElement("Description", doc, input);
+                objectIdentifier.appendChild(description);
+                
description.setTextContent(getDataObjectFormatIdentifierDescription());
+            }
+            if 
(!getDataObjectFormatIdentifierDocumentationReferences().isEmpty()) {
+                Element documentationReferences = 
createElement("DocumentationReferences", doc, input);
+                objectIdentifier.appendChild(documentationReferences);
+                List<String> docReferences = 
getDataObjectFormatIdentifierDocumentationReferences();
+                for (String documentationReferenceValue : docReferences) {
+                    Element documentationReference = 
createElement("DocumentationReference", doc, input);
+                    
documentationReferences.appendChild(documentationReference);
+                    
documentationReference.setTextContent(documentationReferenceValue);
+                }
+            }
+
+        }
+        if (getDataObjectFormatMimeType() != null && 
!getDataObjectFormatMimeType().isEmpty()) {
+            Element mimeType = createElement("MimeType", doc, input);
+            dataObjectFormat.appendChild(mimeType);
+            mimeType.setTextContent(getDataObjectFormatMimeType());
+        }
+        String encoding = 
input.getMessage().getHeader(XmlSignatureConstants.HEADER_XADES_DATA_OBJECT_FORMAT_ENCODING,
 String.class);
+        if (encoding != null && !encoding.isEmpty()) {
+            Element encodingEl = createElement("Encoding", doc, input);
+            dataObjectFormat.appendChild(encodingEl);
+            encodingEl.setTextContent(encoding);
+        }
+        return contentReferenceId;
+    }
+
+    protected boolean isAddDataObjectFormat() {
+        return (getDataObjectFormatIdentifier() != null && 
!getDataObjectFormatIdentifier().isEmpty())
+                || (getDataObjectFormatDescription() != null && 
!getDataObjectFormatDescription().isEmpty())
+                || (getDataObjectFormatMimeType() != null && 
!getDataObjectFormatMimeType().isEmpty());
+    }
+
+    protected void addSignedSignatureProperties(Document doc, Element 
signedProperties, Input input) throws Exception { //NOPMD
+        if (isAddSignedSignatureProperties()) {
+            LOG.debug("Adding signed signature properties");
+            Element signedSignatureProperties = 
createElement("SignedSignatureProperties", doc, input);
+            
setIdAttributeFromHeader(XmlSignatureConstants.HEADER_XADES_SIGNED_SIGNATURE_PROPERTIES_ID,
 signedSignatureProperties, input);
+            signedProperties.appendChild(signedSignatureProperties);
+            addSigningTime(doc, signedSignatureProperties, input);
+            addSigningCertificate(doc, signedSignatureProperties, input);
+            addSignaturePolicyIdentifier(doc, signedSignatureProperties, 
input);
+            addSignatureProductionPlace(doc, signedSignatureProperties, input);
+            addSignerRole(doc, signedSignatureProperties, input);
+        }
+    }
+
+    protected boolean isAddSignedSignatureProperties() throws Exception { 
//NOPMD
+        return isAddSigningTime() || getSigningCertificate() != null
+                || (getSigningCertificateChain() != null && 
getSigningCertificateChain().length > 0) || isAddSignaturePolicy()
+                || isAddSignatureProductionPlace() || isAddSignerRole();
+    }
+
+    protected boolean isAddSignerRole() {
+        return getSignerClaimedRoles().size() > 0 || 
getSignerCertifiedRoles().size() > 0;
+    }
+
+    protected void addSignatureProductionPlace(Document doc, Element 
signedSignatureProperties, Input input) {
+        if (!isAddSignatureProductionPlace()) {
+            return;
+        }
+        Element signatureProductionPlace = 
createElement("SignatureProductionPlace", doc, input);
+        signedSignatureProperties.appendChild(signatureProductionPlace);
+        if (getSignatureProductionPlaceCity() != null && 
!getSignatureProductionPlaceCity().isEmpty()) {
+            LOG.debug("Adding production city");
+            Element city = createElement("City", doc, input);
+            signatureProductionPlace.appendChild(city);
+            city.setTextContent(getSignatureProductionPlaceCity());
+        }
+        if (getSignatureProductionPlaceStateOrProvince() != null && 
!getSignatureProductionPlaceStateOrProvince().isEmpty()) {
+            LOG.debug("Adding production state or province");
+            Element stateOrProvince = createElement("StateOrProvince", doc, 
input);
+            signatureProductionPlace.appendChild(stateOrProvince);
+            
stateOrProvince.setTextContent(getSignatureProductionPlaceStateOrProvince());
+        }
+        if (getSignatureProductionPlacePostalCode() != null && 
!getSignatureProductionPlacePostalCode().isEmpty()) {
+            LOG.debug("Adding production postal code");
+            Element postalCode = createElement("PostalCode", doc, input);
+            signatureProductionPlace.appendChild(postalCode);
+            postalCode.setTextContent(getSignatureProductionPlacePostalCode());
+        }
+        if (getSignatureProductionPlaceCountryName() != null && 
!getSignatureProductionPlaceCountryName().isEmpty()) {
+            LOG.debug("Adding production country name");
+            Element countryName = createElement("CountryName", doc, input);
+            signatureProductionPlace.appendChild(countryName);
+            
countryName.setTextContent(getSignatureProductionPlaceCountryName());
+        }
+    }
+
+    protected boolean isAddSignatureProductionPlace() {
+        return isNotEmpty(getSignatureProductionPlaceCity()) || 
isNotEmpty(getSignatureProductionPlaceCountryName())
+                || isNotEmpty(getSignatureProductionPlacePostalCode()) || 
isNotEmpty(getSignatureProductionPlaceStateOrProvince());
+    }
+
+    protected void addSignerRole(Document doc, Element 
signedSignatureProperties, Input input) throws XmlSignatureException, 
SAXException,
+            IOException, ParserConfigurationException {
+        if (!isAddSignerRole()) {
+            return;
+        }
+        Element signerRole = createElement("SignerRole", doc, input);
+        signedSignatureProperties.appendChild(signerRole);
+        List<String> claimedRoles = getSignerClaimedRoles();
+        if (!claimedRoles.isEmpty()) {
+            LOG.debug("Adding claimed roles");
+            Element claimedRolesEl = createElement("ClaimedRoles", doc, input);
+            signerRole.appendChild(claimedRolesEl);
+            String errorMessage = "The XAdES confguration is invalid. The list 
of the claimed roles contains the invalid entry '%s'."
+                    + " An entry must either be a text or an XML fragment with 
the root element '%s' with the namespace '%s'.";
+            for (String claimedRole : claimedRoles) {
+                Element claimedRoleEl = createChildFromXmlFragmentOrText(doc, 
input, "ClaimedRole", errorMessage, claimedRole);
+                claimedRolesEl.appendChild(claimedRoleEl);
+            }
+        }
+        List<XAdESEncapsulatedPKIData> certifiedRoles = 
getSignerCertifiedRoles();
+        if (!certifiedRoles.isEmpty()) {
+            LOG.debug("Adding certified roles");
+            Element certifiedRolesEl = createElement("CertifiedRoles", doc, 
input);
+            signerRole.appendChild(certifiedRolesEl);
+            for (XAdESEncapsulatedPKIData certifiedRole : certifiedRoles) {
+                Element certifiedRoleEl = createElement("CertifiedRole", doc, 
input);
+                certifiedRolesEl.appendChild(certifiedRoleEl);
+                
certifiedRoleEl.setTextContent(certifiedRole.getBase64Conent());
+                if (certifiedRole.getEncoding() != null && 
!certifiedRole.getEncoding().isEmpty()) {
+                    setAttribute(certifiedRoleEl, "Encoding", 
certifiedRole.getEncoding());
+                }
+                if (certifiedRole.getId() != null && 
!certifiedRole.getId().isEmpty()) {
+                    setAttribute(certifiedRoleEl, "Id", certifiedRole.getId());
+                    certifiedRoleEl.setIdAttribute("Id", true);
+                }
+            }
+        }
+
+    }
+
+    protected void addSignaturePolicyIdentifier(Document doc, Element 
signedProperties, Input input) throws XmlSignatureException,
+            SAXException, IOException, ParserConfigurationException {
+        if (!isAddSignaturePolicy()) {
+            return;
+        }
+        Element signaturePolicyIdentifier = 
createElement("SignaturePolicyIdentifier", doc, input);
+        signedProperties.appendChild(signaturePolicyIdentifier);
+        if (SIG_POLICY_IMPLIED.equals(getSignaturePolicy())) {
+            LOG.debug("Adding implied signature policy");
+            Element implied = createElement("SignaturePolicyImplied", doc, 
input);
+            signaturePolicyIdentifier.appendChild(implied);
+        } else if (SIG_POLICY_EXPLICIT_ID.equals(getSignaturePolicy())) {
+            LOG.debug("Adding signatue policy ID");
+            Element id = createElement("SignaturePolicyId", doc, input);
+            signaturePolicyIdentifier.appendChild(id);
+            Element sigPolicyId = createElement("SigPolicyId", doc, input);
+            id.appendChild(sigPolicyId);
+            Element identifier = createElement("Identifier", doc, input);
+            sigPolicyId.appendChild(identifier);
+            if (getSigPolicyId() == null || getSigPolicyId().isEmpty()) {
+                throw new XmlSignatureException("The XAdES-EPES confguration 
is invalid. The signature policy identifier is missing.");
+            }
+            identifier.setTextContent(getSigPolicyId());
+            if (getSigPolicyIdQualifier() != null && 
!getSigPolicyIdQualifier().isEmpty()) {
+                setAttribute(identifier, "Qualifier", 
getSigPolicyIdQualifier());
+            }
+            if (getSigPolicyIdDescription() != null && 
!getSigPolicyIdDescription().isEmpty()) {
+                Element description = createElement("Description", doc, input);
+                sigPolicyId.appendChild(description);
+                description.setTextContent(getSigPolicyIdDescription());
+            }
+            if (!getSigPolicyIdDocumentationReferences().isEmpty()) {
+                Element documentationReferences = 
createElement("DocumentationReferences", doc, input);
+                sigPolicyId.appendChild(documentationReferences);
+                List<String> docReferences = 
getSigPolicyIdDocumentationReferences();
+                for (String documentationReferenceValue : docReferences) {
+                    Element documentationReference = 
createElement("DocumentationReference", doc, input);
+                    
documentationReferences.appendChild(documentationReference);
+                    
documentationReference.setTextContent(documentationReferenceValue);
+                }
+            }
+            //here we could introduce the transformations for the signature 
policy, which we do not yet support
+            Element sigPolicyHash = createElement("SigPolicyHash", doc, input);
+            id.appendChild(sigPolicyHash);
+            if (getSignaturePolicyDigestAlgorithm() == null || 
getSignaturePolicyDigestAlgorithm().isEmpty()) {
+                throw new XmlSignatureException(
+                        "The XAdES-EPES confguration is invalid. The digest 
algorithm for the signature policy is missing.");
+            }
+            Element digestMethod = createDigSigElement("DigestMethod", doc, 
input.getPrefixForXmlSignatureNamespace());
+            sigPolicyHash.appendChild(digestMethod);
+            setAttribute(digestMethod, "Algorithm", 
getSignaturePolicyDigestAlgorithm());
+            if (getSignaturePolicyDigestValue() == null || 
getSignaturePolicyDigestValue().isEmpty()) {
+                throw new XmlSignatureException(
+                        "The XAdES-EPES confguration is invalid. The digest 
value for the signature policy is missing.");
+            }
+            Element digestValue = createDigSigElement("DigestValue", doc, 
input.getPrefixForXmlSignatureNamespace());
+            sigPolicyHash.appendChild(digestValue);
+            digestValue.setTextContent(getSignaturePolicyDigestValue());
+
+            List<String> qualifiers = getSigPolicyQualifiers();
+            if (!qualifiers.isEmpty()) {
+                Element qualifiersEl = createElement("SigPolicyQualifiers", 
doc, input);
+                id.appendChild(qualifiersEl);
+                String errorMessage = "The XAdES confguration is invalid. The 
list of the signatue policy qualifiers contains the invalid entry '%s'."
+                        + " An entry must either be a text or an XML fragment 
with the root element '%s' with the namespace '%s'.";
+                for (String elementOrText : getSigPolicyQualifiers()) {
+                    Element child = createChildFromXmlFragmentOrText(doc, 
input, "SigPolicyQualifier", errorMessage, elementOrText);
+                    qualifiersEl.appendChild(child);
+                }
+            }
+        } else {
+            // cannot happen
+            throw new IllegalStateException(String.format(
+                    "Invalid value '%s' for parameter 'SignaturePolicy'. 
Possible values are: 'None', 'Implied', and 'ExplictId'.",
+                    getSignaturePolicy()));
+        }
+
+    }
+
+    protected Element createChildFromXmlFragmentOrText(Document doc, Input 
input, String localElementName, String errorMessage,
+            String elementOrText) throws IOException, 
ParserConfigurationException, XmlSignatureException {
+        String ending = localElementName + ">";
+        Element child;
+        if (elementOrText.startsWith("<") && elementOrText.endsWith(ending)) {
+            try {
+                // assume xml
+                InputSource source = new InputSource(new 
StringReader(elementOrText));
+                source.setEncoding("UTF-8");
+                Document parsedDoc = 
XmlSignatureHelper.newDocumentBuilder(Boolean.TRUE).parse(source);
+                replacePrefixes(parsedDoc, input);
+                child = (Element) 
doc.adoptNode(parsedDoc.getDocumentElement());
+                // check for correct namespace
+                String ns = findNamespace(input.getMessage());
+                if (!ns.equals(child.getNamespaceURI())) {
+                    throw new XmlSignatureException(
+                            String.format(
+                                    "The XAdES confguration is invalid. The 
root element '%s' of the provided XML fragment '%s' has the invalid namespace 
'%s'. The correct namespace is '%s'.",
+                                    child.getLocalName(), elementOrText, 
child.getNamespaceURI(), ns));
+                }
+            } catch (SAXException e) {
+                throw new XmlSignatureException(String.format(errorMessage, 
elementOrText, localElementName, namespace), e);
+            }
+        } else {
+            child = createElement(localElementName, doc, input);
+            child.setTextContent(elementOrText);
+        }
+        return child;
+    }
+
+    protected void replacePrefixes(Document qualifierDoc, Input input) {
+
+        Element el = qualifierDoc.getDocumentElement();
+        replacePrefix(el, input);
+
+        List<Element> childElements = getChildElements(el);
+
+        List<Element> collectedNewChildElements = new ArrayList<Element>();
+        for (; !childElements.isEmpty();) {
+            collectedNewChildElements.clear();
+            for (Element child : childElements) {
+                replacePrefix(child, input);
+                List<Element> newChildElements = getChildElements(child);
+                collectedNewChildElements.addAll(newChildElements);
+            }
+            childElements = new ArrayList<Element>(collectedNewChildElements);
+        }
+    }
+
+    protected List<Element> getChildElements(Element el) {
+        List<Element> childElements = new ArrayList<Element>(5);
+        NodeList children = el.getChildNodes();
+        int length = children.getLength();
+        for (int i = 0; i < length; i++) {
+            Node child = children.item(i);
+            if (Node.ELEMENT_NODE == child.getNodeType()) {
+                childElements.add((Element) child);
+            }
+        }
+        return childElements;
+    }
+
+    protected void replacePrefix(Element el, Input input) {
+        replacePrefixForNode(el, input);
+        NamedNodeMap nnm = el.getAttributes();
+        List<Attr> xmlnsToBeRemoved = new ArrayList<Attr>(2);
+        int length = nnm.getLength();
+        for (int i = 0; i < length; i++) {
+            Node attr = nnm.item(i);
+            replacePrefixForNode(attr, input);
+            if (attr.getNodeType() == Node.ATTRIBUTE_NODE) {
+                if ("xmlns".equals(attr.getLocalName()) || 
"xmlns".equals(attr.getPrefix())) {
+                    if (XMLSignature.XMLNS.equals(attr.getTextContent()) || 
findNamespace(input.getMessage()).equals(attr.getTextContent())) {
+                        xmlnsToBeRemoved.add((Attr) attr);
+                    }
+                }
+            }
+        }
+        // remove xml namespace declaration for XML signature and XAdES 
namespace
+        for (Attr toBeRemoved : xmlnsToBeRemoved) {
+            el.removeAttributeNode(toBeRemoved);
+        }
+
+    }
+
+    protected void replacePrefixForNode(Node node, Input input) {
+        if (XMLSignature.XMLNS.equals(node.getNamespaceURI())) {
+            node.setPrefix(input.getPrefixForXmlSignatureNamespace());
+        } else if 
(findNamespace(input.getMessage()).equals(node.getNamespaceURI())) {
+            node.setPrefix(findPrefix(input.getMessage()));
+        }
+    }
+
+    protected boolean isAddSignaturePolicy() {
+        return !SIG_POLICY_NONE.equals(getSignaturePolicy());
+    }
+
+    protected void addSigningCertificate(Document doc, Element 
signedProperties, Input input) throws Exception { //NOPMD
+        if (getSigningCertificate() == null && (getSigningCertificateChain() 
== null || getSigningCertificateChain().length == 0)) {
+            return;
+        }
+        // signed certificate
+        Element signedCertificate = createElement("SigningCertificate", doc, 
input);
+        signedProperties.appendChild(signedCertificate);
+        if (getSigningCertificate() != null) {
+            LOG.debug("Adding signing certificate");
+            X509Certificate cert = getSigningCertificate();
+            addCertificate(cert, signedCertificate, doc, 0, input);
+        } else if (getSigningCertificateChain() != null && 
getSigningCertificateChain().length > 0) {
+            Certificate[] certs = getSigningCertificateChain();
+            int index = 0;
+            for (Certificate cert : certs) {
+                LOG.debug("Adding chain certtificate {}", index);
+                X509Certificate x509Cert = (X509Certificate) cert;
+                addCertificate(x509Cert, signedCertificate, doc, index, input);
+                index++;
+            }
+        } else {
+            // cannot happen
+            throw new IllegalStateException("Unexpected exception");
+        }
+    }
+
+    /**
+     * Returns the signing certificate. If you want to have a
+     * "SigningCertificate" element then either this method or the method
+     * {@link #getSigningCertificateChain()} must return a value which is
+     * different from <code>null</code> or an empty array.
+     * <p>
+     * This implementation returns <code>null</code>
+     */
+    protected X509Certificate getSigningCertificate() throws Exception { 
//NOPMD
+        return null;
+    }
+
+    /**
+     * Returns the signing certificate. If you want to have a
+     * "SigningCertificate" element then either this method or the method
+     * {@link #getSigningCertificate()} must return a value.
+     * <p>
+     * This implementation returns <code>null</code>
+     */
+    protected X509Certificate[] getSigningCertificateChain() throws Exception 
{ //NOPMD
+        return null;
+    }
+
+    protected void addSigningTime(Document doc, Element signedProperties, 
Input input) {
+        if (isAddSigningTime()) {
+            LOG.debug("Adding signing time");
+            //signing time
+            Element signingTime = createElement("SigningTime", doc, input);
+            signedProperties.appendChild(signingTime);
+            Date current = new Date();
+            signingTime.setTextContent(new 
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(current));
+        }
+    }
+
+    protected void addCertificate(X509Certificate cert, Element 
signedCertificate, Document doc, int index, Input input)
+        throws CertificateEncodingException, NoSuchAlgorithmException, 
XmlSignatureException {
+        Element elCert = createElement("Cert", doc, input);
+        signedCertificate.appendChild(elCert);
+
+        String algorithm = 
getMessageDigestAlgorithm(getDigestAlgorithmForSigningCertificate(),
+                "The digest algorithm '%s' for the signing certificate is 
invalid");
+        String digest = calculateDigest(algorithm, cert.getEncoded());
+        Element certDigest = createElement("CertDigest", doc, input);
+        elCert.appendChild(certDigest);
+        Element digestMethod = createDigSigElement("DigestMethod", doc, 
input.getPrefixForXmlSignatureNamespace());
+        certDigest.appendChild(digestMethod);
+        setAttribute(digestMethod, "Algorithm", 
getDigestAlgorithmForSigningCertificate());
+        Element digestValue = createDigSigElement("DigestValue", doc, 
input.getPrefixForXmlSignatureNamespace());
+        certDigest.appendChild(digestValue);
+        digestValue.setTextContent(digest);
+
+        Element issuerSerial = createElement("IssuerSerial", doc, input);
+        elCert.appendChild(issuerSerial);
+        Element x509IssuerName = createDigSigElement("X509IssuerName", doc, 
input.getPrefixForXmlSignatureNamespace());
+        issuerSerial.appendChild(x509IssuerName);
+        
x509IssuerName.setTextContent(cert.getIssuerX500Principal().getName(X500Principal.RFC2253));
+        Element x509SerialNumber = createDigSigElement("X509SerialNumber", 
doc, input.getPrefixForXmlSignatureNamespace());
+        issuerSerial.appendChild(x509SerialNumber);
+        x509SerialNumber.setTextContent(cert.getSerialNumber().toString());
+
+        List<String> uris = getSigningCertificateURIs();
+        if (!uris.isEmpty() && uris.size() > index) {
+            String uri = uris.get(index);
+            if (uri != null && !uri.isEmpty()) {
+                setAttribute(elCert, "URI", uri);
+            }
+        }
+    }
+
+    protected String getMessageDigestAlgorithm(String xmlSigDigestMethod, 
String errorMessage) throws XmlSignatureException {
+        String algorithm;
+        if (DigestMethod.SHA1.equals(xmlSigDigestMethod)) {
+            algorithm = "SHA-1";
+        } else if (DigestMethod.SHA256.equals(xmlSigDigestMethod)) {
+            algorithm = "SHA-256";
+        } else if 
("http://www.w3.org/2001/04/xmldsig-more#sha384".equals(xmlSigDigestMethod)) {
+            algorithm = "SHA-384";
+        } else if 
(DigestMethod.SHA512.equals(getDigestAlgorithmForSigningCertificate())) {
+            algorithm = "SHA-512";
+        } else {
+            throw new XmlSignatureException(String.format(errorMessage, 
xmlSigDigestMethod));
+        }
+        return algorithm;
+    }
+
+    protected String calculateDigest(String algorithm, byte[] bytes) throws 
NoSuchAlgorithmException, CertificateEncodingException {
+        MessageDigest digest = MessageDigest.getInstance(algorithm);
+        byte[] digestBytes = digest.digest(bytes);
+        return new Base64().encodeAsString(digestBytes);
+    }
+
+    protected Element createDigSigElement(String localName, Document doc, 
String prefixForXmlSignatureNamespace) {
+        Element el = doc.createElementNS("http://www.w3.org/2000/09/xmldsig#";, 
localName);
+        if (prefixForXmlSignatureNamespace != null && 
!prefixForXmlSignatureNamespace.isEmpty()) {
+            el.setPrefix(prefixForXmlSignatureNamespace);
+        }
+        return el;
+    }
+
+    protected Element createElement(String localName, Document doc, Input 
input) {
+
+        Element el = doc.createElementNS(findNamespace(input.getMessage()), 
localName);
+        String p = findPrefix(input.getMessage());
+        if (p != null && !p.isEmpty()) {
+            el.setPrefix(p);
+        }
+        return el;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/23688d3d/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureConstants.java
----------------------------------------------------------------------
diff --git 
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureConstants.java
 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureConstants.java
index 4de4358..5fecbcf 100644
--- 
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureConstants.java
+++ 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureConstants.java
@@ -62,6 +62,55 @@ public final class XmlSignatureConstants {
     
     public static final String HEADER_XPATHS_TO_ID_ATTRIBUTES = 
"CamelXmlSignatureXpathsToIdAttributes";
 
+    /*------------------------- headers for XAdES signer 
----------------------------------------------------------*/
+    /**
+     * Header for the 'Id' attribute value of the XAdES element
+     * 'QualifyingProperties'
+     * 
+     */
+    public static final String HEADER_XADES_QUALIFYING_PROPERTIES_ID = 
"CamelXmlSignatureXAdESQualifyingPropertiesId";
+
+    /**
+     * Header for the 'Id' attribute value of the XAdES element
+     * 'SignedDataObjectProperties'
+     * 
+     */
+    public static final String HEADER_XADES_SIGNED_DATA_OBJECT_PROPERTIES_ID = 
"CamelXmlSignatureXAdESSignedDataObjectPropertiesId";
+
+    /**
+     * Header for the 'Id' attribute value of the XAdES element
+     * 'SignedSignatureProperties'
+     * 
+     */
+    public static final String HEADER_XADES_SIGNED_SIGNATURE_PROPERTIES_ID = 
"CamelXmlSignatureXAdESSignedSignaturePropertiesId";
+
+    /**
+     * Header for the "Encoding" element contained in the "DataObjectFormat"
+     * XAdES element.
+     */
+    public static final String HEADER_XADES_DATA_OBJECT_FORMAT_ENCODING = 
"CamelXmlSignatureXAdESDataObjectFormatEncoding";
+
+    /**
+     * Header for the XAdES namespace. Different namespaces represent different
+     * XAdES specification versions. Currently supported namespaces are:
+     * 
+     * http://uri.etsi.org/01903/v1.1.1#,
+     * 
+     * http://uri.etsi.org/01903/v1.2.2#,
+     * 
+     * http://uri.etsi.org/01903/v1.3.2#.
+     * 
+     */
+    public static final String HEADER_XADES_NAMESPACE = 
"CamelXmlSignatureXAdESNamespace";
+
+    /**
+     * Header for the XAdES namespace prefix. An empty string means that no
+     * prefix shall be used. A <code>null</code> header value will have no
+     * effect.
+     * 
+     */
+    public static final String HEADER_XADES_PREFIX = 
"CamelXmlSignatureXAdESPrefix";
+
     private XmlSignatureConstants() {
         // no instance
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/23688d3d/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureProperties.java
----------------------------------------------------------------------
diff --git 
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureProperties.java
 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureProperties.java
index 9fe72c8..3dea473 100644
--- 
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureProperties.java
+++ 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureProperties.java
@@ -58,10 +58,10 @@ public interface XmlSignatureProperties {
 
         /**
          * Returns the parent node of the signature element in the case of
-         * enveloped or detached XML signature. <code>null</code> is returned 
in
+         * enveloped or detached XML signature, or the empty result document in
          * the case of enveloping XML signature.
          * 
-         * @return parent node or <code>null</code>
+         * @return parent node, cannot be <code>null</code>
          */
         Node getParent();
 
@@ -109,10 +109,20 @@ public interface XmlSignatureProperties {
          */
         SignatureType getSignatureType();
 
+        /**
+         * Returns the prefix for the XML Signature namespace
+         * ("http://www.w3.org/2000/09/xmldsig#";). Can be null or empty.
+         */
+        String getPrefixForXmlSignatureNamespace();
+
     }
 
     public static class Output {
 
+        private String contentReferenceId;
+
+        private String signatureId;
+
         private List<? extends XMLObject> objects;
 
         private List<? extends Reference> references;
@@ -133,6 +143,35 @@ public interface XmlSignatureProperties {
             this.references = references;
         }
 
+        public String getContentReferenceId() {
+            return contentReferenceId;
+        }
+
+        /**
+         * Id value for the reference of the signed content. Currently used by
+         * the XAdES parameter DataObjectFormat. See XAdESSignatureProperties.
+         * */
+        public void setContentReferenceId(String contentReferenceId) {
+            this.contentReferenceId = contentReferenceId;
+        }
+
+        public String getSignatureId() {
+            return signatureId;
+        }
+
+        /**
+         * You can overwrite the value of the Id attribute of the Signature
+         * element that you get from {@link Input#getSignatureId()}. Only if 
the
+         * provided value is not <code>null</code> and not empty, then the
+         * signature Id will be overwritten.
+         * 
+         * @param signatureId
+         *            Id attribute value of the Signature element
+         */
+        public void setSignatureId(String signatureId) {
+            this.signatureId = signatureId;
+        }
+
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/23688d3d/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerProcessor.java
----------------------------------------------------------------------
diff --git 
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerProcessor.java
 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerProcessor.java
index eb1e4a7..0122b45 100644
--- 
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerProcessor.java
+++ 
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerProcessor.java
@@ -248,7 +248,7 @@ public class XmlSignerProcessor extends 
XmlSignatureProcessor {
 
             if (getConfiguration().getKeyAccessor() == null) {
                 throw new XmlSignatureNoKeyException(
-                    "Key selector is missing for XML signature generation. 
Specify a key selector in the configuration.");
+                    "Key accessor is missing for XML signature generation. 
Specify a key accessor in the configuration.");
             }
             
             final KeySelector keySelector = 
getConfiguration().getKeyAccessor().getKeySelector(out);
@@ -281,24 +281,31 @@ public class XmlSignerProcessor extends 
XmlSignatureProcessor {
                 // parent only relevant for enveloped or detached signature
                 Node parent = getParentOfSignature(out, node, 
contentReferenceUri, signatureType);
 
+                if (parent == null) {
+                    // for enveloping signature, create new document 
+                    parent = 
XmlSignatureHelper.newDocumentBuilder(Boolean.TRUE).newDocument();
+                }
+                lastParent = parent;
+
                 XmlSignatureProperties.Input input = new 
InputBuilder().contentDigestAlgorithm(getDigestAlgorithmUri()).keyInfo(keyInfo)
                         
.message(out).messageBodyNode(node).parent(parent).signatureAlgorithm(getConfiguration().getSignatureAlgorithm())
                         
.signatureFactory(fac).signatureId(signatureId).contentReferenceUri(contentReferenceUri)
-                        .signatureType(signatureType).build();
+                        .signatureType(signatureType)
+                        
.prefixForXmlSignatureNamespace(getConfiguration().getPrefixForXmlSignatureNamespace()).build();
 
                 XmlSignatureProperties.Output properties = 
getSignatureProperties(input);
 
+                
+                // the signature properties can overwrite the signature Id
+                if (properties != null && properties.getSignatureId() != null 
&& !properties.getSignatureId().isEmpty()) {
+                    signatureId = properties.getSignatureId();
+                }
+
                 List<? extends XMLObject> objects = getObjects(input, 
properties);
                 List<? extends Reference> refs = getReferences(input, 
properties, getKeyInfoId(keyInfo));
 
                 SignedInfo si = createSignedInfo(fac, refs);
 
-                if (parent == null) {
-                    // for enveloping signature, create new document 
-                    parent = 
XmlSignatureHelper.newDocumentBuilder(Boolean.TRUE).newDocument();
-                }
-                lastParent = parent;
-
                 DOMSignContext dsc = createAndConfigureSignContext(parent, 
keySelector);
 
                 XMLSignature signature = fac.newXMLSignature(si, keyInfo, 
objects, signatureId, null);
@@ -559,9 +566,10 @@ public class XmlSignerProcessor extends 
XmlSignatureProcessor {
     protected List<? extends Reference> 
getReferences(XmlSignatureProperties.Input input, XmlSignatureProperties.Output 
properties,
             String keyInfoId) throws Exception { //NOPMD
 
+        String referenceId = properties == null ? null : 
properties.getContentReferenceId();
         // Create Reference with URI="#<objectId>" for enveloping signature, 
URI="" for enveloped signature, and URI = <value from configuration> for 
detached signature and the transforms
         Reference ref = createReference(input.getSignatureFactory(), 
input.getContentReferenceUri(),
-                getContentReferenceType(input.getMessage()), 
input.getSignatureType());
+                getContentReferenceType(input.getMessage()), 
input.getSignatureType(), referenceId);
         Reference keyInfoRef = 
createKeyInfoReference(input.getSignatureFactory(), keyInfoId, 
input.getContentDigestAlgorithm());
 
         int propsRefsSize = properties == null || properties.getReferences() 
== null || properties.getReferences().isEmpty() ? 0
@@ -638,11 +646,11 @@ public class XmlSignerProcessor extends 
XmlSignatureProcessor {
         }
     }
 
-    protected Reference createReference(XMLSignatureFactory fac, String uri, 
String type, SignatureType sigType)
+    protected Reference createReference(XMLSignatureFactory fac, String uri, 
String type, SignatureType sigType, String id)
         throws InvalidAlgorithmParameterException, XmlSignatureException {
         try {
             List<Transform> transforms = getTransforms(fac, sigType);
-            Reference ref = fac.newReference(uri, 
fac.newDigestMethod(getDigestAlgorithmUri(), null), transforms, type, null);
+            Reference ref = fac.newReference(uri, 
fac.newDigestMethod(getDigestAlgorithmUri(), null), transforms, type, id);
             return ref;
         } catch (NoSuchAlgorithmException e) {
             throw new XmlSignatureException("Wrong algorithm specified in the 
configuration.", e);
@@ -880,6 +888,8 @@ public class XmlSignerProcessor extends 
XmlSignatureProcessor {
 
         private SignatureType signatureType;
 
+        private String prefixForXmlSignatureNamespace;
+
         public InputBuilder signatureFactory(XMLSignatureFactory 
signatureFactory) {
             this.signatureFactory = signatureFactory;
             return this;
@@ -930,6 +940,11 @@ public class XmlSignerProcessor extends 
XmlSignatureProcessor {
             return this;
         }
 
+        public InputBuilder prefixForXmlSignatureNamespace(String 
prefixForXmlSignatureNamespace) {
+            this.prefixForXmlSignatureNamespace = 
prefixForXmlSignatureNamespace;
+            return this;
+        }
+
         public XmlSignatureProperties.Input build() {
             return new XmlSignatureProperties.Input() {
 
@@ -983,6 +998,11 @@ public class XmlSignerProcessor extends 
XmlSignatureProcessor {
                     return signatureType;
                 }
 
+                @Override
+                public String getPrefixForXmlSignatureNamespace() {
+                    return prefixForXmlSignatureNamespace;
+                }
+
             };
         }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/23688d3d/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTest.java
 
b/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTest.java
index f3f0957..a0969ce 100644
--- 
a/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTest.java
+++ 
b/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTest.java
@@ -16,15 +16,24 @@
  */
 package org.apache.camel.component.xmlsecurity;
 
+import java.io.ByteArrayInputStream;
 import java.security.KeyPair;
+import java.util.Map;
 
 import javax.xml.crypto.KeySelector;
 
+import org.w3c.dom.Document;
+
 import org.apache.camel.CamelContext;
+import org.apache.camel.Message;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.xmlsecurity.api.KeyAccessor;
+import org.apache.camel.component.xmlsecurity.api.XmlSignatureHelper;
 import org.apache.camel.impl.JndiRegistry;
 import org.apache.camel.spring.SpringCamelContext;
+import org.junit.Test;
+
 
 public class SpringXmlSignatureTest extends XmlSignatureTest {
 
@@ -96,4 +105,23 @@ public class SpringXmlSignatureTest extends 
XmlSignatureTest {
     String getSignerEndpointURIEnveloping() {
         return "xmlsecurity:sign://enveloping?keyAccessor=#accessorRsa";
     }
+
+    @Test
+    public void xades() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(1);
+        sendBody("direct:xades", payload);
+        assertMockEndpointsSatisfied();
+
+        Message message = getMessage(mock);
+        byte[] body = message.getBody(byte[].class);
+        Document doc = XmlSignatureHelper.newDocumentBuilder(true).parse(new 
ByteArrayInputStream(body));
+        Map<String, String> prefix2Ns = 
XAdESSignaturePropertiesTest.getPrefix2NamespaceMap();
+        prefix2Ns.put("t", "http://test.com/";);
+        XAdESSignaturePropertiesTest
+                .checkXpath(
+                        doc,
+                        
"/ds:Signature/ds:Object/etsi:QualifyingProperties/etsi:SignedProperties/etsi:SignedSignatureProperties/etsi:SignerRole/etsi:ClaimedRoles/etsi:ClaimedRole/t:test",
+                        prefix2Ns, "test");
+    }
 }
\ No newline at end of file

Reply via email to