diff --git a/security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java b/security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java
index 03d326f1..0690d920 100644
--- a/security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java
+++ b/security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java
@@ -16,6 +16,7 @@
package org.springframework.ws.soap.security;
+import java.util.Iterator;
import java.util.Locale;
import javax.xml.namespace.QName;
@@ -29,6 +30,7 @@ import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointExceptionResolver;
import org.springframework.ws.soap.SoapBody;
import org.springframework.ws.soap.SoapFault;
+import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.SoapEndpointInterceptor;
@@ -61,6 +63,8 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter
private boolean secureRequest = true;
private boolean validateResponse = true;
+
+ private boolean skipValidationIfNoHeaderPresent = false;
private EndpointExceptionResolver exceptionResolver;
@@ -89,11 +93,17 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter
this.exceptionResolver = exceptionResolver;
}
+ /** Allows skipping validation if no security header is present. */
+ public void setSkipValidationIfNoHeaderPresent(
+ boolean skipValidationIfNoHeaderPresent) {
+ this.skipValidationIfNoHeaderPresent = skipValidationIfNoHeaderPresent;
+ }
+
/*
* Server-side
*/
- /**
+ /**
* Validates a server-side incoming request. Delegates to {@link #validateMessage(org.springframework.ws.soap.SoapMessage,org.springframework.ws.context.MessageContext)}
* if the {@link #setValidateRequest(boolean) validateRequest} property is true.
*
@@ -106,6 +116,9 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter
public final boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
if (validateRequest) {
Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
+ if(skipValidationIfNoHeaderPresent && !isSecurityHeaderPresent((SoapMessage) messageContext.getRequest())){
+ return true;
+ }
try {
validateMessage((SoapMessage) messageContext.getRequest(), messageContext);
return true;
@@ -122,7 +135,7 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter
}
}
- /**
+ /**
* Secures a server-side outgoing response. Delegates to {@link #secureMessage(org.springframework.ws.soap.SoapMessage,org.springframework.ws.context.MessageContext)}
* if the {@link #setSecureResponse(boolean) secureResponse} property is true.
*
@@ -213,6 +226,9 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter
if (validateResponse) {
Assert.isTrue(messageContext.hasResponse(), "MessageContext contains no response");
Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse());
+ if(skipValidationIfNoHeaderPresent && !isSecurityHeaderPresent((SoapMessage) messageContext.getRequest())){
+ return true;
+ }
try {
validateMessage((SoapMessage) messageContext.getResponse(), messageContext);
return true;
@@ -320,4 +336,22 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter
throws WsSecuritySecurementException;
protected abstract void cleanUp();
+
+ /**
+ * Iterates over header elements and returns true if WS-Security header is found.
+ */
+ private boolean isSecurityHeaderPresent(SoapMessage message) {
+ SoapHeader soapHeader = message.getSoapHeader();
+ if(soapHeader == null){
+ return false;
+ }
+ Iterator elements = soapHeader.examineAllHeaderElements();
+ while(elements.hasNext()){
+ SoapHeaderElement e = elements.next();
+ if(e.getName().equals(WS_SECURITY_NAME)){
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/security/src/test/java/org/springframework/ws/soap/security/wss4j/Wss4jMessageInterceptorHeaderTestCase.java b/security/src/test/java/org/springframework/ws/soap/security/wss4j/Wss4jMessageInterceptorHeaderTestCase.java
index 202d6e8f..0f49de7d 100755
--- a/security/src/test/java/org/springframework/ws/soap/security/wss4j/Wss4jMessageInterceptorHeaderTestCase.java
+++ b/security/src/test/java/org/springframework/ws/soap/security/wss4j/Wss4jMessageInterceptorHeaderTestCase.java
@@ -16,11 +16,15 @@
package org.springframework.ws.soap.security.wss4j;
+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;
@@ -28,11 +32,6 @@ import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.security.WsSecurityValidationException;
import org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler;
-import org.junit.Test;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
public abstract class Wss4jMessageInterceptorHeaderTestCase extends Wss4jTestCase {
private Wss4jSecurityInterceptor interceptor;
@@ -50,7 +49,7 @@ public abstract class Wss4jMessageInterceptorHeaderTestCase extends Wss4jTestCas
interceptor.setValidationCallbackHandler(callbackHandler);
interceptor.afterPropertiesSet();
}
-
+
@Test
public void testValidateUsernameTokenPlainText() throws Exception {
SoapMessage message = loadSoap11Message("usernameTokenPlainTextWithHeaders-soap.xml");
@@ -76,17 +75,20 @@ public abstract class Wss4jMessageInterceptorHeaderTestCase extends Wss4jTestCas
}
- @Test
+ @Test(expected=WsSecurityValidationException.class)
public void testEmptySecurityHeader() throws Exception {
SoapMessage message = loadSoap11Message("emptySecurityHeader-soap.xml");
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
- try {
- interceptor.validateMessage(message, messageContext);
- fail("validation must fail for an empty security header.");
- }
- catch (WsSecurityValidationException e) {
- // expected
- }
+ interceptor.validateMessage(message, messageContext);
+ }
+
+ @Test
+ public void testSkipValidationOnEmptyHeader() throws Exception {
+ SoapMessage message = loadSoap11Message("noSecurityHeader-soap.xml");
+ MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
+ interceptor.setSkipValidationIfNoHeaderPresent(true);
+ boolean result = interceptor.handleRequest(messageContext, null);
+ assertTrue("handeRequest result must be true", result);
}
@Test
diff --git a/security/src/test/resources/org/springframework/ws/soap/security/wss4j/noSecurityHeader-soap.xml b/security/src/test/resources/org/springframework/ws/soap/security/wss4j/noSecurityHeader-soap.xml
new file mode 100644
index 00000000..18e3966d
--- /dev/null
+++ b/security/src/test/resources/org/springframework/ws/soap/security/wss4j/noSecurityHeader-soap.xml
@@ -0,0 +1,5 @@
+
+
+ QQQ
+
+