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.