diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j/Wss4jSecurityInterceptor.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j/Wss4jSecurityInterceptor.java index 63e2044d..440e79e1 100755 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j/Wss4jSecurityInterceptor.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j/Wss4jSecurityInterceptor.java @@ -82,6 +82,7 @@ import org.springframework.ws.soap.security.wss4j.callback.UsernameTokenPrincipa * * @author Tareq Abed Rabbo * @author Arjen Poutsma + * @author Greg Turnquist * @see Apache WSS4J * @since 1.5.0 */ @@ -137,6 +138,9 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl private boolean securementUseDerivedKey; + // To maintain same behavior as default, this flag is set to true + private boolean removeSecurityHeader = true; + public void setSecurementActions(String securementActions) { this.securementActions = securementActions; securementActionsVector = new ArrayList(); @@ -502,7 +506,15 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl this.samlIssuer = samlIssuer; } - @Override + public boolean getRemoveSecurityHeader() { + return removeSecurityHeader; + } + + public void setRemoveSecurityHeader(boolean removeSecurityHeader) { + this.removeSecurityHeader = removeSecurityHeader; + } + + @Override public void afterPropertiesSet() throws Exception { Assert.isTrue(validationActions != null || securementActions != null, "validationActions or securementActions are required"); @@ -628,7 +640,9 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl soapMessage.setDocument(envelopeAsDocument); - soapMessage.getEnvelope().getHeader().removeHeaderElement(WS_SECURITY_NAME); + if (this.getRemoveSecurityHeader()) { + soapMessage.getEnvelope().getHeader().removeHeaderElement(WS_SECURITY_NAME); + } } /** diff --git a/spring-ws-security/src/test/java/org/springframework/ws/soap/security/wss4j/Wss4jMessageInterceptorHeaderTestCase.java b/spring-ws-security/src/test/java/org/springframework/ws/soap/security/wss4j/Wss4jMessageInterceptorHeaderTestCase.java index ccf51a75..a3c3ecd0 100755 --- a/spring-ws-security/src/test/java/org/springframework/ws/soap/security/wss4j/Wss4jMessageInterceptorHeaderTestCase.java +++ b/spring-ws-security/src/test/java/org/springframework/ws/soap/security/wss4j/Wss4jMessageInterceptorHeaderTestCase.java @@ -21,10 +21,10 @@ import static org.junit.Assert.*; import java.io.ByteArrayOutputStream; import java.util.Iterator; import java.util.Properties; - import javax.xml.namespace.QName; import org.junit.Test; + import org.springframework.ws.context.DefaultMessageContext; import org.springframework.ws.context.MessageContext; import org.springframework.ws.soap.SoapHeaderElement; @@ -32,9 +32,15 @@ import org.springframework.ws.soap.SoapMessage; import org.springframework.ws.soap.security.WsSecurityValidationException; import org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler; +/** + * @author Arjen Poutsma + * @author Tareq Abedrabbo + * @author Greg Turnquist + */ public abstract class Wss4jMessageInterceptorHeaderTestCase extends Wss4jTestCase { private Wss4jSecurityInterceptor interceptor; + private Wss4jSecurityInterceptor interceptorThatKeepsSecurityHeader; @Override protected void onSetup() throws Exception { @@ -48,6 +54,14 @@ public abstract class Wss4jMessageInterceptorHeaderTestCase extends Wss4jTestCas callbackHandler.setUsers(users); interceptor.setValidationCallbackHandler(callbackHandler); interceptor.afterPropertiesSet(); + + interceptorThatKeepsSecurityHeader = new Wss4jSecurityInterceptor(); + interceptorThatKeepsSecurityHeader.setValidateRequest(true); + interceptorThatKeepsSecurityHeader.setSecureResponse(true); + interceptorThatKeepsSecurityHeader.setValidationActions("UsernameToken"); + interceptorThatKeepsSecurityHeader.setValidationCallbackHandler(callbackHandler); + interceptorThatKeepsSecurityHeader.setRemoveSecurityHeader(false); + interceptorThatKeepsSecurityHeader.afterPropertiesSet(); } @Test @@ -75,6 +89,31 @@ public abstract class Wss4jMessageInterceptorHeaderTestCase extends Wss4jTestCas } + @Test + public void testValidateUsernameTokenPlainTextButKeepSecurityHeader() throws Exception { + SoapMessage message = loadSoap11Message("usernameTokenPlainTextWithHeaders-soap.xml"); + MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory()); + interceptorThatKeepsSecurityHeader.validateMessage(message, messageContext); + Object result = getMessage(message); + assertNotNull("No result returned", result); + + boolean foundSecurityHeader = false; + for (Iterator i = message.getEnvelope().getHeader().examineAllHeaderElements(); i.hasNext();) { + SoapHeaderElement element = i.next(); + QName name = element.getName(); + if (name.getNamespaceURI() + .equals("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")) { + foundSecurityHeader = true; + } + + } + assertTrue(foundSecurityHeader); + + assertXpathExists("header1 not found", "/SOAP-ENV:Envelope/SOAP-ENV:Header/header1", getDocument(message)); + assertXpathExists("header2 not found", "/SOAP-ENV:Envelope/SOAP-ENV:Header/header2", getDocument(message)); + + } + @Test(expected=WsSecurityValidationException.class) public void testEmptySecurityHeader() throws Exception { SoapMessage message = loadSoap11Message("emptySecurityHeader-soap.xml");