SWS-465: Optional WS-Addressing request headers being treated as mandatory

This commit is contained in:
Arjen Poutsma
2009-01-26 12:51:34 +00:00
parent 2983668eac
commit b968d485b3
9 changed files with 99 additions and 35 deletions

View File

@@ -153,23 +153,4 @@ public final class MessageAddressingProperties {
public MessageAddressingProperties getReplyProperties(EndpointReference epr, URI action, URI messageId) {
return new MessageAddressingProperties(epr, action, messageId, this.messageId);
}
/**
* Indicates whether is {@link MessageAddressingProperties} has all required properties.
*
* @return <code>true</code> if the to and action properties have been set, and - if a reply or fault endpoint has
* been set - also checks for the message id
*/
public boolean hasRequiredProperties() {
if (to == null) {
return false;
}
if (action == null) {
return false;
}
if (replyTo != null || faultTo != null) {
return messageId != null;
}
return true;
}
}

View File

@@ -74,7 +74,7 @@ class AddressingEndpointInterceptor implements SoapEndpointInterceptor {
Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
SoapMessage request = (SoapMessage) messageContext.getRequest();
MessageAddressingProperties requestMap = version.getMessageAddressingProperties(request);
if (!requestMap.hasRequiredProperties()) {
if (!version.hasRequiredProperties(requestMap)) {
version.addMessageAddressingHeaderRequiredFault((SoapMessage) messageContext.getResponse());
return false;
}
@@ -119,8 +119,9 @@ class AddressingEndpointInterceptor implements SoapEndpointInterceptor {
private boolean handleNoneAddress(MessageContext messageContext, EndpointReference replyEpr) {
if (replyEpr == null || version.hasNoneAddress(replyEpr)) {
if (logger.isDebugEnabled()) {
logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
"] reply address; reply [" + messageContext.getResponse() + "] discarded");
logger.debug(
"Request [" + messageContext.getRequest() + "] has [" + replyEpr + "] reply address; reply [" +
messageContext.getResponse() + "] discarded");
}
messageContext.clearResponse();
return true;
@@ -131,7 +132,7 @@ class AddressingEndpointInterceptor implements SoapEndpointInterceptor {
private boolean handleAnonymousAddress(MessageContext messageContext, EndpointReference replyEpr) {
if (version.hasAnonymousAddress(replyEpr)) {
if (logger.isDebugEnabled()) {
logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
logger.debug("Request [" + messageContext.getRequest() + "] has [" + replyEpr +
"] reply address; sending in-band reply [" + messageContext.getResponse() + "]");
}
return true;
@@ -141,7 +142,7 @@ class AddressingEndpointInterceptor implements SoapEndpointInterceptor {
private void sendOutOfBand(MessageContext messageContext, EndpointReference replyEpr) throws IOException {
if (logger.isDebugEnabled()) {
logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
logger.debug("Request [" + messageContext.getRequest() + "] has [" + replyEpr +
"] reply address; sending out-of-band reply [" + messageContext.getResponse() + "]");
}

View File

@@ -123,6 +123,9 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport
public MessageAddressingProperties getMessageAddressingProperties(SoapMessage message) {
Element headerElement = getSoapHeaderElement(message);
URI to = getUri(headerElement, toExpression);
if (to == null) {
to = getDefaultTo();
}
EndpointReference from = getEndpointReference(fromExpression.evaluateAsNode(headerElement));
EndpointReference replyTo = getEndpointReference(replyToExpression.evaluateAsNode(headerElement));
if (replyTo == null) {
@@ -392,6 +395,9 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport
return QNameUtils.createQName(getNamespaceUri(), "Address", getNamespacePrefix());
}
/** Returns the default To URI. */
protected abstract URI getDefaultTo();
/** Returns the default ReplyTo EPR. Can be based on the From EPR, or the anonymous URI. */
protected abstract EndpointReference getDefaultReplyTo(EndpointReference from);

View File

@@ -43,6 +43,17 @@ public class Addressing10 extends AbstractAddressingVersion {
super.addAddressingHeaders(message, map);
}
public boolean hasRequiredProperties(MessageAddressingProperties map) {
if (map.getAction() == null) {
return false;
}
if (map.getReplyTo() != null || map.getFaultTo() != null) {
return map.getMessageId() != null;
}
return true;
}
protected String getNamespaceUri() {
return NAMESPACE_URI;
}
@@ -51,6 +62,10 @@ public class Addressing10 extends AbstractAddressingVersion {
return null;
}
protected URI getDefaultTo() {
return getAnonymous();
}
protected EndpointReference getDefaultReplyTo(EndpointReference from) {
return new EndpointReference(getAnonymous());
}

View File

@@ -30,7 +30,8 @@ import org.springframework.xml.namespace.QNameUtils;
* Microsoft's Web Services Enhancements (WSE) 3.0, and supported by Axis 1 and 2, and XFire.
*
* @author Arjen Poutsma
* @see <a href="http://msdn.microsoft.com/ws/2004/08/ws-addressing/">Web Services Addressing, August 2004</a>
* @see <a href="http://www.w3.org/Submission/2004/SUBM-ws-addressing-20040810/">Web Services Addressing, August
* 2004</a>
* @since 1.5.0
*/
public class Addressing200408 extends AbstractAddressingVersion {
@@ -38,11 +39,24 @@ public class Addressing200408 extends AbstractAddressingVersion {
private static final String NAMESPACE_URI = "http://schemas.xmlsoap.org/ws/2004/08/addressing";
public void addAddressingHeaders(SoapMessage message, MessageAddressingProperties map) {
Assert.notNull(map.getAction(), "'Action' must not be null");
Assert.notNull(map.getTo(), "'Action' must not be null");
Assert.notNull(map.getAction(), "'Action' is required");
Assert.notNull(map.getTo(), "'To' is required");
super.addAddressingHeaders(message, map);
}
public boolean hasRequiredProperties(MessageAddressingProperties map) {
if (map.getTo() == null) {
return false;
}
if (map.getAction() == null) {
return false;
}
if (map.getReplyTo() != null || map.getFaultTo() != null) {
return map.getMessageId() != null;
}
return true;
}
protected final URI getAnonymous() {
return URI.create(NAMESPACE_URI + "/role/anonymous");
}
@@ -67,6 +81,10 @@ public class Addressing200408 extends AbstractAddressingVersion {
return NAMESPACE_URI;
}
protected URI getDefaultTo() {
return null;
}
protected final EndpointReference getDefaultReplyTo(EndpointReference from) {
return from;
}
@@ -76,6 +94,6 @@ public class Addressing200408 extends AbstractAddressingVersion {
}
public String toString() {
return "Ws-Addressing August 2004";
return "WS-Addressing August 2004";
}
}

View File

@@ -56,9 +56,17 @@ public interface AddressingVersion {
*/
boolean understands(SoapHeaderElement headerElement);
/*
* Address URIs
/**
* Indicates whether the given {@link MessageAddressingProperties} has all required properties.
*
* @return <code>true</code> if the to and action properties have been set, and - if a reply or fault endpoint has
* been set - also checks for the message id
*/
boolean hasRequiredProperties(MessageAddressingProperties map);
/*
* Address URIs
*/
/**
* Indicates whether the given endpoint reference has a Anonymous address. This address is used to indicate that a

View File

@@ -36,11 +36,11 @@ import org.springframework.ws.transport.WebServiceMessageSender;
public abstract class AbstractAddressingInterceptorTestCase extends AbstractWsAddressingTestCase {
private AddressingEndpointInterceptor interceptor;
protected AddressingEndpointInterceptor interceptor;
private MockControl strategyControl;
protected MockControl strategyControl;
private MessageIdStrategy strategyMock;
protected MessageIdStrategy strategyMock;
protected final void onSetUp() throws Exception {
strategyControl = MockControl.createControl(MessageIdStrategy.class);
@@ -148,8 +148,9 @@ public abstract class AbstractAddressingInterceptorTestCase extends AbstractWsAd
URI replyAction = new URI("urn:replyAction");
URI faultAction = new URI("urn:replyAction");
interceptor = new AddressingEndpointInterceptor(getVersion(), strategyMock,
new WebServiceMessageSender[]{senderMock}, replyAction, faultAction);
interceptor =
new AddressingEndpointInterceptor(getVersion(), strategyMock, new WebServiceMessageSender[]{senderMock},
replyAction, faultAction);
MockControl connectionControl = MockControl.createControl(WebServiceConnection.class);
WebServiceConnection connectionMock = (WebServiceConnection) connectionControl.getMock();

View File

@@ -16,8 +16,15 @@
package org.springframework.ws.soap.addressing.server;
import java.net.URI;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.addressing.version.Addressing10;
import org.springframework.ws.soap.addressing.version.AddressingVersion;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
public class AddressingInterceptor10Test extends AbstractAddressingInterceptorTestCase {
@@ -28,4 +35,20 @@ public class AddressingInterceptor10Test extends AbstractAddressingInterceptorTe
protected String getTestPath() {
return "10";
}
public void testNoTo() throws Exception {
SaajSoapMessage valid = loadSaajMessage(getTestPath() + "/request-no-to.xml");
MessageContext context = new DefaultMessageContext(valid, new SaajSoapMessageFactory(messageFactory));
URI messageId = new URI("uid:1234");
strategyControl.expectAndReturn(strategyMock.newMessageId((SoapMessage) context.getResponse()), messageId);
strategyControl.replay();
boolean result = interceptor.handleResponse(context, null);
assertTrue("Request with no To not handled", result);
assertTrue("Message Context has no response", context.hasResponse());
SaajSoapMessage expectedResponse = loadSaajMessage(getTestPath() + "/response-anonymous.xml");
assertXMLEqual("Invalid response for message with invalid MAP", expectedResponse,
(SaajSoapMessage) context.getResponse());
strategyControl.verify();
}
}

View File

@@ -0,0 +1,11 @@
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<S:Header>
<wsa:Action>http://example.com/fabrikam/mail/Delete</wsa:Action>
<wsa:MessageID>http://example.com/someuniquestring</wsa:MessageID>
</S:Header>
<S:Body>
<f:Delete xmlns:f="http://example.com/fabrikam">
<f:maxCount>42</f:maxCount>
</f:Delete>
</S:Body>
</S:Envelope>