Four Stars

tESBConsumer creates 2 Username Tokens for Security Header

Hi, 

I'm using Talend DI 6.4.1 and I try to call a web service with the tESBConsumer component, which requires WS-Security. I activated "Use Authentication with Username Token" in the component. 

 

Talend generates the following request: 

 

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
	<soap:Header>
		<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
		soap:mustUnderstand="1">
			<wsu:Timestamp wsu:Id="TS-ee13dd41-295c-4312-bf14-591aef92f522">
				<wsu:Created>2018-03-21T11:19:15.236Z</wsu:Created>
				<wsu:Expires>2018-03-21T11:24:15.236Z</wsu:Expires>
			</wsu:Timestamp>
			<wsse:UsernameToken wsu:Id="UsernameToken-8787d266-3d73-4bf0-b851-173e3baf7dc2">
				<wsse:Username>xxxx</wsse:Username>
				<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">xxxx</wsse:Password>
				<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">DhH7/Td855EjxnIOMt3MWA==</wsse:Nonce>
				<wsu:Created>2018-03-21T11:19:15.242Z</wsu:Created>
			</wsse:UsernameToken>
			<wsse:UsernameToken wsu:Id="UsernameToken-11329e95-7124-42c9-b0f6-33aee4b32ac8">
				<wsse:Username>xxxx</wsse:Username>
				<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">xxxx</wsse:Password>
			</wsse:UsernameToken>
		</wsse:Security>
	</soap:Header>
	<soap:Body>
...
	</soap:Body>
</soap:Envelope>

SoapUI generates the same request except the second Username token with "PasswordText". I also checked the WSDL file and in the policy it only asks for Username token with "PasswordDigest". 

 

The service always response with "{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}InvalidSecurity|Er... on verifying message against security policy Error code:1025||||". 

 

Is there a possibility to tell Talend to only generate one Token?

 

Thanks. 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Fifteen Stars

Re: tESBConsumer creates 2 Username Tokens for Security Header

I believe I have experienced this issue before (with 6.2.1). Are you working with a Microsoft exposed SOAP service? It appears that Microsoft have bent the rules with SOAP standards (as they did with web browsers) and Talend does not work to those standards.

 

To get around this, I ended up using a tSOAP and building my own SOAP body as required in code. I saved the SOAP body with the XML document embedded into the globalMap and referenced the globalMap in the tSOAP "SOAP Message" field.

 

package routines;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;

import org.dom4j.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;


public class SoapHeaderHandler {

	public static String createSoapMessage(org.dom4j.Document document, String username, String password){
		String returnVal = "";
		
		MessageFactory messageFactory;
		
		try {
			messageFactory = MessageFactory.newInstance();
			
		SOAPMessage soapMessage = messageFactory.createMessage();

		// Retrieve different parts
		SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();

		// Two ways to extract body
		SOAPBody soapBody = soapEnvelope.getBody();
		soapBody = soapMessage.getSOAPBody();
		soapEnvelope.getHeader().detachNode();
	    SOAPHeader soapHeader = soapEnvelope.addHeader();

        SOAPElement security =
                soapHeader.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");



        SOAPElement usernameToken =
                security.addChildElement("UsernameToken", "wsse");
        usernameToken.addAttribute(new QName("xmlns:wsu"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

        SOAPElement soapUsername =
                usernameToken.addChildElement("Username", "wsse");
        soapUsername.addTextNode(username);

        SOAPElement soapPassword =
                usernameToken.addChildElement("Password", "wsse");
        soapPassword.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
       soapPassword.addTextNode(password);

   
       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
       factory.setNamespaceAware(true);
       DocumentBuilder builder = factory.newDocumentBuilder();
       org.w3c.dom.Document w3cDoc = builder.parse(new InputSource(new StringReader(document.asXML())));
       
       soapBody.addDocument(w3cDoc);
       
        //Print out the outbound SOAP message to System.out
        
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       soapMessage.writeTo(baos);
       
       returnVal = baos.toString("UTF-8");
       //System.out.println(returnVal);
		} catch (SOAPException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return returnVal;
	}

}

I call this by first preparing my payload document in a tXMLMap and then passing it to a tMap where I call the following code.....

routines.SoapHeaderHandler.createSoapMessage(((org.dom4j.Document)row1.payload.getDocument()), context.Username, context.Password) 

The String that is returned is then added to my tSOAP.

 

It is convoluted, but it works.

If you have access to Talend support I would raise this so that they can spend a bit more time with you if this is too convoluted.

 

Hope it helps

Rilhia Solutions
3 REPLIES
Fifteen Stars

Re: tESBConsumer creates 2 Username Tokens for Security Header

I believe I have experienced this issue before (with 6.2.1). Are you working with a Microsoft exposed SOAP service? It appears that Microsoft have bent the rules with SOAP standards (as they did with web browsers) and Talend does not work to those standards.

 

To get around this, I ended up using a tSOAP and building my own SOAP body as required in code. I saved the SOAP body with the XML document embedded into the globalMap and referenced the globalMap in the tSOAP "SOAP Message" field.

 

package routines;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;

import org.dom4j.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;


public class SoapHeaderHandler {

	public static String createSoapMessage(org.dom4j.Document document, String username, String password){
		String returnVal = "";
		
		MessageFactory messageFactory;
		
		try {
			messageFactory = MessageFactory.newInstance();
			
		SOAPMessage soapMessage = messageFactory.createMessage();

		// Retrieve different parts
		SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();

		// Two ways to extract body
		SOAPBody soapBody = soapEnvelope.getBody();
		soapBody = soapMessage.getSOAPBody();
		soapEnvelope.getHeader().detachNode();
	    SOAPHeader soapHeader = soapEnvelope.addHeader();

        SOAPElement security =
                soapHeader.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");



        SOAPElement usernameToken =
                security.addChildElement("UsernameToken", "wsse");
        usernameToken.addAttribute(new QName("xmlns:wsu"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

        SOAPElement soapUsername =
                usernameToken.addChildElement("Username", "wsse");
        soapUsername.addTextNode(username);

        SOAPElement soapPassword =
                usernameToken.addChildElement("Password", "wsse");
        soapPassword.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
       soapPassword.addTextNode(password);

   
       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
       factory.setNamespaceAware(true);
       DocumentBuilder builder = factory.newDocumentBuilder();
       org.w3c.dom.Document w3cDoc = builder.parse(new InputSource(new StringReader(document.asXML())));
       
       soapBody.addDocument(w3cDoc);
       
        //Print out the outbound SOAP message to System.out
        
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       soapMessage.writeTo(baos);
       
       returnVal = baos.toString("UTF-8");
       //System.out.println(returnVal);
		} catch (SOAPException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return returnVal;
	}

}

I call this by first preparing my payload document in a tXMLMap and then passing it to a tMap where I call the following code.....

routines.SoapHeaderHandler.createSoapMessage(((org.dom4j.Document)row1.payload.getDocument()), context.Username, context.Password) 

The String that is returned is then added to my tSOAP.

 

It is convoluted, but it works.

If you have access to Talend support I would raise this so that they can spend a bit more time with you if this is too convoluted.

 

Hope it helps

Rilhia Solutions
Four Stars

Re: tESBConsumer creates 2 Username Tokens for Security Header

Thanks I edited your solution to my needs and now it works!

 

Fifteen Stars

Re: tESBConsumer creates 2 Username Tokens for Security Header

No problem. I had a nightmare with this problem until I figured out how to resolve it. Glad I could help prevent you from losing so much time trying to resolve this :-)

Rilhia Solutions