簡體   English   中英

使用ntlm身份驗證時出現Java URLConnection錯誤,但僅限Linux和Java 7

[英]Java URLConnection error with ntlm authentication, but only on Linux and only Java 7

我正在嘗試打開與NTLM身份驗證方案保護的URL的http連接。 當我們使用Java 6時,這段代碼已經正常工作了2年。我寫了一個小的java程序,它訪問該特定的url,使測試用例盡可能簡單。

問題是我無法使程序在Linux上運行,並且在使用JDK 7的版本時.Java嘗試20次訪問URL,然后我收到一個錯誤,告訴我服務器重定向次數太多。 它適用於linux和JDK 6,以及帶有JDK 6或7的Windows 7。

我檢查並嘗試了此處列出的解決方案(和許多其他人): 獲取“java.net.ProtocolException:服務器重定向次數太多”錯誤 它沒用。 我還要補充一點,當從瀏覽器訪問URL時,我可以看到沒有涉及cookie。

以下是我嘗試過的os / java版本的確切細節:

成功:

  • Windows 7:Java(TM)SE運行時環境(版本1.7.0_15-b03)(64位)
  • Windows 7:Java(TM)SE運行時環境(版本1.7.0_10-b18)(64位)
  • Windows 7:Java(TM)SE運行時環境(版本1.6.0_33-b04)(64位)
  • Redhat enterprise linux 6.4:Java(TM)SE運行環境(版本1.6.0_33-b04)(64位)

失敗:

  • Redhat enterprise linux 6.4:Java(TM)SE運行時環境(版本1.7.0-b147)(64位)
  • Redhat enterprise linux 6.4:Java(TM)SE運行時環境(版本1.7.0_05-b06)(64位)
  • Redhat enterprise linux 6.4:Java(TM)SE運行時環境(版本1.7.0_13-b20)(64位)
  • Redhat enterprise linux 6.4:Java(TM)SE運行時環境(版本1.7.0_15-b03)(64位)

當程序工作時,我看到使用的身份驗證方法和我嘗試下載的文檔作為輸出:

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”強制執行的域,並且由於用戶存在於服務器而不是服務器的域上而失敗。

我不知道該怎么做。

我更改了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身份驗證的第三部分時,使用從服務器收到的域更改我嘗試進行身份驗證的域。 我嘗試進行身份驗證的域實際上是服務器的名稱,因為用戶帳戶是本地的。

我遇到了同樣的問題並通過指定包含在其中的域的用戶名來解決它:

    Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(
                    System.getProperty("DOMAIN\\user"),
                    System.getProperty("password").toCharArray() ) ;
        }
    });

這是正確的:

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

這個問題在JDK 9-ea中通過http://bugs.java.com/view_bug.do?bug_id=7150092解決了,修復程序也通過http://bugs.java.com/反向移植到JDK 8u40 view_bug.do?bug_id=8049690

導致此錯誤的另一個可能原因是:域用戶被阻止

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

我不小心阻止了我的域用戶后,嘗試使用不正確的密碼登錄時,我遇到了同樣的錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM