我正在尝试打开与NTLM身份验证方案保护的网址的http连接。当我们使用Java 6时,这段代码已经正常运行了2年。我编写了一个小型java程序,它访问该特定URL以使测试用例尽可能简单。
问题是我无法使程序在linux上工作,并且在使用JDK 7的版本时.Java会尝试20次访问URL,然后我收到错误,告诉我服务器重定向次数太多。它适用于linux和JDK 6,以及带有JDK 6或7的Windows 7。
我检查并尝试了此处列出的解决方案(和许多其他人):Getting "java.net.ProtocolException: Server redirected too many times" Error。它没用。我还要补充一点,当从浏览器访问URL时,我可以看到没有涉及cookie。
以下是我尝试过的os / java版本的确切细节:
成功:
故障:
当程序运行时,我会看到使用的身份验证方法以及我尝试下载的文档作为输出:
Scheme:Negotiate
Scheme:ntlm
.... document content ....
Done
当它失败时,我有以下输出:
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)
以下是该计划的源代码:
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());
}
}
非常感谢任何帮助。
更新
经过一些调查后,我发现如果我使用域用户,身份验证可以正常工作,但如果我使用本地用户则不行。
来自JDK 7的这段代码给我带来了麻烦(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;
}
因此,由于服务器在域中被加入,它将作为NTLM协议的一部分发送回客户端。 Java每次都会替换我试图通过变量“domainFromServer”强制执行的域,并且由于用户存在于服务器上而不是服务器域上,因此它会失败。
我不知道该怎么做。
答案 0 :(得分:4)
我更改了Client.java类中的代码,并将其与com.sun.security.ntlm包的其余部分一起重新编译,然后创建了一个名为rt_fix.jar的jar,其中包含该特定包的类。然后我使用java启动选项强制它在内部rt.jar之前加载我的jar。
-Xbootclasspath / P:/path_to_jar/rt_fix.jar
我不喜欢这个解决方案,但它确实有效。
以下是我在Client.java中更改的代码,方法类型为3:
之前:
if (domainFromServer != null) {
domain = domainFromServer;
}
之后:
if (domainFromServer != null) {
//domain = domainFromServer;
}
它阻止Java在发送NTLM身份验证的第3部分时,使用从服务器收到的域更改我尝试进行身份验证的域。我尝试进行身份验证的域实际上是服务器的名称,因为用户帐户是本地的。
答案 1 :(得分:3)
我遇到了同样的问题,只是通过指定包含在其中的域的用户名来解决它:
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
System.getProperty("DOMAIN\\user"),
System.getProperty("password").toCharArray() ) ;
}
});
答案 2 :(得分:3)
正确就是这样:
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
"DOMAIN\\user",
"password".toCharArray() ) ;
}
});
答案 3 :(得分:2)
使用http://bugs.java.com/view_bug.do?bug_id=7150092在JDK 9-ea中解决了此问题,并且使用http://bugs.java.com/view_bug.do?bug_id=8049690
将修复程序反向移植到JDK 8u40答案 4 :(得分:0)
此错误的另一个可能原因:域用户被阻止
Scheme:ntlm
Scheme:ntlm
java.net.ProtocolException: Server redirected too many times (20)
我不小心阻止了域用户,但尝试使用错误密码登录的次数超过了域策略所允许的范围,因此我遇到了同样的错误。