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.modelbuilders;
30  
31  import dk.sosi.seal.model.IDCard;
32  import dk.sosi.seal.model.IdentityTokenRequest;
33  import dk.sosi.seal.model.SchemaUtil;
34  import dk.sosi.seal.model.SignatureUtil;
35  import dk.sosi.seal.model.constants.*;
36  import dk.sosi.seal.pki.Federation;
37  import dk.sosi.seal.xml.XmlUtil;
38  import org.w3c.dom.Document;
39  import org.w3c.dom.Element;
40  import org.w3c.dom.Node;
41  import org.xml.sax.SAXException;
42  
43  import javax.xml.transform.dom.DOMSource;
44  import javax.xml.validation.Schema;
45  import javax.xml.validation.Validator;
46  import java.io.IOException;
47  
48  /**
49   * Builder class used for building an Identity Token Request from a <code>Document</code>.<br />
50   *
51   * @author $LastChangedBy:$ $LastChangedDate:$
52   * @version $Revision:$
53   */
54  public class IdentityTokenRequestModelBuilder {
55  
56      private final Federation federation;
57  
58      /**
59       * Sole constructor
60       *
61       * @param federation
62       *          The federation to check 'trust' against for the idcard in the request
63       */
64      public IdentityTokenRequestModelBuilder(Federation federation) {
65          this.federation = federation;
66      }
67  
68      private static Schema schema;
69  
70      /**
71       *  Builds an <code>IdentityTokenRequest</code> from the supplied <code>Document</code>, checks the signature of
72       *  the <code>IDCard</code> in the request and verifies that the certificate used to sign the <code>IDCard</code>
73       *  is trusted.
74       *  </br>
75       *  Validity in time is not checked, as there may be different lifetime requirements depending on the requested
76       *  audience.
77       *
78       * @param document
79       * @return
80       *          The constructed <code>IdentityTokenRequest</code>
81       */
82      public IdentityTokenRequest buildModel(Document document) {
83  
84          schemaValidate(document);
85  
86          final Element header = XmlUtil.getFirstChildElementNS(document.getDocumentElement(), NameSpaces.SOAP_SCHEMA, SOAPTags.HEADER_UNPREFIXED);
87          final Element messageID = XmlUtil.getFirstChildElementNS(header, NameSpaces.WSA_1_0_SCHEMA, WSATags.MESSAGE_ID);
88  
89          final Element body = XmlUtil.getFirstChildElementNS(document.getDocumentElement(), NameSpaces.SOAP_SCHEMA, SOAPTags.BODY_UNPREFIXED);
90          final Element requestSecurityToken = XmlUtil.getFirstChildElementNS(body, NameSpaces.WST_1_3_SCHEMA, WSTrustTags.REQUEST_SECURITY_TOKEN);
91          final String context = requestSecurityToken.getAttribute(WSTrustAttributes.CONTEXT);
92          final Element appliesTo = XmlUtil.getFirstChildElementNS(requestSecurityToken, NameSpaces.WSP_SCHEMA, WSPTags.APPLIES_TO);
93          final Element address = (Element) appliesTo.getFirstChild().getFirstChild();
94  
95          Element assertion;
96          final Element security = XmlUtil.getFirstChildElementNS(header, NameSpaces.WSSE_SCHEMA, WSSETags.SECURITY);
97          if (security != null) {
98              // idcard in header
99              assertion = (Element) security.getFirstChild();
100         } else {
101             // idcard in body
102             final Element actAs = XmlUtil.getFirstChildElementNS(requestSecurityToken, NameSpaces.WST_1_4_SCHEMA, WSTrustTags.WST_1_4_ACT_AS);
103             assertion = XmlUtil.getFirstChildElementNS(actAs, NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.ASSERTION);
104             if (assertion == null) {
105                 throw  new ModelBuildException("Expected idCard under wst14:ActAs");
106             }
107         }
108         final IDCard idCard = new IDCardModelBuilder().buildModel(assertion);
109         final Node signature = assertion.getElementsByTagNameNS(NameSpaces.DSIG_SCHEMA, DSTags.SIGNATURE).item(0);
110         if( ! SignatureUtil.validate(signature, federation, null, true)) {
111             throw new ModelBuildException("Signature on IdCard could not be validated");
112         }
113 
114         return new IdentityTokenRequest(idCard, messageID.getTextContent(), address.getTextContent(), context);
115     }
116 
117     private void schemaValidate(Document envelope) {
118         try {
119             final Validator validator = getSchema().newValidator();
120             validator.validate(new DOMSource(envelope));
121         } catch (SAXException e) {
122             throw new ModelBuildException("Error validating IdentityTokenRequest", e);
123         } catch (IOException e) {
124             throw new ModelBuildException("Error validating IdentityTokenRequest", e);
125         }
126 
127     }
128 
129     private static synchronized Schema getSchema() throws SAXException {
130         if (schema == null) {
131             schema = SchemaUtil.loadSchema("/idwsh/idtreq/soap.xsd");
132         }
133         return schema;
134     }
135 
136 }