Why is my JAX-WS handler updating the same namespace for each item?

I wrote a JAX-WS handler to add the WS-Security header to my outgoing SOAP client messages:

package com.soap.client; import javax.xml.namespace.QName; import javax.xml.soap.Name; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPFactory; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; public class ClientHeaderHandler implements SOAPHandler<SOAPMessageContext> { private static final String WSSECURITY_PREFIX = "wsse"; private static final String WSSECURITY_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; private static final String PASSWORD_TEXT_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"; /** * {@inheritDoc} * @see javax.xml.ws.handler.Handler#handleMessage(javax.xml.ws.handler.MessageContext) */ @Override public boolean handleMessage(final SOAPMessageContext context) { boolean outbound = false; outbound = (Boolean) context.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (outbound) { try { addSecurityHeader(context); } catch (SOAPException e) { // do nothing } } return true; } private void addSecurityHeader(final SOAPMessageContext context) throws SOAPException { SOAPFactory sf = SOAPFactory.newInstance(); SOAPElement securityElem = sf.createElement("Security", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE); SOAPElement tokenElem = sf.createElement("UsernameToken", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE); SOAPElement usernameElem = sf.createElement("Username", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE); usernameElem.addTextNode("myusername"); tokenElem.addChildElement(usernameElem); Name passwordTypeName = sf.createName("Type", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE); SOAPElement passwordElem = sf.createElement("Password", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE); passwordElem.addAttribute(passwordTypeName, PASSWORD_TEXT_TYPE); passwordElem.addTextNode("mypassword"); tokenElem.addChildElement(passwordElem); securityElem.addChildElement(tokenElem); context.getMessage().getSOAPPart().getEnvelope().addHeader().addChildElement(securityElem); } } 

It basically works; however, the namespace and WS-Security prefix are re-declared for each element in which they are used ( xmlns: wsse = http: // ... ):

 <?xml version='1.0' encoding='UTF-8'?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:Username xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">myusername</wsse:Username> <wsse:Password wsse:Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">mypassword</wsse:Password> </wsse:UsernameToken> </wsse:Security> </S:Header> <S:Body> <MyBody/> </S:Body> </S:Envelope> 

I tried various combinations of QNames, Names, etc., but I can not do this work. What do I need to change so that the WS-Security namespace is declared only in the topmost security element?


UPDATE: The gpeche suggestion below worked for me. Moving from creating an element using SOAPFactory, adding it through addChildElement to create it through addChildElement:

 private void addSecurityHeader(final SOAPMessageContext context) throws SOAPException { SOAPFactory sf = SOAPFactory.newInstance(); SOAPElement securityElem = context.getMessage().getSOAPPart().getEnvelope().addHeader().addChildElement("Security", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE); SOAPElement tokenElem = securityElem.addChildElement("UsernameToken", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE); SOAPElement usernameElem = tokenElem.addChildElement("Username", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE); usernameElem.addTextNode("myusername"); Name passwordTypeName = sf.createName("Type", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE); SOAPElement passwordElem = tokenElem.addChildElement("Password", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE); passwordElem.addAttribute(passwordTypeName, PASSWORD_TEXT_TYPE); passwordElem.addTextNode("mypassword"); } 

generates much cleaner XML:

 <?xml version='1.0' encoding='UTF-8'?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>myusername</wsse:Username> <wsse:Password wsse:Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">mypassword</wsse:Password> </wsse:UsernameToken> </wsse:Security> </S:Header> <S:Body> <MyBody/> </S:Body> </S:Envelope> 
+4
source share
1 answer

I had the same problem, and the only way I saw this was to restore the XML tree of the node to node:

  • get the link to the node in which you want to set the namespace
  • Attach a child to its parent with the desired prefix, name, attributes, and namespaces.
  • recursively copy descendants to a new child, adapting prefixes and namespaces
  • when you are done, detach the original node

However, I keep thinking that there should be an easier way ...

UPDATE:

Good. I think I see what the problem is: you are creating all SOAPElement directly from SOAPFactory . At the time of creating SOAPElement there is no parent set, so they cannot inherit the namespaces that you specified from anyone, and decided to write the namespace declaration themselves. Once they have been created, they will not check the time append() / setParent() if they can remove any declaration.

Can you try to create only the outermost element from SOAPFactory and then create the rest via SOAPElement.addChildElement() ?

+3
source

Source: https://habr.com/ru/post/1435136/


All Articles