/**
* 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.processor;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.spec.XPathFilterParameterSpec;
import org.apache.camel.CamelContext;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.component.xmlsecurity.api.KeyAccessor;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureConstants;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureHelper;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureProperties;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureTransform;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriParams;
@UriParams
public class XmlSignerConfiguration extends XmlSignatureConfiguration {
@UriParam(label = "sign")
private XPathFilterParameterSpec parentXpath;
@UriParam(label = "sign")
private List<XPathFilterParameterSpec> xpathsToIdAttributes = Collections.emptyList();
@UriParam(label = "sign")
private List<AlgorithmMethod> transformMethods = Collections.singletonList(XmlSignatureHelper
.getCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE));
private String transformMethodsName;
@UriParam(label = "sign")
private KeyAccessor keyAccessor;
private String keyAccessorName;
@UriParam(label = "sign", defaultValue = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
private AlgorithmMethod canonicalizationMethod = new XmlSignatureTransform(CanonicalizationMethod.INCLUSIVE);
private String canonicalizationMethodName;
@UriParam(label = "sign", defaultValue = "http://www.w3.org/2000/09/xmldsig#rsa-sha1")
private String signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
@UriParam(label = "sign")
private String digestAlgorithm;
@UriParam(label = "sign", defaultValue = "true")
private Boolean addKeyInfoReference = Boolean.TRUE;
@UriParam(label = "sign", defaultValue = "ds")
private String prefixForXmlSignatureNamespace = "ds";
@UriParam(label = "sign")
private String contentObjectId;
@UriParam(label = "sign")
private String signatureId;
@UriParam(label = "sign")
private String contentReferenceUri;
@UriParam(label = "sign")
private String contentReferenceType;
@UriParam(label = "sign")
private String parentLocalName;
@UriParam(label = "sign")
private String parentNamespace;
@UriParam(label = "sign", defaultValue = "false")
private Boolean plainText = Boolean.FALSE;
@UriParam(label = "sign", defaultValue = "UTF-8")
private String plainTextEncoding = "UTF-8";
@UriParam(label = "sign")
private XmlSignatureProperties properties;
private String propertiesName;
public XmlSignerConfiguration() {
}
public XmlSignerConfiguration copy() {
try {
return (XmlSignerConfiguration) clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeCamelException(e);
}
}
@Override
public void setCamelContext(CamelContext camelContext) {
super.setCamelContext(camelContext);
// try to retrieve the references once the context is available.
setTransformMethods(transformMethodsName);
setCanonicalizationMethod(canonicalizationMethodName);
setKeyAccessor(keyAccessorName);
setProperties(propertiesName);
}
public KeyAccessor getKeyAccessor() {
return keyAccessor;
}
/**
* For the signing process, a private key is necessary. You specify a key accessor bean which provides this private key.
* The key accessor bean must implement the KeyAccessor interface. The package org.apache.camel.component.xmlsecurity.api
* contains the default implementation class DefaultKeyAccessor which reads the private key from a Java keystore.
*/
public void setKeyAccessor(KeyAccessor keyAccessor) {
this.keyAccessor = keyAccessor;
}
/**
* Sets the reference name for a KeyAccessor that can be found in the registry.
*/
public void setKeyAccessor(String keyAccessorName) {
if (getCamelContext() != null && keyAccessorName != null) {
KeyAccessor accessor = getCamelContext().getRegistry().lookupByNameAndType(keyAccessorName, KeyAccessor.class);
if (accessor != null) {
setKeyAccessor(accessor);
}
}
if (keyAccessorName != null) {
this.keyAccessorName = keyAccessorName;
}
}
public AlgorithmMethod getCanonicalizationMethod() {
return canonicalizationMethod;
}
/**
* Canonicalization method used to canonicalize the SignedInfo element before the digest is calculated.
* You can use the helper methods XmlSignatureHelper.getCanonicalizationMethod(String algorithm)
* or getCanonicalizationMethod(String algorithm, List<String> inclusiveNamespacePrefixes) to create a canonicalization method.
*/
public void setCanonicalizationMethod(AlgorithmMethod canonicalizationMethod) {
this.canonicalizationMethod = canonicalizationMethod;
}
/**
* Sets the reference name for a AlgorithmMethod that can be found in the registry.
*/
public void setCanonicalizationMethod(String canonicalizationMethodName) {
if (getCamelContext() != null && canonicalizationMethodName != null) {
AlgorithmMethod method = getCamelContext().getRegistry().lookupByNameAndType(canonicalizationMethodName, AlgorithmMethod.class);
if (method != null) {
setCanonicalizationMethod(method);
}
}
if (canonicalizationMethodName != null) {
this.canonicalizationMethodName = canonicalizationMethodName;
}
}
public List<AlgorithmMethod> getTransformMethods() {
return transformMethods;
}
/**
* Transforms which are executed on the message body before the digest is calculated.
* By default, C14n is added and in the case of enveloped signature (see option parentLocalName) also http://www.w3.org/2000/09/xmldsig#enveloped-signature
* is added at position 0 of the list. Use methods in XmlSignatureHelper to create the transform methods.
*/
public void setTransformMethods(List<AlgorithmMethod> transformMethods) {
this.transformMethods = transformMethods;
}
/**
* Sets the reference name for a List<AlgorithmMethod> that can be found in the registry.
*/
public void setTransformMethods(String transformMethodsName) {
if (getCamelContext() != null && transformMethodsName != null) {
@SuppressWarnings("unchecked")
List<AlgorithmMethod> list = getCamelContext().getRegistry().lookupByNameAndType(transformMethodsName, List.class);
if (list != null) {
setTransformMethods(list);
}
}
if (transformMethodsName != null) {
this.transformMethodsName = transformMethodsName;
}
}
public String getSignatureAlgorithm() {
return signatureAlgorithm;
}
/**
* Signature algorithm. Default value is
* "http://www.w3.org/2000/09/xmldsig#rsa-sha1".
*/
public void setSignatureAlgorithm(String signatureAlgorithm) {
this.signatureAlgorithm = signatureAlgorithm;
}
public String getDigestAlgorithm() {
return digestAlgorithm;
}
/**
* Digest algorithm URI. Optional parameter. This digest algorithm is used
* for calculating the digest of the input message. If this digest algorithm
* is not specified then the digest algorithm is calculated from the
* signature algorithm. Example: "http://www.w3.org/2001/04/xmlenc#sha256"
*/
public void setDigestAlgorithm(String digestAlgorithm) {
this.digestAlgorithm = digestAlgorithm;
}
public Boolean getAddKeyInfoReference() {
return addKeyInfoReference;
}
/**
* In order to protect the KeyInfo element from tampering you can add a
* reference to the signed info element so that it is protected via the
* signature value. The default value is <tt>true</tt>.
* <p>
* Only relevant when a KeyInfo is returned by {@link KeyAccessor}. and
* {@link KeyInfo#getId()} is not <code>null</code>.
*/
public void setAddKeyInfoReference(Boolean addKeyInfoReference) {
this.addKeyInfoReference = addKeyInfoReference;
}
public String getPrefixForXmlSignatureNamespace() {
return prefixForXmlSignatureNamespace;
}
/**
* Namespace prefix for the XML signature namespace
* "http://www.w3.org/2000/09/xmldsig#". Default value is "ds".
*
* If <code>null</code> or an empty value is set then no prefix is used for
* the XML signature namespace.
* <p>
* See best practice
* http://www.w3.org/TR/xmldsig-bestpractices/#signing-xml-
* without-namespaces
*
* @param prefixForXmlSignatureNamespace
* prefix
*/
public void setPrefixForXmlSignatureNamespace(String prefixForXmlSignatureNamespace) {
this.prefixForXmlSignatureNamespace = prefixForXmlSignatureNamespace;
}
public String getParentLocalName() {
return parentLocalName;
}
/**
* Local name of the parent element to which the XML signature element will
* be added. Only relevant for enveloped XML signature. Alternatively you can
* also use {@link #setParentXpath(XPathFilterParameterSpec)}.
*
* <p> Default value is
* <code>null</code>. The value must be <code>null</code> for enveloping and
* detached XML signature.
* <p>
* This parameter or the parameter {@link #setParentXpath(XPathFilterParameterSpec)}
* for enveloped signature and the parameter {@link #setXpathsToIdAttributes(List)}
* for detached signature must not be set in the same configuration.
* <p>
* If the parameters <tt>parentXpath</tt> and <tt>parentLocalName</tt> are specified
* in the same configuration then an exception is thrown.
*
* @param parentLocalName
* local name
*/
public void setParentLocalName(String parentLocalName) {
this.parentLocalName = parentLocalName;
}
public String getParentNamespace() {
return parentNamespace;
}
/**
* Namespace of the parent element to which the XML signature element will
* be added.
*/
public void setParentNamespace(String parentNamespace) {
this.parentNamespace = parentNamespace;
}
public String getContentObjectId() {
if (contentObjectId == null) {
// content object ID must always be set, because it is only used in enveloping case.
contentObjectId = "_" + UUID.randomUUID().toString();
}
return contentObjectId;
}
/**
* Sets the content object Id attribute value. By default a UUID is
* generated. If you set the <code>null</code> value, then a new UUID will
* be generated. Only used in the enveloping case.
*/
public void setContentObjectId(String contentObjectId) {
this.contentObjectId = contentObjectId;
}
public String getSignatureId() {
return signatureId;
}
/**
* Sets the signature Id. If this parameter is not set (null value) then a
* unique ID is generated for the signature ID (default). If this parameter
* is set to "" (empty string) then no Id attribute is created in the
* signature element.
*/
public void setSignatureId(String signatureId) {
this.signatureId = signatureId;
}
public String getContentReferenceUri() {
return contentReferenceUri;
}
/**
* Reference URI for the content to be signed. Only used in the enveloped
* case. If the reference URI contains an ID attribute value, then the
* resource schema URI ( {@link #setSchemaResourceUri(String)}) must also be
* set because the schema validator will then find out which attributes are
* ID attributes. Will be ignored in the enveloping or detached case.
*/
public void setContentReferenceUri(String referenceUri) {
this.contentReferenceUri = referenceUri;
}
public String getContentReferenceType() {
return contentReferenceType;
}
/**
* Type of the content reference. The default value is <code>null</code>.
* This value can be overwritten by the header
* {@link XmlSignatureConstants#HEADER_CONTENT_REFERENCE_TYPE}.
*/
public void setContentReferenceType(String referenceType) {
this.contentReferenceType = referenceType;
}
public Boolean getPlainText() {
return plainText;
}
/**
* Indicator whether the message body contains plain text. The default value
* is <code>false</code>, indicating that the message body contains XML. The
* value can be overwritten by the header
* {@link XmlSignatureConstants#HEADER_MESSAGE_IS_PLAIN_TEXT}.
*/
public void setPlainText(Boolean plainText) {
this.plainText = plainText;
}
public String getPlainTextEncoding() {
return plainTextEncoding;
}
/**
* Encoding of the plain text. Only relevant if the message body is plain
* text (see parameter {@link #plainText}. Default value is "UTF-8".
*/
public void setPlainTextEncoding(String plainTextEncoding) {
this.plainTextEncoding = plainTextEncoding;
}
public XmlSignatureProperties getProperties() {
return properties;
}
/**
* For adding additional References and Objects to the XML signature which contain additional properties,
* you can provide a bean which implements the XmlSignatureProperties interface.
*/
public void setProperties(XmlSignatureProperties properties) {
this.properties = properties;
}
/**
* Sets the reference name for a XmlSignatureProperties that can be found in the registry.
*/
public void setProperties(String propertiesName) {
if (getCamelContext() != null && propertiesName != null) {
XmlSignatureProperties props = getCamelContext().getRegistry()
.lookupByNameAndType(propertiesName, XmlSignatureProperties.class);
if (props != null) {
setProperties(props);
}
}
if (propertiesName != null) {
this.propertiesName = propertiesName;
}
}
public String getKeyAccessorName() {
return keyAccessorName;
}
public void setKeyAccessorName(String keyAccessorName) {
this.keyAccessorName = keyAccessorName;
}
public String getCanonicalizationMethodName() {
return canonicalizationMethodName;
}
public void setCanonicalizationMethodName(String canonicalizationMethodName) {
this.canonicalizationMethodName = canonicalizationMethodName;
}
public String getTransformMethodsName() {
return transformMethodsName;
}
public void setTransformMethodsName(String transformMethodsName) {
this.transformMethodsName = transformMethodsName;
}
public String getPropertiesName() {
return propertiesName;
}
public void setPropertiesName(String propertiesName) {
this.propertiesName = propertiesName;
}
public List<XPathFilterParameterSpec> getXpathsToIdAttributes() {
return xpathsToIdAttributes;
}
/**
* Define the elements which are signed in the detached case via XPATH
* expressions to ID attributes (attributes of type ID). For each element
* found via the XPATH expression a detached signature is created whose
* reference URI contains the corresponding attribute value (preceded by
* '#'). The signature becomes the last sibling of the signed element.
* Elements with deeper hierarchy level are signed first.
* <p>
* You can also set the XPATH list dynamically via the header
* {@link XmlSignatureConstants#HEADER_XPATHS_TO_ID_ATTRIBUTES}.
* <p>
* The parameter {@link #setParentLocalName(String)} or {@link #setParentXpath(XPathFilterParameterSpec)}
* for enveloped signature and this parameter for detached signature must not
* be set in the same configuration.
*/
public void setXpathsToIdAttributes(List<XPathFilterParameterSpec> xpathsToIdAttributes) {
if (xpathsToIdAttributes == null) {
this.xpathsToIdAttributes = Collections.emptyList();
} else {
this.xpathsToIdAttributes = Collections.unmodifiableList(xpathsToIdAttributes);
}
}
public XPathFilterParameterSpec getParentXpath() {
return parentXpath;
}
/**
* Sets the XPath to find the parent node in the enveloped case.
* Either you specify the parent node via this method or the local name and namespace of the parent
* with the methods {@link #setParentLocalName(String)} and {@link #setParentNamespace(String)}.
* <p>
* Default value is <code>null</code>. The value must be <code>null</code> for enveloping and
* detached XML signature.
* <p>
* If the parameters <tt>parentXpath</tt> and <tt>parentLocalName</tt> are specified
* in the same configuration then an exception is thrown.
*
* @param parentXpath xpath to the parent node, if the xpath returns several values then the first Element node is used
*/
public void setParentXpath(XPathFilterParameterSpec parentXpath) {
this.parentXpath = parentXpath;
}
}