Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am trying to open an http connection to an url protected with the NTLM authentication scheme. This code has been working correctly for 2 year when we were on Java 6.I wrote a small java program which access that particular url to make the test case as simple as possible.

The problem is that I am unable to make the program work on linux and when using versions of the JDK 7. Java tries 20 times to access the URL and then I get an error telling me that the server redirected too many times. It works fine with linux and JDK 6, and in windows 7 with JDK 6 or 7.

I checked and tried the solution listed here (and many others) : Getting "java.net.ProtocolException: Server redirected too many times" Error. It didn't work. I also have to add that when accessing the url from a browser, I can see that there are no cookies involved.

Here is the exact detail of the os/java versions that I have tried :

Success:

  • Windows 7: Java(TM) SE Runtime Environment (build 1.7.0_15-b03) (64 bit)
  • Windows 7: Java(TM) SE Runtime Environment (build 1.7.0_10-b18) (64 bit)
  • Windows 7: Java(TM) SE Runtime Environment (build 1.6.0_33-b04) (64 bit)
  • Redhat enterprise linux 6.4: Java(TM) SE Runtime Environment (build 1.6.0_33-b04) (64 bit)

Fail:

  • Redhat enterprise linux 6.4: Java(TM) SE Runtime Environment (build 1.7.0-b147) (64 bit)
  • Redhat enterprise linux 6.4: Java(TM) SE Runtime Environment (build 1.7.0_05-b06) (64 bit)
  • Redhat enterprise linux 6.4: Java(TM) SE Runtime Environment (build 1.7.0_13-b20) (64 bit)
  • Redhat enterprise linux 6.4: Java(TM) SE Runtime Environment (build 1.7.0_15-b03) (64 bit)

When the program works, I see the authentication methods that were used and the document that I am trying to download as the output:

Scheme:Negotiate
Scheme:ntlm
.... document content ....
Done

When it fails, I have the following output :

Scheme:Negotiate
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
java.net.ProtocolException: Server redirected too many  times (20)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1635)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
        at TestWs.testWs(TestWs.java:67)
        at TestWs.main(TestWs.java:20)

Here is the source code of the program:

package com.test;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;

public class TestWs {

    public static void main(String[] args) throws Exception {
        new TestWs().testWs();
    }

    public void testWs() {
        try {
            CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
            Authenticator.setDefault(new MyAuthenticator("username", "password"));

            URL url = new URL("https://someurlprotectedbyntlmauthentication.com");
            URLConnection connection = url.openConnection();
            InputStream is = connection.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            while (true) {
                String s = br.readLine();
                if (s == null)
                    break;
                System.out.println(s);
            }
            System.out.println("Done");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

class MyAuthenticator extends Authenticator {
    private String httpUsername;
    private String httpPassword;

    public MyAuthenticator(String httpUsername, String httpPassword) {
        this.httpUsername = httpUsername;
        this.httpPassword = httpPassword;
    }

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        System.out.println("Scheme:" + getRequestingScheme());
        return new PasswordAuthentication(httpUsername, httpPassword.toCharArray());
    }
}

Any help would be greatly appreciated.

UPDATE:

After some more investigation, I found that the authentication works if I use a domain user, but not if I use a local user.

This code from the JDK 7 causes me troubles (class com.sun.security.ntlm.Client) :

public byte[] type3(byte[] type2, byte[] nonce) throws NTLMException {
if (type2 == null || (v != Version.NTLM && nonce == null)) {
throw new NullPointerException("type2 and nonce cannot be null");
}
debug("NTLM Client: Type 2 received\n");
debug(type2);
Reader r = new Reader(type2);
byte[] challenge = r.readBytes(24, 8);
int inputFlags = r.readInt(20);
boolean unicode = (inputFlags & 1) == 1;
String domainFromServer = r.readSecurityBuffer(12, unicode);
if (domainFromServer != null) {
domain = domainFromServer;
}

So, since the server is enroled in a domain, it sends back to the client it's domain as part of the NTLM protocol. Java replaces the domain that I'm trying to force by the variable "domainFromServer" everytime and it fails since the user exists on the server and not on the server's domain.

I don't know exactly what to do with that.

share|improve this question
 
what java 7 release are you using? I have some issues when working with https or authentication or security. An application I develop just worked with java 1.7_02 (Java 7.2) but when I used latest releases it didn't work anymore. There are some modifications that Oracle made in the latest releases specially in security policies. Try with an old release of the java 7 like the 1.7_02. –  Marcelo Tataje Feb 27 '13 at 23:26
 
I just tried it with the Java jdk version 1.7.0_02 64 bit for linux, and it didn't work, same result. –  Yanick Feb 28 '13 at 0:02
 
Also bogus 1.7.0_25-b15 for linux (64 bit) –  Carlo Pellegrini Jul 25 '13 at 12:15
 
tried with 1.7.0_40 - 64bit fail on linux - 32bit fail on solaris - 64bit success in windows7 –  Patrick Roumanoff Oct 15 '13 at 5:07
add comment

3 Answers

up vote 3 down vote accepted

I changed code in the Client.java class, and recompiled it along with the rest of the com.sun.security.ntlm package, then I created a jar called rt_fix.jar which contains the classes of that particular package. Then I used a java startup option to force it to load my jar before the internal rt.jar.

-Xbootclasspath/p:/path_to_jar/rt_fix.jar

I don't like this solution, but it worked.

Here is the code I changed in Client.java, in the method type3:

Before :

    if (domainFromServer != null) {
        domain = domainFromServer;
    }

After :

    if (domainFromServer != null) {
        //domain = domainFromServer;
    }

It stops Java from altering the domain I try to authenticate to with the one recieved from the server when sending the 3rd part of the NTLM authentication. The domain I was trying to authenticate to is in fact the name of the server because the user accounts are local.

share|improve this answer
 
You are a hero! thanks for this answer. –  Patrick Roumanoff Oct 15 '13 at 5:05
add comment

I had the same problem and solved it just by specifying the user name with the domain included in it:

    Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(
                    System.getProperty("DOMAIN\\user"),
                    System.getProperty("password").toCharArray() ) ;
        }
    });
share|improve this answer
add comment

Correct is this:

Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(
                    "DOMAIN\\user",
                    "password".toCharArray() ) ;
        }
    });
share|improve this answer
 
Explain why this works. –  Bleeding Fingers Jan 27 at 16:59
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.