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$
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       *  &lt;wst:RequestSecurityTokenResponseCollection&gt;
87       *      <&lt;wst:RequestSecurityTokenResponse Context="urn:uuid:00000"&gt;
88       *      ...
89       *  &lt;/wst:RequestSecurityTokenResponseCollection&gt;
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      *   &lt;soap:Body&gt;
110      *     &lt;soap:Fault&gt;
111      *       &lt;faultcode&gt;wst:FailedAuthentication&lt;/faultcode&gt;
112      *       ...
113      *     &lt;/soap:Fault&gt;
114      *   &lt;/soap:Body&gt;
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      *   &lt;soap:Body&gt;
136      *     &lt;soap:Fault&gt;
137      *       ...
138      *       &lt;faultactor&gt;http://sosi.dk/sts&lt;/faultactor&gt;
139      *     &lt;/soap:Fault&gt;
140      *   &lt;/soap:Body&gt;
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      *   &lt;soap:Body&gt;
162      *     &lt;soap:Fault&gt;
163      *       ...
164      *       &lt;faultstring&gt;Authentication failed: Token in request signed by untrusted party&lt;/faultstring&gt;
165      *       ...
166      *     &lt;/soap:Fault&gt;
167      *   &lt;/soap:Body&gt;
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      *  &lt;soap:Header&gt;
198      *      ...
199      *      &lt;wsa:RelatesTo&gt;urn:uuid:99999999-0000-0000&lt;/wsa:RelatesTo&gt;
200      *  &lt;/soap:Header&gt;
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 }