Follow Us on Twitter

Connecting to a NTLM Web Service using a Java Servlet

by Jos Nieuwenhuis on January 23, 2011 · 4 comments

Connecting to a NTLM web service can be troublesome. This blog post shows the source code of a servlet which converts HTTP calls into HTTPS calls with NTLM. The servlet takes care of the NTLM handshake.

For a customer I needed to create a BPEL process which needed information from a web service that uses NTLM. There are many ways to solve this problem. My colleague used an Authenticator: JAX-WS web service proxy client and HTTP authentication. I followed a different approach. I used the Apache HttpComponents libraries. The idea is to call a servlet as if it is the actual web service. It can be used from any application: e.g. BPEL process or soapUI. The application can be deployed on any servlet container, e.g. Apache Tomcat or OC4J.

NTLM Serlvlet

So, what is NTLM? NTLM is a Microsoft authentication protocol. Sometimes this protocol is used by applications delevoped using the Microsoft .Net Framework. The protocol involves a handshake in several steps. NTLM is a proprietary protocol, but it is fairly well documented. How to implement NTLM in a Java client? The answer is Apache HttpComponents. The latest version of Apache HttpComponents (version 4.1 GA) has full support for NTLMv1, NTLMv2, and NTLM2 Session authentication.

Since SOAP usually means sending XML over HTTP Post a Servlet can be used to handle these requests. There is no need to modify the contents of the HTTP Post Message. When handling a SOAP request, just remember to copy the HTTP Headers.

The servlet is part of a web application which contains only one class: NTLMProxyServlet. The libraries of Apache HttpComponents (version 4.1 GA) should be included in the war file. Do not forget to map an URL to the servlet in the deployment descriptor (web.xml).

The code of the doPost method of the class NTLMProxyServlet (implements HttpServlet) is shown below. Please replace the hardcoded values for host, domain, user, url, password:

protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    response.setCharacterEncoding("utf-8");
    PrintWriter out = response.getWriter();
    if(httpclient == null){
        httpclient = new DefaultHttpClient();
        httpclient.getAuthSchemes().register(
                "NTLM", new NTLMSchemeFactory());
        httpclient.getCredentialsProvider().setCredentials(
                new AuthScope("host", 443, "domain"),
                new NTCredentials("user", "password", "host", "domain"));
        httpclient.getParams().setParameter(
                CoreProtocolPNames.USE_EXPECT_CONTINUE, Boolean.FALSE);
        httpclient.getParams().setParameter(
                CoreProtocolPNames.PROTOCOL_VERSION,
                HttpVersion.HTTP_1_1);
        httpclient.getParams().setParameter(
                CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8");
    }
    HttpPost httppost = new HttpPost(
            "https://host/webservices/getdata.asmx");
    InputStream in = null;
    try {
        in = request.getInputStream();
        Writer writer = new StringWriter();
        char[] buffer = new char[1024];
        Reader reader = new BufferedReader(
                new InputStreamReader(in, "UTF-8"));
        int n;
        while ((n = reader.read(buffer)) != -1) {
            writer.write(buffer, 0, n);
        }
        httppost.setEntity(new StringEntity(writer.toString()));
        Enumeration headernames = request.getHeaderNames();
        while (headernames.hasMoreElements()) {
            String headerName = (String) headernames.nextElement();
            String headerValue = request.getHeader(headerName);
            httppost.setHeader(headerName, headerValue);
        }
        Header h1 = httppost.getFirstHeader(HTTP.CONTENT_LEN);
        if (h1 != null) {
            httppost.removeHeader(h1);
        }
        Header h2 = httppost.getFirstHeader(HTTP.TARGET_HOST);
        if (h2 != null) {
            httppost.removeHeader(h2);
        }
        httppost.setHeader(HTTP.TARGET_HOST, "host");
        HttpResponse httpresponse = httpclient.execute(
                new HttpHost("host", 443, "https"),
                httppost,
                new BasicHttpContext());
        HttpEntity output = httpresponse.getEntity();
        Header[] headers = httpresponse.getAllHeaders();
        for (Header header : headers) {
            if (!header.getName().equals(HTTP.CONTENT_LEN)) {
                response.setHeader(header.getName(),
                        header.getValue());
            }
        }
        if (output != null) {
            out.write(EntityUtils.toString(output));
        }
    } catch (Exception e) {
        e.printStackTrace(out);
    } finally {
        in.close();
        out.flush();
        out.close();
    }
}
private DefaultHttpClient httpclient = null;

If the target server uses self-signed SSL certificates you might want to apply the code in Avoiding the “javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated” with HttpClient.

In order to use use the servlet make a local copy of the WSDL of the target web service and change the port address into the URL of the servlet, e.g.:

<wsdl:definitions>
  [...]
  <wsdl:service name="TargetWS">
    <wsdl:port name="TargetWSSoap12" binding="tns:TargetWSSoap12">
      <soap12:address location="http://localhost:8080/NTLMProxyApp/NTLMProxyServlet" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Use this modified copy of the WSDL in your BPEL process of SoapUI project.

Connecting to a NTLM Web Service using a Java Servlet, 4.2 out of 5 based on 5 ratings
Ratings:
VN:F [1.9.22_1171]
Rating: 4.2/5 (5 votes cast)

4 comments on “Connecting to a NTLM Web Service using a Java Servlet

  1. Jorge Cavaleiro on said:

    Hi Jos,

    Congrats for the fantastic solution approach!

    I’m facing a similar situation, but the machine where I’m running the BPEL process it’s placed on a network with a Proxy Server that uses NTLM Authentication.

    Resuming, I need to authenticate the machine in the Proxy and then dispatch the HTTP Post message with the WS invocation to the Proxy, to be forwarded to the WS host machine (this WS host machine doesn’t have any kind of authentication).

    Looking to this cenario, I have 2 questions:

    1.) Has this approach the hability to do the NTLM authentication against the proxy and then dispatch the WS invocation message to the proxy?

    2.) Could you help me to understand the meaning of the multiple “host” values on the code? I realized that the “host” on the NTCredentials refers to the local machine where the servlet is running. Are all others host values refering to the destination machine (the WS host)?

    Best Regards,
    Jorge Cavaleiro

    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
    • Hi Jorge,

      1) I do not have experience with proxy servers. I assume you can regard the proxy server as a target host, even though the service is delegated to a WS on a different host.
      2) The host variable mentioned in the servlet source code is the the host name (or IP address) of the target server (the server being called from the servlet). The host name in the local copy of the wsdl file (included within the BPEL component, or loaded in SoapUI) is the host name of the server on which the servlet is deployed.

      VN:F [1.9.22_1171]
      Rating: 0 (from 0 votes)
      • Jorge Cavaleiro on said:

        Hi Jos,

        Thank you for your fast anwser.
        I’ll try the approach with the Proxy server acting as a target host.

        If it works I’ll let you know.

        Regards,
        Jorge Cavaleiro

        VA:F [1.9.22_1171]
        Rating: 0 (from 0 votes)
  2. Could you kindly let me know do I have to create a SOAP request and post it to this Proxy servlet

    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)

Leave a Reply

Your email address will not be published. Required fields are marked *

*

* Copy This Password *

* Type Or Paste Password Here *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 

Previous post:

Next post:

About Whitehorses
Company profile
Services
Technology

Whitehorses website

Home page
Whitebooks
Jobs

Follow us
Blog post RSS
Comment RSS
Twitter