2014-02-07 36 views
10

我正在嘗試使用kerberos/HTTP主機進行身份驗證。使用Apache HttpClient作爲我的客戶端 - 以及稍微修改後的版本this source. 我的Kerberos身份驗證非常好,我希望知道如何以編程方式設置登錄憑據。目前,憑據是通過控制檯手動輸入的,但我希望在運行時讓我選擇它。 [因爲我希望實際上自動化並加載大量用戶的服務器測試。 ]。HttpClient爲Kerberos身份驗證設置憑據

編輯:這裏是相關部分的代碼片段:

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

     Credentials use_jaas_creds = new Credentials() { 

      public String getPassword() { 
       return null; 
      } 

      public Principal getUserPrincipal() { 
       return null; 
      }  
     }; 

     httpclient.getCredentialsProvider().setCredentials(
       new AuthScope(null, -1, null), 
       use_jaas_creds); 

     HttpUriRequest request = new HttpGet("http://kerberoshost/"); 
     HttpResponse response = httpclient.execute(request); 
.. 

接口Credentials有兩個方法 - getPassword()getUserPrincipal(),但是從一些調試我這樣做,他們似乎並不在被調用所有。

我在這裏錯過了什麼?什麼是靜態設置憑據的更簡潔的方法?

非常similar question had been asked before,但keytabs/login.conf hack過於繁瑣,而且對於具有大量用戶憑據的自動負載測試來說不是一個實用的選項。 欣賞這方面的任何幫助。

+0

在C中,您將使用例程c例程'krb5_get_init_creds_password'。在幾分鐘內,我無法在Java kerberos api中找到一個直接的模擬器,我查看了 http://web.mit。edu/kerberos/krb5-devel/doc/appdev/refs/api/krb5_get_init_creds_password.html –

+0

@FredtheMagicWonderDog C不適合我。因爲測試用例不僅涉及kerberos,還涉及HTTP。該測試基於HTTP成功重定向狀態代碼等進行驗證。但是,如果有任何現有的Kerberos + HTTP實用程序(C /命令行),將很樂意嘗試。我不知道任何。 – user30622

+0

我相當確定捲曲可以做到這一點。 'curl -V curl 7.19.7(x86_64-redhat-linux-gnu)libcurl/7.19.7 NSS/3.14.3.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2 協議:tftp ftp telnet dict ldap ldaps http文件https ftps scp sftp 特性:GSS協商IDN IPv6大文件NTLM SSL libz' –

回答

16

由於SPNEGO您發佈的代碼段代碼(憑證類的東西設置)不會被httpclient用於認證。

您可以使用DoAs + CallBackhandler在運行時傳遞用戶密碼&。

然後,你需要一個login.conf的或任何名義與這裏面:

KrbLogin{ 
com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=false debug=true useTicketCache=false; 
}; 

您可以從「KrbLogin」將名稱更改爲你喜歡(記得在你的java使用相同名稱的名稱代碼)

並將此用java系統屬性:

System.setProperty("java.security.auth.login.config", "login.conf"); 

或具有

-Djava.security.auth.login.config=login.config 

然後,你需要一個krb5的配置文件(通常krb5.ini或krb5.conf的與正確的配置裏面)

如果您的工作站(或服務器)正確配置爲Kerberos此類應作品是(與propper文件login.conf中和krb5.ini)我用的HttpClient 4.3.3和Java 1.7來測試它:

import org.apache.http.HttpEntity; 
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.CredentialsProvider; 
import org.apache.http.client.HttpClient; 
import org.apache.http.client.config.AuthSchemes; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.client.methods.HttpUriRequest; 
import org.apache.http.config.Registry; 
import org.apache.http.config.RegistryBuilder; 
import org.apache.http.impl.auth.SPNegoSchemeFactory; 
import org.apache.http.impl.client.BasicCredentialsProvider; 
import org.apache.http.impl.client.CloseableHttpClient; 
import org.apache.http.impl.client.HttpClients; 
import org.apache.http.util.EntityUtils; 
import javax.security.auth.Subject; 
import javax.security.auth.callback.*; 
import javax.security.auth.login.LoginContext; 
import javax.security.auth.login.LoginException; 
import java.io.IOException; 
import java.security.AccessController; 
import java.security.Principal; 
import java.security.PrivilegedAction; 
import java.util.Set; 

