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