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/SOSIFactory.java $
27 * $Id: SOSIFactory.java 9704 2012-01-10 11:55:16Z chg@lakeside.dk $
28 */
29 package dk.sosi.seal;
30
31 import dk.sosi.seal.model.*;
32 import dk.sosi.seal.model.constants.DGWSConstants;
33 import dk.sosi.seal.modelbuilders.*;
34 import dk.sosi.seal.pki.AuditEventHandler;
35 import dk.sosi.seal.pki.CredentialVaultSignatureProvider;
36 import dk.sosi.seal.pki.Federation;
37 import dk.sosi.seal.pki.SignatureProvider;
38 import dk.sosi.seal.pki.impl.PropertiesSOSIConfiguration;
39 import dk.sosi.seal.vault.CredentialVault;
40 import dk.sosi.seal.xml.XmlUtil;
41 import dk.sosi.seal.xml.XmlUtilException;
42 import org.w3c.dom.Document;
43
44 import java.security.cert.X509Certificate;
45 import java.util.Properties;
46
47 /**
48 * The "factory" used to construct realizations of the SOSI abstractions in the
49 * seal component. The factory acts as the entrypoint in the component, and on
50 * it, you will find factory methods for nearly all types in the SOSI component.
51 *
52 * @author kkj
53 * @author $LastChangedBy: chg@lakeside.dk $
54 * @since 1.0
55 */
56 public class SOSIFactory {
57
58 //TODO change properties names to include packages instead of "sosi:"
59 public static final String PROPERTYNAME_SOSI_VALIDATE = "sosi:validate";
60 public static final String PROPERTYNAME_SOSI_ISSUER = "sosi:issuer";
61 public static final String PROPERTYNAME_SOSI_ROOTSCHEMA = "sosi:rootschema";
62 public static final String PROPERTYNAME_SOSI_FEDERATION_AUDITHANDLER = "sosi:federation.audithandler";
63 public static final String PROPERTYNAME_SOSI_CRYPTOPROVIDER_PKCS12 = "sosi:cryptoprovider.pkcs12";
64 public static final String PROPERTYNAME_SOSI_CRYPTOPROVIDER_RSA = "sosi:cryptoprovider.rsa";
65 public static final String PROPERTYNAME_SOSI_CRYPTOPROVIDER_SHA1WITHRSA = "sosi:cryptoprovider.sha1withrsa";
66 public static final String PROPERTYNAME_SOSI_CRYPTOPROVIDER_X509 = "sosi:cryptoprovider.x509";
67 public static final String PROPERTYNAME_SOSI_CRYPTOFACADE_CERTIFICATE_REQUEST_HANDLER = "sosi:cryptofacade.certificaterequesthandler";
68 public static final String PROPERTYVALUE_SOSI_CRYPTOPROVIDER_BOUNCYCASTLE = "BC";
69 public static final String PROPERTYVALUE_SOSI_CRYPTOFACADE_BC_CERTIFICATE_REQUEST_HANDLER = "dk.sosi.seal.security.BCCertificateRequestHandler";
70 public static final String SOSI_DEFAULT_AUDIT_EVENT_HANDLER = "dk.sosi.seal.pki.NoAuditEventHandler";
71
72 public static final String PROPERTYNAME_SOSI_LDAP_CERTIFICATE_HOST_OCES1 = "sosi:federationcertificate.host.oces1";
73 public static final String PROPERTYNAME_SOSI_LDAP_CERTIFICATE_PORT_OCES1 = "sosi:federationcertificate.port.oces1";
74 //public static final String PROPERTYNAME_SOSI_LDAP_CERTIFICATE_HOST_OCES2 = "sosi:federationcertificate.host.oces2";
75 //public static final String PROPERTYNAME_SOSI_LDAP_CERTIFICATE_PORT_OCES2 = "sosi:federationcertificate.port.oces2";
76
77 /** Cache the DOM <code>DocumentBuilderFactory</code>. Please note that this constitutes a JEE compliance problem. Set to <code>false</code> if this is a problem */
78 public static final String PROPERTYNAME_SOSI_USE_DOCUMENT_BUILDER_FACTORY_CACHE = "sosi:useDBFCache";
79 public static final String PROPERTYVALUE_SOSI_USE_DOCUMENT_BUILDER_FACTORY_CACHE = "true";
80
81 // enhanced validation against specialized schemas
82 public static final String PROPERTYNAME_SOSI_VALIDATE_ENHANCED = "sosi:validate.enhanced";
83 public static final String PROPERTYVALUE_SOSI_VALIDATE_ENHANCED = "true";
84
85 // DGWS version - currently 1.0 and 1.0.1 are supported
86 public static final String PROPERTYNAME_SOSI_DGWS_VERSION = "sosi:dgws.version";
87 public static final String SOSI_DEFAULT_DGWS_VERSION = DGWSConstants.VERSION_1_0_1;
88
89 // Seal (Not DGWS) message version - currently [1.0_0,1.0_1,1.0_2] supported
90 public static final String PROPERTYNAME_SOSI_SEAL_MESSAGE_VERSION = "sosi:seal.msg.version";
91 public static final String PROPERTYVALUE_SOSI_SEAL_MESSAGE_VERSION = "1.0_0";
92
93 public static final String PROPERTYNAME_SOSI_DO_NOT_REGISTER_STR_TRANSFORM = "sosi:do.not.register.STRTransform";
94
95 private Federation federation;
96 private SignatureProvider provider;
97 private Properties properties;
98
99 /**
100 * <p>
101 * Creates a <code>SOSIFactory</code> instance given a
102 * <code>SignatureProvider</code> and a <code>Federation</code>.
103 * </p>
104 *
105 * @param federation
106 * The <code>Federation</code> to embed in this factory
107 * instance.
108 * @param provider
109 * The <code>SignatureProvider</code> to embed in this factory
110 * instance.
111 * @param properties
112 * A set of properties containing configuration values for the
113 * SOSI library.
114 */
115 public SOSIFactory(Federation federation, SignatureProvider provider, Properties properties) throws ModelException {
116 super();
117 this.federation = federation;
118 initialize(provider, properties);
119 }
120
121 /**
122 * <p>
123 * Creates a <code>SOSIFactory</code> instance given a
124 * <code>CredentialVault</code> and a <code>Federation</code>.
125 * </p>
126 *
127 * @param federation
128 * The <code>Federation</code> to embed in this factory
129 * instance.
130 * @param credentialVault
131 * The <code>CredentialVault</code> to embed in this factory
132 * instance.
133 * @param properties
134 * A set of properties containing configuration values for the
135 * SOSI library.
136 */
137 public SOSIFactory(Federation federation, CredentialVault credentialVault, Properties properties) throws ModelException {
138 super();
139 this.federation = federation;
140 if (credentialVault == null) {
141 throw new ModelException("The SOSI factory must have a CredentialVault instance");
142 }
143 initialize(new CredentialVaultSignatureProvider(credentialVault, properties), properties);
144 }
145
146 /**
147 * <p>
148 * Creates a <code>SOSIFactory</code> instance given a
149 * <code>CredentialVault</code>.
150 * </p>
151 *
152 * @param credentialVault
153 * The <code>CredentialVault</code> to embed in this factory
154 * instance.
155 * @param properties
156 * A set of properties containing configuration values for the
157 * SOSI library.
158 */
159 public SOSIFactory(CredentialVault credentialVault, Properties properties) throws ModelException {
160 this(null, credentialVault, properties);
161 }
162
163 private void initialize(SignatureProvider provider, Properties props) throws ModelException {
164 if (provider == null) {
165 throw new ModelException("You cannot construct a SOSIFactory without SignatureProvider");
166 }
167 if (props == null) {
168 throw new ModelException("You cannot construct a SOSIFactory without properties");
169 }
170 this.provider = provider;
171 this.properties = props;
172 }
173
174 /**
175 * Returns the federation associated to this credential vault.
176 */
177 public Federation getFederation() {
178 return federation;
179 }
180
181
182 /**
183 * Returns the associated credential vault.
184 */
185 public CredentialVault getCredentialVault() {
186 if (provider instanceof CredentialVaultSignatureProvider) {
187 return ((CredentialVaultSignatureProvider) provider).getCredentialVault();
188 } else {
189 throw new ModelException("No CredentialVault configured for this SOSIFactory");
190 }
191 }
192
193 /**
194 * Returns the properties for the SOSI library.
195 */
196 public Properties getProperties() {
197 return properties;
198 }
199
200 /**
201 * Constructs a <code>Request</code> model instance.
202 * <p/>
203 * After the object has been created, and an <code>IDCard</code> has been
204 * associated with the request, the request can be <i>"serialized"</i> into XML
205 * (or more precisely a DOM representation) by calling the <code>serialize2DOMDocument()</code> method.
206 *
207 * @param demandNonRepudiationReceipt If <code>true</code> this request demands a digital signature on the response to this request.
208 * @param flowID an optional "session" or "workflow" ID. If the value is <code>null</code> is
209 * the <code>flowID</code> will get the same value as <code>messageID</code>.
210 */
211 public Request createNewRequest(boolean demandNonRepudiationReceipt, String flowID) {
212 return new Request(getDGWSVersion(), demandNonRepudiationReceipt, flowID, this);
213 }
214
215 /**
216 * Constructs a <code>SecurityTokenRequest</code> model instance. <p/>
217 * After the object has been created, and an <code>IDCard</code> has been
218 * associated with the request, the request can be <i>"serialized"</i> into
219 * XML (or more precisely a DOM representation) by calling the
220 * <code>getDOMDocument()</code> method.
221 *
222 */
223 public SecurityTokenRequest createNewSecurityTokenRequest() {
224 return new SecurityTokenRequest(getDGWSVersion(), this);
225 }
226
227 /**
228 * Creates a <code>SecurityTokenResponse</code> model element for a
229 * positive SecurityTokenResponse. Per default a
230 * <code>SecurityTokenResponse</code> is created as a response to a
231 * request. To enable protection against replay attacks, the response embeds
232 * the ID of the corresponding request (see the <code>inResponseToID</code>)
233 * which is actually a <i>nonce</i>. The request will also get its own
234 * federation unique message ID (also a nonce). <p/> After the object has
235 * been created, and an optional <code>IDCard</code> has been associated
236 * with the response, the response can be <i>"serialized"</i> into XML (or
237 * more precisely a DOM representation) by calling the
238 * <code>getDOMDocument()</code> method.
239 *
240 * @param request
241 * The request that this a response to
242 *
243 * @return A new SecurityTokenResponse for a positive response
244 */
245 public SecurityTokenResponse createNewSecurityTokenResponse(SecurityTokenRequest request) {
246 return createNewSecurityTokenResponse(request.getDGWSVersion(), request.getMessageID());
247 }
248
249 /**
250 * Creates a <code>SecurityTokenResponse</code> model element for a
251 * positive SecurityTokenResponse. Per default a
252 * <code>SecurityTokenResponse</code> is created as a response to a
253 * request. To enable protection against replay attacks, the response embeds
254 * the ID of the corresponding request (see the <code>inResponseToID</code>)
255 * which is actually a <i>nonce</i>. The request will also get its own
256 * federation unique message ID (also a nonce). <p/> After the object has
257 * been created, and an optional <code>IDCard</code> has been associated
258 * with the response, the response can be <i>"serialized"</i> into XML (or
259 * more precisely a DOM representation) by calling the
260 * <code>getDOMDocument()</code> method.
261 *
262 * @param dgwsVersion
263 * The DGWS version to use for this message
264 * @param inResponseToID
265 * The messageID of the request that this error is in response to
266 *
267 * @return A new SecurityTokenResponse for a positive response
268 */
269 public SecurityTokenResponse createNewSecurityTokenResponse(String dgwsVersion, String inResponseToID) {
270 return new SecurityTokenResponse(dgwsVersion, inResponseToID, this);
271 }
272
273 /**
274 * Creates a <code>Reply</code> model element for a negative Reply. Per
275 * default a <code>Reply</code> is created as a response to a request. To
276 * enable protection against replay attacks, the response embeds the ID of
277 * the corresponding request (see the <code>inResponseToID</code>) which
278 * is actually a <i>nonce</i>.
279 * <p/>
280 * The response can be <i>"serialized"</i> into XML (or more
281 * precisely a DOM representation) by calling the
282 * <code>getDOMDocument()</code> method.
283 * @param request
284 * The request that this a response to
285 * @param faultCode
286 * The status code from FaultCodeValues
287 * @param faultString
288 * A human readable error text
289 * @param faultActor
290 * The "actor" who is sending the fault, for instance <code>http://www.sosi.dk/STS</code>
291 * @return A new SecurityTokenResponse for a negative response
292 */
293 public SecurityTokenResponse createNewSecurityTokenErrorResponse(SecurityTokenRequest request, String faultCode, String faultString, String faultActor) {
294 return createNewSecurityTokenErrorResponse(request.getDGWSVersion(), request.getMessageID(), faultCode, faultString, faultActor);
295 }
296
297 /**
298 * Creates a <code>Reply</code> model element for a negative Reply. Per
299 * default a <code>Reply</code> is created as a response to a request. To
300 * enable protection against replay attacks, the response embeds the ID of
301 * the corresponding request (see the <code>inResponseToID</code>) which
302 * is actually a <i>nonce</i>.
303 * <p/>
304 * The response can be <i>"serialized"</i> into XML (or more
305 * precisely a DOM representation) by calling the
306 * <code>getDOMDocument()</code> method.
307 * @param dgwsVersion
308 * The DGWS version to use for this message
309 * @param inResponseToID
310 * The messageID of the request that this error is in response to
311 * @param faultCode
312 * The status code from FaultCodeValues
313 * @param faultString
314 * A human readable error text
315 * @param faultActor
316 * The "actor" who is sending the fault, for instance <code>http://www.sosi.dk/STS</code>
317 *
318 * @return A new SecurityTokenResponse for a negative response
319 */
320 public SecurityTokenResponse createNewSecurityTokenErrorResponse(String dgwsVersion, String inResponseToID, String faultCode, String faultString, String faultActor) {
321 return new SecurityTokenResponse(dgwsVersion, inResponseToID, faultCode, faultString, faultActor, this);
322 }
323
324 /**
325 * Creates a <code>Reply</code> model element for a positive Reply. Per
326 * default a <code>Reply</code> is created as a response to a request. To
327 * enable protection against replay attacks, the response embeds the ID of
328 * the corresponding request (see the <code>inResponseToID</code>) which
329 * is actually a <i>nonce</i>. The request will also get its own federation
330 * unique message ID (also a nonce). <p/> After the object has been created,
331 * and an optional <code>IDCard</code> has been associated with the
332 * response, the response can be <i>"serialized"</i> into XML (or more
333 * precisely a DOM representation) by calling the
334 * <code>getDOMDocument()</code> method.
335 *
336 * @param request
337 * The request that this a response to
338 * @param flowStatus
339 * The status code from FlowStatusValues
340 * @return A new Reply for a positive response
341 */
342 public Reply createNewReply(Request request, String flowStatus) {
343 return new Reply(request.getDGWSVersion(), request.getMessageID(), request.getFlowID(), flowStatus, this);
344 }
345
346 /**
347 * Creates a <code>Reply</code> model element for a positive Reply. Per
348 * default a <code>Reply</code> is created as a response to a request. To
349 * enable protection against replay attacks, the response embeds the ID of
350 * the corresponding request (see the <code>inResponseToID</code>) which
351 * is actually a <i>nonce</i>. The request will also get its own federation
352 * unique message ID (also a nonce). <p/> After the object has been created,
353 * and an optional <code>IDCard</code> has been associated with the
354 * response, the response can be <i>"serialized"</i> into XML (or more
355 * precisely a DOM representation) by calling the
356 * <code>getDOMDocument()</code> method.
357 *
358 * @param dgwsVersion
359 * The DGWS version of this
360 * @param inResponseToID
361 * The ID of the request that this instance is a reponse to.
362 * @param flowID
363 * an optional "session" or "workflow" ID. If the value is
364 * <code>null</code> is the <code>flowID</code> will get the
365 * same value as <code>messageID</code>. For replies the
366 * <code>flowID</code> is usually taken from the corresponding
367 * request.
368 * @param flowStatus
369 * The status code from FlowStatusValues
370 * @return A new Reply for a positive response
371 */
372 public Reply createNewReply(String dgwsVersion, String inResponseToID, String flowID, String flowStatus) {
373 return new Reply(dgwsVersion, inResponseToID, flowID, flowStatus, this);
374 }
375
376 /**
377 * Creates a <code>Reply</code> model element for a negative Reply. Per
378 * default a <code>Reply</code> is created as a response to a request. To
379 * enable protection against replay attacks, the response embeds the ID of
380 * the corresponding request (see the <code>inResponseToID</code>) which
381 * is actually a <i>nonce</i>. The request will also get its own federation
382 * unique message ID (also a nonce). <p/> After the object has been created,
383 * and an optional <code>IDCard</code> has been associated with the
384 * response, the response can be <i>"serialized"</i> into XML (or more
385 * precisely a DOM representation) by calling the
386 * <code>getDOMDocument()</code> method.
387 *
388 * @param dgwsVersion
389 * The DGWS version to use for this message
390 * @param inResponseToID
391 * The ID of the request that this instance is a reponse to.
392 * @param flowID
393 * an optional "session" or "workflow" ID. If the value is
394 * <code>null</code> is the <code>flowID</code> will get the
395 * same value as <code>messageID</code>. For replies the
396 * <code>flowID</code> is usually taken from the corresponding
397 * request.
398 * @param faultCode
399 * The status code from FaultCodeValues
400 * @param faultString
401 * A human readable error text
402 * @return A new Reply for a negative response
403 */
404 public Reply createNewErrorReply(String dgwsVersion, String inResponseToID, String flowID, String faultCode, String faultString) {
405 return new Reply(dgwsVersion, inResponseToID, flowID, faultCode, faultString, this);
406 }
407
408 /**
409 * Creates a <code>Reply</code> model element for a negative Reply. Per
410 * default a <code>Reply</code> is created as a response to a request. To
411 * enable protection against replay attacks, the response embeds the ID of
412 * the corresponding request (see the <code>inResponseToID</code>) which
413 * is actually a <i>nonce</i>. The request will also get its own federation
414 * unique message ID (also a nonce). <p/> After the object has been created,
415 * and an optional <code>IDCard</code> has been associated with the
416 * response, the response can be <i>"serialized"</i> into XML (or more
417 * precisely a DOM representation) by calling the
418 * <code>getDOMDocument()</code> method.
419 *
420 * @param request
421 * The request that this an error reply to
422 * @param faultCode
423 * The status code from FaultCodeValues
424 * @param faultString
425 * A human readable error text
426 * @return A new Reply for a negative response
427 */
428 public Reply createNewErrorReply(Request request, String faultCode, String faultString) {
429 return createNewErrorReply(request.getDGWSVersion(), request.getMessageID(), request.getFlowID(), faultCode, faultString);
430 }
431
432 /**
433 * Creates a new <code>SystemIDCard</code>.
434 *
435 * @param itSystemName
436 * The IT system name to embed in the IDCard.
437 * @param careProvider
438 * The organizational unit that the user is acting on behalf of
439 * @param authenticationLevel
440 * The requested type of signature for this ID card (DGWS level 1 through 3). See @link{dk.sosi.seal.model.AuthenticationLevel}.
441 * @param certificate
442 * The public certificate that can validate this ID-card
443 * @param alternativeIdentifier
444 * A <code>String</code> denoting an alternative identifier that
445 * will be used as SAML Subject (of type medcom:other) when serializing
446 * this IDCard instead. May be <code>null</null>.
447 * @deprecated
448 * Use {@link #createNewSystemIDCard(String, CareProvider, AuthenticationLevel, String, String, X509Certificate, String)} instead
449 */
450 @Deprecated
451 public SystemIDCard createNewSystemIDCard(String itSystemName, CareProvider careProvider, AuthenticationLevel authenticationLevel, X509Certificate certificate,
452 String alternativeIdentifier) {
453 return createNewSystemIDCard(itSystemName, careProvider, authenticationLevel, null, null, certificate, alternativeIdentifier);
454 }
455
456 /**
457 * Creates a new <code>SystemIDCard</code>.
458 *
459 * @param itSystemName
460 * The IT system name to embed in the IDCard.
461 * @param careProvider
462 * The organizational unit that the user is acting on behalf of
463 * @param authenticationLevel
464 * The requested type of signature for this ID card (DGWS level 1 through 3). See @link{dk.sosi.seal.model.AuthenticationLevel}.
465 * @param username
466 * The username to employ when creating an idcard with authenticationLeve 2. May be <code>null</code>.
467 * @param password
468 * The password to employ when creating an idcard with authenticationLeve 2. May be <code>null</code>.
469 * @param certificate
470 * The public certificate that can validate this ID-card
471 * @param alternativeIdentifier
472 * A <code>String</code> denoting an alternative identifier that
473 * will be used as SAML Subject (of type medcom:other) when serializing
474 * this IDCard instead. May be <code>null</null>.
475 */
476 public SystemIDCard createNewSystemIDCard(String itSystemName, CareProvider careProvider, AuthenticationLevel authenticationLevel, String username, String password,
477 X509Certificate certificate, String alternativeIdentifier) {
478 SystemInfo systemInfo = new SystemInfo(careProvider, itSystemName);
479 return new SystemIDCard(getDGWSVersion(), authenticationLevel, getIssuer(), systemInfo, SignatureUtil.getDigestOfCertificate(certificate), alternativeIdentifier, username, password);
480 }
481
482 /**
483 * Creates a new <code>UserIDCard</code>.
484 *
485 * @param itSystemName
486 * The IT system name to embed in the IDCard.
487 * @param cpr
488 * Civil Registration number for the user
489 * @param givenName
490 * Given name of the user (da:fornavn)
491 * @param surName
492 * Surname of the user (da:Efternavn)
493 * @param email
494 * The users e-mail address
495 * @param occupation
496 * The occupation for the user
497 * @param role
498 * The role in which the user is acting, for instance doctor or
499 * Nurse
500 * @param careProvider
501 * The organizational unit that the user is acting on behalf of
502 * @param authorizationCode
503 * The authorization code for the user (SST)
504 * @param authenticationLevel
505 * The requested type of signature for this ID card
506 * @param certificate
507 * The public certificate that can validate this ID-card. May be <code>null</code>.
508 * @param alternativeIdentifier
509 * A <code>String</code> denoting an alternative identifier that
510 * will be used as SAML Subject (of type medcom:other) when serializing
511 * this IDCard instead. May be <code>null</null>.
512 * @deprecated
513 * Use {@link #createNewUserIDCard(String, UserInfo, CareProvider, AuthenticationLevel, String, String, X509Certificate, String)} instead
514 */
515 @Deprecated
516 public UserIDCard createNewUserIDCard(String itSystemName, String cpr, String givenName, String surName, String email, String occupation, String role,
517 CareProvider careProvider, String authorizationCode, AuthenticationLevel authenticationLevel, X509Certificate certificate, String alternativeIdentifier) {
518
519 UserInfo userInfo = new UserInfo(cpr, givenName, surName, email, occupation, role, authorizationCode);
520 return createNewUserIDCard(itSystemName, userInfo, careProvider, authenticationLevel, null, null, certificate, alternativeIdentifier);
521 }
522
523 /**
524 * Creates a new <code>UserIDCard</code>.
525 *
526 * @param itSystemName
527 * The IT system name to embed in the IDCard.
528 * @param userInfo
529 * A <code>UserInfo</code> instance representing the user
530 * @param careProvider
531 * The organizational unit that the user is acting on behalf of
532 * @param authenticationLevel
533 * The requested type of signature for this ID card
534 * @param username
535 * The username to employ when creating an idcard with authenticationLeve 2. May be <code>null</code>.
536 * @param password
537 * The password to employ when creating an idcard with authenticationLeve 2. May be <code>null</code>.
538 * @param certificate
539 * The public certificate that can validate this ID-card. May be <code>null</code>.
540 * @param alternativeIdentifier
541 * A <code>String</code> denoting an alternative identifier that
542 * will be used as SAML Subject (of type medcom:other) when serializing
543 * this IDCard instead. May be <code>null</null>.
544 */
545 public UserIDCard createNewUserIDCard(String itSystemName, UserInfo userInfo, CareProvider careProvider, AuthenticationLevel authenticationLevel, String username,
546 String password, X509Certificate certificate, String alternativeIdentifier) {
547
548 SystemInfo systemInfo = new SystemInfo(careProvider, itSystemName);
549 return new UserIDCard(getDGWSVersion(), authenticationLevel, getIssuer(), systemInfo, userInfo, SignatureUtil.getDigestOfCertificate(certificate), alternativeIdentifier, username, password);
550 }
551
552 /**
553 * Creates a new <code>IDCard</code> based on the data from an existing id
554 * card. The <code>IDCard</code> will get a new unique <code>id</code>
555 * and will have the same authentication level as the original
556 * <code>IDCard</code>, but will always get signed with a VOCES
557 * signature, making this method ideal for <code>IDCard</code> issuing
558 * libraries like IdP's.
559 *
560 * @param origCard
561 * the id card to copy data from
562 * @param cpr
563 * cpr to add if origCard doesnt contain it
564 * @return a new <code>UserIDCard</code> if the original id card was a
565 * <code>UserIDCard</code> or a new <code>SystemIDCard</code> if
566 * the original id card was a <code>SystemIDCard</code>.
567 *
568 * @deprecated Use one of the methods taking a specific type of IDCard instead
569 */
570 @Deprecated
571 public IDCard copyToVOCESSignedIDCard(IDCard origCard, String cpr) {
572 if (origCard instanceof UserIDCard) {
573 UserIDCard userIdCard = (UserIDCard) origCard;
574 final UserInfo userInfo;
575 if(cpr == null || "".equals(cpr))
576 userInfo = userIdCard.getUserInfo();
577 else {
578 userInfo = new UserInfo(userIdCard.getUserInfo(), cpr);
579 }
580 return copyToVOCESSignedIdCard(userIdCard, userInfo);
581 } else if (origCard instanceof SystemIDCard) {
582 return copyToVOCESSignedIdCard((SystemIDCard) origCard);
583 } else {
584 throw new ModelException("Unknown IDCard type");
585 }
586 }
587
588 /**
589 * Creates a new <code>IDCard</code> based on the data from an existing id
590 * card. The <code>IDCard</code> will get a new unique <code>id</code>
591 * and will have the same authentication level as the original
592 * <code>IDCard</code>, but will always get signed with a VOCES
593 * signature, making this method ideal for <code>IDCard</code> issuing
594 * libraries like IdP's.
595 *
596 * @param origCard
597 * the id card to copy data from
598 * @return a new <code>UserIDCard</code> if the original id card was a
599 * <code>UserIDCard</code> or a new <code>SystemIDCard</code> if
600 * the original id card was a <code>SystemIDCard</code>.
601 */
602 public IDCard copyToVOCESSignedIDCard(IDCard origCard) {
603 if (origCard instanceof UserIDCard) {
604 UserIDCard userIdCard = (UserIDCard) origCard;
605 return copyToVOCESSignedIdCard(userIdCard, userIdCard.getUserInfo());
606 } else if (origCard instanceof SystemIDCard) {
607 return copyToVOCESSignedIdCard((SystemIDCard) origCard);
608 } else {
609 throw new ModelException("Unknown IDCard type");
610 }
611 }
612
613 /**
614 * Creates a new <code>UserIDCard</code> based on the data from an existing id
615 * card. The <code>IDCard</code> will get a new unique <code>id</code>
616 * and will have the same authentication level as the original
617 * <code>IDCard</code>, but will always get signed with a VOCES
618 * signature, making this method ideal for <code>IDCard</code> issuing
619 * libraries like IdP's.
620 *
621 * @param origUserIdCard
622 * the id card to copy data from
623 * @param newUserInfo
624 * UserInfo to insert instead of the original
625 * @return a new <code>UserIDCard</code>.
626 */
627 public IDCard copyToVOCESSignedIdCard(UserIDCard origUserIdCard, UserInfo newUserInfo) {
628 // if no certHash exists on origCard, generate new on copy
629 final String certHash = getOrGenerateCertHash(origUserIdCard);
630 final IDCard result = new UserIDCard(origUserIdCard, getIssuer(), newUserInfo, certHash);
631 return getSignedIdCard(result);
632 }
633
634 /**
635 * Creates a new <code>UserIDCard</code> based on the data from an existing id
636 * card. The <code>IDCard</code> will get a new unique <code>id</code>
637 * and will have the same authentication level as the original
638 * <code>IDCard</code>, but will always get signed with a VOCES
639 * signature, making this method ideal for <code>IDCard</code> issuing
640 * libraries like IdP's.
641 *
642 * @param origSystemIdCard
643 * the id card to copy data from
644 * @return a new <code>UserIDCard</code>.
645 */
646 private IDCard copyToVOCESSignedIdCard(SystemIDCard origSystemIdCard) {
647 // if no certHash exists on origCard, generate new on copy
648 final String certHash = getOrGenerateCertHash(origSystemIdCard);
649 final IDCard result = new SystemIDCard(origSystemIdCard, getIssuer(), certHash);
650 return getSignedIdCard(result);
651 }
652
653 private String getOrGenerateCertHash(IDCard origCard) {
654 if (origCard.getCertHash() == null || "".equals(origCard.getCertHash())) {
655 return origCard.generateCertHash();
656 } else {
657 return origCard.getCertHash();
658 }
659 }
660
661 private IDCard getSignedIdCard(IDCard result) {
662 Request tmp = createNewRequest(false, "");
663 tmp.setIDCard(result);
664 Document doc = tmp.serialize2DOMDocument();
665 result.sign(doc, provider);
666 return tmp.getIDCard();
667 }
668
669 /**
670 * "Deserializes" an XML document into a <code>Request</code> model
671 * object.
672 *
673 * @param xml
674 * The XML to deserialize.
675 * @throws XmlUtilException
676 * Thrown if the XML could not be read and schema-validated.
677 * @throws ModelBuildException
678 * Thrown if the model builder was not able to deserialize the
679 * XML.
680 */
681 public Request deserializeRequest(String xml) throws XmlUtilException, ModelBuildException {
682 RequestModelBuilder b = new RequestModelBuilder(this);
683 return b.buildModel(XmlUtil.readXml(properties, xml, validate()));
684 }
685
686 /**
687 * "Deserializes" an XML document into a <code>Reply</code> model object.
688 *
689 * @param xml
690 * The XML to deserialize.
691 * @throws XmlUtilException
692 * Thrown if the XML could not be read and schema-validated.
693 * @throws ModelBuildException
694 * Thrown if the model builder was not able to deserialize the
695 * XML.
696 */
697 public Reply deserializeReply(String xml) throws XmlUtilException, ModelBuildException {
698 ReplyModelBuilder b = new ReplyModelBuilder(this);
699 return b.buildModel(XmlUtil.readXml(properties, xml, validate()));
700 }
701
702 /**
703 * "Deserializes" an XML document into a <code>SecurityTokenRequest</code>
704 * model object.
705 *
706 * @param xml
707 * The XML to deserialize.
708 * @throws XmlUtilException
709 * Thrown if the XML could not be read and schema-validated.
710 * @throws ModelBuildException
711 * Thrown if the model builder was not able to deserialize the
712 * XML.
713 */
714 public SecurityTokenRequest deserializeSecurityTokenRequest(String xml) throws XmlUtilException, ModelBuildException {
715 SecurityTokenRequestModelBuilder b = new SecurityTokenRequestModelBuilder(this);
716 return b.buildModel(XmlUtil.readXml(properties, xml, validate()));
717 }
718
719 /**
720 * "Deserializes" an XML document into a <code>Reply</code> model object.
721 *
722 * @param xml
723 * The XML to deserialize.
724 * @throws XmlUtilException
725 * Thrown if the XML could not be read and schema-validated.
726 * @throws ModelBuildException
727 * Thrown if the model builder was not able to deserialize the
728 * XML.
729 */
730 public SecurityTokenResponse deserializeSecurityTokenResponse(String xml) throws XmlUtilException, ModelBuildException {
731 SecurityTokenResponseModelBuilder b = new SecurityTokenResponseModelBuilder(this);
732 return b.buildModel(XmlUtil.readXml(properties, xml, validate()));
733 }
734
735
736 /**
737 * "Deserializes" an XML document into an <code>IDCard</code> model object.
738 *
739 * @param xml
740 * The XML to deserialize.
741 * @throws XmlUtilException
742 * Thrown if the XML could not be read and schema-validated.
743 * @throws ModelBuildException
744 * Thrown if the model builder was not able to deserialize the
745 * XML.
746 */
747 public IDCard deserializeIDCard(String xml) throws XmlUtilException, ModelBuildException {
748 IDCardModelBuilder builder = new IDCardModelBuilder();
749 return builder.buildModel(XmlUtil.readXml(properties, xml, validate()));
750 }
751
752 /**
753 * "Deserializes" an XML document into a <code>RequestHeader</code> model object.
754 *
755 * @param xml
756 * The XML to deserialize.
757 * @throws XmlUtilException
758 * Thrown if the XML could not be read and schema-validated.
759 * @throws ModelBuildException
760 * Thrown if the model builder was not able to deserialize the
761 * XML.
762 *
763 * @since 1.5.10
764 */
765 public RequestHeader deserializeRequestHeader(String xml) throws XmlUtilException, ModelBuildException {
766 RequestHeaderModelBuilder builder = new RequestHeaderModelBuilder(this);
767 return builder.buildModel(XmlUtil.readXml(properties, xml, validate()));
768 }
769
770 /**
771 * "Deserializes" an XML document into a <code>ReplyHeader</code> model object.
772 *
773 * @param xml
774 * The XML to deserialize.
775 * @throws XmlUtilException
776 * Thrown if the XML could not be read and schema-validated.
777 * @throws ModelBuildException
778 * Thrown if the model builder was not able to deserialize the
779 * XML.
780 *
781 * @since 1.5.10
782 */
783 public ReplyHeader deserializeReplyHeader(String xml) throws XmlUtilException, ModelBuildException {
784 ReplyHeaderModelBuilder builder = new ReplyHeaderModelBuilder(this);
785 return builder.buildModel(XmlUtil.readXml(properties, xml, validate()));
786 }
787
788 public static AuditEventHandler getAuditEventHandler(Properties properties) throws ModelException {
789 // TODO: the configuration created should probably be stored to avoid recreating it every time.
790 return new PropertiesSOSIConfiguration(properties).getAuditEventHandler();
791 }
792
793 // ==================================
794 // Private methods
795 // ==================================
796
797 private String getIssuer() {
798 return properties.getProperty(PROPERTYNAME_SOSI_ISSUER, "TheSOSILibrary");
799 }
800
801 private boolean validate() {
802 return properties.getProperty(PROPERTYNAME_SOSI_VALIDATE, "true").equalsIgnoreCase("true");
803 }
804
805 private String getDGWSVersion() {
806 return properties.getProperty(PROPERTYNAME_SOSI_DGWS_VERSION, SOSI_DEFAULT_DGWS_VERSION);
807 }
808 }