HttpClient 为 Kerberos 身份验证设置凭据 [英] HttpClient set credentials for Kerberos authentication

查看:41
本文介绍了HttpClient 为 Kerberos 身份验证设置凭据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 kerberos/HTTP 主机进行身份验证.使用 Apache HttpClient 作为我的客户端 - 以及 此来源.我的 Kerberos 身份验证非常顺利,我想知道如何以编程方式设置登录凭据.目前,凭据是通过控制台手动输入的,但我希望在运行时由我选择.[实际上,我希望使用大量用户对服务器进行自动化和负载测试.].

I am trying to authenticate with a kerberos/HTTP host. Using Apache HttpClient as my client - and a slightly modified version of this source. My Kerberos authentication goes perfectly fine, and I wish to know how to set the login credentials programatically. At the moment, the credentials are entered manually through the console, but I want to have it chosen by me at run time. [ As I wish to automate and load test the server with a large number of users, actually. ].

这是相关部分的代码片段:

EDIT : Here is a code snippet of the relevant parts :

..
        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(),但是从我做的一些调试来看,它们没有似乎根本没有被调用.

The interface Credentials has two methods - getPassword() and getUserPrincipal(), but from some debugging I did, they don't seem to be invoked at all.

我在这里错过了什么?静态设置凭据的更简洁方法是什么?

What am I missing here ? What is a cleaner way to statically set the credentials ?

一个非常之前有人问过类似的问题,但是 keytabs/login.conf hack 太麻烦,对于具有大量用户凭据的自动负载测试来说不是一个实用的选项.感谢您对此的任何帮助.

A very similar question had been asked before, but keytabs/login.conf hack is too cumbersome and not a practical option for an automated load test with a large number of user credentials. Appreciate any help on this.

推荐答案

由于 SPNEGO,httpclient 不使用您发布的片段代码(凭据类内容设置)进行身份验证.

Because of SPNEGO the snippet code you post (Credentials class stuff setup) is not used by httpclient to authenticate.

您可以使用 DoAs + CallBackhandler 来传递用户 &运行时密码.

You can use a DoAs + a CallBackhandler to pass user & password at runtime.

然后你需要一个 login.conf 或者任何里面有这个的名字:

Then you need a login.conf or whatever the name with this inside:

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

您可以将名称从KrbLogin"更改为您喜欢的名称(记住在您的java代码中使用相同的名称)

You can change the name from "KrbLogin" to the name you like (remember to use the same name in your java code)

并使用 java 系统属性进行设置:

and set this with java system properties:

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

或带有

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

然后你需要一个 krb5 配置文件(通常是 krb5.ini 或 krb5.conf 里面有正确的配置)

Then you need a krb5 config file (usually krb5.ini or krb5.conf with correct configuration inside)

如果您的工作站(或服务器)为 Kerberos 正确配置了这个类应该可以正常工作(使用适当的文件 login.conf 和 krb5.ini)我使用 httpclient 4.3.3 和 java 1.7 来测试它:

If your workstation (or server) is properly configured for Kerberos this class should works as is (with propper file login.conf and krb5.ini) I used httpclient 4.3.3 and java 1.7 to test it:

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

调查问题.

这篇关于HttpClient 为 Kerberos 身份验证设置凭据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