all bits considered data to information to knowledge

29Sep/118

NTLM authentication with JMeter (sort of)

I have been using JMeter for quite some time now, and consider it to be an exteremely useful tool for all kinds of testing - especially web apps. It is not as polished as some commercial apps out there but by virtue of being an open source (and free!) it proved to be quite adequate for my team. Until we bumped our heads againtst NTLM authentication required by Sharepoint 2007 server.
Following the documentation  [HTTP Authorization Manager] was added and configured all the properties as described in the documentation. Yet no matter what we've tried, we were always getting 401 response - "Not authorized"; quick Internet search confirmed that I am not the only one struggling with this problem yet somehow solutions proposed did not work in my particular situation.

Digging into the source code (gotta love open source!) I've found that it fails NTLN challenge/response hoops (see this link for a very detailed explanation on how NTLM works), and then the following information posted on Apache Foundation site regarding use of NTLM with version 4.1.2 HTTP Components (used by the JMeter 2.5 version we are using)
Turns out that "there are still known compatibility issues with newer Microsoft products as the default NTLM engine implementation is still relatively new"... and the maintainer of the code put together a quick workaround to show how to use "more established and mature NTLM engine developed by Samba project."

The article does a great jobs showing details of implementation (along with the reasons why it is not part of HTTPClient library) but stops short of providing a working example, which is the purpose of this post.

Disclaimer: this is but a quick'n'dirty proof of concept (hardcoded values, console outputs, no unit tests or logging etc);   the sole intention of this code is to illustrate the concept.

The project contains two source packages, one for NTLMEngine and NTLMSchemeFactory  interfaces, and one - NTLM_ping - providing the main executable which imports JCIFSEngine.NTLMSchemeFactory.

The structure of the project (including depensdency JAR(s)) is shown on the picture below

 

 

 

 

 

 

 

 

 

and here are the results of successful execution


 

 

