001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2007 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: SecureSOAPMessage.java,v 1.30 2010/01/23 00:20:27 mrudul_uchil Exp $ 026 * 027 */ 028 029package com.sun.identity.wss.security.handler; 030 031import java.io.ByteArrayInputStream; 032import java.io.ByteArrayOutputStream; 033import java.util.List; 034import java.util.ArrayList; 035import java.util.ResourceBundle; 036import java.util.Date; 037import java.util.Map; 038import java.util.HashMap; 039import java.util.logging.Level; 040 041import org.w3c.dom.Element; 042import org.w3c.dom.Document; 043import org.w3c.dom.Node; 044import org.w3c.dom.NodeList; 045 046import javax.xml.soap.SOAPMessage; 047import javax.xml.soap.SOAPElement; 048import javax.xml.soap.SOAPException; 049import javax.xml.soap.SOAPHeader; 050import javax.xml.soap.SOAPBody; 051import javax.xml.soap.SOAPEnvelope; 052import javax.xml.soap.SOAPPart; 053 054import com.sun.identity.wss.security.WSSConstants; 055import com.sun.identity.wss.security.WSSUtils; 056import com.sun.identity.wss.security.SecurityMechanism; 057import com.sun.identity.wss.security.SecurityException; 058import com.sun.identity.wss.security.SecurityToken; 059import com.sun.identity.wss.security.AssertionToken; 060import com.sun.identity.wss.security.SecurityPrincipal; 061import com.sun.identity.wss.security.BinarySecurityToken; 062import com.sun.identity.wss.security.UserNameToken; 063import com.sun.identity.wss.security.SAML2Token; 064import com.sun.identity.wss.security.SAML2TokenUtils; 065import com.sun.identity.wss.logging.LogUtil; 066 067import com.sun.identity.shared.DateUtils; 068import com.sun.identity.saml.common.SAMLConstants; 069import com.sun.identity.saml.common.SAMLException; 070import com.sun.identity.saml.common.SAMLUtils; 071import com.sun.identity.saml.xmlsig.XMLSignatureException; 072import com.sun.identity.saml.xmlsig.XMLSignatureManager; 073import com.sun.identity.saml.xmlsig.KeyProvider; 074import com.sun.identity.saml2.common.SAML2Constants; 075import com.sun.identity.saml2.common.SAML2Exception; 076 077import javax.security.auth.Subject; 078import java.security.Principal; 079import java.security.Key; 080import java.security.cert.X509Certificate; 081import java.security.cert.Certificate; 082import java.security.PublicKey; 083import com.sun.identity.shared.xml.XMLUtils; 084import com.sun.identity.common.SystemConfigurationUtil; 085import com.sun.identity.shared.debug.Debug; 086import com.sun.identity.shared.Constants; 087 088import com.sun.identity.xmlenc.XMLEncryptionManager; 089import com.sun.identity.xmlenc.EncryptionConstants; 090import com.sun.identity.xmlenc.EncryptionException; 091import com.sun.identity.shared.DateUtils; 092import java.text.ParseException; 093 094 095/** 096 * This class <code>SecureSOAPMessage</code> constructs the secured 097 * <code>SOAPMessage</code> for the given security mechanism token. 098 * @supported.all.api 099 */ 100public class SecureSOAPMessage { 101 102 private SOAPMessage soapMessage = null; 103 private SecurityToken securityToken = null; 104 private SecurityMechanism securityMechanism = null; 105 private boolean create = false; 106 private Element wsseHeader = null; 107 private X509Certificate messageCertificate = null; 108 private static Debug debug = WSSUtils.debug; 109 private static ResourceBundle bundle = WSSUtils.bundle; 110 111 private String server_proto = 112 SystemConfigurationUtil.getProperty(Constants.AM_SERVER_PROTOCOL); 113 private String server_host = 114 SystemConfigurationUtil.getProperty(Constants.AM_SERVER_HOST); 115 private String server_port = 116 SystemConfigurationUtil.getProperty(Constants.AM_SERVER_PORT); 117 private List signingIds = new ArrayList(); 118 private String messageID = null; 119 private long msgTimestamp = 0; 120 private SecurityContext securityContext = null; 121 private String clientDnsClaim = null; 122 private List signedElements = new ArrayList(); 123 124 /** 125 * Constructor to create secure SOAP message. 126 * 127 * @param soapMessage the SOAP message to be secured. 128 * 129 * @param create if true, creates a new secured SOAP message by adding 130 * security headers. 131 * if false, parses the secured SOAP message. 132 * 133 * @exception SecurityException if failed in creating or parsing the 134 * new secured SOAP message. 135 */ 136 public SecureSOAPMessage(SOAPMessage soapMessage, boolean create) 137 throws SecurityException { 138 this(soapMessage, create, new ArrayList()); 139 } 140 141 /** 142 * Constructor to create secure SOAP message. 143 * 144 * @param soapMessage the SOAP message to be secured. 145 * 146 * @param create if true, creates a new secured SOAP message by adding 147 * security headers. 148 * if false, parses the secured SOAP message. 149 * @param signedElements list of signed elements 150 * 151 * @exception SecurityException if failed in creating or parsing the 152 * new secured SOAP message. 153 */ 154 public SecureSOAPMessage(SOAPMessage soapMessage, boolean create, 155 List signedElements) throws SecurityException { 156 157 this.soapMessage = soapMessage; 158 this.create = create; 159 this.signedElements = signedElements; 160 161 if(debug.messageEnabled()) { 162 debug.message("SecureSOAPMessage.Input SOAP message : " + 163 WSSUtils.print(soapMessage.getSOAPPart())); 164 } 165 166 if(!create) { 167 parseSOAPMessage(soapMessage); 168 } else { 169 ((Node) soapMessage.getSOAPPart()).normalize(); 170 171 if(debug.messageEnabled()) { 172 debug.message("SecureSOAPMessage.Input SOAP message After " + 173 "normalization: "+ WSSUtils.print(soapMessage.getSOAPPart())); 174 } 175 addNameSpaces(); 176 addSecurityHeader(); 177 178 } 179 180 if (debug.messageEnabled()) { 181 debug.message("SecureSOAPMessage.Output SOAP message: " + WSSUtils.print(soapMessage.getSOAPPart())); 182 } 183 } 184 185 /** 186 * Returns the Security Header Element. 187 * 188 * @return the Security Header Element. 189 */ 190 public Element getSecurityHeaderElement() { 191 return this.wsseHeader; 192 } 193 194 /** 195 * Returns the secured SOAP message. 196 * 197 * @return the secured SOAP message. 198 */ 199 public SOAPMessage getSOAPMessage() { 200 return this.soapMessage; 201 } 202 203 /** 204 * Sets the secured SOAP message. 205 * 206 * @param inSoapMessage the input secured SOAP message. 207 */ 208 public void setSOAPMessage(SOAPMessage inSoapMessage) { 209 this.soapMessage = inSoapMessage; 210 } 211 212 /** 213 * Parses the secured SOAP message. 214 * @param soapMessage the secured SOAP message which needs to be parsed. 215 * 216 * @exception SecurityException if there is any failure in parsing. 217 */ 218 private void parseSOAPMessage(SOAPMessage soapMessage) 219 throws SecurityException { 220 try { 221 SOAPHeader header = 222 soapMessage.getSOAPPart().getEnvelope().getHeader(); 223 if(header == null) { 224 if(debug.messageEnabled()) { 225 debug.message("SecureSOAPMessage.parseSOAPMessage: " + 226 "No SOAP header found."); 227 } 228 } 229 NodeList headerChildNodes = header.getChildNodes(); 230 if((headerChildNodes == null) || 231 (headerChildNodes.getLength() == 0)) { 232 if(debug.messageEnabled()) { 233 debug.message("SecureSOAPMessage.parseSOAPMessage: " + 234 "No security header found."); 235 } 236 } 237 for(int i=0; i < headerChildNodes.getLength(); i++) { 238 239 Node currentNode = headerChildNodes.item(i); 240 if(currentNode.getNodeType() != Node.ELEMENT_NODE) { 241 continue; 242 } 243 244 String nodeName = currentNode.getLocalName(); 245 String nodeNS = currentNode.getNamespaceURI(); 246 247 if((WSSConstants.WSSE_SECURITY_LNAME.equals(nodeName)) && 248 (WSSConstants.WSSE_NS.equals(nodeNS))) { 249 wsseHeader = (Element) currentNode; 250 } 251 252 if((WSSConstants.wsaMessageID.equals(nodeName)) && 253 (WSSConstants.wsaNS.equals(nodeNS))) { 254 messageID = XMLUtils.getElementValue((Element)currentNode); 255 } 256 257 if(("From".equals(nodeName)) && 258 (WSSConstants.wsaNS.equals(nodeNS))) { 259 Element fromElement = (Element)currentNode; 260 NodeList nodeList = 261 fromElement.getElementsByTagNameNS( 262 WSSConstants.WSID_NS, WSSConstants.DNS_CLAIM); 263 if(nodeList == null || nodeList.getLength() == 0) { 264 continue; 265 } 266 clientDnsClaim = XMLUtils.getElementValue( 267 (Element)nodeList.item(0)); 268 } 269 } 270 } catch (SOAPException se) { 271 debug.error("SecureSOAPMessage.parseSOAPMessage: SOAP" + 272 "Exception in parsing the headers.", se); 273 String[] data = {se.getLocalizedMessage()}; 274 LogUtil.error(Level.INFO, 275 LogUtil.ERROR_PARSING_SOAP_HEADERS, 276 data, 277 null); 278 throw new SecurityException(se.getMessage()); 279 } 280 } 281 282 /** 283 * Parses for the security header. 284 * @param node security header node. 285 * 286 * @exception SecurityException if there is any error occured. 287 */ 288 public void parseSecurityHeader(Node node) throws SecurityException { 289 securityMechanism = SecurityMechanism.WSS_NULL_ANONYMOUS; 290 if (node != null) { 291 NodeList securityHeaders = node.getChildNodes(); 292 for(int i=0; i < securityHeaders.getLength(); i++) { 293 Node currentNode = securityHeaders.item(i); 294 if(currentNode.getNodeType() != Node.ELEMENT_NODE) { 295 continue; 296 } 297 String localName = currentNode.getLocalName(); 298 String nameSpace = currentNode.getNamespaceURI(); 299 300 if( (SAMLConstants.TAG_ASSERTION.equals(localName)) && 301 (SAMLConstants.assertionSAMLNameSpaceURI.equals( 302 nameSpace)) ) { 303 304 if(debug.messageEnabled()) { 305 debug.message("SecureSOAPMessage.parseSecurityHeader:: " 306 + "Assertion token found in the security header."); 307 } 308 try { 309 securityToken = 310 new AssertionToken((Element)currentNode); 311 AssertionToken assertionToken = 312 (AssertionToken)securityToken; 313 if(assertionToken.isSenderVouches()) { 314 securityMechanism = 315 SecurityMechanism.WSS_NULL_SAML_SV; 316 } else { 317 securityMechanism = 318 SecurityMechanism.WSS_NULL_SAML_HK; 319 } 320 messageCertificate = 321 WSSUtils.getCertificate(assertionToken); 322 } catch (SAMLException se) { 323 debug.error("SecureSOAPMessage.parseSecurity" + 324 "Header: unable to parse the token", se); 325 throw new SecurityException(se.getMessage()); 326 } 327 328 } else if( (SAMLConstants.TAG_ASSERTION.equals(localName)) && 329 (SAML2Constants.ASSERTION_NAMESPACE_URI.equals( 330 nameSpace)) ) { 331 332 if(debug.messageEnabled()) { 333 debug.message("SecureSOAPMessage.parseSecurityHeader:: " 334 + "SAML2 token found in the security header."); 335 } 336 try { 337 securityToken = new SAML2Token((Element)currentNode); 338 SAML2Token saml2Token = (SAML2Token)securityToken; 339 if(saml2Token.isSenderVouches()) { 340 securityMechanism = 341 SecurityMechanism.WSS_NULL_SAML2_SV; 342 } else { 343 securityMechanism = 344 SecurityMechanism.WSS_NULL_SAML2_HK; 345 } 346 messageCertificate = 347 SAML2TokenUtils.getCertificate(saml2Token); 348 } catch (SAML2Exception se) { 349 debug.error("SecureSOAPMessage.parseSecurity" + 350 "Header: unable to parse the token", se); 351 throw new SecurityException(se.getMessage()); 352 } 353 354 } else if( (WSSConstants.TAG_BINARY_SECURITY_TOKEN. 355 equals(localName)) && 356 (WSSConstants.WSSE_NS.equals(nameSpace)) ) { 357 358 if(debug.messageEnabled()) { 359 debug.message("SecureSOAPMessage.parseSecurityHeader:: " 360 + "binary token found in the security header."); 361 } 362 securityToken = 363 new BinarySecurityToken((Element)currentNode); 364 if(securityToken.getTokenType().equals( 365 securityToken.WSS_KERBEROS_TOKEN)) { 366 securityMechanism = 367 SecurityMechanism.WSS_NULL_KERBEROS_TOKEN; 368 } else { 369 securityMechanism = 370 SecurityMechanism.WSS_NULL_X509_TOKEN; 371 messageCertificate = 372 WSSUtils.getCertificate(securityToken); 373 } 374 375 } else if( (WSSConstants.TAG_USERNAME_TOKEN.equals(localName)) && 376 (WSSConstants.WSSE_NS.equals(nameSpace)) ) { 377 378 if(debug.messageEnabled()) { 379 debug.message("SecureSOAPMessage.parseSecurityHeader:: " 380 + "username token found in the security header."); 381 } 382 securityToken = new UserNameToken((Element)currentNode); 383 UserNameToken usernameToken = (UserNameToken)securityToken; 384 String passwordType = usernameToken.getPasswordType(); 385 if (passwordType != null) { 386 if (passwordType.equals( 387 WSSConstants.PASSWORD_DIGEST_TYPE)) { 388 securityMechanism = 389 SecurityMechanism.WSS_NULL_USERNAME_TOKEN; 390 } else if 391 (passwordType.equals( 392 WSSConstants.PASSWORD_PLAIN_TYPE)) { 393 securityMechanism = 394 SecurityMechanism.WSS_NULL_USERNAME_TOKEN_PLAIN; 395 } 396 } 397 398 } else if((SAMLConstants.XMLSIG_ELEMENT_NAME.equals(localName)) 399 && (SAMLConstants.XMLSIG_NAMESPACE_URI.equals(nameSpace))){ 400 if(securityToken != null) { 401 continue; 402 } 403 messageCertificate = 404 WSSUtils.getMessageCertificate((Element)node); 405 if(messageCertificate != null) { 406 securityMechanism = 407 SecurityMechanism.WSS_NULL_X509_TOKEN; 408 } 409 } else if((WSSConstants.TIME_STAMP.equals(localName)) || 410 (WSSConstants.WSSE_NS.equals(nameSpace))) { 411 if(!validateTimestamp((Element)currentNode)) { 412 throw new SecurityException( 413 bundle.getString("invalidTimestamp")); 414 } 415 } else { 416 if(debug.messageEnabled()) { 417 debug.message("SecureSOAPMessage.parseSecurityHeader: " 418 + "ignore header element, " + localName); 419 } 420 } 421 } 422 } 423 } 424 425 /** 426 * Returns the security mechanism of the secure soap message. 427 * 428 * @return SecurityMechanism the security mechanism of the secure 429 * <code>SOAPMessage</code>. 430 */ 431 public SecurityMechanism getSecurityMechanism() { 432 return securityMechanism; 433 } 434 435 /** 436 * Sets the security mechanism for securing the soap message. 437 * 438 * @param securityMechanism the security mechanism that will be used 439 * to secure the soap message. 440 */ 441 public void setSecurityMechanism(SecurityMechanism securityMechanism) { 442 this.securityMechanism = securityMechanism; 443 } 444 445 /** 446 * Sets the security token for securing the soap message. 447 * 448 * @param token the security token that is used to secure the soap message. 449 * 450 * @exception SecurityException if the security token can not be added 451 * to the security header. 452 */ 453 public void setSecurityToken(SecurityToken token) 454 throws SecurityException { 455 456 if(wsseHeader == null) { 457 debug.error("SecureSOAPMessage.setSecurityToken:: WSSE security" + 458 " Header is not found in the Secure SOAP Message."); 459 throw new SecurityException( 460 bundle.getString("securityHeaderNotFound")); 461 } 462 this.securityToken = token; 463 String tokenType = securityToken.getTokenType(); 464 if(SecurityToken.WSS_USERNAME_TOKEN.equals(tokenType)) { 465 UserNameToken userNameToken = (UserNameToken)securityToken; 466 if(signedElements.contains(WSSConstants.SECURITY_TOKEN)) { 467 signingIds.add(userNameToken.getSigningId()); 468 } 469 } else if(SecurityToken.WSS_X509_TOKEN.equals(tokenType)) { 470 BinarySecurityToken binaryToken = 471 (BinarySecurityToken)securityToken; 472 if(signedElements.contains(WSSConstants.SECURITY_TOKEN)) { 473 signingIds.add(binaryToken.getSigningId()); 474 } 475 } 476 Element tokenE = token.toDocumentElement(); 477 Node tokenNode = soapMessage.getSOAPPart().importNode(tokenE, true); 478 WSSUtils.prependChildElement(wsseHeader, (Element)tokenNode, true, 479 (Document)soapMessage.getSOAPPart()); 480 try { 481 soapMessage.saveChanges(); 482 } catch (SOAPException se) { 483 debug.error("SecureSOAPMessage.setSecurityToken: " + 484 "SOAPException" , se); 485 throw new SecurityException(se.getMessage()); 486 } 487 } 488 489 /** 490 * Returns the security token associated with this secure soap message. 491 * 492 * @return SecurityToken the security token for this secure soap message. 493 */ 494 public SecurityToken getSecurityToken() { 495 return securityToken; 496 } 497 498 public SecurityContext getSecurityContext() { 499 return securityContext; 500 } 501 502 public void setSecurityContext(SecurityContext securityContext) { 503 this.securityContext = securityContext; 504 } 505 506 /** 507 * Adds the WSSE related name spaces to the SOAP Envelope. 508 */ 509 private void addNameSpaces() throws SecurityException { 510 try { 511 SOAPEnvelope envelope = soapMessage.getSOAPPart().getEnvelope(); 512 envelope.setAttributeNS(WSSConstants.NS_XML, 513 WSSConstants.TAG_XML_WSU, 514 WSSConstants.WSU_NS); 515 516 SOAPBody body = envelope.getBody(); 517 body.setAttributeNS(WSSConstants.NS_XML, 518 WSSConstants.TAG_XML_WSU, 519 WSSConstants.WSU_NS); 520 body.setAttribute(WSSConstants.WSU_ID, SAMLUtils.generateID()); 521 522 } catch (SOAPException se) { 523 debug.error("SecureSOAPMessage.addNameSpaces:: Could not add " + 524 "Name spaces. ", se); 525 throw new SecurityException( 526 bundle.getString("nameSpaceAdditionfailure")); 527 } 528 } 529 530 /** 531 * Adds the security header to the SOAP Envelope. 532 */ 533 private void addSecurityHeader() throws SecurityException { 534 535 if(debug.messageEnabled()) { 536 debug.message("SecureSOAPMessage.addSecurityHeader:: preparing the"+ 537 " security header"); 538 } 539 try { 540 SOAPPart soapPart = soapMessage.getSOAPPart(); 541 SOAPEnvelope envelope = soapMessage.getSOAPPart().getEnvelope(); 542 SOAPHeader header = envelope.getHeader(); 543 if(header == null) { 544 header = envelope.addHeader(); 545 } 546 checkForAddressingHeaders(); 547 548 wsseHeader = soapPart.createElementNS( 549 WSSConstants.WSSE_NS, 550 WSSConstants.WSSE_TAG + ":" + 551 WSSConstants.WSSE_SECURITY_LNAME); 552 wsseHeader.setAttributeNS( 553 WSSConstants.NS_XML, 554 WSSConstants.TAG_XML_WSSE, 555 WSSConstants.WSSE_NS); 556 wsseHeader.setAttributeNS(WSSConstants.NS_XML, 557 WSSConstants.TAG_XML_WSU, 558 WSSConstants.WSU_NS); 559 wsseHeader.setAttributeNS( 560 WSSConstants.NS_XML, 561 WSSConstants.TAG_XML_WSSE11, 562 WSSConstants.WSSE11_NS); 563 564 String envPrefix = envelope.getPrefix(); 565 if(envPrefix != null) { 566 wsseHeader.setAttribute(envPrefix + ":" + 567 WSSConstants.MUST_UNDERSTAND, "1"); 568 } 569 570 //Add time stamp 571 Element timeStamp = soapPart.createElementNS( 572 WSSConstants.WSU_NS, 573 WSSConstants.WSU_TAG + ":" + 574 WSSConstants.TIME_STAMP); 575 String tsId = SAMLUtils.generateID(); 576 if(signedElements.contains(WSSConstants.TIME_STAMP)) { 577 if(signingIds != null) { 578 signingIds.add(tsId); 579 } 580 } 581 timeStamp.setAttribute(WSSConstants.WSU_ID, tsId); 582 wsseHeader.appendChild(timeStamp); 583 Element created = soapPart.createElementNS( 584 WSSConstants.WSU_NS, 585 WSSConstants.WSU_TAG + ":" + WSSConstants.CREATED); 586 587 Date createTime = new Date(); 588 Date expireTime = new Date(); 589 expireTime.setTime(createTime.getTime() + 590 WSSConstants.INTERVAL * 1000); 591 592 created.appendChild(soapPart.createTextNode( 593 DateUtils.toUTCDateFormat(createTime))); 594 timeStamp.appendChild(created); 595 596 Element expires = soapPart.createElementNS( 597 WSSConstants.WSU_NS, 598 WSSConstants.WSU_TAG + ":" + WSSConstants.EXPIRES); 599 expires.appendChild(soapPart.createTextNode( 600 DateUtils.toUTCDateFormat(expireTime))); 601 timeStamp.appendChild(expires); 602 header.appendChild(wsseHeader); 603 604 } catch (SOAPException se) { 605 debug.error("SecureSOAPMessage.addSecurityHeader:: SOAPException"+ 606 " while adding the security header.", se); 607 String[] data = {se.getLocalizedMessage()}; 608 LogUtil.error(Level.INFO, 609 LogUtil.ERROR_ADDING_SECURITY_HEADER, 610 data, 611 null); 612 throw new SecurityException( 613 bundle.getString("addSecurityHeaderFailed")); 614 } 615 } 616 617 private void checkForAddressingHeaders() throws SecurityException { 618 try { 619 SOAPHeader header = soapMessage.getSOAPHeader(); 620 java.util.Iterator childElements = header.getChildElements(); 621 while(childElements.hasNext()) { 622 Element childElement = (Element)childElements.next(); 623 String localName = childElement.getLocalName(); 624 String nameSpace = childElement.getNamespaceURI(); 625 if(WSSConstants.wsaNS.equals(nameSpace) 626 &&( localName.equals("To") || 627 localName.equals("From") || 628 localName.equals("MessageID") || 629 localName.equals("Action"))) { 630 childElement.setAttributeNS(WSSConstants.NS_XML, 631 WSSConstants.TAG_XML_WSU, 632 WSSConstants.WSU_NS); 633 String id = SAMLUtils.generateID(); 634 childElement.setAttribute(WSSConstants.WSU_ID, id); 635 if(signedElements.contains(localName)) { 636 signingIds.add(id); 637 } 638 } 639 640 } 641 642 } catch (SOAPException se) { 643 debug.error("SecureSOAPMessage.addNameSpaces:: Could not add " + 644 "Name spaces. ", se); 645 throw new SecurityException( 646 bundle.getString("nameSpaceAdditionfailure")); 647 } 648 } 649 650 /** 651 * Signs the <code>SOAPMessage</code> for the given security profile. 652 * 653 * @exception SecurityException if there is any failure in signing. 654 */ 655 public void sign() 656 throws SecurityException { 657 658 if(debug.messageEnabled()) { 659 debug.message("SecureSOAPMessage.sign:: Before Signing : "+ 660 WSSUtils.print(soapMessage.getSOAPPart())); 661 } 662 663 Document doc = toDocument(); 664 String tokenType = null; 665 // securityToken=null if the secmech is Anonymous 666 if (securityToken!=null) { 667 tokenType = securityToken.getTokenType(); 668 } else { 669 if((securityMechanism != null) && 670 (securityMechanism.getURI().equals( 671 SecurityMechanism.WSS_NULL_X509_TOKEN_URI))) { 672 tokenType = SecurityToken.WSS_X509_TOKEN; 673 } 674 675 } 676 677 if(SecurityToken.WSS_SAML_TOKEN.equals(tokenType) || 678 SecurityToken.WSS_SAML2_TOKEN.equals(tokenType)) { 679 signWithAssertion(doc); 680 } else if(SecurityToken.WSS_X509_TOKEN.equals(tokenType)) { 681 signWithBinaryToken(doc, securityContext.getSigningCertAlias(), 682 securityContext.getSigningRef()); 683 // treat Anonymous secmech (securityToken=null) same as UserName 684 // Token 685 } else if ((SecurityToken.WSS_USERNAME_TOKEN.equals(tokenType)) || 686 (null==securityToken)){ 687 signWithUNToken(doc, securityContext.getSigningCertAlias()); 688 } else if ((SecurityToken.WSS_KERBEROS_TOKEN.equals(tokenType))) { 689 signWithKerberosToken(doc); 690 } else { 691 debug.error("SecureSOAPMessage.sign:: Invalid token type for" + 692 " XML signing."); 693 } 694 695 if(debug.messageEnabled()) { 696 debug.message("SecureSOAPMessage.sign:: After Signing : "+ 697 WSSUtils.print(soapMessage.getSOAPPart())); 698 } 699 } 700 701 /** 702 * Signs the SOAP Message with SAML Assertion. 703 */ 704 private void signWithAssertion(Document doc) throws SecurityException { 705 706 XMLSignatureManager sigManager = WSSUtils.getXMLSignatureManager(); 707 KeyProvider keyProvider = sigManager.getKeyProvider(); 708 Certificate cert = null; 709 String uri = securityMechanism.getURI(); 710 711 boolean symmetricKey = SecurityContext.SYMMETRIC_KEY.equals( 712 securityContext.getKeyType()) ? true : false; 713 714 if( (SecurityMechanism.WSS_NULL_SAML_HK_URI.equals(uri)) || 715 (SecurityMechanism.WSS_TLS_SAML_HK_URI.equals(uri)) || 716 (SecurityMechanism.WSS_CLIENT_TLS_SAML_HK_URI.equals(uri))) { 717 if(!symmetricKey) { 718 cert = WSSUtils.getCertificate(securityToken); 719 } 720 721 } else if( (SecurityMechanism.WSS_NULL_SAML2_HK_URI.equals(uri)) || 722 (SecurityMechanism.WSS_TLS_SAML2_HK_URI.equals(uri)) || 723 (SecurityMechanism.WSS_CLIENT_TLS_SAML2_HK_URI.equals(uri))) { 724 if(!symmetricKey) { 725 cert = SAML2TokenUtils.getCertificate(securityToken); 726 } 727 728 } else if( (SecurityMechanism.WSS_NULL_SAML_SV_URI.equals(uri)) || 729 (SecurityMechanism.WSS_TLS_SAML_SV_URI.equals(uri)) || 730 (SecurityMechanism.WSS_CLIENT_TLS_SAML_SV_URI.equals(uri)) || 731 (SecurityMechanism.WSS_NULL_SAML2_SV_URI.equals(uri)) || 732 (SecurityMechanism.WSS_TLS_SAML2_SV_URI.equals(uri)) || 733 (SecurityMechanism.WSS_CLIENT_TLS_SAML2_SV_URI.equals(uri))) { 734 cert = keyProvider.getX509Certificate( 735 securityContext.getSigningCertAlias()); 736 737 } else if (SecurityMechanism.STS_SECURITY_URI.equals(uri)) { 738 if(SecurityToken.WSS_SAML_TOKEN.equals( 739 securityToken.getTokenType())) { 740 if(!symmetricKey) { 741 cert = WSSUtils.getCertificate(securityToken); 742 } 743 } else if(SecurityToken.WSS_SAML2_TOKEN.equals( 744 securityToken.getTokenType())) { 745 if(!symmetricKey) { 746 cert = SAML2TokenUtils.getCertificate(securityToken); 747 } 748 } 749 if (cert == null) { 750 cert = keyProvider.getX509Certificate( 751 securityContext.getSigningCertAlias()); 752 } 753 754 } else { 755 debug.error("SecureSOAPMessage.signWithSAMLAssertion:: " + 756 "Unknown security mechanism"); 757 throw new SecurityException( 758 bundle.getString("unknownSecurityMechanism")); 759 } 760 761 Element sigElement = null; 762 try { 763 String assertionID = null; 764 if(securityToken instanceof AssertionToken) { 765 AssertionToken assertionToken = (AssertionToken)securityToken; 766 assertionID = assertionToken.getAssertion().getAssertionID(); 767 } else if (securityToken instanceof SAML2Token) { 768 SAML2Token saml2Token = (SAML2Token)securityToken; 769 assertionID = saml2Token.getAssertion().getID(); 770 } 771 Key signingKey = securityContext.getSigningKey(); 772 if(signingKey == null) { 773 if(cert != null) { 774 String signAlias = keyProvider.getCertificateAlias(cert); 775 signingKey = keyProvider.getPrivateKey(signAlias); 776 } 777 } 778 779 Key encryptionKey = securityContext.getEncryptionKey(); 780 Certificate encryptCert = null; 781 if(encryptionKey == null) { 782 String encryptAlias = securityContext.getEncryptionKeyAlias(); 783 encryptCert = keyProvider.getX509Certificate(encryptAlias); 784 } else { 785 encryptCert = keyProvider.getCertificate( 786 (PublicKey)encryptionKey); 787 } 788 789 sigElement = sigManager.signWithSAMLToken(doc, 790 signingKey, symmetricKey, cert, encryptCert, 791 assertionID, "", getSigningIds()); 792 793 794 } catch (XMLSignatureException se) { 795 debug.error("SecureSOAPMessage.signWithAssertion:: " + 796 "signing failed", se); 797 String[] data = {se.getLocalizedMessage()}; 798 LogUtil.error(Level.INFO, 799 LogUtil.UNABLE_TO_SIGN, 800 data, 801 null); 802 throw new SecurityException( 803 bundle.getString("unabletoSign")); 804 } catch (Exception ex) { 805 debug.error("SecureSOAPMessage.signWithAssertion:: " + 806 "signing failed", ex); 807 String[] data = {ex.getLocalizedMessage()}; 808 LogUtil.error(Level.INFO, 809 LogUtil.UNABLE_TO_SIGN, 810 data, 811 null); 812 throw new SecurityException( 813 bundle.getString("unabletoSign")); 814 } 815 wsseHeader.appendChild( 816 soapMessage.getSOAPPart().importNode(sigElement, true)); 817 try { 818 this.soapMessage.saveChanges(); 819 } catch (Exception ex) { 820 debug.error("SecureSOAPMessage.signWithAssertion:: " + 821 "SOAP message save failed : ", ex); 822 } 823 } 824 825 826 /** 827 * Signs the document with binary security token. 828 */ 829 private void signWithBinaryToken(Document doc, String certAlias, 830 String refType) throws SecurityException { 831 832 Certificate cert = null; 833 Element sigElement = null; 834 XMLSignatureManager sigManager = WSSUtils.getXMLSignatureManager(); 835 KeyProvider keyProvider = sigManager.getKeyProvider(); 836 try { 837 cert = keyProvider.getX509Certificate(certAlias); 838 sigElement = sigManager.signWithBinarySecurityToken( 839 doc, cert, "", getSigningIds(), refType); 840 } catch (XMLSignatureException se) { 841 debug.error("SecureSOAPMessage.signWithBinaryToken:: Signature " + 842 "Exception.", se); 843 String[] data = {se.getLocalizedMessage()}; 844 LogUtil.error(Level.INFO, 845 LogUtil.UNABLE_TO_SIGN, 846 data, 847 null); 848 throw new SecurityException( 849 bundle.getString("unabletoSign")); 850 } catch (Exception ex) { 851 debug.error("SecureSOAPMessage.signWithBinaryToken:: " + 852 "signing failed", ex); 853 String[] data = {ex.getLocalizedMessage()}; 854 LogUtil.error(Level.INFO, 855 LogUtil.UNABLE_TO_SIGN, 856 data, 857 null); 858 throw new SecurityException( 859 bundle.getString("unabletoSign")); 860 } 861 wsseHeader.appendChild( 862 soapMessage.getSOAPPart().importNode(sigElement, true)); 863 try { 864 this.soapMessage.saveChanges(); 865 } catch (Exception ex) { 866 debug.error("SecureSOAPMessage.signWithBinaryToken:: " + 867 "SOAP message save failed : ", ex); 868 } 869 870 } 871 872 /** 873 * Signs the document with kerberos security token. 874 */ 875 private void signWithKerberosToken(Document doc) 876 throws SecurityException { 877 878 Element sigElement = null; 879 XMLSignatureManager sigManager = WSSUtils.getXMLSignatureManager(); 880 try { 881 BinarySecurityToken bst = (BinarySecurityToken)securityToken; 882 sigElement = sigManager.signWithKerberosToken( 883 doc, bst.getSecretKey(), SAMLConstants.ALGO_ID_MAC_HMAC_SHA1, 884 getSigningIds()); 885 } catch (XMLSignatureException se) { 886 debug.error("SecureSOAPMessage.signWithBinaryToken:: Signature " + 887 "Exception.", se); 888 String[] data = {se.getLocalizedMessage()}; 889 LogUtil.error(Level.INFO, 890 LogUtil.UNABLE_TO_SIGN, 891 data, 892 null); 893 throw new SecurityException( 894 bundle.getString("unabletoSign")); 895 } catch (Exception ex) { 896 debug.error("SecureSOAPMessage.signWithBinaryToken:: " + 897 "signing failed", ex); 898 String[] data = {ex.getLocalizedMessage()}; 899 LogUtil.error(Level.INFO, 900 LogUtil.UNABLE_TO_SIGN, 901 data, 902 null); 903 throw new SecurityException( 904 bundle.getString("unabletoSign")); 905 } 906 wsseHeader.appendChild( 907 soapMessage.getSOAPPart().importNode(sigElement, true)); 908 try { 909 this.soapMessage.saveChanges(); 910 } catch (Exception ex) { 911 debug.error("SecureSOAPMessage.signWithBinaryToken:: " + 912 "SOAP message save failed : ", ex); 913 } 914 } 915 916 /** 917 * Signs the document with binary security token. 918 */ 919 private void signWithUNToken(Document doc, String certAlias) 920 throws SecurityException { 921 922 Certificate cert = null; 923 Element sigElement = null; 924 XMLSignatureManager sigManager = WSSUtils.getXMLSignatureManager(); 925 KeyProvider keyProvider = sigManager.getKeyProvider(); 926 try { 927 cert = keyProvider.getX509Certificate(certAlias); 928 sigElement = sigManager.signWithUserNameToken( 929 doc, cert, "", getSigningIds()); 930 } catch (XMLSignatureException se) { 931 debug.error("SecureSOAPMessage.signWithUNToken:: Signature " + 932 "Exception.", se); 933 String[] data = {se.getLocalizedMessage()}; 934 LogUtil.error(Level.INFO, 935 LogUtil.UNABLE_TO_SIGN, 936 data, 937 null); 938 throw new SecurityException( 939 bundle.getString("unabletoSign")); 940 } catch (Exception ex) { 941 debug.error("SecureSOAPMessage.signWithUNToken:: " + 942 "signing failed", ex); 943 String[] data = {ex.getLocalizedMessage()}; 944 LogUtil.error(Level.INFO, 945 LogUtil.UNABLE_TO_SIGN, 946 data, 947 null); 948 throw new SecurityException( 949 bundle.getString("unabletoSign")); 950 } 951 wsseHeader.appendChild( 952 soapMessage.getSOAPPart().importNode(sigElement, true)); 953 try { 954 this.soapMessage.saveChanges(); 955 } catch (Exception ex) { 956 debug.error("SecureSOAPMessage.signWithUNToken:: " + 957 "SOAP message save failed : ", ex); 958 } 959 } 960 961 /** 962 * Returns the list of signing ids. 963 */ 964 private List getSigningIds() throws Exception { 965 if(signingIds == null) { 966 signingIds = new ArrayList(); 967 } 968 SOAPBody body = soapMessage.getSOAPBody(); 969 String id = body.getAttribute(WSSConstants.WSU_ID); 970 if(signedElements.isEmpty() || 971 signedElements.contains(WSSConstants.BODY_LNAME)) { 972 signingIds.add(id); 973 } 974 return signingIds; 975 } 976 977 /** 978 * Returns the messageID from the <wsa:Addressing> header. 979 * @return the messageID from the <wsa:Addressing> header. 980 */ 981 public String getMessageID() { 982 return messageID; 983 } 984 985 /** 986 * Retruns the message timestamp. 987 * @return the message timestamp. 988 */ 989 public long getMessageTimestamp() { 990 return msgTimestamp; 991 } 992 /** 993 * Verifies the signature of the SOAP message. 994 * @return true if the signature verification is successful. 995 * @exception SecurityException if there is any failure in validation. 996 */ 997 public boolean verifySignature() throws SecurityException { 998 999 try { 1000 Document doc = toDocument(); 1001 Key verificationKey = null; 1002 XMLSignatureManager sigManager = WSSUtils.getXMLSignatureManager(); 1003 String tokenType = null; 1004 if(securityToken != null) { 1005 tokenType = securityToken.getTokenType(); 1006 } else { 1007 tokenType = SecurityMechanism.WSS_NULL_ANONYMOUS_URI; 1008 } 1009 1010 if(tokenType.equals(SecurityToken.WSS_SAML2_TOKEN) || 1011 tokenType.equals(SecurityToken.WSS_SAML_TOKEN)) { 1012 1013 String issuer = null; 1014 if(tokenType.equals(SecurityToken.WSS_SAML2_TOKEN)) { 1015 SAML2Token saml2Token = (SAML2Token)securityToken; 1016 issuer = saml2Token.getAssertion().getIssuer().getValue(); 1017 } else if (tokenType.equals(SecurityToken.WSS_SAML_TOKEN)) { 1018 AssertionToken assertionToken = (AssertionToken)securityToken; 1019 issuer = assertionToken.getAssertion().getIssuer(); 1020 } 1021 String issuerAlias = WSSUtils.getCertAlias(issuer); 1022 if(issuerAlias == null) { 1023 WSSUtils.debug.message("SecureSOAPMessage.verifySignature: " 1024 + " issuer alias does not present in the trusted ca" + 1025 " alias list"); 1026 return false; 1027 } 1028 Element assertionE = securityToken.toDocumentElement(); 1029 Document document = XMLUtils.newDocument(); 1030 document.appendChild(document.importNode(assertionE, true)); 1031 if(WSSUtils.debug.messageEnabled()) { 1032 WSSUtils.debug.message("SecureSOAPMessage.verifySignature "+ 1033 " Assertion to be verified" + XMLUtils.print(assertionE)); 1034 } 1035 if(!sigManager.verifyXMLSignature(document, issuerAlias)){ 1036 if(WSSUtils.debug.messageEnabled()) { 1037 WSSUtils.debug.message("SecureSOAPMessage.verifySignature:" 1038 + " Signature verification for the assertion failed"); 1039 } 1040 return false; 1041 } else { 1042 if(WSSUtils.debug.messageEnabled()) { 1043 WSSUtils.debug.message("SecureSOAPMessage.verifySignature:" 1044 + "Signature verification successful for the assertion"); 1045 } 1046 } 1047 1048 } 1049 1050 if(messageCertificate != null) { 1051 String alias = sigManager.getKeyProvider(). 1052 getCertificateAlias(messageCertificate); 1053 verificationKey = sigManager.getKeyProvider().getPublicKey(alias); 1054 } else { 1055 // check if this symmetric encrypted key 1056 if(tokenType.equals(SecurityToken.WSS_SAML2_TOKEN)) { 1057 verificationKey = SAML2TokenUtils.getSecretKey(securityToken, 1058 securityContext.getDecryptionAlias()); 1059 } else if (tokenType.equals(SecurityToken.WSS_SAML_TOKEN)) { 1060 verificationKey = WSSUtils.getSecretKey(securityToken, 1061 securityContext.getDecryptionAlias()); 1062 } 1063 } 1064 1065 return sigManager.verifyWSSSignature(doc, verificationKey, 1066 securityContext.getVerificationCertAlias(), 1067 securityContext.getDecryptionAlias()); 1068 1069 } catch (SAMLException se) { 1070 debug.error("SecureSOAPMessage.verify:: Signature validation " + 1071 "failed", se); 1072 String[] data = {se.getLocalizedMessage()}; 1073 LogUtil.error(Level.INFO, 1074 LogUtil.SIGNATURE_VALIDATION_FAILED, 1075 data, 1076 null); 1077 throw new SecurityException( 1078 bundle.getString("signatureValidationFailed")); 1079 } catch (Exception ex) { 1080 debug.error("SecureSOAPMessage.verify:: Signature validation " + 1081 "failed", ex); 1082 throw new SecurityException( 1083 bundle.getString("signatureValidationFailed")); 1084 } 1085 } 1086 1087 /** 1088 * Verifies the signature of the SOAP message that has kerberos key. 1089 * @param secretKey the secret key that is used for signature verification. 1090 * @return true if the signature verification is successful. 1091 * @exception SecurityException if there is any failure in validation. 1092 */ 1093 public boolean verifyKerberosTokenSignature(java.security.Key secretKey) 1094 throws SecurityException { 1095 try { 1096 Document doc = toDocument(); 1097 XMLSignatureManager sigManager = WSSUtils.getXMLSignatureManager(); 1098 return sigManager.verifyWSSSignature(doc, secretKey); 1099 } catch (SAMLException se) { 1100 debug.error("SecureSOAPMessage.verify:: Signature validation " + 1101 "failed", se); 1102 throw new SecurityException( 1103 bundle.getString("signatureValidationFailed")); 1104 } 1105 } 1106 1107 /** 1108 * Converts the SOAP Message into an XML document. 1109 */ 1110 private Document toDocument() throws SecurityException { 1111 try { 1112 1113 /* make sure changes to the soapMessage are persisted before 1114 * using writeTo() ... possibly SAAJ bug as 'writeTo()' should always 1115 * save the changes first 1116 */ 1117 soapMessage.saveChanges(); 1118 1119 1120 ByteArrayOutputStream bop = new ByteArrayOutputStream(); 1121 1122 soapMessage.writeTo(bop); 1123 1124 if (debug.messageEnabled()) { 1125 debug.message("SecureSOAPMessage.toDocument:: message used: " + bop.toString()); 1126 } 1127 1128 ByteArrayInputStream bin = 1129 new ByteArrayInputStream(bop.toByteArray()); 1130 Document doc = XMLUtils.toDOMDocument(bin, WSSUtils.debug); 1131 if (debug.messageEnabled()) { 1132 debug.message("SecureSOAPMessage.toDocument: Converted SOAPMessage: " + XMLUtils.print(doc)); 1133 } 1134 return doc; 1135 } catch (Exception ex) { 1136 debug.error("SecureSOAPMessage.toDocument: Could not" + 1137 " Convert the SOAP Message to XML document.", ex); 1138 throw new SecurityException(ex.getMessage()); 1139 } 1140 } 1141 1142 /** 1143 * Returns the <code>X509Certificate</code> that is used to secure 1144 * the <code>SOAPMessage</code>. 1145 * 1146 * @return the X509 certificate. 1147 */ 1148 public X509Certificate getMessageCertificate() { 1149 return messageCertificate; 1150 } 1151 1152 /** 1153 * Encrypts the <code>SOAPMessage</code> for the given security profile. 1154 * 1155 * @param certAlias the certificate alias 1156 * @param encryptBody boolean flag to encrypt Body 1157 * @param encryptHeader boolean flag to encrypt Security header 1158 * 1159 * @exception SecurityException if there is any failure in encryption. 1160 */ 1161 public void encrypt(String certAlias, 1162 String encryptionAlgorithm, 1163 int encryptionKeyStrength, 1164 boolean encryptBody, 1165 boolean encryptHeader) throws SecurityException { 1166 1167 Document doc = toDocument(); 1168 String tokenType = null; 1169 // securityToken=null if the secmech is Anonymous 1170 if (securityToken == null) { 1171 tokenType = SecurityToken.WSS_X509_TOKEN; 1172 } else { 1173 tokenType = securityToken.getTokenType(); 1174 } 1175 Map elmMap = new HashMap(); 1176 Document encryptedDoc = null; 1177 String searchType = null; 1178 String searchNS = WSSConstants.WSSE_NS; 1179 1180 try { 1181 if (encryptBody) { 1182 Element elmDoc = (Element) doc.getDocumentElement(); 1183 String nameSpaceURI = elmDoc.getNamespaceURI(); 1184 Element bodyElement = 1185 (Element) elmDoc.getElementsByTagNameNS(nameSpaceURI, 1186 WSSConstants.BODY_LNAME).item(0); 1187 String bodyId = bodyElement.getAttribute(WSSConstants.WSU_ID); 1188 Node firstNodeInsideBody = bodyElement.getFirstChild(); 1189 elmMap.put((Element)firstNodeInsideBody, bodyId); 1190 } 1191 1192 if (encryptHeader) { 1193 String tokenId = null; 1194 1195 if (SecurityToken.WSS_X509_TOKEN.equals(tokenType)) { 1196 searchType = SAMLConstants.BINARYSECURITYTOKEN; 1197 } else if (SecurityToken.WSS_USERNAME_TOKEN.equals(tokenType)) { 1198 searchType = WSSConstants.TAG_USERNAME_TOKEN; 1199 } else if (SecurityToken.WSS_SAML_TOKEN.equals(tokenType)) { 1200 searchType = SAMLConstants.TAG_ASSERTION; 1201 AssertionToken assertionToken = 1202 (AssertionToken)securityToken; 1203 tokenId = assertionToken.getAssertion().getAssertionID(); 1204 searchNS = SAMLConstants.assertionSAMLNameSpaceURI; 1205 } else if (SecurityToken.WSS_SAML2_TOKEN.equals(tokenType)) { 1206 searchType = SAMLConstants.TAG_ASSERTION; 1207 SAML2Token saml2Token = (SAML2Token)securityToken; 1208 tokenId = saml2Token.getAssertion().getID(); 1209 searchNS = SAML2Constants.ASSERTION_NAMESPACE_URI; 1210 } 1211 1212 Element secHeaderElement = (Element) doc.getDocumentElement(). 1213 getElementsByTagNameNS(WSSConstants.WSSE_NS, 1214 WSSConstants.WSSE_SECURITY_LNAME).item(0); 1215 1216 if(debug.messageEnabled()) { 1217 debug.message("SecureSOAPMessage.encrypt:: Security " + 1218 "Header : " + WSSUtils.print(secHeaderElement)); 1219 } 1220 if (secHeaderElement != null) { 1221 Element token = 1222 (Element)secHeaderElement.getElementsByTagNameNS( 1223 searchNS,searchType).item(0); 1224 1225 if ((token != null) && (tokenId == null)) { 1226 tokenId = token.getAttributeNS(WSSConstants.WSU_NS, 1227 SAMLConstants.TAG_ID); 1228 } 1229 elmMap.put(token, tokenId); 1230 } 1231 } 1232 1233 XMLEncryptionManager encManager = 1234 WSSUtils.getXMLEncryptionManager(); 1235 encryptedDoc = encManager.encryptAndReplaceWSSElements( 1236 doc, 1237 elmMap, 1238 encryptionAlgorithm, 1239 encryptionKeyStrength, 1240 certAlias, 1241 0, 1242 tokenType, 1243 server_proto + "://" + server_host + ":" + server_port); 1244 1245 } catch (EncryptionException ee) { 1246 debug.error("SecureSOAPMessage.encrypt:: Encryption " + 1247 "Exception : ", ee); 1248 String[] data = {ee.getLocalizedMessage()}; 1249 LogUtil.error(Level.INFO, 1250 LogUtil.UNABLE_TO_ENCRYPT, 1251 data, 1252 null); 1253 throw new SecurityException( 1254 bundle.getString("unabletoEncrypt")); 1255 } catch (Exception ex) { 1256 debug.error("SecureSOAPMessage.encrypt:: " + 1257 "encryption failed : ", ex); 1258 String[] data = {ex.getLocalizedMessage()}; 1259 LogUtil.error(Level.INFO, 1260 LogUtil.UNABLE_TO_ENCRYPT, 1261 data, 1262 null); 1263 throw new SecurityException( 1264 bundle.getString("unabletoEncrypt")); 1265 } 1266 1267 try { 1268 Element encryptedKeyElem = null; 1269 1270 NodeList nl = encryptedDoc.getElementsByTagNameNS( 1271 EncryptionConstants.ENC_XML_NS, "EncryptedKey"); 1272 for(int i=0; i < nl.getLength(); i++ ) { 1273 Element elem = (Element)nl.item(i); 1274 if(elem.getParentNode().getParentNode().getLocalName() 1275 .equals("Signature")) { 1276 continue; 1277 } 1278 encryptedKeyElem = elem; 1279 break; 1280 } 1281 if(debug.messageEnabled()) { 1282 debug.message("SecureSOAPMessage.encrypt:EncryptedKey DOC : " 1283 + WSSUtils.print(encryptedKeyElem)); 1284 } 1285 // Append EncryptedKey element in the Security header 1286 Node encKeyNode = 1287 (soapMessage.getSOAPPart()).importNode(encryptedKeyElem, 1288 true); 1289 wsseHeader.appendChild(encKeyNode); 1290 soapMessage.saveChanges(); 1291 // Append some how does not work for webshpere SOAP runtime 1292 // So, if it's not added for whatever reason, get the enveloped 1293 // and add it. 1294 NodeList nodeList = soapMessage.getSOAPPart(). 1295 getElementsByTagNameNS(EncryptionConstants.ENC_XML_NS, 1296 "EncryptedKey"); 1297 if(nodeList == null || nodeList.getLength() == 0) { 1298 soapMessage.getSOAPPart().getEnvelope().getHeader(). 1299 appendChild(encKeyNode); 1300 } 1301 1302 if(debug.messageEnabled()) { 1303 debug.message("SecureSOAPMessage.encrypt:: wsseHeader: " 1304 + "after Encrypt : " 1305 + WSSUtils.print(soapMessage.getSOAPPart())); 1306 } 1307 // EncryptedData elements 1308 NodeList nodes = encryptedDoc.getElementsByTagNameNS( 1309 EncryptionConstants.ENC_XML_NS, "EncryptedData"); 1310 int length = nodes.getLength(); 1311 1312 for (int i=0; i < length; i++) { 1313 Element encryptedDataElem = (Element)nodes.item(i); 1314 1315 if(debug.messageEnabled()) { 1316 debug.message("SecureSOAPMessage.encrypt:" + 1317 "EncryptedData DOC (" + i + ") : " 1318 + WSSUtils.print(encryptedDataElem)); 1319 } 1320 // Replace first child of Body element or Security 1321 // header element with the EncryptedData element 1322 Node encDataNode = (soapMessage.getSOAPPart()). 1323 importNode(encryptedDataElem,true); 1324 1325 if( (WSSConstants.BODY_LNAME.equals( 1326 ((Node)encryptedDataElem).getParentNode().getLocalName()))) { 1327 Node firstNodeInsideBody = 1328 soapMessage.getSOAPPart().getEnvelope().getBody(). 1329 getFirstChild(); 1330 soapMessage.getSOAPPart().getEnvelope().getBody(). 1331 replaceChild(encDataNode, firstNodeInsideBody); 1332 } else if (encryptHeader) { 1333 Element token = 1334 (Element)wsseHeader.getElementsByTagNameNS( 1335 searchNS,searchType).item(0); 1336 1337 if(debug.messageEnabled()) { 1338 debug.message("SecureSOAPMessage.encrypt:: wsseHeader: " 1339 + "token element : " + WSSUtils.print(token)); 1340 } 1341 1342 if (token != null) { 1343 wsseHeader.removeChild(encKeyNode); 1344 wsseHeader.insertBefore(encKeyNode,(Node)token); 1345 1346 wsseHeader.replaceChild(encDataNode, (Node)token); 1347 } 1348 } 1349 } 1350 1351 1352 this.soapMessage.saveChanges(); 1353 1354 1355 if(debug.messageEnabled()) { 1356 debug.message("SecureSOAPMessage.encrypt:*** SOAP PART ***"); 1357 debug.message(WSSUtils.print(soapMessage.getSOAPPart())); 1358 } 1359 } catch (Exception ex) { 1360 debug.error("SecureSOAPMessage.encrypt:: " + 1361 "encryption failed : ", ex); 1362 throw new SecurityException( 1363 bundle.getString("unabletoGetFinalSoapMessage")); 1364 } 1365 1366 } 1367 1368 /** 1369 * Decrypts the <code>SOAPMessage</code> for the given security profile. 1370 * @param keyAlias private key alias that is used to decrypt. 1371 * @param decryptBody boolean flag to decrypt Body 1372 * @param decryptHeader boolean flag to decrypt Security header 1373 * @exception SecurityException if there is any failure in decryption. 1374 */ 1375 public void decrypt(String keyAlias, 1376 boolean decryptBody, 1377 boolean decryptHeader) 1378 throws SecurityException { 1379 1380 Document decryptedDoc = null; 1381 try { 1382 Document doc = toDocument(); 1383 1384 NodeList nodes = doc.getElementsByTagNameNS( 1385 EncryptionConstants.ENC_XML_NS, "EncryptedData"); 1386 if((nodes == null) || (nodes.getLength() == 0)) { 1387 debug.error("SecureSOAPMessage.decrypt:: Request " + 1388 "is not encrypted."); 1389 throw new SecurityException( 1390 bundle.getString("decryptEncryptionFailed")); 1391 } 1392 1393 XMLSignatureManager sigManager = 1394 XMLSignatureManager.getInstance(); 1395 XMLEncryptionManager encManager = 1396 WSSUtils.getXMLEncryptionManager(); 1397 String certAlias = null; 1398 if(messageCertificate != null) { 1399 certAlias = sigManager.getKeyProvider(). 1400 getCertificateAlias(messageCertificate); 1401 } else { 1402 certAlias = keyAlias; 1403 } 1404 decryptedDoc = encManager.decryptAndReplace(doc,certAlias); 1405 } catch (EncryptionException ee) { 1406 debug.error("SecureSOAPMessage.decrypt:: Decrypt " + 1407 "encryption failed : ", ee); 1408 String[] data = {ee.getLocalizedMessage()}; 1409 LogUtil.error(Level.INFO, 1410 LogUtil.UNABLE_TO_DECRYPT, 1411 data, 1412 null); 1413 throw new SecurityException( 1414 bundle.getString("decryptEncryptionFailed")); 1415 } catch (Exception ex) { 1416 debug.error("SecureSOAPMessage.decrypt:: " + 1417 "exception : ", ex); 1418 String[] data = {ex.getLocalizedMessage()}; 1419 LogUtil.error(Level.INFO, 1420 LogUtil.UNABLE_TO_DECRYPT, 1421 data, 1422 null); 1423 throw new SecurityException( 1424 bundle.getString("unabletoDecrypt")); 1425 } 1426 1427 try { 1428 if (decryptBody) { 1429 // Decrypted Body element replacement 1430 Element elmDoc = (Element) decryptedDoc.getDocumentElement(); 1431 String nameSpaceURI = elmDoc.getNamespaceURI(); 1432 Element decryptedBodyElem = 1433 (Element)decryptedDoc.getElementsByTagNameNS( 1434 nameSpaceURI, WSSConstants.BODY_LNAME).item(0); 1435 1436 Element bodyElement = 1437 (Element)soapMessage.getSOAPPart().getEnvelope().getBody(); 1438 1439 if(debug.messageEnabled()) { 1440 debug.message("SecureSOAPMessage.decrypt::decrypted " + 1441 "Body element : " + WSSUtils.print(decryptedBodyElem)); 1442 debug.message("SecureSOAPMessage.decrypt::SOAP " + 1443 "Body element : " + WSSUtils.print(bodyElement)); 1444 } 1445 1446 // Replace first child of Body element with the 1447 // first child of Decrypted Body element 1448 Node decDataNode = 1449 (soapMessage.getSOAPPart()).importNode(decryptedBodyElem, 1450 true); 1451 NodeList nl = soapMessage.getSOAPPart().getEnvelope(). 1452 getBody().getChildNodes(); 1453 for (int i=0; i < nl.getLength(); i++) { 1454 Node node = nl.item(i); 1455 if(node.getNodeType() != Node.ELEMENT_NODE) { 1456 continue; 1457 } 1458 soapMessage.getSOAPPart().getEnvelope().getBody(). 1459 removeChild(node); 1460 soapMessage.getSOAPPart().getEnvelope().getBody(). 1461 appendChild(decDataNode.getFirstChild()); 1462 break; 1463 } 1464 } 1465 1466 // Decrypted Security token element replacement 1467 if (decryptHeader) { 1468 Element decryptedSecHeaderElement = (Element) decryptedDoc. 1469 getElementsByTagNameNS(WSSConstants.WSSE_NS, 1470 WSSConstants.WSSE_SECURITY_LNAME).item(0); 1471 Node decSecHeaderDataNode = 1472 (soapMessage.getSOAPPart()).importNode( 1473 decryptedSecHeaderElement, true); 1474 1475 Node tokenNode = getTokenNode(decSecHeaderDataNode); 1476 Element token = (Element)wsseHeader.getElementsByTagNameNS( 1477 EncryptionConstants.ENC_XML_NS, "EncryptedData").item(0); 1478 1479 if(debug.messageEnabled()) { 1480 debug.message("SecureSOAPMessage.decrypt: decrypted " + 1481 "Security Header doc : " + 1482 WSSUtils.print(decryptedSecHeaderElement)); 1483 debug.message("SecureSOAPMessage.decrypt: " + 1484 "SOAP HEADER DOC : " + WSSUtils.print(wsseHeader)); 1485 debug.message("SecureSOAPMessage.decrypt: tokenNode " + 1486 "from decrypted Security header doc: " + 1487 WSSUtils.print(tokenNode)); 1488 debug.message("SecureSOAPMessage.decrypt: token " + 1489 "from current SOAP wsseHeader : " + 1490 WSSUtils.print(token)); 1491 } 1492 1493 if (token != null) { 1494 Element encKey = (Element)wsseHeader.getElementsByTagNameNS( 1495 EncryptionConstants.ENC_XML_NS, "EncryptedKey").item(0); 1496 wsseHeader.removeChild((Node) encKey); 1497 wsseHeader.appendChild((Node) encKey); 1498 1499 wsseHeader.replaceChild(tokenNode, (Node) token); 1500 } 1501 1502 } 1503 1504 this.soapMessage.saveChanges(); 1505 1506 if(debug.messageEnabled()) { 1507 debug.message("SecureSOAPMessage.decrypt:*** SOAP PART ***"); 1508 debug.message(WSSUtils.print(soapMessage.getSOAPPart())); 1509 } 1510 } catch (Exception ex) { 1511 debug.error("SecureSOAPMessage.decrypt:: " + 1512 "decryption failed : ", ex); 1513 throw new SecurityException( 1514 bundle.getString("unabletoGetFinalSoapMessage")); 1515 } 1516 1517 } 1518 1519 1520 /** 1521 * Returns the token Node for corresponding Security token. 1522 */ 1523 private Node getTokenNode(Node secHeaderNode) throws Exception { 1524 Node tokenNode = null; 1525 String searchType = null; 1526 NodeList securityHeaders = secHeaderNode.getChildNodes(); 1527 for(int i=0; i < securityHeaders.getLength(); i++) { 1528 Node currentNode = securityHeaders.item(i); 1529 String localName = currentNode.getLocalName(); 1530 String nameSpace = currentNode.getNamespaceURI(); 1531 1532 if( (SAMLConstants.TAG_ASSERTION.equals(localName)) && 1533 (SAMLConstants.assertionSAMLNameSpaceURI.equals(nameSpace))) { 1534 searchType = SAMLConstants.TAG_ASSERTION; 1535 } else if( (SAMLConstants.TAG_ASSERTION.equals(localName)) && 1536 (SAML2Constants.ASSERTION_NAMESPACE_URI.equals(nameSpace))) { 1537 searchType = SAMLConstants.TAG_ASSERTION; 1538 } else if( (WSSConstants.TAG_BINARY_SECURITY_TOKEN. 1539 equals(localName)) && 1540 (WSSConstants.WSSE_NS.equals(nameSpace)) ) { 1541 searchType = SAMLConstants.BINARYSECURITYTOKEN; 1542 } else if( (WSSConstants.TAG_USERNAME_TOKEN.equals(localName)) && 1543 (WSSConstants.WSSE_NS.equals(nameSpace)) ) { 1544 searchType = WSSConstants.TAG_USERNAME_TOKEN; 1545 } 1546 if (searchType != null) { 1547 tokenNode = currentNode; 1548 break; 1549 } 1550 } 1551 return tokenNode; 1552 } 1553 1554 private boolean validateTimestamp(Element tsElement) { 1555 1556 String created = null; 1557 String expires = null; 1558 NodeList nl = tsElement.getChildNodes(); 1559 for (int i=0; i < nl.getLength(); i++) { 1560 Node child = nl.item(i); 1561 if(child.getNodeType() != Node.ELEMENT_NODE) { 1562 continue; 1563 } 1564 1565 String childName = child.getLocalName(); 1566 if(WSSConstants.CREATED.equals(childName)) { 1567 created = XMLUtils.getElementValue((Element)child); 1568 } else if(WSSConstants.EXPIRES.equals(childName)) { 1569 expires = XMLUtils.getElementValue((Element)child); 1570 } 1571 } 1572 try { 1573 msgTimestamp = DateUtils.stringToDate(created).getTime(); 1574 long createdTS = msgTimestamp - WSSUtils.getTimeSkew(); 1575 long expiresTS = DateUtils.stringToDate(expires).getTime(); 1576 long now = new Date().getTime(); 1577 if (created == null ) { 1578 if (expires == null) { 1579 return false; 1580 } else { 1581 if (now < expiresTS) { 1582 return true; 1583 } 1584 } 1585 } else if (expires == null ) { 1586 if (now >= createdTS) { 1587 return true; 1588 } 1589 } else if ((now >= createdTS) && 1590 (now < expiresTS)) { 1591 return true; 1592 } 1593 return false; 1594 } catch (java.text.ParseException pe) { 1595 WSSUtils.debug.error("SecureSOAPMessage.validateTimestamp: " + 1596 "parsing exception", pe); 1597 return false; 1598 } 1599 1600 } 1601 1602 public void setSenderIdentity(String dnsName) { 1603 try { 1604 SOAPPart soapPart = soapMessage.getSOAPPart(); 1605 SOAPHeader header = soapPart.getEnvelope().getHeader(); 1606 if(header == null) { 1607 return; 1608 } 1609 NodeList nl = header.getElementsByTagNameNS(WSSConstants.wsaNS, 1610 "Action"); 1611 if(nl == null || nl.getLength() == 0) { 1612 return; 1613 } 1614 NodeList childNodes = 1615 header.getElementsByTagNameNS(WSSConstants.wsaNS, "From"); 1616 Element fromElement = null; 1617 if(childNodes == null || childNodes.getLength() == 0) { 1618 fromElement = soapPart.createElementNS( 1619 WSSConstants.wsaNS, "From"); 1620 fromElement.setAttributeNS(WSSConstants.NS_XML, 1621 WSSConstants.TAG_XML_WSU, 1622 WSSConstants.WSU_NS); 1623 String id = SAMLUtils.generateID(); 1624 fromElement.setAttribute(WSSConstants.WSU_ID, id); 1625 if(signedElements.contains(WSSConstants.FROM)) { 1626 signingIds.add(id); 1627 } 1628 } else { 1629 fromElement = (Element)childNodes.item(0); 1630 } 1631 1632 Element identityE = soapPart.createElementNS( 1633 WSSConstants.WSID_NS, 1634 WSSConstants.TAG_IDENTITY); 1635 1636 identityE.setAttributeNS( 1637 WSSConstants.NS_XML, 1638 WSSConstants.TAG_XML_WSID, 1639 WSSConstants.WSID_NS); 1640 1641 Element dnsClaim = soapPart.createElementNS( 1642 WSSConstants.WSID_NS, 1643 WSSConstants.TAG_DNSCLAIM); 1644 1645 org.w3c.dom.Text textNode = soapPart.createTextNode(dnsName); 1646 dnsClaim.appendChild(textNode); 1647 identityE.appendChild(dnsClaim); 1648 fromElement.appendChild(identityE); 1649 Element replyTo = 1650 (Element)header.getElementsByTagNameNS( 1651 WSSConstants.wsaNS, "ReplyTo").item(0); 1652 header.insertBefore(fromElement, replyTo); 1653 } catch (SOAPException se) { 1654 WSSUtils.debug.error("SecureSOAPMessage.setSenderIdentity: " + 1655 "SOAP Exception", se); 1656 } 1657 } 1658 1659 public String getClientDnsClaim() { 1660 return clientDnsClaim; 1661 } 1662 1663 public void setSignedElements(List elements) { 1664 this.signedElements = elements; 1665 } 1666 1667}
Copyright © 2010-2017, ForgeRock All Rights Reserved.