2012-03-27 177 views
5

我正在使用Kerberos身份驗證寫入HTTP連接。我有「HTTP/1.1 401 Unauthorized」。你能推薦我應該檢查什麼嗎?我認爲這有一些技巧,但我沒有看到它。使用HTTP客戶端的Kerberos連接

可能是我應該設置標題「WWW-Authenticate」與「協商」?

非常感謝先進的任何幫助和想法。

public class ClientKerberosAuthentication { 

    public static void main(String[] args) throws Exception { 

     System.setProperty("java.security.auth.login.config", "login.conf"); 
     System.setProperty("java.security.krb5.conf", "krb5.conf"); 
     System.setProperty("sun.security.krb5.debug", "true"); 
     System.setProperty("javax.security.auth.useSubjectCredsOnly","false"); 

     DefaultHttpClient httpclient = new DefaultHttpClient(); 
     try { 
      NegotiateSchemeFactory nsf = new NegotiateSchemeFactory(); 
      httpclient.getAuthSchemes().register(AuthPolicy.SPNEGO, nsf);    

      List<String> authpref = new ArrayList<String>(); 
      authpref.add(AuthPolicy.BASIC); 
      authpref.add(AuthPolicy.SPNEGO); 
      httpclient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref);    


      httpclient.getCredentialsProvider().setCredentials(
        new AuthScope(null, -1, AuthScope.ANY_REALM, AuthPolicy.SPNEGO), 
        new UsernamePasswordCredentials("myuser", "mypass"));    

      System.out.println("----------------------------------------"); 
      HttpUriRequest request = new HttpGet("http://localhost:8084/web-app/webdav/213/_test.docx"); 
      HttpResponse response = httpclient.execute(request); 
      HttpEntity entity = response.getEntity(); 

      System.out.println("----------------------------------------"); 
      System.out.println(response.getStatusLine()); 
      System.out.println("----------------------------------------"); 
      if (entity != null) { 
       System.out.println(EntityUtils.toString(entity)); 
      } 
      System.out.println("----------------------------------------"); 

      // This ensures the connection gets released back to the manager 
      EntityUtils.consume(entity); 

     } finally { 
      httpclient.getConnectionManager().shutdown(); 
     } 
    } 
} 
+0

我已經爲此問題寫了一個替代解決方案在這裏:http://stackoverflow.com/a/22865583/381161 – 2014-04-04 14:53:03

回答

0

我有同樣的問題,只是找到您的文章。我將它加入書籤,以便我在修復它時發佈答案。我發佈了一個鏈接到我的問題,在那裏有人回答,所以如果有人通過Google發現這個問題,他們會找到答案:

HttpClient在URL有端口時爲AD創建SPN時出現問題。

見我的問題回答+這裏:HttpClient check Kerberos secured webpage. NTLM login didn't work

3

SPNEGO不會起作用,因爲你用localhost爲URL的主機名。

您的服務器配置爲在ActiveDirectory服務帳戶上註冊的以HTTP/開頭的一組SPN(或至少一個)。您可以從AD查詢它們,感謝setspn -l yourServiceAccount

您的URL必須使用ActiveDirectory中稱爲SPN的有效服務器主機名,以便Apache Http Client可以協商此服務的TGS並將其發送到您的服務器。

0

這是我在我的項目中編寫的測試客戶端。 此客戶端依賴於所有加密類型要在JDK啓用,

如果你看到下面在你的日誌和你的密鑰表在256位默認的etypes被加密default_tkt_enctypes: 17 16 23 1 3.

則以下jar http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html 需求是下載並放置在JDK/jre/lib/security使AES256位加密後,你應該看到以下日誌中默認的etypes爲default_tkt_enctypes: 18 17 16 23 1 3.

import java.io.IOException; 
import java.io.InputStream; 
import java.security.Principal; 
import java.security.PrivilegedAction; 
import java.util.Arrays; 
import java.util.HashMap; 
import java.util.HashSet; 
import java.util.Set; 

import javax.security.auth.Subject; 
import javax.security.auth.kerberos.KerberosPrincipal; 
import javax.security.auth.login.AppConfigurationEntry; 
import javax.security.auth.login.Configuration; 
import javax.security.auth.login.LoginContext; 

import org.apache.commons.io.IOUtils; 
import org.apache.http.HttpResponse; 
import org.apache.http.auth.AuthSchemeProvider; 
import org.apache.http.auth.AuthScope; 
import org.apache.http.auth.Credentials; 
import org.apache.http.client.CookieStore; 
import org.apache.http.client.HttpClient; 
import org.apache.http.client.config.AuthSchemes; 
import org.apache.http.client.config.CookieSpecs; 
import org.apache.http.client.config.RequestConfig; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.client.methods.HttpUriRequest; 
import org.apache.http.config.Lookup; 
import org.apache.http.config.RegistryBuilder; 
import org.apache.http.impl.auth.SPNegoSchemeFactory; 
import org.apache.http.impl.client.BasicCookieStore; 
import org.apache.http.impl.client.BasicCredentialsProvider; 
import org.apache.http.impl.client.CloseableHttpClient; 
import org.apache.http.impl.client.HttpClientBuilder; 
import org.apache.http.impl.cookie.BasicClientCookie; 

