2013-02-27 41 views
11

Tôi đang cố gắng mở kết nối http đến một url được bảo vệ bằng lược đồ xác thực NTLM. Mã này đã hoạt động chính xác trong 2 năm khi chúng tôi sử dụng Java 6.I đã viết một chương trình java nhỏ truy cập vào url cụ thể đó để làm cho trường hợp thử nghiệm đơn giản nhất có thể.Lỗi Java URLConnection với xác thực ntlm, nhưng chỉ trên Linux và chỉ Java 7

Vấn đề là tôi không thể làm cho chương trình hoạt động trên Linux và khi sử dụng phiên bản của JDK 7. Java cố gắng 20 lần để truy cập URL và sau đó tôi nhận được thông báo lỗi cho máy chủ chuyển hướng quá nhiều lần . Nó hoạt động tốt với linux và JDK 6, và trong windows 7 với JDK 6 hoặc 7.

Tôi đã kiểm tra và thử giải pháp được liệt kê ở đây (và nhiều cách khác): Getting "java.net.ProtocolException: Server redirected too many times" Error. Nó không hoạt động. Tôi cũng phải thêm rằng khi truy cập url từ trình duyệt, tôi có thể thấy rằng không có cookie nào liên quan.

Dưới đây là các chi tiết chính xác của các phiên bản os/java mà tôi đã cố gắng:

thành công:

  • Windows 7: Java (TM) SE Runtime Environment (xây dựng 1.7.0_15-b03) (64 bit)
  • Windows 7: Java (TM) SE Môi trường Thời gian chạy (xây dựng 1.7.0_10-b18) (64 bit)
  • Windows 7: Java (TM) SE Môi trường Thời gian Chạy (xây dựng 1.6.0_33-b04) (64 bit)
  • Redhat enterprise li nux 6.4: Java (TM) SE Runtime Environment (xây dựng 1.6.0_33-b04) (64 bit)

Fail:

  • doanh nghiệp Redhat Linux 6.4: Java (TM) SE Runtime Environment (xây dựng 1.7.0-b147) (64 bit)
  • Redhat enterprise linux 6.4: Java (TM) SE môi trường thời gian chạy (xây dựng 1.7.0_05-b06) (64 bit)
  • Redhat enterprise linux 6.4: Java (TM) SE Môi trường thời gian chạy (xây dựng 1.7.0_13-b20) (64 bit)
  • Redhat enterprise linux 6.4: Java (TM) S E Runtime Environment (xây dựng 1.7.0_15-b03) (64 bit)

Khi chương trình hoạt động, tôi thấy các phương pháp xác thực đã được sử dụng và tài liệu mà tôi đang cố gắng để tải về càng đầu ra:

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

Khi nó không thành công, tôi có kết quả như sau:

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) 

đây là mã nguồn của chương trình:

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

Mọi trợ giúp sẽ được đánh giá cao.

UPDATE:

Sau khi một số nghiên cứu kỹ hơn, tôi thấy rằng các việc chứng thực nếu tôi sử dụng một người dùng tên miền, nhưng không nếu tôi sử dụng một người dùng cục bộ.

Mã này từ JDK 7 khiến tôi gặp khó khăn (class com.sun.security.ntlm.Khách hàng):

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; 
} 

Vì vậy, vì máy chủ được đăng ký trong một miền, nó sẽ gửi lại cho khách hàng đó là một phần của giao thức NTLM. Java thay thế tên miền mà tôi đang cố gắng ép buộc bởi biến "domainFromServer" mọi lúc và nó không thành công vì người dùng tồn tại trên máy chủ chứ không phải trên miền của máy chủ.

Tôi không biết chính xác phải làm gì với điều đó.

+0

bạn đang sử dụng bản phát hành java 7 nào? Tôi có một số vấn đề khi làm việc với https hoặc xác thực hoặc bảo mật. Một ứng dụng tôi phát triển chỉ làm việc với java 1.7_02 (Java 7.2) nhưng khi tôi sử dụng các bản phát hành mới nhất, nó không hoạt động nữa. Có một số sửa đổi mà Oracle đã thực hiện trong các bản phát hành mới nhất đặc biệt trong các chính sách bảo mật. Hãy thử với một phiên bản cũ của java 7 như 1.7_02. –

+0

Tôi đã thử nó với phiên bản Java jdk 1.7.0_02 64 bit cho Linux, và nó không hoạt động, cùng một kết quả. – Yanick

+0

Cũng không có thật 1.7.0_25-b15 cho linux (64 bit) –

Trả lời

4

Tôi đã thay đổi mã trong lớp Client.java và biên dịch lại nó cùng với phần còn lại của gói com.sun.security.ntlm, sau đó tôi tạo một jar gọi là rt_fix.jar chứa các lớp của gói cụ thể đó. Sau đó, tôi đã sử dụng tùy chọn khởi động java để buộc nó tải jar của tôi trước rt.jar nội bộ.

-Xbootclasspath/p: /path_to_jar/rt_fix.jar

Tôi không thích giải pháp này, nhưng nó làm việc.

Đây là mã tôi đã thay đổi trong Client.java, trong phương pháp type3:

Trước:

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

Sau:

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

Nó dừng lại Java từ thay đổi tên miền của tôi cố gắng xác thực với một trong những nhận được từ máy chủ khi gửi phần 3 của xác thực NTLM. Tên miền mà tôi đang cố gắng xác thực là trên thực tế tên của máy chủ vì tài khoản người dùng là địa phương.

+0

Bạn là một anh hùng! cảm ơn câu trả lời này. –

+0

Bạn có báo cáo lỗi cho Oracle không? – Armand

+0

Báo cáo lỗi: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8058419. Vẫn được đánh dấu là mở. –

3

tôi đã cùng một vấn đề và giải quyết nó chỉ bằng cách xác định tên người dùng với các tên miền bao gồm trong nó:

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

Đúng là thế này:

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

Giải thích lý do tại sao tính năng này hoạt động. –

+0

Tính năng này có hoạt động với Java 7 trên Linux không? – Suman

Các vấn đề liên quan