You can read the soap header from the SOAPMessageContext
in a SOAPHandler
class, then pass the values to your @WebService
implementation via attributes in the MessageContext
.
Whereas the HeaderList
API is specific to the JAX-WS reference implementation, the following sample should be portable across any JAX-WS runtime.
Example:
Web service impl:
package org.example.sampleservice;
import javax.annotation.Resource;
import javax.jws.HandlerChain;
import javax.jws.WebService;
import javax.xml.ws.WebServiceContext;
@WebService(endpointInterface = "org.example.sampleservice.SampleService")
@HandlerChain(file="handlers.xml")
public class SampleServiceImpl implements SampleService {
@Resource
private WebServiceContext ctx;
@Override
public String sayHello(String name) {
String usernameFromHeader = (String) ctx.getMessageContext().get("USERNAME");
return "Hello, "
+ name
+ " (invoked by "
+ (usernameFromHeader == null ? "[err or no 'Security' header found]"
: usernameFromHeader) + ")";
}
}
Handler chain XML (handlers.xml, a file in the same package as SampleServiceImpl.java
):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-class>org.example.sampleservice.UsernameTokenHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
The JAX-WS handler class:
package org.example.sampleservice;
import java.util.Iterator;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.MessageContext.Scope;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class UsernameTokenHandler implements SOAPHandler<SOAPMessageContext> {
private static final String WSSE_NS_URI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
private static final QName QNAME_WSSE_USERNAMETOKEN = new QName(WSSE_NS_URI, "UsernameToken");
private static final QName QNAME_WSSE_USERNAME = new QName(WSSE_NS_URI, "Username");
private static final QName QNAME_WSSE_PASSWORD = new QName(WSSE_NS_URI, "Password");
@Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean outbound = (Boolean) context
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if ((outbound != null) && (!outbound.booleanValue())) {
handleInboundMessage(context);
}
return true;
}
private void handleInboundMessage(SOAPMessageContext context) {
String wsseUsername = null;
String wssePassword = null;
try {
SOAPHeader header = context.getMessage().getSOAPHeader();
Iterator<?> headerElements = header.examineAllHeaderElements();
while (headerElements.hasNext()) {
SOAPHeaderElement headerElement = (SOAPHeaderElement) headerElements
.next();
if (headerElement.getElementName().getLocalName()
.equals("Security")) {
SOAPHeaderElement securityElement = headerElement;
Iterator<?> it2 = securityElement.getChildElements();
while (it2.hasNext()) {
Node soapNode = (Node) it2.next();
if (soapNode instanceof SOAPElement) {
SOAPElement element = (SOAPElement) soapNode;
QName elementQname = element.getElementQName();
if (QNAME_WSSE_USERNAMETOKEN.equals(elementQname)) {
SOAPElement usernameTokenElement = element;
wsseUsername = getFirstChildElementValue(usernameTokenElement, QNAME_WSSE_USERNAME);
wssePassword = getFirstChildElementValue(usernameTokenElement, QNAME_WSSE_PASSWORD);
break;
}
}
if (wsseUsername != null) {
break;
}
}
}
context.put("USERNAME", wsseUsername);
context.setScope("USERNAME", Scope.APPLICATION);
context.put("PASSWORD", wssePassword);
context.setScope("PASSWORD", Scope.APPLICATION);
}
} catch (Exception e) {
System.out.println("Error reading SOAP message context: " + e);
e.printStackTrace();
}
}
private String getFirstChildElementValue(SOAPElement soapElement, QName qNameToFind) {
String value = null;
Iterator<?> it = soapElement.getChildElements(qNameToFind);
while (it.hasNext()) {
SOAPElement element = (SOAPElement) it.next(); //use first
value = element.getValue();
}
return value;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
@Override
public void close(MessageContext context) {
}
@Override
public Set<QName> getHeaders() {
return null;
}
}
PasswordValidationCallback.PasswordValidator
, and in this caseheader.examineAllHeaderElements()
returns an empty interator, as if there wasn't any nodes in the header,getChildElements()
does the same. Why is that? The validator somehow deletes the header from the request? – Hainaut