How to change SOAP Request prefix in JAX-WS. I updated setprofix method in handlemessage
SOAPMessage msgs = ctx.getMessage();
SOAPMessage sm = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL).createMessage();
sm.getSOAPPart().getEnvelope().setPrefix("soap");
sm.getSOAPPart().getEnvelope().removeNamespaceDeclaration("env");
sm.getSOAPHeader().setPrefix("soap");
sm.getSOAPBody().setPrefix("soap");*/
But Still I am getting the Same Request
<?xml version="1.0"?>
<S:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
I needed
<Soap:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
Please help
final SOAPMessage soapMsg = context.getMessage();
soapMsg.getSOAPPart().getEnvelope().setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/");
soapMsg.getSOAPPart().getEnvelope().removeAttributeNS("http://schemas.xmlsoap.org/soap/envelope/", "env");
soapMsg.getSOAPPart().getEnvelope().removeAttribute("xmlns:env");
soapMsg.getSOAPPart().getEnvelope().setPrefix("soap");
soapMsg.getSOAPBody().setPrefix("soap");
soapMsg.getSOAPPart().getEnvelope().getHeader().detachNode();
I need to change the default prefix from S to soapenv. Here is what I did:
Create an implementation of SOAPHandler, which sets the prefix.
public class SoapNamespaceHandler implements SOAPHandler<SOAPMessageContext>{
private final static String SOAP_PREFIX = "soapenv";
#Override
public boolean handleMessage(final SOAPMessageContext context){
//only update the namespace prefix for outbound messages (requests)
final Boolean isSoapRequest = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (isSoapRequest){
try{
//get the soap message and envelope
SOAPMessage soapMsg = context.getMessage();
SOAPEnvelope env = soapMsg.getSOAPPart().getEnvelope();
//set the prefix
env.setPrefix(SOAP_PREFIX);
// **** apply the changes to the message
soapMsg.saveChanges();
}
catch (SOAPException e) {
e.printStackTrace();
}
}
return true;
}
Do one of the following:
create an XML file that functions as a HandlerResolver (see Changing JAX-WS default XML namespace prefix) and then annotate your web service client class with #HandlerChain(file = "handler.xml")
<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
<handler-chain>
<handler>
<handler-name>mypackage.SoapNamespaceHandler</handler-name>
<handler-class>mypackage.SoapNamespaceHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
create an implementation of HandlerResolver ...
public class SoapNamespaceHandlerResolver implements HandlerResolver {
#SuppressWarnings({ "rawtypes" })
#Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlerChain = new ArrayList<Handler>();
Handler handler = (SOAPHandler<SOAPMessageContext>) new SoapNamespaceHandler();
String bindingID = portInfo.getBindingID();
if (bindingID.equals("http://schemas.xmlsoap.org/wsdl/soap/http")) {
handlerChain.add(handler);
} else if (bindingID.equals("http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/")) {
handlerChain.add(handler);
}
return handlerChain;
}
}
... and then programmatically attach your HandlerResolver implementation to your web service client by calling
webServiceClient.setHandlerResolver(new SoapNamespaceHandlerResolver());
Related
i am working on web services project with Apache CXF.
I wan't to handle exception and customize response:
public class FaultInterceptor extends
AbstractSoapInterceptor {
public FaultInterceptor() {
super(Phase.MARSHAL);
}
public void handleMessage(SoapMessage soapMessage) throws Fault {
Fault fault = (Fault) soapMessage.getContent(Exception.class);
QName faultCode = new QName("11111");
fault.setFaultCode(faultCode);
So here is what i get in the response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:11111</faultcode>
<faultstring>Message</faultstring>
</soap:Fault>
</soap:Body>
How can i remove the text "soap:" and let only 11111?
Please help me and thanks in advance
To customize the SOAP response, you can implement either one of these:
JAX-WS handler;
CXF interceptor (extend AbstractSoapInterceptor);
Servlet Filter.
--EDIT 2019-02-20--
According to Javadoc (and SOAP spec), the faultcode must be in the form "prefix:localname" where "prefix" is the prefix of a declared XML namespace in your XML, or you can have no prefix - that you want - if it is declared as the default namespace, e.g. with xmlns="my-custom-faultcode-namespace-uri" somewhere, e.g. in the soap:Envelope element. So one way - not sure it's the easiest but it is SOAP standard compliant - consists to:
1) Make up your own custom namespace for this faultcode
2) Try changing the QName with empty string as namespace prefix:
QName faultCode = new QName("my-custom-faultcode-namespace-uri", "11111", "");
If this is not enough (I would be surprised it is that simple), you may have force CXF to use your custom namespace as the default (without prefix). According to this post, to customize namespaces and prefixes on the soap enveloppe in CXF, you change the Map in the jaxws 'soap.env.ns.map' property.
I was looking for the exactly same thing since migrating an old system to behave exactly the same.
I came up with the following Solution.
class SoapFaultEndpointInterceptor extends EndpointInterceptorAdapter
{
private static final Pattern SOAP_CODE_FAULT_SPLITTER = Pattern.compile(":");
#Override
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception
{
SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext.getResponse();
modifySoapFaultCode(soapResponse);
return super.handleFault(messageContext, endpoint);
}
private void modifySoapFaultCode(SaajSoapMessage soapResponse)
{
try {
SOAPMessage soapMessage = soapResponse.getSaajMessage();
SOAPBody body = soapMessage.getSOAPBody();
SOAPFault soapFault = body.getFault();
modifyFaultCodeIfPresent(soapFault);
} catch (SOAPException e) {
throw new SoapModifiyingException("Modifying faultcode did not work properly.", e);
}
}
private void modifyFaultCodeIfPresent(SOAPFault fault)
{
if (fault != null) {
String newFaultCode = cleanFaultCode(fault.getFaultCode());
fault.setFaultCode(newFaultCode);
}
}
private String cleanFaultCode(String oldFaultCode)
{
String[] cleanFaultCode = SOAP_CODE_FAULT_SPLITTER.split(oldFaultCode);
Assert.isTrue(cleanFaultCode.length == 2, "No proper faultcode provided!");
return cleanFaultCode[1].trim();
}
And by adding SoapFaultEndpointInterceptor to your Interceptor, it should work.
#EnableWs
#Configuration
public class SoapServerConfig extends WsConfigurerAdapter
{
#Override
public void addInterceptors(List<EndpointInterceptor> interceptors)
{
interceptors.add(new SoapFaultEndpointInterceptor());
}
}
I am trying to extract custom SOAP header using the chain-handler mechanism as below:
Webservice:
`#HandlerChain(file="handler-chain.xml")
public class CustomAPI extends SessionBeanBase {
#WebMethod
public GetBalanceResponse getBalances(
#WebParam(name="subscriptionId")long subscriptionId,
#WebParam(name="validityPeriodFromDt")Date validityPeriodFromDt,
#WebParam(name="validityPeriodToDt")Date validityPeriodToDt) throws APIException
{
try {
GetBalancesItem item = new GetBalancesItem(subscriptionId, validityPeriodFromDt, validityPeriodToDt);
final BalanceBusinessLogic api = (BalanceBusinessLogic)startCall(RSLogic.class, this, "getBalances");
BusinessLogicCallable<GetBalancesItem> t = new BusinessLogicCallable<GetBalancesItem>() {
public Response callBusinessLogic(GetBalancesItem getBalancesItem) throws CCSException, APIException {
Date validityPeriodFromDt = getBalancesItem.getValidityPeriodFromDt();
Date validityPeriodToDt = getBalancesItem.getValidityPeriodToDt();
long subscriptionId = getBalancesItem.getSubscriptionId();
return api.checkBalance(subscriptionId, validityPeriodFromDt, validityPeriodToDt);
}
};
return (GetBalanceResponse)callBusinessLogic(t, item);
} catch (Throwable e) {
// Handle exception (and rethrow it hence the need for return null)
handleExceptions(e);
return null;
}
}`
Handler-chain. xml as:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/javaee_web_services_metadata_handler_2_0.xsd">
<handler-chain>
<handler>
<handler-name>ApiSoapHandler</handler-name>
<handler-class>com.api.framework.ApiSoapHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
ApiSOAPhandlercode as:
public boolean handleMessage(SOAPMessageContext context) {
logger.debug("Inside ApiSoapHandler");
try {
SOAPMessage message = context.getMessage();
SOAPPart soapPart= message.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
if (soapEnvelope.getHeader() == null) {
soapEnvelope.addHeader();
}
// set the soap header
SOAPHeader latestSOAPHeader = soapHeader.get();
if (latestSOAPHeader != null) {
Iterator iterator = latestSOAPHeader.getChildElements();
while(iterator.hasNext()) {
SOAPHeaderElement soapHeaderElement = (SOAPHeaderElement)iterator.next();
soapEnvelope.getHeader().addChildElement(soapHeaderElement);
}
}
message.saveChanges();
System.out.println("header" + header.getAttribute("token"));
} catch (Exception e) {
logger.error("Error occurred while adding credentials to SOAP header.",
e);
}
return true;
}
The problem is that my header is fetched as null here . can anyone please suggest how to get the header here . For the reference , here is my sample SOAP request :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:bal="http://balance.api.ccs.cerillion.com/">
<soapenv:Header>
<token>187328364</token>
<soapenv:Header/>
<soapenv:Body>
<bal:getBalances>
<subscriptionId>664</subscriptionId>
</bal:getBalances>
</soapenv:Body>
</soapenv:Envelope>
While extracting token , am getting null in my code .
I have a problem with WS-Addresing in SOAP header. I succesfully imported classes from xsd file with configuration, but server require WS-Addressing attributes in soap header("wsa:action", "wsa:to"). Unfortunettly client service dont inject these attributes and server return http code 400 "Bad Request".
How can I automatically inject a proper SOAP header for requests?
I tried with #Addressing(enabled=true, required=true) annotation, but header was wrong for webservice
Configuration in Config.groovy
Service endpoint: https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc
Main xsd file: https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/wsdl/UslugaBIRzewnPubl.xsd
I use Grails 2.5.0 and plugin grails-cfx
Grails-cfx configuration in Config.groovy
birCompanyDataEndPoint {
wsdl = "wsdl/UslugaBIRzewnPubl.xsd"
namespace = "pl.truesoftware.crm.company.regon"
client = true
contentType = "application/soap+xml"
mtomEnabled = true
exsh = true
or = true
wsdlArgs = ['-autoNameResolution']
// outInterceptors = 'smartApiMetaOutInterceptor'
clientInterface = IUslugaBIRzewnPubl
serviceEndpointAddress = "https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc"
}
Example
Plain SOAP request from client service
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:DaneKomunikat xmlns="http://CIS/BIR/PUBL/2014/07/DataContract" xmlns:ns2="http://CIS/BIR/PUBL/2014/07" xmlns:ns3="http://CIS/BIR/2014/07" xmlns:ns4="http://schemas.microsoft.com/2003/10/Serialization/"/>
</soap:Body>
</soap:Envelope>
With using annotation #Addressing(enabled=true, required=true)
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<Action xmlns="http://www.w3.org/2005/08/addressing">http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DaneKomunikat</Action>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:f43e7c86-99dd-42fc-a626-ccbd44136682</MessageID>
<To xmlns="http://www.w3.org/2005/08/addressing">https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</To>
<ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
<Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</ReplyTo>
</soap:Header>
<soap:Body>
<ns2:DaneKomunikat xmlns="http://CIS/BIR/PUBL/2014/07/DataContract" xmlns:ns2="http://CIS/BIR/PUBL/2014/07" xmlns:ns3="http://CIS/BIR/2014/07" xmlns:ns4="http://schemas.microsoft.com/2003/10/Serialization/"/>
</soap:Body>
</soap:Envelope>
Expected
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://CIS/BIR/PUBL/2014/07">
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:To>https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</wsa:To>
<wsa:Action>http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DaneKomunikat</wsa:Action>
</soap:Header>
<soap:Body>
<ns:DaneKomunikat/>
</soap:Body>
</soap:Envelope>
Update with solution
Created two cfx interceptor. First convert soap addressing tags(Action, To) to acceptable format
public class BirSoapHeaderInterceptor extends AbstractSoapInterceptor
{
static String birSID = ""
public BirSoapHeaderInterceptor() {
super(Phase.PRE_PROTOCOL);
}
#Override
public void handleMessage(SoapMessage message) throws Fault
{
try
{
message.put("disable.outputstream.optimization", true)
List<Header> soapHeaders = message.getHeaders()
//----------------- copy values from old header
String wsaAction = ""
String wsaTo = ""
soapHeaders.each { tag ->
log.debug("Soap request header tag: ${tag.name} ${tag.dataBinding}")
String tagName = (tag.name as String)
def objectValue = tag.object?.value
if (!wsaAction && tagName.contains("Action"))
wsaAction = objectValue?.value
if (!wsaTo && tagName.contains("To"))
wsaTo = objectValue?.value
}
soapHeaders.clear()
//-----------------wsa:To
Header headTo = new Header(new QName("http://www.w3.org/2005/08/addressing", "To", "wsa"), wsaTo, new JAXBDataBinding(String.class))
soapHeaders.add(headTo)
//-----------------wsa:Action
Header headAction = new Header(new QName("http://www.w3.org/2005/08/addressing", "Action", "wsa"), wsaAction, new JAXBDataBinding(String.class))
soapHeaders.add(headAction)
message.put(Header.HEADER_LIST, soapHeaders)
//Session identyficator in HTTP Header
if(birSID.length())
{
Map<String, List<String>> outHeaders = (Map<String, List<String>>) message.get(Message.PROTOCOL_HEADERS)
outHeaders.put("sid", Arrays.asList(birSID));
message.put(Message.PROTOCOL_HEADERS, outHeaders);
}
} catch (SOAPException e)
{
log.error(e)
}
}
}
Second interceptor converts attributes 'xmlns:soap', 'xmlns:wsa', 'xmlns:soap' with acceptable namespaces
class BirSoapContextInterceptor implements SOAPHandler<SOAPMessageContext>
{
/*
Based on https://stackoverflow.com/questions/10678723/changing-jax-ws-default-xml-namespace-prefix
*/
public boolean handleMessage(final SOAPMessageContext context)
{
try
{
SOAPMessage soapMsg = context.getMessage();
SOAPEnvelope envelope = soapMsg.getSOAPPart().getEnvelope()
soapMsg.getSOAPPart().getEnvelope().removeAttributeNS("http://schemas.xmlsoap.org/soap/envelope/", "soap");
soapMsg.getSOAPPart().getEnvelope().removeAttributeNS("http://www.w3.org/2000/xmlns/", "soap");
soapMsg.getSOAPPart().getEnvelope().removeAttribute("xmlns:soap");
soapMsg.getSOAPPart().getEnvelope().removeNamespaceDeclaration("xmlns:soap")
envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://www.w3.org/2003/05/soap-envelope");
envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ns", "http://CIS/BIR/PUBL/2014/07");
soapMsg.getSOAPHeader().setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wsa", "http://www.w3.org/2005/08/addressing")
soapMsg.getSOAPHeader().setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://www.w3.org/2003/05/soap-envelope");
soapMsg.saveChanges()
context.setMessage(soapMsg)
} catch (SOAPException e)
{
e.printStackTrace();
}
return true;
}
#Override
boolean handleFault(SOAPMessageContext context) {
return false
}
#Override
void close(MessageContext context) {
log.debug("Closing...")
}
#Override
Set<QName> getHeaders() {
return null
}
}
I have developed a webservice in java using Metro RI( Along with an AuthenticationHandler), But when I am sending a SOAP request to the webservice, I am not able to get the SOAPHeader in the SOAPHandler.
Below is the SOAP Request which I am passing to the webservice.(I am using SOAP UI for this purpose)
`
<soapenv:Envelope xmlns:ser="http://server.webservice.bank/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-4" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>kshitij.jain</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Phone0144</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">jf97anyZJUpR216tw4GRIw==</wsse:Nonce>
<wsu:Created>2013-05-15T17:38:49.610Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<ser:getCreditCardTransaction>
<cardId>2</cardId>
<amt>109</amt>
<!--Optional:-->
<descr>test</descr>
</ser:getCreditCardTransaction>
</soapenv:Body>
</soapenv:Envelope>
`
Following is my code for webservice and Handler :
`
#WebService(serviceName = "getTransaction")
#HandlerChain(file = "ServerHandler.xml")
public class getTransaction {
#Inject
TransactionService tranService;
#Resource
private WebServiceContext wsContext;
#WebMethod(operationName = "getCreditCardTransaction")
public CreCardTranResponse getCreditCardTransaction(#WebParam(name = "cardId") int cardId, #WebParam(name = "amt") int amt, #WebParam(name = "descr") String descr) {
CreCardTranResponse res = new CreCardTranResponse();
tranService.addTransaction(amt, descr, "Debit", cardId);
res.setAmtDeducted(new Integer(amt).toString());
res.setCardID(new Integer(cardId).toString());
ReturnMessage ret = new ReturnMessage();
ret.setReturnCode("0");
ret.setReturnMessage("Successful");
res.setRetMessage(ret);
return res;
}
}
`
`
public class AuthenticationHandler implements SOAPHandler<SOAPMessageContext> {
private static Set<QName> headers;
static {
HashSet<QName> set = new HashSet<QName>();
set.add(new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security"));
headers = Collections.unmodifiableSet(set);
}
#Override
public Set<QName> getHeaders() {
return headers;
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
try {
handleSecurityMessage(context);
} catch (SOAPException ex) {
}
return true;
}
public boolean handleSecurityMessage(SOAPMessageContext context) throws SOAPException {
SOAPHeader soapHeader = context.getMessage().getSOAPHeader();
SOAPFault fault = SOAPFactory.newInstance().createFault();
if (soapHeader == null) {
fault.setFaultCode("failed");
fault.setFaultString("Soap header missing");
throw new SOAPFaultException(fault);
}
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
#Override
public void close(MessageContext context) {
}
}
`
Below is the serverHandler.xml
`
<?xml version="1.0" encoding="UTF-8"?>
<handler-config>
<handler-chain>
<handler-chain-name>AuthenticationHandlerChain</handler-chain-name>
<handler>
<handler-name>AuthenticationHandler</handler-name>
<handler-class>bank.webservice.security.AuthenticationHandler</handler-class>
</handler>
</handler-chain>
</handler-config>
`
I have already wasted 2 days on this, But After adding the header from SOAP UI also, code is showing header as null .
Is it the problem with SOAP UI or with the code?
I have a class that implements the SOAPHandler interface. The handleMessage is defined as:
public boolean handleMessage(SOAPMessageContext context) {
SOAPMessage msg = context.getMessage();
SOAPPart part = msg.getSOAPPart();
SOAPEnvelope envelope = part.getEnvelope();
// add namespaces
SOAPElement envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-
// add the header with additional elements
Name qname = envelope.createName("Security", "sse", "http://example.com/security.xsd");
element = envelope.addHeader().addChildElement(qname);
qname = envelope.createName("mustUnderstand");
element.addAttribute(qname, "1");
qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = envelope.getHeader().addHeaderElement(qname);
element.addTextNode("user1");
qname = envelope.createName("Password");
element = envelope.getHeader().addHeaderElement(qname);
element.addTextNode("1234");
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
This generates the following message:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<S:Header>
<sse:Security xmlns:sse="http://example.com/security.xsd" mustUnderstand="1"/>
<sse:UsernameToken xmlns:sse="http://example.com/user.xsd">user1</sse:UsernameToken>
</S:Header>
<S:Body>
....The rest of the transaction
</S:Body>
</S:Envelope>
The problem is I need to generate a message with the following format:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<sse:Security soapenv:mustUnderstand="1" xmlns:sse="http://example.com/security.xsd">
<sse:UsernameToken wsu:Id="UsernameToken-9993341" xmlns:wsu="http://example.com/user.xsd">
<sse:Username>user1</sse:Username>
<sse:Password Type="http://example.com/password#PasswordText">1234</sse:Password>
</sse:UsernameToken>
</sse:Security>
</soapenv:Header>
<soapenv:Body>
....The rest of the transaction
</soapenv:Body>
</soapenv:Envelope>
The "mustUnderstand" attribute doesn't have the soapenv prefix, the sse:Security tag is closed right away instead of having the other tags as children, and the UserName isn't properly formatted as
<sse:Username>user1</sse:Username>
. How can I format the message properly using the SOAPElement methods? The biggest thing I need to know is how to properly next the tags inside of the Security tag and how to have the username/password tags properly formatted.
I've tried different combinations of the addHeaderElement and addChildElement methods, but I can't get it formatted properly and the javadocs don't give enough detail about what they will generate.
This is taken from my working handler. Hope it works for you.
public static final String WSSE_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
public static final String PASSWORD_TEXT_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
public static final String WSSE_SECURITY_LNAME = "Security";
public static final String WSSE_NS_PREFIX = "wsse";
private String username;
private String password;
private boolean mustUnderstand = false;
public boolean handleMessage(SOAPMessageContext messageContext) {
Object bOutbound = messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (bOutbound == Boolean.TRUE) {
try {
if (username != null && username.length() != 0) {
addSecurityHeader(messageContext);
LOG.debug("Added security header");
} else {
LOG.debug("No username configured thus not adding a security header");
}
} catch (Exception e) {
LOG.error("Exception in handleMessage", e);
return false;
}
}
return true;
}
private void addSecurityHeader(SOAPMessageContext messageContext) throws SOAPException {
SOAPFactory sf = SOAPFactory.newInstance();
SOAPHeader header = messageContext.getMessage().getSOAPPart().getEnvelope().getHeader();
if (header == null) {
header = messageContext.getMessage().getSOAPPart().getEnvelope().addHeader();
}
Name securityName = sf.createName(WSSE_SECURITY_LNAME, WSSE_NS_PREFIX, WSSE_NS);
SOAPHeaderElement securityElem = header.addHeaderElement(securityName);
securityElem.setMustUnderstand(mustUnderstand);
Name usernameTokenName = sf.createName("UsernameToken", WSSE_NS_PREFIX, WSSE_NS);
SOAPElement usernameTokenMsgElem = sf.createElement(usernameTokenName);
Name usernameName = sf.createName("Username", WSSE_NS_PREFIX, WSSE_NS);
SOAPElement usernameMsgElem = sf.createElement(usernameName);
usernameMsgElem.addTextNode(username);
usernameTokenMsgElem.addChildElement(usernameMsgElem);
Name passwordName = sf.createName("Type", WSSE_NS_PREFIX, WSSE_NS);
SOAPElement passwordMsgElem = sf.createElement("Password", WSSE_NS_PREFIX, WSSE_NS);
passwordMsgElem.addAttribute(passwordName, PASSWORD_TEXT_TYPE);
passwordMsgElem.addTextNode(password);
usernameTokenMsgElem.addChildElement(passwordMsgElem);
securityElem.addChildElement(usernameTokenMsgElem);
}
Just posting my solution if someone is still wondering --
Name name = soapenv.createName("Security", "sse", "URL");
SOAPHeaderElement security = soapenv.getHeader().addHeaderElement(name);
security.setMustUnderstand(true);
SOAPElement usernameToken = security.addChildElement("UsernameToken", "sse");
SOAPElement username = usernameToken.addChildElement("Username", "sse");
username.addTextNode("TestUser");
SOAPElement password = usernameToken.addChildElement("Password", "sse");
password.addTextNode("TestPassword");
There's enough problems in this code that I'm thinking it's a troll, but heres a start:
The line :
element = envelope.addHeader().addChildElement(qname);
should read:
SOAPHeaderElement secHdrElement = envelope.addHeader().addHeaderElement(qname);
next, instead of:
qname = envelope.createName("mustUnderstand");
element.addAttribute(qname, "1");
probably:
secHdrElement.setMustUnderstand(true);
and
qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = envelope.getHeader().addHeaderElement(qname);
element.addTextNode("user1");
should be something like:
qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = secHdrElement.addHeaderElement(
envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd"));
and so on...