View Javadoc

1   /*
2    * The MIT License
3    *
4    * Original work sponsored and donated by National Board of e-Health (NSI), Denmark (http://www.nsi.dk)
5    *
6    * Copyright (C) 2011 National Board of e-Health (NSI), Denmark (http://www.nsi.dk)
7    *
8    * Permission is hereby granted, free of charge, to any person obtaining a copy of
9    * this software and associated documentation files (the "Software"), to deal in
10   * the Software without restriction, including without limitation the rights to
11   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12   * of the Software, and to permit persons to whom the Software is furnished to do
13   * so, subject to the following conditions:
14   *
15   * The above copyright notice and this permission notice shall be included in all
16   * copies or substantial portions of the Software.
17   *
18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24   * SOFTWARE.
25   *
26   * $HeadURL: https://svn.softwareborsen.dk/sosi/trunk/modules/seal/src/main/java/dk/sosi/seal/model/dombuilders/SOAPMessageDOMBuilder.java $
27   * $Id: SOAPMessageDOMBuilder.java 8697 2011-09-02 10:33:55Z chg@lakeside.dk $
28   */
29  package dk.sosi.seal.model.dombuilders;
30  
31  import dk.sosi.seal.SOSIFactory;
32  import dk.sosi.seal.model.AuthenticationLevel;
33  import dk.sosi.seal.model.IDCard;
34  import dk.sosi.seal.model.Message;
35  import dk.sosi.seal.model.constants.NameSpaces;
36  import dk.sosi.seal.model.constants.SOAPTags;
37  import dk.sosi.seal.vault.CredentialVault;
38  import org.w3c.dom.Document;
39  import org.w3c.dom.Element;
40  import org.w3c.dom.Node;
41  import org.w3c.dom.NodeList;
42  
43  import java.util.Iterator;
44  import java.util.LinkedList;
45  import java.util.List;
46  import java.util.Map;
47  
48  /**
49   * Abstract builder class for SOSI SOAP messages.
50   * 
51   * @author Jan Riis
52   * @author $LastChangedBy: chg@lakeside.dk $
53   * @since 1.0
54   */
55  abstract class SOAPMessageDOMBuilder {
56  
57  	private Document document;
58  	private final Message message;
59  
60  	private Element header;
61  	private Element body;
62  	protected CredentialVault vault;
63  
64  	/**
65  	 * Constructs the DOM builder for a SOAP message.
66  	 * 
67  	 * @param document
68  	 *            the enclosing DOM document
69  	 * @param message
70  	 *            The <code>Message</code> model element
71  	 * @param vault
72  	 *            The credential valt with system signature
73  	 */
74  	protected SOAPMessageDOMBuilder(Document document, Message message, CredentialVault vault) {
75  
76  		super();
77  		this.document = document;
78  		this.message = message;
79  		this.vault = vault;
80  		initializeSOAP(); 
81  	}
82  
83  	// ===============================
84  	// Protected methods
85  	// ===============================
86  
87  	/**
88  	 * Initializes a SOAP message (Header+Body) with elements that are common to
89  	 * all SOSI messages.
90  	 */
91  	protected void initializeSOAP() {
92  
93  		Element root = document.getDocumentElement();
94  		if (root == null) {
95  			root = document.createElementNS(NameSpaces.SOAP_SCHEMA, SOAPTags.ENVELOPE_PREFIXED);
96  			document.appendChild(root);
97  		}
98  
99  		Map<String, String> nameSpaces;
100 		if(message.isFault()) nameSpaces = NameSpaces.SOSI_FAULT_NAMESPACES;
101 		else nameSpaces = NameSpaces.SOSI_NAMESPACES;
102 		for (Iterator<String> iter = nameSpaces.keySet().iterator(); iter.hasNext();) {
103 			String key = iter.next();
104 			addNameSpaceAttribute(key, nameSpaces.get(key));
105 		}
106 
107         String sealMsgVersion = SOSIFactory.PROPERTYVALUE_SOSI_SEAL_MESSAGE_VERSION;
108         if(message.getFactory() != null) 
109             sealMsgVersion = message.getFactory().getProperties().getProperty(SOSIFactory.PROPERTYNAME_SOSI_SEAL_MESSAGE_VERSION, SOSIFactory.PROPERTYVALUE_SOSI_SEAL_MESSAGE_VERSION);
110         
111         if("1.0_0".equals(sealMsgVersion)) {
112             root.setAttribute("id", "Envelope");
113         } else if("1.0_1".equals(sealMsgVersion)) {
114             root.setAttributeNS(NameSpaces.WSU_SCHEMA, NameSpaces.NS_WSU+":id", SOAPTags.ENVELOPE_UNPREFIXED);
115         } else if("1.0_2".equals(sealMsgVersion)) {
116             root.setAttributeNS(NameSpaces.WSU_SCHEMA, NameSpaces.NS_WSU+":id", SOAPTags.ENVELOPE_UNPREFIXED);
117         }
118 
119 		NodeList nodes = root.getElementsByTagNameNS(NameSpaces.SOAP_SCHEMA, SOAPTags.HEADER_UNPREFIXED);
120 		if (nodes.getLength() == 0) {
121 			header = document.createElementNS(NameSpaces.SOAP_SCHEMA, SOAPTags.HEADER_PREFIXED);
122 			root.appendChild(header);
123 		} else if (nodes.getLength() == 1) {
124 			header = (Element) nodes.item(0);
125 			NodeList children = header.getChildNodes();
126 			List<Node> list = new LinkedList<Node>();
127 			for (int i = 0; i < children.getLength(); i++) {
128 				list.add(children.item(0));
129 			}
130 			for (Iterator<Node> iter = list.iterator(); iter.hasNext();) {
131                 header.removeChild(iter.next());
132 			}
133 		} else {
134 			throw new DOMBuilderException("Too many soap:Header elements in document!", null);
135 		}
136 
137 		nodes = root.getElementsByTagNameNS(NameSpaces.SOAP_SCHEMA, SOAPTags.BODY_UNPREFIXED);
138 		if (nodes.getLength() == 0) {
139 			body = document.createElementNS(NameSpaces.SOAP_SCHEMA, SOAPTags.BODY_PREFIXED);
140 			root.appendChild(body);
141 		} else if (nodes.getLength() == 1) {
142 			body = (Element) nodes.item(0);
143 		} else {
144 			throw new DOMBuilderException("Too many soap:Body elements in document!", null);
145 		}
146 	}
147 
148 	/**
149 	 * Returns the Message object.
150 	 */
151 	protected Message getMessage() {
152 
153 		return message;
154 	}
155 
156 	/**
157 	 * Builds the DOM document for a message.
158 	 */
159 	public final Document buildDOMDocument() {
160 		_buildDOMDocument(document, header, body);
161 
162 		// Digital signature on the IDCard - only possible when signing with
163 		// VOCES
164 		IDCard idCard = message.getIDCard();
165 		if (idCard != null && idCard.getAuthenticationLevel().getLevel() == AuthenticationLevel.VOCES_TRUSTED_SYSTEM.getLevel()) {
166 			idCard.sign(document, vault);
167 		}
168 
169         // Add Non SOSI Headers
170         if (message.getNonSOSIHeaders() != null) {
171             for (Iterator<Element> it = message.getNonSOSIHeaders().iterator(); it.hasNext();) {
172                 Element e = it.next();
173                 header.appendChild(document.importNode(e, true));
174             }
175         }
176         
177 		// Body
178 		if (message.getBody() != null && body.getChildNodes().getLength() == 0) {
179 			// insert body from message if not already inserted (SecurityTokenRequestResponse)
180 			body.appendChild(document.importNode(message.getBody(), true));
181 		}
182 
183 		// Other digital signatures should go here
184 
185 		return document;
186 
187 	}
188 
189 	/**
190 	 * Adds a XML name space attribute to the DOM document contained in this
191 	 * builder.
192 	 * 
193 	 * @param name
194 	 *            The name of the name space.
195 	 * @param value
196 	 *            The value for the name space.
197 	 */
198 	protected void addNameSpaceAttribute(String name, String value) {
199 
200 		Element documentElement = document.getDocumentElement();
201 		if (documentElement.getAttributeNS(NameSpaces.XMLNS_SCHEMA, name) == null
202 				|| documentElement.getAttributeNS(NameSpaces.XMLNS_SCHEMA, name).equals("")) {
203 			documentElement.setAttributeNS(NameSpaces.XMLNS_SCHEMA, NameSpaces.NS_XMLNS + ":" + name, value);
204 		}
205 	}
206 
207 	/**
208 	 * Builds and returns a DOM element for a given sub class message.
209 	 */
210 	protected abstract void _buildDOMDocument(Document doc, Element headerElement, Element bodyElement);
211 }