1 /* 2 * $Header: /cvsroot/ebxmlrr/ebxmlrr/test/com/sun/ebxml/registry/interfaces/soap/SOAPSender.java,v 1.39 2002/12/30 02:45:55 skchonghk Exp $ 3 * 4 */ 5 6 package com.sun.ebxml.registry.interfaces.soap; 7 8 import java.io.*; 9 import java.security.*; 10 import java.security.cert.*; 11 import java.util.*; 12 13 import javax.activation.*; 14 import javax.mail.*; 15 import javax.mail.internet.*; 16 import javax.servlet.ServletException; 17 import javax.xml.messaging.URLEndpoint; 18 import javax.xml.parsers.*; 19 import javax.xml.soap.*; 20 21 import org.apache.xml.security.exceptions.XMLSecurityException; 22 import org.apache.xml.security.signature.XMLSignature; 23 import org.xml.sax.SAXException; 24 25 import com.sun.ebxml.registry.RegistryException; 26 import com.sun.ebxml.registry.security.SecurityUtil; 27 import com.sun.ebxml.registry.security.authentication.AuthenticationServiceImpl; 28 import com.sun.ebxml.registry.util.Utility; 29 30 /*** 31 * Sends a SOAP 1.1 message with attachments to an ebXML Registry <br> 32 * 33 * It takes these command line parameters:<br> 34 * 35 * req - The file containing the ebXML registry request <br> 36 * 37 * alias - Optional. If it is provided the request will be signed with the 38 * private key of the alias in the keystore<br> 39 * 40 * keyStore - Optional. The keystore is used for signing. If it is not provided 41 * but the alias is provided, the keystore specified by 42 * ebxmlrr.security.keystoreFile properties in ebxmlrr.properties is used for 43 * signing. The supported keystore types are pkcs12 and jks <br> 44 * 45 * keyPassword - The key password for accessing the private key<br> 46 * 47 * keyStoreType - The type of the keystore. It may be pkcs12 or jks <br> 48 * 49 * keyStorePassword - The password for accessing the keystore <br> 50 * 51 * url - The URL of the ebXML registry server<br> 52 * 53 * attach - comma-delimited list of attached file, MIME type of the file and the UUID (either 54 * temporary or real) of corresponding ExtrinsicObject in the SubmitObjectsRequest. More than 55 * one attach parameter can be added<br> 56 * 57 * res - If this parameter exists, the response from registry will be saved to the file 58 * of path specified by this parameter<br> 59 * 60 * @see 61 * @author Farrukh S. Najmi 62 */ 63 64 public class SOAPSender { 65 66 private static AuthenticationServiceImpl authc = AuthenticationServiceImpl.getInstance(); 67 private static final String defaultRequestFileName = "c:/osws/ebxmlrr-spec/misc/samples/SubmitObjectsRequest_Sun.xml"; 68 String reqFileName = null; 69 70 private String registryURL = null; 71 72 73 private static final String defaultAlias = null; 74 private String alias = defaultAlias; 75 76 private static final boolean defaultLocalCall = true; 77 private static boolean localCall = defaultLocalCall; 78 79 private static boolean requestIsAScheme = false; 80 private static boolean debug = false; 81 82 private SOAPMessage msg = null; 83 84 private HashMap attachmentMap = new HashMap(); 85 private static ArrayList attachments = new ArrayList(); 86 87 private KeyStore keyStore; 88 private String keyPassword; 89 private String signingAlgo; 90 private java.security.cert.Certificate [] certs; 91 private java.security.PrivateKey privateKey; 92 93 public void setKeyStore(String keyStoreFile, String keyStoreType, String keyStorePassword 94 , String keyPassword) throws KeyStoreException, IOException, NoSuchAlgorithmException, 95 CertificateException { 96 keyStore = KeyStore.getInstance(keyStoreType); 97 keyStore.load(new FileInputStream(keyStoreFile), stringToCharArray(keyStorePassword)); 98 } 99 100 private char[] stringToCharArray(String str) { 101 char[] arr = null; 102 if (str != null) { 103 arr = str.toCharArray(); 104 } 105 106 return arr; 107 } 108 109 public void setKeyPassword(String keyPassword) { 110 this.keyPassword = keyPassword; 111 } 112 113 public void setRequestFileName(String reqFileName) { 114 this.reqFileName = reqFileName; 115 } 116 117 public void setRegistryURL(String registryURL) { 118 this.registryURL = registryURL; 119 } 120 121 public void setAlias(String alias) { 122 this.alias = alias; 123 } 124 125 public void setLocalCall(boolean localCall) { 126 this.localCall = localCall; 127 } 128 129 private static void printUsage() { 130 System.err.println("...SOAPSender [-help] req=<requestFile.xml>|scheme=<schemeFile.xml> keyStore=<KeyStore> " 131 + "keyStoreType=<jks|pkcs12> keyStorePassword=<password> keyPassword=<password> alias=<aliasInKeyStore> url=<registryURL> " 132 + "attach=<file>,mimeType,id localCall=<true|false> " 133 + "res=<responseFile.xml>"); 134 System.exit(-1); 135 } 136 137 private static class AttachmentInfo { 138 public AttachmentInfo(String fileName, String mimeType, String id) { 139 this.id = id; 140 this.fileName = fileName; 141 this.mimeType = mimeType; 142 } 143 144 String id = null; 145 String fileName = null; 146 String mimeType = null; 147 } 148 149 public static void main(String[] args) { 150 try { 151 152 String reqFileName = defaultRequestFileName; 153 String resFileName = null; 154 String url = null; 155 String alias = defaultAlias; 156 boolean localCall = defaultLocalCall; 157 String keyStoreFile = null; 158 String keyStoreType = null; 159 String keyStorePassword = null; 160 String keyPassword = null; 161 162 for (int i=0; i<args.length; i++) { 163 if (args[i].equalsIgnoreCase("-help")) { 164 printUsage(); 165 } 166 else if (args[i].equalsIgnoreCase("-debug")) { 167 debug = true; 168 } 169 else if (args[i].startsWith("req=")) { 170 reqFileName = args[i].substring(4, args[i].length()); 171 } 172 else if (args[i].startsWith("res=")) { 173 resFileName = args[i].substring(4, args[i].length()); 174 } 175 else if (args[i].startsWith("scheme=")) { 176 reqFileName = args[i].substring(7, args[i].length()); 177 requestIsAScheme = true; 178 } 179 else if (args[i].startsWith("alias=")) { 180 alias = args[i].substring(6, args[i].length()); 181 182 if (alias.equalsIgnoreCase("RegistryOperator")) { 183 alias = authc.ALIAS_REGISTRY_OPERATOR; 184 } 185 else if (alias.equalsIgnoreCase("RegistryGuest")) { 186 alias = authc.ALIAS_REGISTRY_GUEST; 187 } 188 else if (alias.equalsIgnoreCase("Farrukh")) { 189 alias = authc.ALIAS_FARRUKH; 190 } 191 else if (alias.equalsIgnoreCase("Nikola")) { 192 alias = authc.ALIAS_NIKOLA; 193 } 194 else if (alias.equalsIgnoreCase("Adrian")) { 195 alias = authc.ALIAS_ADRIAN; 196 } 197 else if (alias.equalsIgnoreCase("CY")) { 198 alias = authc.ALIAS_CY; 199 } 200 } 201 else if (args[i].startsWith("url=")) { 202 url = args[i].substring(4, args[i].length()); 203 } 204 else if (args[i].startsWith("attach=")) { 205 StringTokenizer tokenizer = 206 new StringTokenizer(args[i], "=," ); 207 208 String attachFileName = null; 209 String mimeType = "text/plain"; 210 String attachId = "id"; 211 212 int j=0; 213 while ( tokenizer.hasMoreTokens() ) { 214 String token = tokenizer.nextToken(); 215 if (j==1) { 216 attachFileName = token; 217 } 218 else if (j==2) { 219 mimeType = token; 220 } 221 if (j==3) { 222 attachId = token; 223 } 224 j++; 225 } 226 227 AttachmentInfo ai = new AttachmentInfo(attachFileName, mimeType, attachId); 228 attachments.add(ai); 229 } 230 else if (args[i].startsWith("localCall=")) { 231 String localCallStr = args[i].substring(10, args[i].length()); 232 if (localCallStr.equalsIgnoreCase("false")) { 233 localCall = false; 234 } 235 } 236 else if (args[i].startsWith("keyStore=")) { 237 keyStoreFile = args[i].substring(9, args[i].length()); 238 } 239 else if (args[i].startsWith("keyStoreType=")) { 240 keyStoreType = args[i].substring(13, args[i].length()); 241 } 242 else if (args[i].startsWith("keyStorePassword=")) { 243 keyStorePassword = args[i].substring(17, args[i].length()); 244 } 245 else if (args[i].startsWith("keyPassword=")) { 246 keyPassword = args[i].substring(12, args[i].length()); 247 } 248 else { 249 System.err.println("Unknown parameter: '" + args[i] + "' at position " + i); 250 if (i > 0) { 251 System.err.println("Last valid parameter was '" + args[i-1] + "'"); 252 } 253 printUsage(); 254 } 255 } 256 257 // checking whether enough parameters are provided 258 if (reqFileName==null) { 259 System.err.println("'req' is mandatory!"); 260 printUsage(); 261 } 262 if (url==null) { 263 System.err.println("'url' is mandatory!"); 264 printUsage(); 265 } 266 if (keyStoreFile != null) { 267 if (keyStoreType==null) { 268 System.err.println("'keyStoreType' is mandatory for signing if keyStore parameter is provided!"); 269 printUsage(); 270 } 271 if (keyPassword==null) { 272 System.err.println("'keyPassword' is mandatory for signing if keyStore parameter is provided!"); 273 printUsage(); 274 } 275 if (keyStorePassword==null) { 276 System.err.println("'keyStorePassword' is mandatory for signing if keyStore parameter is provided!"); 277 printUsage(); 278 } 279 } 280 281 SOAPSender sender = new SOAPSender(); 282 sender.setRequestFileName(reqFileName); 283 sender.setRegistryURL(url); 284 sender.setAlias(alias); 285 sender.setLocalCall(localCall); 286 if (keyStoreFile != null) { 287 sender.setKeyStore(keyStoreFile, keyStoreType, keyStorePassword 288 , keyPassword); 289 } 290 sender.setKeyPassword(keyPassword); 291 292 SOAPMessage reply = sender.send(); 293 if (resFileName !=null && reply != null) { 294 FileOutputStream responseFileStream = new FileOutputStream(resFileName); 295 reply.writeTo(responseFileStream); 296 } 297 298 299 SOAPPart sp = reply.getSOAPPart(); 300 SOAPEnvelope se = sp.getEnvelope(); 301 SOAPBody body = se.getBody(); 302 303 Iterator iter = body.getChildElements(); 304 305 //Skip any text nodes 306 Object obj = null; 307 SOAPElement rootElem = null; 308 while (iter.hasNext()) { 309 obj = iter.next(); 310 if (obj instanceof SOAPElement) { 311 rootElem = (SOAPElement)obj; 312 break; 313 } 314 } 315 316 if (rootElem != null) { 317 String rootElemName = rootElem.getElementName().getLocalName(); 318 //System.err.println("rootElem = " + rootElemName); 319 320 if (rootElemName.equalsIgnoreCase("RegistryResponse")) { 321 iter = rootElem.getChildElements(); 322 323 324 //Skip any text nodes 325 obj = null; 326 SOAPElement childElem = null; 327 while (iter.hasNext()) { 328 obj = iter.next(); 329 if (obj instanceof SOAPElement) { 330 childElem = (SOAPElement)obj; 331 break; 332 } 333 } 334 335 if (childElem != null) { 336 String childElemName = childElem.getElementName().getLocalName(); 337 //System.err.println("childElem = " + childElemName); 338 339 if (childElemName.equalsIgnoreCase("RegistryErrorList")) { 340 System.exit(-1); 341 } 342 } 343 } 344 } 345 346 System.exit(0); 347 348 } catch (RegistryException e) { 349 e.printStackTrace(); 350 Exception e1 = e.getException(); 351 if (e1 != null) { 352 System.err.println("Nested exception was: "); 353 e1.printStackTrace(); 354 } 355 System.exit(-1); 356 } 357 catch (Exception e) { 358 e.printStackTrace(); 359 System.exit(-1); 360 } 361 362 } 363 364 private SOAPMessage createSOAPMessage(String alias, String reqFileName) throws RegistryException, IOException 365 , FileNotFoundException, SOAPException, ParseException, KeyStoreException, NoSuchAlgorithmException, 366 UnrecoverableKeyException { 367 SOAPMessage msg = null; 368 File file = new File(reqFileName); 369 FileInputStream fis = new FileInputStream(file); 370 371 if (requestIsAScheme) { 372 } 373 374 InputStream soapStream = Utility.getInstance().createSOAPStreamFromRequestStream(fis); 375 // Utility.getInstance().createSOAPMessageFromRequestStream(docInStream); 376 fis.close(); 377 378 // System.err.println(alias + "!!!!!"); 379 380 if (alias != null) { 381 // use the keystore specified in ebxmlrr.properties 382 if (keyStore==null) { 383 certs = authc.getCertificateChain(alias); 384 privateKey = authc.getPrivateKey(alias, alias); 385 } 386 else { 387 // use other keystore 388 certs = keyStore.getCertificateChain(alias); 389 //System.err.println(keyPassword); 390 privateKey = (PrivateKey) keyStore.getKey(alias 391 , stringToCharArray(keyPassword)); 392 } 393 394 if(privateKey==null) { 395 System.err.println("No private key with alias " + "'" + alias + 396 "'"); 397 System.exit(-1); 398 } 399 400 File soapFile = new File("signedSOAPRequest.xml"); 401 402 // System.err.println(signingAlgo + "!!!!"); 403 404 // Get the algorithm of the key 405 signingAlgo = privateKey.getAlgorithm(); 406 if (signingAlgo.equalsIgnoreCase("DSA")) { 407 signingAlgo = XMLSignature.ALGO_ID_SIGNATURE_DSA; 408 } 409 else if (signingAlgo.equalsIgnoreCase("RSA")) { 410 signingAlgo = XMLSignature.ALGO_ID_SIGNATURE_RSA; 411 } 412 else { 413 throw new NoSuchAlgorithmException("Algorithm not supported"); 414 } 415 416 /* 417 * TO TEST WHETHER THE SIGNATURE IS REALLY VERIFIED PROPERLY, YOU CAN 418 * MODIFY signedSOAPRequest.xml (enter some empty lines between elements) 419 * , COMMENT THE FOLLOWING 3 LINES, AND RUN THE PROGRAM AGAIN 420 */ 421 422 423 FileOutputStream fos = new FileOutputStream(soapFile); 424 SecurityUtil.getInstance().signSOAPMessage(soapStream, fos, privateKey, certs, signingAlgo); 425 fos.close(); 426 427 428 soapStream = new FileInputStream(soapFile); 429 } 430 431 msg = Utility.getInstance().createSOAPMessageFromSOAPStream(soapStream); 432 433 return msg; 434 } 435 436 public void addAttachment(String id, String fileName, String mimeType) throws 437 FileNotFoundException, MessagingException, RegistryException { 438 //Create a multipart with two bodyparts 439 //First bodypart is an XMLDSIG and second is the attached file 440 441 MimeMultipart mp = new MimeMultipart(); 442 443 MimeBodyPart bp2 = new MimeBodyPart(); 444 File attachFile = new File(fileName); 445 FileDataSource ds = new FileDataSource(attachFile); 446 DataHandler dh = new DataHandler(ds); 447 bp2.setDataHandler(dh); 448 bp2.addHeader("Content-Type", mimeType); 449 bp2.addHeader("Content-ID", "payload2"); 450 mp.addBodyPart(bp2); 451 452 SecurityUtil secUtil = SecurityUtil.getInstance(); 453 ByteArrayOutputStream payloadSigStream = new ByteArrayOutputStream(); 454 455 secUtil.signPayload(mp, id, payloadSigStream, 456 privateKey, (X509Certificate)certs[0], signingAlgo); 457 458 /* add the payload signature to the MimeMultipart. But the signature 459 is added at the first BodyPart and the payload is added to the second*/ 460 mp.removeBodyPart(0); 461 MimeBodyPart bp1 = new MimeBodyPart(); 462 bp1.setContent(new String(payloadSigStream.toByteArray()), "text/plain"); 463 bp1.addHeader("Content-ID", "payload1"); 464 mp.addBodyPart(bp1); 465 mp.addBodyPart(bp2); 466 attachmentMap.put(id, mp); 467 } 468 469 public SOAPMessage send() throws RegistryException, ServletException, SOAPException, IOException, ParseException, 470 MessagingException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException, 471 ParserConfigurationException, SAXException, XMLSecurityException { 472 msg = createSOAPMessage(alias, reqFileName); 473 474 Iterator attachIter = attachments.iterator(); 475 while (attachIter.hasNext()) { 476 AttachmentInfo ai = (AttachmentInfo)attachIter.next(); 477 addAttachment(ai.id, ai.fileName, ai.mimeType); 478 } 479 480 Iterator iter = attachmentMap.keySet().iterator(); 481 while (iter.hasNext()) { 482 String id = (String)iter.next(); 483 MimeMultipart mp = (MimeMultipart)attachmentMap.get(id); 484 485 486 AttachmentPart ap = msg.createAttachmentPart(mp, "multipart/related"); 487 ap.setContentId(id); 488 489 //Get existing boundary from mp and use it for ap 490 ContentType contentTypeMP = new ContentType(mp.getContentType()); 491 492 493 String boundary = contentTypeMP.getParameter("boundary"); 494 ContentType contentType = new ContentType("multipart/related"); 495 contentType.setParameter("boundary", boundary); 496 //contentType.setParameter("type", "text/xml"); 497 String contentTypeStr = contentType.toString(); 498 499 if (debug) { 500 System.err.println("payloads contentTypeStr = '" + contentTypeStr + "'"); 501 } 502 503 ap.setContentType(contentTypeStr); 504 505 msg.addAttachmentPart(ap); 506 } 507 508 return sendSOAPMessage(msg, this.registryURL); 509 } 510 511 512 private static SOAPMessage sendSOAPMessage(SOAPMessage msg, String url) 513 throws ServletException, SOAPException, MessagingException, 514 RegistryException, IOException { 515 516 if (url == null) { 517 throw new RegistryException("Destination URL for SOAP message not set."); 518 } 519 520 //Send the SOAPMesssage 521 SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance(); 522 SOAPConnection connection = scf.createConnection(); 523 URLEndpoint endPoint = new URLEndpoint(url); 524 525 //System.err.println("Sending folowing SOAP request:\n"); 526 527 FileOutputStream os = new FileOutputStream("senderReq.mime"); 528 msg.writeTo(os); 529 os.close(); 530 531 long t1 = System.currentTimeMillis(); 532 533 SOAPMessage reply = null; 534 if (localCall) { 535 RegistryJAXMServlet servlet = new RegistryJAXMServlet(); 536 servlet.init(); 537 reply = servlet.onMessage(msg); 538 } 539 else { 540 reply = connection.call(msg, endPoint); 541 } 542 543 long t2 = System.currentTimeMillis(); 544 545 if (reply != null) { 546 processReplyAttachments(reply); 547 reply.writeTo(System.err); 548 } 549 550 System.err.println("Elapsed time in seconds: " + (t2-t1)/1000); 551 552 return reply; 553 } 554 555 556 private static void processReplyAttachments(SOAPMessage reply) 557 throws SOAPException, MessagingException, RegistryException 558 { 559 560 Iterator apIter = reply.getAttachments(); 561 while(apIter.hasNext()) { 562 AttachmentPart ap = (AttachmentPart)apIter.next(); 563 564 String id = ap.getContentId(); 565 System.err.println("Processing repository item with contentId: '" + id + "'"); 566 567 Object obj = ap.getContent(); 568 569 if(!(obj instanceof javax.mail.internet.MimeMultipart)) { 570 throw new RegistryException("Expected javax.mail.internet.MimeMultipart got " + obj.getClass().getName()); 571 } 572 573 //The Multipart should have two BodyParts. First is the signature, second is the payload 574 MimeMultipart mp = (MimeMultipart)obj; 575 576 if(mp.getCount() != 2) { 577 throw new RegistryException("Found " + mp.getCount() + " BodyParts. A Multipart for a RepositoryItem must have exactly 2 BodyParts. First is the signature, second is the repository item."); 578 } 579 580 System.out.println("Verifying payload signature for repository item: '" + id + "'"); 581 SecurityUtil.getInstance().verifyPayloadSignature(id, mp); 582 583 BodyPart bp1 = mp.getBodyPart(0); //The XMLSignature 584 BodyPart bp2 = mp.getBodyPart(1); //The repository item 585 DataHandler dh = bp2.getDataHandler(); 586 String contentType = dh.getContentType(); 587 System.out.println("contentType = " + contentType); 588 589 Object o; 590 try { 591 o = dh.getContent(); 592 } catch(IOException ioe) { 593 o = ioe; 594 } 595 596 System.out.println("DataHandler, name=" + dh.getName() 597 + ", type=" + contentType 598 + ", content: (" + o.getClass().getName() 599 + ")\n" + o); 600 601 DataSource ds = dh.getDataSource(); 602 603 try { 604 String extension = ".out"; 605 int slashIndex = contentType.indexOf("/"); 606 int contentTypeLen = contentType.length(); 607 608 if(slashIndex >= 0 && 609 contentTypeLen > slashIndex + 1) { 610 extension = contentType.substring(slashIndex + 1, contentTypeLen); 611 } 612 613 //write attachment to file 614 //with appropriate ending. 615 InputStream inputStream = ds.getInputStream(); 616 FileOutputStream attachFileOs = 617 new FileOutputStream("attachFile-" + 618 Utility.getInstance().stripId(id) + "." + extension); 619 OutputStream attachOs = 620 new BufferedOutputStream(attachFileOs); 621 622 ByteArrayOutputStream byteArrayOs = 623 new ByteArrayOutputStream(); 624 byte buf[] = new byte[4096]; 625 int len; 626 while (true){ 627 len = inputStream.read(buf); 628 if (len < 0) 629 break; 630 byteArrayOs.write(buf, 0, len); 631 } 632 byte[] data = byteArrayOs.toByteArray(); 633 attachOs.write(data); 634 attachOs.flush(); 635 attachOs.close(); 636 637 } catch(Exception e) { 638 String errmsg = "[SOAPSender::processReplyAttachments()] -->" + 639 " Exception writing attachment to file ..." + e; 640 System.err.println(errmsg); 641 throw new RegistryException(errmsg); 642 } 643 } 644 645 /* 646 If we do not remove the attachment, the SOAPMessage.writeTo() mehtod 647 will output a MIME-encoded form of the message, not pure SOAP part. 648 */ 649 if(reply.countAttachments() > 0) { 650 reply.removeAllAttachments(); 651 if(reply.saveRequired()) { 652 reply.saveChanges(); 653 } 654 } 655 656 } 657 658 659 660 661 }

This page was automatically generated by Maven