2014-02-07 37 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',它有点整洁。 –