11

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.

Community
  • 1
  • 1
Yanick
  • 151
  • 1
  • 1
  • 8
  • 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 00: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 05:07

5 Answers5

4

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.

Yanick
  • 151
  • 1
  • 1
  • 8
3

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() ) ;
        }
    });
3

Correct is this:

Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(
                    "DOMAIN\\user",
                    "password".toCharArray() ) ;
        }
    });
berk76
  • 39
  • 1
2

This issue was resolved in JDK 9-ea with http://bugs.java.com/view_bug.do?bug_id=7150092 and the fix was back-ported to JDK 8u40 also with the http://bugs.java.com/view_bug.do?bug_id=8049690

Pallavi Sonal
  • 3,661
  • 1
  • 15
  • 19
0

One more possible cause for this error: domain user is blocked

Scheme:ntlm
Scheme:ntlm
java.net.ProtocolException: Server redirected too many  times (20)

I had the same error after I accidentally blocked my domain user, when tried to login with incorrect password more than it allowed by domain policy.

Aleksey Timohin
  • 591
  • 1
  • 9
  • 15