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$
27 * $Id$
28 */
29 package dk.sosi.seal.model.dombuilders;
30
31 import dk.sosi.seal.model.IdentityToken;
32 import dk.sosi.seal.model.ModelException;
33 import dk.sosi.seal.model.constants.*;
34 import dk.sosi.seal.xml.XmlUtil;
35 import org.w3c.dom.Document;
36 import org.w3c.dom.Element;
37
38 /**
39 * Builder class used for creating an Identity token response.<br />
40 * <br />
41 * This class is not thread safe.<br />
42 * An <code>IdentityTokenResponseDOMBuilder</code> should be created for each <code>IdentityTokenResponse</code> needed. <br />
43 * <br />
44 * All operations related to constructing, wrappring, etc. of the <code>IdentityToken</code> should be done through the <code>IDWSHFactory</code>.
45 *
46 * @author ads
47 * @since 2.1
48 */
49 public final class IdentityTokenResponseDOMBuilder extends IDWSHDOMBuilder {
50
51 private String context;
52 private String faultCode;
53 private String faultFactor;
54 private String faultString;
55 private IdentityToken identityToken;
56 private boolean isFault;
57 private String relatesTo;
58
59 /**
60 * Constructor for the <code>IdentityTokenResponseDOMBuilder</code> class.
61 */
62 public IdentityTokenResponseDOMBuilder() {
63 // Do nothing
64 }
65
66 /**
67 * Build the final response <code>Document</code>.<br />
68 * Before the <code>Document</code> is generated all attributes will be validated.<br />
69 * <br />
70 * A <code>Document</code> is generated each time this method is called. Calling this method multiple times will therefore return multiple objects.
71 *
72 * @return DOM representation of the Identity token response.
73 * @throws ModelException
74 * Thrown if the builder finds a validation problem.
75 */
76 public Document build() throws ModelException {
77 Document document = createDocument();
78 return document;
79 }
80
81 /**
82 * <b>Mandatory</b>: Set the context of the identity token.<br />
83 * Example:
84 *
85 * <pre>
86 * <wst:RequestSecurityTokenResponseCollection>
87 * <<wst:RequestSecurityTokenResponse Context="urn:uuid:00000">
88 * ...
89 * </wst:RequestSecurityTokenResponseCollection>
90 * </pre>
91 *
92 * @param context
93 * The context.
94 * @return The <code>IdentityTokenResponseDOMBuilder</code> instance.
95 */
96 public IdentityTokenResponseDOMBuilder setContext(String context) {
97 this.context = context;
98 return this;
99 }
100
101 /**
102 * Set the code uniquely identifying the fault type.<br />
103 * <br />
104 * <b>Mandatory</b>: This field is mandatory for fault messages.<br />
105 * The builder automatically changes into fault mode if this attribute is set.<br />
106 * When in fault mode, all non fault attributes will be ignored.<br />
107 *
108 * <pre>
109 * <soap:Body>
110 * <soap:Fault>
111 * <faultcode>wst:FailedAuthentication</faultcode>
112 * ...
113 * </soap:Fault>
114 * </soap:Body>
115 * </pre>
116 *
117 * @param faultCode
118 * The fault code.
119 * @return The <code>IdentityTokenResponseDOMBuilder</code> instance.
120 */
121 public IdentityTokenResponseDOMBuilder setFaultCode(String faultCode) {
122 this.faultCode = faultCode;
123 this.isFault = true;
124 return this;
125 }
126
127 /**
128 * Set the identity of the system reporting the fault.<br />
129 * <br />
130 * <b>Mandatory</b>: This field is mandatory for fault messages.<br />
131 * The builder automatically changes into fault mode if this attribute is set.<br />
132 * When in fault mode, all non fault attributes will be ignored.<br />
133 *
134 * <pre>
135 * <soap:Body>
136 * <soap:Fault>
137 * ...
138 * <faultactor>http://sosi.dk/sts</faultactor>
139 * </soap:Fault>
140 * </soap:Body>
141 * </pre>
142 *
143 * @param faultFactor
144 * Id of the system reporting the fault.
145 * @return The <code>IdentityTokenResponseDOMBuilder</code> instance.
146 */
147 public IdentityTokenResponseDOMBuilder setFaultFactor(String faultFactor) {
148 this.faultFactor = faultFactor;
149 this.isFault = true;
150 return this;
151 }
152
153 /**
154 * Set a text message describing the cause of the fault.<br />
155 * <br />
156 * <b>Mandatory</b>: This field is mandatory for fault messages.<br />
157 * The builder automatically changes into fault mode if this attribute is set.<br />
158 * When in fault mode, all non fault attributes will be ignored.<br />
159 *
160 * <pre>
161 * <soap:Body>
162 * <soap:Fault>
163 * ...
164 * <faultstring>Authentication failed: Token in request signed by untrusted party</faultstring>
165 * ...
166 * </soap:Fault>
167 * </soap:Body>
168 * </pre>
169 *
170 * @param faultString
171 * Text message describing the fault.
172 * @return The <code>IdentityTokenResponseDOMBuilder</code> instance.
173 */
174 public IdentityTokenResponseDOMBuilder setFaultString(String faultString) {
175 this.faultString = faultString;
176 this.isFault = true;
177 return this;
178 }
179
180 /**
181 * <b>Mandatory</b>: Set the <code>IdentityToken</code> of the response.<br />
182 *
183 * @param identityToken
184 * The identity token.
185 * @return The <code>IdentityTokenResponseDOMBuilder</code> instance.
186 */
187 public IdentityTokenResponseDOMBuilder setIdentityToken(IdentityToken identityToken) {
188 this.identityToken = identityToken;
189 return this;
190 }
191
192 /**
193 * <b>Mandatory</b>: Set the <code>RelatesTo</code> message id.<br />
194 * Example:
195 *
196 * <pre>
197 * <soap:Header>
198 * ...
199 * <wsa:RelatesTo>urn:uuid:99999999-0000-0000</wsa:RelatesTo>
200 * </soap:Header>
201 * </pre>
202 *
203 * @param relatesTo
204 * The message id of the request message.
205 * @return The <code>IdentityTokenResponseDOMBuilder</code> instance.
206 */
207 public IdentityTokenResponseDOMBuilder setRelatesTo(String relatesTo) {
208 this.relatesTo = relatesTo;
209 return this;
210 }
211
212 @Override
213 protected final void addBodyContent(Document doc, Element body) {
214 if(isFault) {
215 appendFaultBody(doc, body);
216 } else {
217 appendNormalBody(doc, body);
218 }
219 }
220
221 @Override
222 protected void addExtraHeaders(Document doc, Element header) {
223 Element relatesToElm = doc.createElementNS(NameSpaces.WSA_1_0_SCHEMA, WSATags.RELATES_TO_PREFIXED);
224 relatesToElm.setTextContent(relatesTo);
225 header.appendChild(relatesToElm);
226 }
227
228 @Override
229 protected void addExtraNamespaceDeclarations(Element envelope) {
230 addNS(envelope, NameSpaces.NS_WSU, NameSpaces.WSU_SCHEMA);
231 }
232
233 @Override
234 protected String getWsaAction() {
235 return WSTrustConstants.WST_1_3_ISSUE_ACTION;
236 }
237
238 @Override
239 protected void validateBeforeBuild() {
240 validate("relatesTo", relatesTo);
241 if(isFault) {
242 validate("faultCode", faultCode);
243 validate("faultFactor", faultFactor);
244 validate("faultString", faultString);
245 } else {
246 validate("identityToken", identityToken);
247 validate("context", context);
248 }
249 }
250
251 private void appendFaultBody(Document doc, Element body) {
252 Element faultElm = doc.createElementNS(NameSpaces.SOAP_SCHEMA, SOAPTags.FAULT_PREFIXED);
253
254 Element faultCodeElm = doc.createElement("faultcode");
255 faultCodeElm.setTextContent(faultCode);
256 faultElm.appendChild(faultCodeElm);
257
258 Element faultStringElm = doc.createElement("faultstring");
259 faultStringElm.setTextContent(faultString);
260 faultElm.appendChild(faultStringElm);
261
262 Element faultFactorElm = doc.createElement("faultactor");
263 faultFactorElm.setTextContent(faultFactor);
264 faultElm.appendChild(faultFactorElm);
265
266 body.appendChild(faultElm);
267 }
268
269 private void appendNormalBody(Document doc, Element body) {
270 Element requestSecurityTokenResponseCollectionElm = doc.createElementNS(NameSpaces.WST_1_3_SCHEMA, WSTTags.REQUEST_SECURITY_TOKEN_RESPONSE_COLLECTION_PREFIXED);
271 body.appendChild(requestSecurityTokenResponseCollectionElm);
272
273 // Append RequestSecurityTokenResponse
274 Element requestSecurityTokenResponseElm = doc.createElementNS(NameSpaces.WST_1_3_SCHEMA, WSTTags.REQUEST_SECURITY_TOKEN_RESPONSE_PREFIXED);
275 requestSecurityTokenResponseElm.setAttribute(WSTrustAttributes.CONTEXT, context);
276 requestSecurityTokenResponseCollectionElm.appendChild(requestSecurityTokenResponseElm);
277
278 // Append TokenType
279 Element tokenTypeElm = doc.createElementNS(NameSpaces.WST_1_3_SCHEMA, WSTTags.TOKEN_TYPE_PREFIXED);
280 tokenTypeElm.setTextContent(WSSEValues.SAML_TOKEN_TYPE);
281 requestSecurityTokenResponseElm.appendChild(tokenTypeElm);
282
283 // Append security token
284 Element requestedSecurityTokenElm = doc.createElementNS(NameSpaces.WST_1_3_SCHEMA, WSTTags.REQUEST_SECURITY_TOKEN_PREFIXED);
285
286 Document itDoc = identityToken.getDOM();
287 Element documentElement = itDoc.getDocumentElement();
288 requestedSecurityTokenElm.appendChild(doc.importNode(documentElement, true));
289 requestSecurityTokenResponseElm.appendChild(requestedSecurityTokenElm);
290
291 // Append AppliesTo
292 Element appliesToElm = doc.createElementNS(NameSpaces.WSP_SCHEMA, WSPTags.APPLIES_TO_PREFIXED);
293 Element endpointReferenceElm = doc.createElementNS(NameSpaces.WSA_1_0_SCHEMA, WSATags.ENDPOINT_REFERENCE_PREFIXED);
294 Element addressElm = doc.createElementNS(NameSpaces.WSA_1_0_SCHEMA, WSATags.ADDRESS_PREFIXED);
295 addressElm.setTextContent(identityToken.getAudienceRestriction());
296 endpointReferenceElm.appendChild(addressElm);
297 appliesToElm.appendChild(endpointReferenceElm);
298 requestSecurityTokenResponseElm.appendChild(appliesToElm);
299
300 // Append lifetime
301 Element lifetimeElm = doc.createElementNS(NameSpaces.WST_1_3_SCHEMA, WSTTags.LIFETIME_PREFIXED);
302 Element createdElm = doc.createElementNS(NameSpaces.WSU_SCHEMA, WSUTags.CREATED_PREFIXED);
303 createdElm.setTextContent(XmlUtil.getDateFormat(true).format(identityToken.getNotBefore()));
304 lifetimeElm.appendChild(createdElm);
305 Element expiresElm = doc.createElementNS(NameSpaces.WSU_SCHEMA, WSUTags.EXPIRES_PREFIXED);
306 expiresElm.setTextContent(XmlUtil.getDateFormat(true).format(identityToken.getNotOnOrAfter()));
307 lifetimeElm.appendChild(expiresElm);
308 requestSecurityTokenResponseElm.appendChild(lifetimeElm);
309 }
310 }