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/IDCardDOMBuilder.java $
27   * $Id: IDCardDOMBuilder.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.*;
33  import dk.sosi.seal.model.constants.*;
34  import dk.sosi.seal.xml.XmlUtil;
35  import org.apache.xml.security.utils.IdResolver;
36  import org.w3c.dom.Document;
37  import org.w3c.dom.Element;
38  import org.w3c.dom.Node;
39  
40  /**
41   * Converts an <code>IDCard</code> model instance into a DOM element. <p/>
42   * This DOM builder will automatically adds a digital signature to the DOM if
43   * the idcard.signatureType is "VOCES". <p/> <b>This class should only be
44   * accessed through model classes</b>
45   * </p>
46   *
47   * @author Jan Riis
48   * @author $Author: chg@lakeside.dk $
49   * @since 1.0
50   */
51  public class IDCardDOMBuilder {
52  
53  	private static final String SAML_MAJOR_VERSION = "2";
54  	private static final String SAML_MINOR_VERSION = "0";
55  	private static final String HOLDER_OF_KEY = "urn:oasis:names:tc:SAML:2.0:cm:holder-of-key";
56  
57  	private final IDCard idCard;
58  	private final Document document;
59  	private final SAMLUtil samlUtil = new SAMLUtil();
60  
61      private final SOSIFactory factory;
62  	/**
63  	 * Constructs an <code>IDCardDOMBuilder</code> instance.
64  	 * @param factory
65  	 */
66  	public IDCardDOMBuilder(SOSIFactory factory, Document domDocument, IDCard idCard) {
67  
68  		super();
69  		this.idCard = idCard;
70  		this.document = domDocument;
71          this.factory = factory;
72  	}
73  
74  	/**
75  	 * Generates a DOM element (XML) representing the <code>IDCard</code>.
76  	 * Currently the IDCard is represented as a SAML assertion.
77  	 */
78  	public Element buildDOMElement() {
79  
80  		Element elem = document.createElementNS(NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.ASSERTION_PREFIXED);
81  
82          String sealMsgVersion = SOSIFactory.PROPERTYVALUE_SOSI_SEAL_MESSAGE_VERSION;
83          if(factory != null)
84              sealMsgVersion = factory.getProperties().getProperty(SOSIFactory.PROPERTYNAME_SOSI_SEAL_MESSAGE_VERSION, SOSIFactory.PROPERTYVALUE_SOSI_SEAL_MESSAGE_VERSION);
85          if("1.0_0".equals(sealMsgVersion)) {
86              elem.setAttribute(IDValues.id, IDValues.IDCARD);
87          } else if("1.0_1".equals(sealMsgVersion)) {
88              elem.setAttribute(IDValues.id, IDValues.IDCARD);
89          } else if("1.0_2".equals(sealMsgVersion)) {
90              elem.setAttribute(IDValues.ID, IDValues.IDCARD);
91          }
92  
93          boolean useZuluTime = DGWSConstants.VERSION_1_0_1.equals(idCard.getVersion());
94  
95          elem.setAttribute(SAMLAttributes.ISSUE_INSTANT, XmlUtil.toXMLTimeStamp(idCard.getCreatedDate(), useZuluTime));
96  		elem.setAttribute(SAMLAttributes.VERSION, SAML_MAJOR_VERSION + "." + SAML_MINOR_VERSION);
97  		elem.setAttributeNS(NameSpaces.XMLNS_SCHEMA, "xmlns:" + NameSpaces.NS_SAML, NameSpaces.SAML2ASSERTION_SCHEMA);
98  		elem.setAttributeNS(NameSpaces.XMLNS_SCHEMA, "xmlns:" + NameSpaces.NS_DS, NameSpaces.DSIG_SCHEMA);
99  
100 		// Add the IDCard ID to the IDResolver (wsu:id elements cannot be found
101 		// otherwise)
102 		IdResolver.registerElementById(elem, IDValues.IDCARD);
103 
104 		Element issuerElem = document.createElementNS(NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.ISSUER_PREFIXED);
105 		String issuer = idCard.getIssuer();
106 		issuerElem.appendChild(document.createTextNode(issuer));
107 		elem.appendChild(issuerElem);
108 
109 		// <saml:AttributeStatement>
110 		elem.appendChild(buildSubject());
111 
112 		// <saml:Conditions NotBefore="2006-01-05T07:53:00.00Z"
113 		// NotOnOrAfter="2006-01-06T07:53:00.000Z"/>
114 		Element condition = document.createElementNS(NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.CONDITIONS_PREFIXED);
115 		condition.setAttribute(SAMLAttributes.NOT_BEFORE, XmlUtil.toXMLTimeStamp(idCard.getCreatedDate(), useZuluTime));
116 		condition.setAttribute(SAMLAttributes.NOT_ON_OR_AFTER, XmlUtil.toXMLTimeStamp(idCard.getExpiryDate(), useZuluTime));
117 		elem.appendChild(condition);
118 
119 		elem.appendChild(buildIDCardAttributes());
120 		if (idCard instanceof UserIDCard) {
121 			elem.appendChild(buildUserLog(((UserIDCard) idCard).getUserInfo()));
122 		}
123 		elem.appendChild(buildSystemLog(((SystemIDCard) idCard).getSystemInfo()));
124 
125 		return elem;
126 	}
127 
128 	// ======================================
129 	// Private helpers
130 	// ======================================
131 	private Element buildSystemLog(SystemInfo info) {
132 
133 		Element data = samlUtil.createSAMLAttributeStatement(document, IDValues.SYSTEM_LOG);
134 		samlUtil.createSAMLAttribute(document, MedcomAttributes.IT_SYSTEM_NAME, info.getITSystemName(), data);
135 		Element careProvider = samlUtil.createSAMLAttribute(document, MedcomAttributes.CARE_PROVIDER_ID, info.getCareProvider().getID(), data);
136 		careProvider.setAttribute(SAMLAttributes.NAME_FORMAT, info.getCareProvider().getType());
137 		samlUtil.createSAMLAttribute(document, MedcomAttributes.CARE_PROVIDER_NAME, info.getCareProvider().getOrgName(), data);
138 		return data;
139 	}
140 
141 	private Element buildUserLog(UserInfo info) {
142 
143 		Element data = samlUtil.createSAMLAttributeStatement(document, IDValues.USER_LOG);
144 		if (!ModelUtil.isEmpty(info.getCPR()))
145 			samlUtil.createSAMLAttribute(document, MedcomAttributes.USER_CIVIL_REGISTRATION_NUMBER, info.getCPR(), data);
146 
147 		samlUtil.createSAMLAttribute(document, MedcomAttributes.USER_GIVEN_NAME, info.getGivenName(), data);
148 		samlUtil.createSAMLAttribute(document, MedcomAttributes.USER_SURNAME, info.getSurName(), data);
149 
150 		if (!ModelUtil.isEmpty(info.getEmail()))
151 			samlUtil.createSAMLAttribute(document, MedcomAttributes.USER_EMAIL_ADDRESS, info.getEmail(), data);
152 
153 		samlUtil.createSAMLAttribute(document, MedcomAttributes.USER_ROLE, info.getRole(), data);
154 
155 		if (!ModelUtil.isEmpty(info.getAuthorizationCode()))
156 			samlUtil.createSAMLAttribute(document, MedcomAttributes.USER_AUTHORIZATION_CODE, info.getAuthorizationCode(), data);
157 
158 		if (!ModelUtil.isEmpty(info.getOccupation()))
159 			samlUtil.createSAMLAttribute(document, MedcomAttributes.USER_OCCUPATION, info.getOccupation(), data);
160 
161 		return data;
162 	}
163 
164 	private Element buildIDCardAttributes() {
165 
166 		Element data = samlUtil.createSAMLAttributeStatement(document, IDValues.IDCARD_DATA);
167 		samlUtil.createSAMLAttribute(document, SOSIAttributes.IDCARD_ID, idCard.getIDCardID(), data);
168 		samlUtil.createSAMLAttribute(document, SOSIAttributes.IDCARD_VERSION, idCard.getVersion(), data);
169 		samlUtil.createSAMLAttribute(document, SOSIAttributes.IDCARD_TYPE, getIDCardType(), data);
170 		samlUtil.createSAMLAttribute(document, SOSIAttributes.AUTHENTICATION_LEVEL, Integer.toString(idCard.getAuthenticationLevel().getLevel()), data);
171 
172 		if(idCard.getCertHash() != null) {
173 			samlUtil.createSAMLAttribute(document, SOSIAttributes.OCES_CERT_HASH, idCard.getCertHash(), data);
174 		}
175 		return data;
176 	}
177 
178 	private String getIDCardType() {
179 
180 		String result;
181 		if (idCard instanceof UserIDCard)
182 			result = IDCard.IDCARDTYPE_USER;
183 		else
184 			result = IDCard.IDCARDTYPE_SYSTEM;
185 		return result;
186 	}
187 
188 	private Node buildSubject() {
189 
190 		// <saml:Subject>
191 		// <saml:NameID> ...</saml:NameID>
192 		// ...
193 		// </saml:Subject>
194 		Element subj = document.createElementNS(NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.SUBJECT_PREFIXED);
195 		Element nameID = document.createElementNS(NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.NAMEID_PREFIXED);
196 		subj.appendChild(nameID);
197 		if (idCard.getAlternativeIdentifier() != null) {
198 			nameID.setAttribute(SAMLAttributes.FORMAT, SubjectIdentifierTypeValues.OTHER);
199 			nameID.appendChild(document.createTextNode(idCard.getAlternativeIdentifier()));
200 		} else if (idCard instanceof UserIDCard) {
201 			nameID.setAttribute(SAMLAttributes.FORMAT, SubjectIdentifierTypeValues.CPR_NUMBER);
202 			UserIDCard idc = (UserIDCard) idCard;
203 			nameID.appendChild(document.createTextNode(idc.getUserInfo().getCPR()));
204 		} else {
205 			SystemIDCard idc = (SystemIDCard) idCard;
206 			CareProvider cp = idc.getSystemInfo().getCareProvider();
207 			nameID.setAttribute(SAMLAttributes.FORMAT, cp.getType());
208 			nameID.appendChild(document.createTextNode(cp.getID()));
209 		}
210 
211 		if ( ! AuthenticationLevel.NO_AUTHENTICATION.equals(idCard.getAuthenticationLevel())) {
212 
213             Element conf = (Element) subj.appendChild(document.createElementNS(NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.SUBJECT_CONFIRMATION_PREFIXED));
214 
215             String sealMsgVersion = SOSIFactory.PROPERTYVALUE_SOSI_SEAL_MESSAGE_VERSION;
216             if(factory != null)
217                 sealMsgVersion = factory.getProperties().getProperty(SOSIFactory.PROPERTYNAME_SOSI_SEAL_MESSAGE_VERSION, SOSIFactory.PROPERTYVALUE_SOSI_SEAL_MESSAGE_VERSION);
218             if("1.0_0".equals(sealMsgVersion)) {
219                 Element confMethod = (Element) conf.appendChild(document.createElementNS(NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.CONFIRMATION_METHOD_PREFIXED));
220                 confMethod.appendChild(document.createTextNode(HOLDER_OF_KEY));
221             } else if("1.0_1".equals(sealMsgVersion)) {
222                 Element confMethod = (Element) conf.appendChild(document.createElementNS(NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.CONFIRMATION_METHOD_PREFIXED));
223                 confMethod.appendChild(document.createTextNode(HOLDER_OF_KEY));
224             } else if("1.0_2".equals(sealMsgVersion)) {
225                 conf.setAttribute("Method", HOLDER_OF_KEY);
226             }
227 
228             Element confData = (Element) conf.appendChild(document.createElementNS(NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.SUBJECT_CONFIRMATION_DATA_PREFIXED));
229             if (AuthenticationLevel.USERNAME_PASSWORD_AUTHENTICATION.equals(idCard.getAuthenticationLevel())) {
230             	Element usernameToken = (Element) confData.appendChild(document.createElementNS(NameSpaces.WSSE_SCHEMA, WSSETags.USERNAME_TOKEN_PREFIXED));
231             	Element username = (Element) usernameToken.appendChild(document.createElementNS(NameSpaces.WSSE_SCHEMA, WSSETags.USERNAME_PREFIXED));
232             	username.appendChild(document.createTextNode(idCard.getUsername()));
233             	Element password = (Element) usernameToken.appendChild(document.createElementNS(NameSpaces.WSSE_SCHEMA, WSSETags.PASSWORD_PREFIXED));
234             	password.appendChild(document.createTextNode(idCard.getPassword()));
235             } else {
236             	Element keyInfo = (Element) confData.appendChild(document.createElementNS(NameSpaces.DSIG_SCHEMA, SAMLTags.KEY_INFO_PREFIXED));
237             	Element keyName = (Element) keyInfo.appendChild(document.createElementNS(NameSpaces.DSIG_SCHEMA, SAMLTags.KEY_NAME_PREFIXED));
238             	keyName.appendChild(document.createTextNode(IDValues.OCES_SIGNATURE));
239             }
240 		}
241 
242 		return subj;
243 	}
244 }