Finally, the source code for NTLM_ping.java ( the contents of the JCIFSEngine.java and NTLMSchemeFactory files are provided at the Apache Foundation post I've mentioned above).

------------------------------------------------------------------------------------------------

package NTLM_ping;

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.HttpResponse;
import org.apache.http.client.params.CookiePolicy;

import JCIFSEngine.NTLMSchemeFactory;

public class NTLM_ping {
 public NTLM_ping() {
     super();
     }

 public static void main(String[] args) throws Exception {

        DefaultHttpClient httpclient = new DefaultHttpClient();
        httpclient.getAuthSchemes().register("ntlm", new NTLMSchemeFactory());

        //add credentials
        httpclient.getCredentialsProvider().setCredentials(
            new AuthScope("host", -1),
            new NTCredentials(
                      "user"
                    , "password"
                    , "host"
                    , "domain"));

        HttpGet httpget = new HttpGet("http://<url>");
        //ignore cookies
        httpget.getParams().setParameter("http.protocol.cookie-policy", CookiePolicy.IGNORE_COOKIES);
     try {
     // execute the GET
            HttpResponse status = httpclient.execute(httpget);
            System.out.println(status.getProtocolVersion());
            System.out.println(status.getStatusLine().getStatusCode());
            System.out.println(status.getStatusLine().getReasonPhrase());
            System.out.println(status.getStatusLine().toString());
     } finally {
     // release any resources
        }
    }
}

------------------------------------------------------------------------------------------

It would be relatively simple to wrap this code as a custom element/sampler for JMeter though one would have to pay attention to licensing issues (JMeter is licensed under Apache licennse, while JCIFS Samba libraries are under LGPL)

A very detailed tutorial by Mike Stover and Peter Lin on extending JMeter w/plugins can be found at Jakarta website.

Comments (8) Trackbacks (0)
  1. Hi,
    I was running into the same issue as you did with SP2007 and I also came across the Samba JCIFS project. But since I’m not really a Java expert I did not know how to implement this into my JMeter script.
    Can you give an example how your JMeter script now works?

    The workaround I used for running JMeter scripts on SP2007, was by using the cntlm proxy

    Kind Regards,

    Sander

  2. Hi,
    The JCIFS library can be used to implement your very own JMeter sampler so it goes beyond scripting JMeter itself. The main reason it is not implemented by the JMeter developers is licensing conflict (Apache vs. LGPL).
    The code I posted here does not require JMeter, it can be used as a stand-alone executable; with but a minor modification one could make it to accept command line params (“user”, “password” , “host” , “domain” and URL). The wget/cntlm utilities are acceptable workarounds along the same lines..

  3. Hi Alex

    I’m also facing the same issue in SP 2007, could you please help me if want this to get it working in Jmeter, want steps to be done.

    regards

    Kumar

  4. Kumar,
    To incorporate this functionality into JMeter you would have to write your very own sampler. The code I posted in this blog would be a good start; the details on creating plugins for JMeter can be found on Jakarta site ( http://jakarta.apache.org/jmeter/extending/jmeter_tutorial.pdf ).

    I am running JMeter as part of continuous integration process automation (with Hudson CI and a number of plugins, all within Software Factory framework), and there are workarounds that do not involve coding your own JMeter samplers (say, enabling basic authentication on Sharepoint server just for the testing, or running the above code as a separate executable..)

  5. Alex Thanks for your inpurs, will try as suggested

  6. Hi

    I have tried your code but when the first 401 response is received the log reports that “[DEBUG] DefaultHttpClient – Credentials not found” and the authentication then stops. I have been using the JARs from Jmeter v2.6 and jcifis-1.3.17.

    Any idea what I am doing wrong!

    [DEBUG] DefaultClientConnection – Receiving response: HTTP/1.1 401 Unauthorized
    [DEBUG] headers – << HTTP/1.1 401 Unauthorized
    [DEBUG] headers – << Server: Microsoft-IIS/7.5
    [DEBUG] headers – << WWW-Authenticate: NTLM
    [DEBUG] headers – << X-Powered-By: ASP.NET
    [DEBUG] headers – << MicrosoftSharePointTeamServices: 12.0.0.6545
    [DEBUG] headers – << Date: Wed, 27 Jun 2012 16:33:26 GMT
    [DEBUG] headers – << Content-Length: 0
    [DEBUG] DefaultHttpClient – Connection can be kept alive indefinitely
    [DEBUG] DefaultHttpClient – Target requested authentication
    [DEBUG] DefaultTargetAuthenticationHandler – Authentication schemes in the order of preference: [negotiate, NTLM, Digest, Basic]
    [DEBUG] DefaultTargetAuthenticationHandler – Challenge for negotiate authentication scheme not available
    [DEBUG] DefaultTargetAuthenticationHandler – NTLM authentication scheme selected
    [DEBUG] DefaultHttpClient – Authorization challenge processed
    [DEBUG] DefaultHttpClient – Authentication scope: NTLM @mysite.mycompany.com:80
    [DEBUG] DefaultHttpClient – Credentials not found

  7. Peter,
    My guess is that AuthScope might be wrong for your environment.
    Try this:
    AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT)

    -alex

  8. Thanks Alex that helped..

    Now I can see after the client received the first 401 message it is not returning a NLTM challange. Also there is an ERROR in the debug trace which is worrying.

    [DEBUG] DefaultHttpClient – Connection can be kept alive indefinitely
    [DEBUG] DefaultHttpClient – Target requested authentication
    [DEBUG] DefaultTargetAuthenticationHandler – Authentication schemes in the order
    of preference: [negotiate, NTLM, Digest, Basic]
    [DEBUG] DefaultTargetAuthenticationHandler – negotiate authentication scheme sel
    ected
    [DEBUG] NegotiateScheme – Received challenge ” from the auth server
    [DEBUG] DefaultHttpClient – Authorization challenge processed
    [DEBUG] DefaultHttpClient – Authentication scope: NEGOTIATE @www.myserver.com:80
    [DEBUG] DefaultHttpClient – Found credentials
    [DEBUG] wire – <> “GET /clickschedulewebclient/default.aspx HTTP/1.1[\r][\n]”
    [DEBUG] wire – >> “Host: http://www.myserver.com[\r][\n]”
    [DEBUG] wire – >> “Connection: Keep-Alive[\r][\n]”
    [DEBUG] wire – >> “User-Agent: Apache-HttpClient/4.1.2 (java 1.5)[\r][\n]”
    [DEBUG] wire – >> “[\r][\n]”


Leave a comment

No trackbacks yet.