View Javadoc

1   /*
2    * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.opensaml.xml.signature.impl;
18  
19  import javax.xml.parsers.DocumentBuilderFactory;
20  import javax.xml.parsers.ParserConfigurationException;
21  
22  import org.apache.xml.security.Init;
23  import org.apache.xml.security.exceptions.XMLSecurityException;
24  import org.apache.xml.security.signature.XMLSignature;
25  import org.opensaml.xml.Configuration;
26  import org.opensaml.xml.XMLObject;
27  import org.opensaml.xml.io.Marshaller;
28  import org.opensaml.xml.io.MarshallingException;
29  import org.opensaml.xml.security.SecurityHelper;
30  import org.opensaml.xml.signature.ContentReference;
31  import org.opensaml.xml.signature.KeyInfo;
32  import org.opensaml.xml.signature.Signature;
33  import org.opensaml.xml.util.XMLHelper;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  import org.w3c.dom.Document;
37  import org.w3c.dom.Element;
38  
39  /**
40   * A marshaller for {@link org.opensaml.xml.signature.Signature} objects. This marshaller is really a no-op class. All
41   * the creation of the signature DOM elements is handled by {@link org.opensaml.xml.signature.Signer} when it signs the
42   * object.
43   */
44  public class SignatureMarshaller implements Marshaller {
45  
46      /** Class logger. */
47      private final Logger log = LoggerFactory.getLogger(SignatureMarshaller.class);
48  
49      /** Constructor. */
50      public SignatureMarshaller() {
51          if (!Init.isInitialized()) {
52              log.debug("Initializing XML security library");
53              Init.init();
54          }
55      }
56  
57      /** {@inheritDoc} */
58      public Element marshall(XMLObject xmlObject) throws MarshallingException {
59          try {
60              Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
61              return marshall(xmlObject, document);
62          } catch (ParserConfigurationException e) {
63              throw new MarshallingException("Unable to create Document to place marshalled elements in", e);
64          }
65      }
66  
67      /** {@inheritDoc} */
68      public Element marshall(XMLObject xmlObject, Element parentElement) throws MarshallingException {
69          Element signatureElement = createSignatureElement((SignatureImpl) xmlObject, parentElement.getOwnerDocument());
70          XMLHelper.appendChildElement(parentElement, signatureElement);
71          return signatureElement;
72      }
73  
74      /** {@inheritDoc} */
75      public Element marshall(XMLObject xmlObject, Document document) throws MarshallingException {
76          Element signatureElement = createSignatureElement((SignatureImpl) xmlObject, document);
77  
78          Element documentRoot = document.getDocumentElement();
79          if (documentRoot != null) {
80              document.replaceChild(signatureElement, documentRoot);
81          } else {
82              document.appendChild(signatureElement);
83          }
84  
85          return signatureElement;
86      }
87  
88      /**
89       * Creates the signature elements but does not compute the signatuer.
90       * 
91       * @param signature the XMLObject to be signed
92       * @param document the owning document
93       * 
94       * @return the Signature element
95       * 
96       * @throws MarshallingException thrown if the signature can not be constructed
97       */
98      private Element createSignatureElement(Signature signature, Document document) throws MarshallingException {
99          log.debug("Starting to marshall {}", signature.getElementQName());
100 
101         try {
102             log.debug("Creating XMLSignature object");
103             XMLSignature dsig = null;
104             if (signature.getHMACOutputLength() != null && SecurityHelper.isHMAC(signature.getSignatureAlgorithm())) {
105                 dsig = new XMLSignature(document, "", signature.getSignatureAlgorithm(), signature
106                         .getHMACOutputLength(), signature.getCanonicalizationAlgorithm());
107             } else {
108                 dsig = new XMLSignature(document, "", signature.getSignatureAlgorithm(), signature
109                         .getCanonicalizationAlgorithm());
110             }
111 
112             log.debug("Adding content to XMLSignature.");
113             for (ContentReference contentReference : signature.getContentReferences()) {
114                 contentReference.createReference(dsig);
115             }
116 
117             log.debug("Creating Signature DOM element");
118             Element signatureElement = dsig.getElement();
119 
120             if (signature.getKeyInfo() != null) {
121                 Marshaller keyInfoMarshaller = Configuration.getMarshallerFactory().getMarshaller(
122                         KeyInfo.DEFAULT_ELEMENT_NAME);
123                 keyInfoMarshaller.marshall(signature.getKeyInfo(), signatureElement);
124             }
125 
126             ((SignatureImpl) signature).setXMLSignature(dsig);
127             signature.setDOM(signatureElement);
128             signature.releaseParentDOM(true);
129             return signatureElement;
130 
131         } catch (XMLSecurityException e) {
132             log.error("Unable to construct signature Element " + signature.getElementQName(), e);
133             throw new MarshallingException("Unable to construct signature Element " + signature.getElementQName(), e);
134         }
135     }
136 
137 }