axis2 client NTLM authentication

12,060

Solution 1

HttpClient doesnt support NTLM v2 hence I use JCIFS library to return NTLM v1,2,3 message type as described in this website

http://devsac.blogspot.com/2010/10/supoprt-for-ntlmv2-with-apache.html

I just used the JCIFS_NTLMScheme.java file from the above website to register the auth scheme and it worked !!!!

Sample client:

List authSchema = new ArrayList();
AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, org.tempuri.JCIFS_NTLMScheme.class);
HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
auth.setUsername("");
auth.setPassword("");
auth.setDomain("");
auth.setHost("");
auth.setPort();
List authPrefs = new ArrayList(1);
authPrefs.add(AuthPolicy.NTLM);
auth.setAuthSchemes(authPrefs);
stub._getServiceClient().getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, auth); 

Solution 2

There is a problem with NTLM in AXIS2. It centres around the ntlm.setHost() method. The entry here is used as both WORKSTATION in the NTLM exchange and as Remote Host when AuthScope is created. This creates a Catch-22 situation where NTLM does not work using the HttpTransportProperties.Authenticator technique. You either get a "401 unauthorized" or you get a "No credentials found for < REALM>@HOST".

See https://issues.apache.org/jira/browse/AXIS2-4595

Peter

Solution 3

Based on the notes at this link NTLM issues with Axis2

Axis2 still uses old HTTPClient library and it seems that version does not support all versions(v1, v2 ) of NTLM. And also it was not trivial to switch the transport to HTTPClient v4.1

I gave up on Axis2 and used CXF instead.

The following link really us get past the Kerboros/NTLM issues

http://download.oracle.com/javase/6/docs/technotes/guides/net/http-auth.html

Solution 4

An alternative to JCIFS is to use the Apache HTTPComponents 4 NTLMScheme (which works with new NTLM) inside a custom Apache Commons HTTP AuthScheme:

public class BackportedNTLMScheme extends org.apache.http.impl.auth.NTLMScheme implements org.apache.commons.httpclient.auth.AuthScheme {

    @Override
    public String authenticate(final Credentials credentials, final HttpMethod method) throws AuthenticationException {
        org.apache.commons.httpclient.NTCredentials oldCredentials;
        try {
            oldCredentials = (org.apache.commons.httpclient.NTCredentials) credentials;
        } catch (final ClassCastException e) {
            throw new InvalidCredentialsException(
                    "Credentials cannot be used for NTLM authentication: " 
                    + credentials.getClass().getName());
        }
        final org.apache.http.auth.Credentials adaptedCredentials = new NTCredentials(oldCredentials.getUserName(), oldCredentials.getPassword(), oldCredentials.getHost(), oldCredentials.getDomain());

        try {
            final Header header = super.authenticate(adaptedCredentials, null);
            return header.getValue();
        } catch (final org.apache.http.auth.AuthenticationException e) {
            throw new AuthenticationException("AuthenticationException", e);
        }
    }

    @Override
    public void processChallenge(final String challenge) throws MalformedChallengeException {
        final String s = AuthChallengeParser.extractScheme(challenge);
        if (!s.equalsIgnoreCase(getSchemeName())) {
            throw new MalformedChallengeException("Invalid NTLM challenge: " + challenge);
        }
        int challengeIdx = challenge.indexOf(' ');
        final CharArrayBuffer challengeBuffer;
        if(challengeIdx != -1){
            challengeBuffer = new CharArrayBuffer(challenge.length());
            challengeBuffer.append(challenge);
        } else {
            challengeBuffer = new CharArrayBuffer(0);
            challengeIdx = 0;
        }
        try {
            parseChallenge(challengeBuffer, challengeIdx, challengeBuffer.length());
        } catch (final org.apache.http.auth.MalformedChallengeException e) {
            throw new MalformedChallengeException("MalformedChallengeException", e);
        }
    }

    @Override
    @Deprecated
    public String getID() {
        throw new RuntimeException("deprecated vc.bjn.catalyst.forecast.BackportedNTLMScheme.getID()");
    }


    @Override
    @Deprecated
    public String authenticate(final Credentials credentials, final String method, final String uri) throws AuthenticationException {
        throw new RuntimeException("deprecated vc.bjn.catalyst.forecast.BackportedNTLMScheme.authenticate(Credentials, String, String)");
    }
}

Usage

AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, BackportedNTLMScheme.class);

I tested this on IIS 7.5 on Windows Server 2008 R2.

Share:
12,060
Vijay Mathew
Author by

Vijay Mathew

Computer programmer.

Updated on June 04, 2022

Comments

  • Vijay Mathew
    Vijay Mathew almost 2 years

    I have an axis2 (v1.5.3) client that needs to do Kerberos/NTLM authentication with IIS. How can I do this? This is the code I have right now and it fails with 401 - unauthorized error:

    List<String> authScheme = new ArrayList<String>();
    authScheme.add(HttpTransportProperties.Authenticator.NTLM);
    HttpTransportProperties.Authenticator ntlm =
                     new HttpTransportProperties.Authenticator();
    ntlm.setAuthSchemes(authScheme);
    ntlm.setUsername("Administrator");
    ntlm.setPassword("password");
    ntlm.setHost("http://server/_vti_bin/someservice.asmx");
    ntlm.setPort(80);
    ntlm.setDomain("server_domain");
    Options options = webs._getServiceClient().getOptions();
    options.setProperty(HTTPConstants.AUTHENTICATE, ntlm);
    stub._getServiceClient().setOptions(options);  
    

    A client written in C# works fine with the same auth settings:

    CredentialCache myCache = new CredentialCache();            
    myCache.Add(new Uri(webs.Url), "NTLM", 
                new NetworkCredential("Administrator", "password", "server_domain"));
    stub.Credentials = myCache;