HttpClient устанавливает учетные данные для проверки подлинности Kerberos

Я пытаюсь пройти аутентификацию на хосте kerberos / HTTP. Использование Apache HttpClient в качестве моего клиента и слегка измененной версии this source. Моя проверка подлинности 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(), но судя по некоторым отладкам, которые я выполнял, они вообще не вызываются.

Что мне здесь не хватает? Каков более чистый способ статической установки учетных данных?

Очень подобный вопрос задавался раньше, но Взлом keytabs / login.conf слишком громоздкий и непрактичный вариант для автоматического нагрузочного теста с большим количеством учетных данных пользователя. Благодарим за любую помощь в этом вопросе.


person Alavalathi    schedule 07.02.2014    source источник
comment
В C вы должны использовать подпрограмму c krb5_get_init_creds_password. Я не смог найти прямого аналога в Java kerberos api за несколько минут, когда посмотрел web.mit.edu/kerberos/krb5-devel/doc/appdev/refs/api/   -  person Fred the Magic Wonder Dog    schedule 08.02.2014
comment
@FredtheMagicWonderDog C для меня не вариант. Потому что в тестовом примере задействован не только Kerberos, но и HTTP. Тест проверяется на основе кодов состояния успешного перенаправления HTTP и т. Д. Но если есть какие-либо существующие утилиты (C / командная строка), которые выполняют Kerberos + HTTP, мы с радостью попробуем это. Я ничего не знаю.   -  person Alavalathi    schedule 08.02.2014
comment
Я уверен, что 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 Protocols: tftp ftp telnet dict ldap ldaps http file https ftps scp sftp Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz   -  person Fred the Magic Wonder Dog    schedule 08.02.2014
comment
Я считаю, что есть java-версия kinit, поэтому apis должен где-то существовать. Я просто не особо разбираюсь в java. Возможно, этот вопрос поможет stackoverflow.com/questions/1037009/   -  person Fred the Magic Wonder Dog    schedule 08.02.2014
comment
@FredtheMagicWonderDog ну да. Я попробую завиток. Хотя это и не прямой ответ на вопрос, это может помочь решить мою настоящую проблему! :) Спасибо за указатели.   -  person Alavalathi    schedule 11.02.2014


Ответы (1)


Из-за SPNEGO код фрагмента, который вы публикуете (настройка материала класса Credentials), не используется httpclient для аутентификации.

Вы можете использовать DoA + 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");

or:

-Dsun.security.krb5.debug=true

исследовать проблемы.

person eljeko    schedule 15.05.2014
comment
Спасибо. У меня никогда не было возможности попробовать это. Тем временем я придумал другой способ с помощью curl и т. Д. - person Alavalathi; 22.05.2014
comment
Отлично работает - спасибо! Для тех, кто использует простой java URLConnection, установка аутентификатора по умолчанию может быть проще - см. docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/ - person Juraj Martinka; 16.08.2017
comment
Если вы используете Windows, вам может потребоваться настроить запись в реестре. Эта статья помогла мне получить этот рабочий cr.openjdk. java.net/~weijun/special/krb5winguide-2/raw_files/, а также немного документирует файл login.conf. Вы также можете использовать KerberosCredentials вместо реализации «Учетных данных», как в исходном вопросе выше, это немного аккуратнее. - person Martin Cassidy; 05.03.2018