public class HttpClientKerberosDoAS { 

    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("javax.security.auth.useSubjectCredsOnly", "false"); 

     String user = ""; 
     String password = ""; 
     String url = ""; 

     if (args.length == 3) { 
      user = args[0]; 
      password = args[1]; 
      url = args[2]; 


      HttpClientKerberosDoAS kcd = new HttpClientKerberosDoAS(); 

      System.out.println("Loggin in with user [" + user + "] password [" + password + "] "); 
      kcd.test(user, password, url); 
     } else { 
      System.out.println("run with User Password URL"); 
     } 

    } 

    public void test(String user, String password, final String url) { 
     try { 

      LoginContext loginCOntext = new LoginContext("KrbLogin", new KerberosCallBackHandler(user, password)); 
      loginCOntext.login(); 

      PrivilegedAction sendAction = new PrivilegedAction() { 

       @Override 
       public Object run() { 
        try { 

         Subject current = Subject.getSubject(AccessController.getContext()); 
         System.out.println("----------------------------------------"); 
         Set<Principal> principals = current.getPrincipals(); 
         for (Principal next : principals) { 
          System.out.println("DOAS Principal: " + next.getName()); 
         } 
         System.out.println("----------------------------------------"); 

         call(url); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
        return true; 
       } 
      }; 

      Subject.doAs(loginCOntext.getSubject(), sendAction); 

     } catch (LoginException le) { 
      le.printStackTrace(); 
     } 
    } 

    private void call(String url) throws IOException { 
     HttpClient httpclient = getHttpClient(); 

     try { 

      HttpUriRequest request = new HttpGet(url); 
      HttpResponse response = httpclient.execute(request); 
      HttpEntity entity = response.getEntity(); 

      System.out.println("----------------------------------------"); 

      System.out.println("STATUS >> " + response.getStatusLine()); 

      if (entity != null) { 
       System.out.println("RESULT >> " + EntityUtils.toString(entity)); 
      } 

      System.out.println("----------------------------------------"); 

      EntityUtils.consume(entity); 

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

    private HttpClient getHttpClient() { 

     Credentials use_jaas_creds = new Credentials() { 
      public String getPassword() { 
       return null; 
      } 

      public Principal getUserPrincipal() { 
       return null; 
      } 
     }; 

     CredentialsProvider credsProvider = new BasicCredentialsProvider(); 
     credsProvider.setCredentials(new AuthScope(null, -1, null), use_jaas_creds); 
     Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create().register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true)).build(); 
     CloseableHttpClient httpclient = HttpClients.custom().setDefaultAuthSchemeRegistry(authSchemeRegistry).setDefaultCredentialsProvider(credsProvider).build(); 

     return httpclient; 
    } 

    class KerberosCallBackHandler implements CallbackHandler { 

     private final String user; 
     private final String password; 

     public KerberosCallBackHandler(String user, String password) { 
      this.user = user; 
      this.password = password; 
     } 

     public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { 

      for (Callback callback : callbacks) { 

       if (callback instanceof NameCallback) { 
        NameCallback nc = (NameCallback) callback; 
        nc.setName(user); 
       } else if (callback instanceof PasswordCallback) { 
        PasswordCallback pc = (PasswordCallback) callback; 
        pc.setPassword(password.toCharArray()); 
       } else { 
        throw new UnsupportedCallbackException(callback, "Unknown Callback"); 
       } 

      } 
     } 
    } 

} 

注:

你可以使用:

System.setProperty("sun.security.krb5.debug", "true"); 

或:

-Dsun.security.krb5.debug=true 

調查問題。

+0

謝謝。從來沒有機會嘗試。與此同時,我用捲曲等方法找出了另一種方式。 – user30622

+1

完美的作品 - 謝謝! 對於那些使用普通Java URLConnection的用戶,設置默認的身份驗證器可能更容易 - 請參閱https://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/lab/part6.html#Proxy_Authentication –

+1

如果你在Windows上,你可能需要配置一個註冊表項。這篇文章幫助我得到這個工作http://cr.openjdk.java.net/~weijun/special/krb5winguide-2/raw_files/new/kwin,並且還記錄了login.conf。您也可以使用'KerberosCredentials'而不是像上面的原始問題那樣實現'Credentials',它有點整潔。 –