2016-03-29 2 views
3

Я написал простой Java HTTP-клиент, который работает под Windows. Клиент связывается с веб-сервером, который требует аутентификации Kerberos через SPNego.Как сохранить билет службы Kerberos с помощью клиента Windows Java?

Я испытываю две проблемы:

  • Билет службы не хранятся в моем кэше учетных данных. После выполнения запроса я ожидал увидеть билет службы Kerberos, хранящийся в кеше моих учетных данных, под номером C:\Users\<user>\krb5cc_<user>. Не было ли я ошибочным предположить, что Java хранит служебные билеты в кеше учетных данных? Я хотел бы повторно использовать Service Ticket, полученный в Client A для запросов в Client B (где оба Клиента являются Java-приложениями на одном компьютере). Возможно ли это с Java?

  • Если я запускаю код ниже сто раз в цикле, он работает только n раз (где n - случайное число от 1 до 100). Запрос на отказ возвращает сообщение об ошибке 401, потому что Java не смог получить билет на услугу (помните: поскольку мое приложение не хранит служебные билеты между запросами, оно пытается получить новый билет на обслуживание из TGT для каждого запроса) , Я добавил сообщение об ошибке в конец этого вопроса.

Я создал TGT через kinit в папке bin JDK. Следующий фрагмент кода используется для создания простых запросов GET:

static void testJavaHttpKerberosAuthentication() throws IOException { 
    URL obj = new URL(URI); 
    HttpURLConnection con = (HttpURLConnection) obj.openConnection(); 
    int responseCode = con.getResponseCode(); 
    System.out.println("\nSending 'GET' request to URL : " + URI); 
    System.out.println("Response Code : " + responseCode); 

    BufferedReader in = new BufferedReader(
    new InputStreamReader(con.getInputStream())); 
    String inputLine; 
    StringBuffer response = new StringBuffer(); 
    while ((inputLine = in.readLine()) != null) { 
     response.append(inputLine); 
    } 
    in.close(); 

    //print result 
    System.out.println(response.toString()); 
    } 

Вот содержание моего jaas.conf (как описано here):

com.sun.security.jgss.krb5.initiate { 
com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=false useTicketCache=true; 
}; 

Я бегу мое приложение со следующими параметрами :

-Djava.security.auth.login.config=D:\jaas.conf 
-Dsun.security.krb5.debug=true 
-Djavax.security.auth.useSubjectCredsOnly=false 

Я не использую в качестве krb5.ini, так как мой клиент получает правильный KDC из конфигурации домена.

я могу генерировать TGT для моих учетных данных кэша с помощью следующей команды: (. Исх Задача 2)

C:\Program Files\Java\jdk1.8.0_77\bin>kinit 
Password for <user>@<domain>: 
New ticket is stored in cache file C:\Users\<user>\krb5cc_<user> 

И, наконец, вот исключение и Kerberos Debug Output для случая, когда разрешение терпит неудачу. Обратите внимание, что ctime явно ошибочно. У меня было много разных попыток, а период времени для диапазонов ctime - с 1970 по 2040 год. Интересно, что этого не происходит для каждого запроса.

>>>KRBError: 
cTime is Wed Jun 07 12:24:03 CEST 2017 1496831043000 
sTime is Tue Mar 29 16:38:24 CEST 2016 1459262304000 
suSec is 283371 
error code is 34 
error Message is Request is a replay 
sname is HTTP/<spn>@<domain> 
msgType is 30 
KrbException: Request is a replay (34) - PROCESS_TGS 

Я уже пытался работать с JAAS использованием Subject.doAs, но это вызывает те же самые проблемы. Доступ к серверу через браузер работает отлично (хотя это не сопоставимо, поскольку браузеры используют собственный кэш учетных данных Windows AFAICT).

Я был бы благодарен за некоторые советы о том, как отлаживать проблему вроде этого.

EDIT: Спецификация пути к кешу учетных данных через переменную среды KRB5CCNAME явно не изменяет поведение. Похоже, что TGT получен из кэша учетных данных, но служебные билеты там не хранятся.

+0

BTW, есть два дополнительных флага трассировки, которые могут оказаться полезными: '-Djava.security.debug = gssloginconfig, configfile, configparser, logincontext' для отладки проблем конфигурации JAAS и, конечно же,' -Dsun.security.spnego.debug = true' –

ответ

0

О кэше >> Похоже, вы не указали, что такое кеш по умолчанию в вашей системе (ср.env variable KRB5CCNAME), поэтому Java и kinit возвращаются к жестко заданной по умолчанию. И это не то же самое по умолчанию ...

  • ваша версия kinit явно использует стандарт Linux т.е. FILE:
  • Java обычно использует стандарт Windows, т.е. API: под управлением службы MIT-Kerberos-для-Windows,

Возможное обходное решение: либо использовать пользовательский интерфейс Kerberos для Windows, чтобы создать TGT, либо заставить Java использовать кеш-файл, установив KRB5CCNAME.

Ссылка:MIT Kerberos documentation и особенно самые последняя ссылка о нелегкой кодировке по умолчанию

~~~~~~~

О случайных значениях времени >> Я понятия не имею.

+0

Спасибо за ваш ответ, Самсон. У меня создалось впечатление, что Java по умолчанию использует стандарт Linux для кеша учетных данных (см. [Исходные учетные данные] (http://cr.openjdk.java.net/~weijun/special/krb5winguide-2/raw_files/ новый/KWin)). По крайней мере, Java уже смог найти TGT в кеше учетных данных в папке пользователя. Тем не менее, я попытался явно указать кеш учетных данных через 'KRB5CCNAME', и он не изменил поведение. Мои HTTP-запросы получают билет на обслуживание, но он не хранится в кэше учетных данных. – Thomas

+0

Хмм ... любая вероятность того, что ваша HTTP-библиотека использует другую запись конфигурации JAAS для управления билетом службы (например, «Клиент {...}'), делегируя управление TGT в стандартную процедуру JAAS, которая использует значение по умолчанию config (например, 'com.sun.security.jgss.krb5.initiate {...}')?!? –

+0

Я использую только компоненты java.net и рассматриваю [эту документацию] (http://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/lab/part6.html). Я не знаю, t полагают, что любые другие записи в 'jaas.conf' должны быть релевантными для рассматриваемого примера. Я не могу найти источники, которые описывают процесс хранения билетов на обслуживание в кеше учетных данных с помощью Java, либо по умолчанию это не работает для меня по какой-то причине, или кажется, что это невозможно. – Thomas

0

Что касается случайных значений времени, которые появляются иногда: мы обнаружили, что установка udp_preference_limit = 1 в krb5.ini решает проблему. Это эффективно говорит Kerberos, чтобы всегда пытаться сначала использовать TCP для отправки пакетов. По-видимому, есть проблема при переключении на UDP (не уверен, является ли UDP проблемой или переключается между протоколами).

+0

Uh - похоже, что UDP участвует во многих и, казалось бы, несвязанных проблемах https://steveloughran.gitbooks.io/kerberos_and_hadoop/content/sections/errors.html –

0

JAAS не собирается сохранять билеты в кеш, вы должны использовать kinit или ссылаться на код kinit программным путем по вашему коду. Я написал вопрос и ответ на эту проблему here.