Java HttpClient为Kerberos身份验证设置凭据

Java HttpClient为Kerberos身份验证设置凭据,java,authentication,httpclient,kerberos,userprincipal,Java,Authentication,Httpclient,Kerberos,Userprincipal,我正在尝试使用kerberos/HTTP主机进行身份验证。使用ApacheHttpClient作为我的客户机,并对 我的Kerberos身份验证进行得非常顺利,我想知道如何以编程方式设置登录凭据。目前,凭据是通过控制台手动输入的,但我希望在运行时选择它。[实际上,我希望通过大量用户对服务器进行自动化和负载测试。] 编辑:以下是相关部分的代码片段: .. NegotiateSchemeFactory nsf = new NegotiateSchemeFactory();

我正在尝试使用kerberos/HTTP主机进行身份验证。使用ApacheHttpClient作为我的客户机,并对 我的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()
,但是从我做的一些调试来看,它们似乎根本没有被调用

我错过了什么?静态设置凭据的更干净的方法是什么

一个非常复杂但却非常复杂的keytab/login.conf hack太麻烦了,对于具有大量用户凭证的自动负载测试来说,这不是一个实用的选项。
感谢您在这方面的帮助。

由于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");
                }

            }
        }
    }

}
或:


调查问题。

在C中,您将使用例程C例程
krb5\u get\u init\u creds\u password
。在我看了几分钟后,我在JavaKerberos api中找不到直接的类似物@FredthemagicOnDerdog C对我来说并不是一个真正的选项。因为测试用例不仅涉及kerberos,还涉及HTTP。该测试是基于HTTP成功重定向状态代码等进行验证的。但是,如果有任何现有的实用程序(C/命令行)执行Kerberos+HTTP,则很乐意尝试。我不知道,我有理由相信curl能做到
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 ldap http文件https ftps scp sftp功能:GSS协商IDN IPv6大文件NTLM SSL libz
我相信有一个java版本的kinit,所以api必须存在于某个地方。我只是不太擅长java。也许这个问题可以帮助@FredtheMagicWonderDog哦,是的。我要试试卷发。虽然不是这个问题的直接答案,但这可能有助于解决我的实际问题!:)谢谢你的指点,谢谢。从来没有机会尝试过。同时,我想出了卷发的另一种方法。效果非常好-谢谢!对于那些使用纯java URLConnection的用户,设置默认验证器可能会更容易-如果您在Windows上,您可能需要配置注册表项。本文帮助我实现这一点,并且还记录了login.conf。您还可以使用
KerberosCredentials
而不是像上面的原始问题那样实现“凭证”,这样更简洁。
System.setProperty("sun.security.krb5.debug", "true");
-Dsun.security.krb5.debug=true