tESBConsumer creates 2 Username Tokens for Security Header

Five 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. 

 


Accepted Solutions
Community Manager

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


All Replies
Community Manager

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

Five Stars

Re: tESBConsumer creates 2 Username Tokens for Security Header

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

 

Community Manager

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 :-)

2019 GARNER MAGIC QUADRANT FOR DATA INTEGRATION TOOL

Talend named a Leader.

Get your copy

OPEN STUDIO FOR DATA INTEGRATION

Kickstart your first data integration and ETL projects.

Download now

What’s New for Talend Summer ’19

Watch the recorded webinar!

Watch Now

An API-First Approach to Modernizing Applications

Learn how to use an API-First Approach to Modernize your Applications

Watch Now

Talend API Designer – Technical Overview

Take a look at this technical overview video of Talend API Designer

Watch Now

Getting Started with APIs

Find out how to get started with APIs

Read