Monday, October 30, 2017

How to consume NTLM (MSDynamics) authentication based SOAP services in JAVA using httpclient

I have a need to consume the Webservices published in MSDynamics applications.  This uses the Microsoft specific NTLM based authentication and authorization mechanism.  However to consume the SOAP services I did find any direct solution.  Below is the code that is working.  You have to change the credentials and the input SOAP message formation strings remaining all you can use as it is.

Note: Use the latest httpclient-4.2.3.jar or above ,  commons-codec-1.11  or above.  Few more other jars which you can take from Axis application.

CODE  ( TestCustomerRead.java )
============================

import java.io.InputStream;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;

public class TestCustomerRead {

static String HOST  = "120.142.157.189";
static int    PORT  = 81;
static String USER  = "yourusername";
static String PWD   = "slf#pwd";
static String DOMAIN    = "mcpdl";
static String PROTOCOL  = "http";
static String WSDL_PATH = "/MicrosoftDynamicsAXAif60/AXCustomerService/xppservice.svc?wsdl";
static String SERVICE_ENDPOINT = "/MicrosoftDynamicsAXAif60/AXCustomerService/xppservice.svc";

// soap action you can find in the WSDL at the action attribute of the operation you want to consume //
static String SOAP_ACTION    = "http://schemas.microsoft.com/dynamics/2008/01/services/CustomerService/read";

public static void main(String[] args) {

try {
CloseableHttpClient httpclient = HttpClientBuilder.create().build();
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY, new NTCredentials(USER, PWD, HOST, DOMAIN));
HttpHost target = new HttpHost(HOST, PORT , PROTOCOL);

HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);

System.out.println("authenticated started");

// Execute a cheap method first. This will trigger NTLM
// authentication  (optional )
HttpGet httpget = new HttpGet( WSDL_PATH );
CloseableHttpResponse response1 = httpclient.execute(target,
httpget, context);
try {
HttpEntity entity1 = response1.getEntity();
System.out.println("=====GET=======>>>>" + response1.toString());
} finally {
response1.close();
}

// Execute an expensive method next reusing the same context (and
// connection)
HttpPost httppost = new HttpPost( SERVICE_ENDPOINT );
httppost.setHeader("SOAPAction",SOAP_ACTION );
httppost.setHeader("Content-Type", "text/xml; charset=utf-8");
StringEntity stringEntity = new StringEntity(getReadRequestSOAP().toString(), "UTF-8");
stringEntity.setChunked(true);
httppost.setEntity(stringEntity);

CloseableHttpResponse response2 = httpclient.execute(target, httppost, context);
try {
HttpEntity entity2 = response2.getEntity();

if(response2.getStatusLine().getStatusCode()== 200){
System.out.println("=====POST=======>>>>HTTP Response Status :"
+ response2.getStatusLine().toString());

System.out.println("RESPONSE MESSAGE IS \n ===================="  );
InputStream in = entity2.getContent();
String body = IOUtils.toString(in, "UTF-8");
System.out.println(body);
System.out.println("\n ===================="  );

}else{
System.out.println("AUTHENTICATION ERROR WITH CODE " + response2.getStatusLine().toString());
}

} catch (Exception ex) {
ex.printStackTrace();
} finally {
response2.close();
System.out
.println("COMPLETED THE REQUEST/RESONSE.");
}

} catch (Exception ex) {
ex.printStackTrace();
}
}

  // replace the SOAP message with your request messages.
// change the the input values as per your request data

private static String getReadRequestSOAP() {
// Below just form the complete SOAP message as a string
String statusRequest = " "
+ "    "
+ "         "
+ "               mcpl"
+ "       
" + "   
" + "    "
+ "          "
+ "              "
+ "              "
+ "                "
+ "                      "
+ "                           AccountNum "
+ "                           C-1008 "
+ "                     
" + "               
" + "             
" + "             
" + "               
" + "             
" + "         
"; return statusRequest;
}

}

=====================END =============
References:

http://hc.apache.org/httpcomponents-client-ga/

https://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html

http://hc.apache.org/httpcomponents-client-4.5.x/ntlm.html


https://www.mkyong.com/java/apache-httpclient-examples/

https://rathinasaba.wordpress.com/2013/02/01/call-webservice-wsdl-based-using-apache-httpconnection/

https://stackoverflow.com/questions/12561503/how-to-call-a-soap-webservice-with-a-simple-string-xml-in-string-format