3737
3838import org .springframework .beans .factory .InitializingBean ;
3939import org .springframework .util .Assert ;
40+ import org .springframework .util .StringUtils ;
4041import org .springframework .ws .context .MessageContext ;
4142import org .springframework .ws .soap .SoapMessage ;
4243import org .springframework .ws .soap .axiom .AxiomSoapMessage ;
4748import org .springframework .ws .soap .security .WsSecurityValidationException ;
4849
4950/**
50- * A WS-Security endpoint interceptor based on Apache Wss4j. The inteceptor supports both Axiom and Saaj messages. The
51- * interceptor's configuration does not rely on an external configuration files and thus is set using the various
52- * attributes.
51+ * A WS-Security endpoint interceptor based on Apache's WSS4J. This inteceptor supports messages created by the {@link
52+ * org.springframework.ws.soap.axiom.AxiomSoapMessageFactory} and the {@link org.springframework.ws.soap.saaj.SaajSoapMessageFactory}.
5353 * <p/>
54- * The actions executed by the interceptor are configured via <code>validationActions</code> and
55- * <code>securementActions</code> attributes . Actions are passed as a space separated string .
54+ * The validation and securement actions executed by this interceptor are configured via <code>validationActions</code> and
55+ * <code>securementActions</code> properties, respectively . Actions should be passed as a space- separated strings .
5656 * <p/>
57- * Validation actions are: <ul> <li><strong>UsernameToken</strong>: validates username token</li>
58- * <li><strong>Timestamp</strong>: validates the timestamp</li> <li><strong>Encrypt</strong>: decrypts the message</li>
59- * <li><strong>Signature</strong>: validates the signature</li> <li><strong>NoSecurity</strong>: no action
60- * performed</li> </ul> The order of the actions that the client performed to secure the messages is significant and is
61- * enforced by the interceptor.
57+ * Valid <strong>validation</strong> actions are:
58+ *
59+ * <blockquote><table>
60+ * <tr><th>Validation action</th><th>Description</th></tr>
61+ * <tr><td><code>UsernameToken</code></td><td>Validates username token</td></tr>
62+ * <tr><td><code>Timestamp</code></td><td>Validates the timestamp</td></tr>
63+ * <tr><td><code>Encrypt</code></td><td>Decrypts the message</td></tr>
64+ * <tr><td><code>Signature</code></td><td>Validates the signature</td></tr>
65+ * <tr><td><code>NoSecurity</code></td><td>No action performed</td></tr>
66+ * </table></blockquote>
67+ * <p/>
68+ * <strong>Securement</strong> actions are:
69+ * <blockquote><table>
70+ * <tr><th>Securement action</th><th>Description</th></tr>
71+ * <tr><td><code>UsernameToken</td></code><td>Adds a username token</td></tr>
72+ * <tr><td><code>UsernameTokenSignature</td></code><td>Adds a username token and a signature username token secrect key</td></tr>
73+ * <tr><td><code>Timestamp</td></code><td>Adds a timestamp</td></tr>
74+ * <tr><td><code>Encrypt</td></code><td>Encrypts the response</td></tr>
75+ * <tr><td><code>Signature</td></code><td>Signs the response</td></tr>
76+ * <tr><td><code>NoSecurity</td></code><td>No action performed</td></tr>
77+ * </table></blockquote>
6278 * <p/>
63- * Securement actions are: <ul> <li><strong>UsernameToken</strong>: adds a username token</li>
64- * <li><strong>UsernameTokenSignature</strong>: adds a username token and a sinagture username token secrect key</li>
65- * <li><strong>Timestamp</strong>: adds a timestamp</li> <li><strong>Encrypt</strong>: encrypts the response</li>
66- * <li><strong>Signature</strong>: signs the response</li> <li><strong>NoSecurity</strong>: no action performed</li>
67- * </ul>
79+ * The order of the actions that the client performed to secure the messages is significant and is
80+ * enforced by the interceptor.
81+ *
6882 *
6983 * @author Tareq Abed Rabbo
7084 * @author Arjen Poutsma
85+ * @see <a href="http://ws.apache.org/wss4j/">Apache WSS4J</a>
7186 * @since 1.5.0
7287 */
7388public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor implements InitializingBean {
@@ -397,7 +412,7 @@ protected void secureMessage(SoapMessage soapMessage, MessageContext messageCont
397412 }
398413 RequestData requestData = initializeRequestData (messageContext );
399414
400- Document envelopeAsDocument = getEnvelopeAsDocument (soapMessage );
415+ Document envelopeAsDocument = toDocument (soapMessage );
401416 try {
402417 // In case on signature confirmation with no other securement
403418 // action, we need to pass an empty securementActionsVector to avoid
@@ -412,7 +427,7 @@ protected void secureMessage(SoapMessage soapMessage, MessageContext messageCont
412427 throw new Wss4jSecuritySecurementException (ex .getMessage (), ex );
413428 }
414429
415- replaceMessageIfNecessary (soapMessage , envelopeAsDocument );
430+ replaceMessage (soapMessage , envelopeAsDocument );
416431 }
417432
418433 /** Creates and initializes a request data */
@@ -422,31 +437,27 @@ private RequestData initializeRequestData(MessageContext messageContext) {
422437
423438 // reads securementUsername first from the context then from the
424439 // property
425- String su = (String ) messageContext
426- .getProperty (SECUREMENT_USER_PROPERTY_NAME );
427- if (su != null && !su .equals ("" )) {
428- requestData .setUsername (su );
440+ String contextUsername = (String ) messageContext .getProperty (SECUREMENT_USER_PROPERTY_NAME );
441+ if (StringUtils .hasLength (contextUsername )) {
442+ requestData .setUsername (contextUsername );
429443 }
430444 else {
431445 requestData .setUsername (securementUsername );
432-
433446 }
434-
435- requestData .setUsername (securementUsername );
436447 return requestData ;
437448 }
438449
439450 protected void validateMessage (SoapMessage soapMessage , MessageContext messageContext )
440451 throws WsSecurityValidationException {
441452 if (logger .isDebugEnabled ()) {
442- logger .debug ("validating message: " + soapMessage + " with actions: " + validationActions );
453+ logger .debug ("Validating message [ " + soapMessage + "] with actions " + validationActions );
443454 }
444455
445456 if (validationAction == WSConstants .NO_SECURITY ) {
446457 return ;
447458 }
448459
449- Document envelopeAsDocument = getEnvelopeAsDocument (soapMessage );
460+ Document envelopeAsDocument = toDocument (soapMessage );
450461
451462 // Header processing
452463 WSSecurityEngine securityEngine = WSSecurityEngine .getInstance ();
@@ -476,34 +487,14 @@ protected void validateMessage(SoapMessage soapMessage, MessageContext messageCo
476487 throw new Wss4jSecurityValidationException (ex .getMessage (), ex );
477488 }
478489
479- replaceMessageIfNecessary (soapMessage , envelopeAsDocument );
490+ replaceMessage (soapMessage , envelopeAsDocument );
480491
481492 soapMessage .getEnvelope ().getHeader ().removeHeaderElement (WS_SECURITY_NAME );
482493 }
483494
484- /**
485- * Transforms a soap message to a DOM document.
486- *
487- * @param soapMessage the message to transform
488- * @return a DOM document representing the message
489- */
490- private Document getEnvelopeAsDocument (SoapMessage soapMessage ) {
491- if (soapMessage instanceof SaajSoapMessage ) {
492- SaajSoapMessage saajMessage = (SaajSoapMessage ) soapMessage ;
493- return saajMessage .getSaajMessage ().getSOAPPart ();
494- }
495-
496- if (soapMessage instanceof AxiomSoapMessage ) {
497- AxiomSoapMessage axiomMessage = (AxiomSoapMessage ) soapMessage ;
498- return AxiomUtils .toDocument (axiomMessage .getAxiomMessage ().getSOAPEnvelope ());
499- }
500-
501- throw new UnsupportedOperationException ("Message type not supported: " + soapMessage );
502- }
503-
504495 /**
505496 * Puts the results of WS-Security headers processing in the message context. Some actions like Signature
506- * Confirmation
497+ * Confirmation require this.
507498 */
508499 private void updateContextWithResults (MessageContext messageContext , Vector results ) {
509500 Vector handlerResults ;
@@ -518,7 +509,7 @@ private void updateContextWithResults(MessageContext messageContext, Vector resu
518509 }
519510
520511 /**
521- *
512+ * Verifies the trust of a certificate.
522513 * @param results
523514 * @throws WSSecurityException
524515 */
@@ -555,13 +546,27 @@ protected void verifyTimestamp(Vector results) throws WSSecurityException {
555546
556547 }
557548
549+ /** Converts the given {@link SoapMessage} into a {@link Document}. */
550+ private Document toDocument (SoapMessage soapMessage ) {
551+ if (soapMessage instanceof SaajSoapMessage ) {
552+ SaajSoapMessage saajMessage = (SaajSoapMessage ) soapMessage ;
553+ return saajMessage .getSaajMessage ().getSOAPPart ();
554+ }
555+ else if (soapMessage instanceof AxiomSoapMessage ) {
556+ AxiomSoapMessage axiomMessage = (AxiomSoapMessage ) soapMessage ;
557+ return AxiomUtils .toDocument (axiomMessage .getAxiomMessage ().getSOAPEnvelope ());
558+ }
559+ else {
560+ throw new IllegalArgumentException ("Message type not supported [" + soapMessage + "]" );
561+ }
562+ }
563+
558564 /**
559- * Replaces an axiom message.
560- *
561- * @param soapMessage the soap message to replace
562- * @param envelope the new envelope
565+ * Replaces the contents of the given {@link SoapMessage} with that of the document parameter. Only required when
566+ * using Axiom, since the document returned by {@link #toDocument(org.springframework.ws.soap.SoapMessage)} is live
567+ * for a {@link SaajSoapMessage}.
563568 */
564- private void replaceMessageIfNecessary (SoapMessage soapMessage , Document envelope ) {
569+ private void replaceMessage (SoapMessage soapMessage , Document envelope ) {
565570 if (soapMessage instanceof AxiomSoapMessage ) {
566571 // construct a new Axiom message with the processed envelope
567572 AxiomSoapMessage axiomMessage = (AxiomSoapMessage ) soapMessage ;
0 commit comments