的實用工具類

public class KerberosHttpClient { 
    private String principal; 
    private String keyTabLocation; 

    public KerberosHttpClient() {} 
    public KerberosHttpClient(String principal, String keyTabLocation) { 
     super(); 
     this.principal = principal; 
     this.keyTabLocation = keyTabLocation; 
    } 

    public KerberosHttpClient(String principal, String keyTabLocation, String krb5Location) { 
     this(principal, keyTabLocation); 
     System.setProperty("java.security.krb5.conf", krb5Location); 
    } 

    public KerberosHttpClient(String principal, String keyTabLocation, boolean isDebug) { 
     this(principal, keyTabLocation); 
     if (isDebug) { 
      System.setProperty("sun.security.spnego.debug", "true"); 
      System.setProperty("sun.security.krb5.debug", "true"); 
     } 
    } 

    public KerberosHttpClient(String principal, String keyTabLocation, String krb5Location, boolean isDebug) { 
     this(principal, keyTabLocation, isDebug);   
     System.setProperty("java.security.krb5.conf", krb5Location); 
    } 

    private static HttpClient buildSpengoHttpClient() { 
     HttpClientBuilder builder = HttpClientBuilder.create();    
     Lookup<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create(). 
       register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true)).build(); 
     builder.setDefaultAuthSchemeRegistry(authSchemeRegistry); 
     BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); 
     credentialsProvider.setCredentials(new AuthScope(null, -1, null), new Credentials() { 
      @Override 
      public Principal getUserPrincipal() { 
       return null; 
      } 
      @Override 
      public String getPassword() { 
       return null; 
      } 
     }); 
     builder.setDefaultCredentialsProvider(credentialsProvider);   
     CloseableHttpClient httpClient = builder.build(); 
     return httpClient; 
    } 

    public HttpResponse callRestUrl(final String url,final String userId) { 
     //keyTabLocation = keyTabLocation.substring("file://".length()); 
     System.out.println(String.format("Calling KerberosHttpClient %s %s %s",this.principal, this.keyTabLocation, url)); 
     Configuration config = new Configuration() { 
      @SuppressWarnings("serial") 
      @Override 
      public AppConfigurationEntry[] getAppConfigurationEntry(String name) { 
       return new AppConfigurationEntry[] { new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", 
         AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, new HashMap<String, Object>() { 
          { 
           put("useTicketCache", "false"); 
           put("useKeyTab", "true"); 
           put("keyTab", keyTabLocation); 
           //Krb5 in GSS API needs to be refreshed so it does not throw the error 
           //Specified version of key is not available 
           put("refreshKrb5Config", "true"); 
           put("principal", principal); 
           put("storeKey", "true"); 
           put("doNotPrompt", "true"); 
           put("isInitiator", "true"); 
           put("debug", "true"); 
          } 
         }) }; 
      } 
     }; 
     Set<Principal> princ = new HashSet<Principal>(1); 
     princ.add(new KerberosPrincipal(userId)); 
     Subject sub = new Subject(false, princ, new HashSet<Object>(), new HashSet<Object>()); 
     try { 
      LoginContext lc = new LoginContext("", sub, null, config); 
      lc.login(); 
      Subject serviceSubject = lc.getSubject(); 
      return Subject.doAs(serviceSubject, new PrivilegedAction<HttpResponse>() { 
       HttpResponse httpResponse = null; 
       @Override 
       public HttpResponse run() { 
        try {  
         HttpUriRequest request = new HttpGet(url); 
         HttpClient spnegoHttpClient = buildSpengoHttpClient(); 
         httpResponse = spnegoHttpClient.execute(request); 
               return httpResponse; 
        } catch (IOException ioe) { 
         ioe.printStackTrace(); 
        } 
        return httpResponse; 
       } 
      }); 
     } catch (Exception le) { 
      le.printStackTrace();; 
     } 
     return null; 
    } 

    public static void main(String[] args) throws UnsupportedOperationException, IOException { 
     KerberosHttpClient restTest = new KerberosHttpClient("HTTP/[email protected]", 
       "file://C://Development//test.keytab", true); 
     HttpResponse response = restTest.callRestUrl("http://test.com/service/employees", 
       "HTTP/[email protected]"); 
     InputStream is = response.getEntity().getContent(); 
     System.out.println("Status code " + response.getStatusLine().getStatusCode()); 
     System.out.println(Arrays.deepToString(response.getAllHeaders())); 
     System.out.println(new String(IOUtils.toByteArray(is), "UTF-8")); 
    } 
}