GSSContext с нулевым SrcName
Я работаю над веб-приложением с помощью единого входа на основе входа в домен Windows, для этого я выбрал проверку билетов Kerberos. Но сейчас я столкнулся с проблемой, для которой не могу найти решение. Мне удается проверить заявку без исключений, но когда я пытаюсь получить имя пользователя, NullPointerException
брошен, потому что имя пользователя null
и я не знаю, где проблема.
Почему имя пользователя равно нулю, если я не получаю никаких исключений во время проверки?
Как я получу имя пользователя:String clientName = gssContext.getSrcName().toString();
Я создаю свой клиент на основе этого:
Использование GSSManager для проверки билета Kerberos
Как получить билет на сервис Kerberos через GSS-API?
http://docs.oracle.com/javase/7/docs/technotes/guides/security/jgss/single-signon.html
Обновление 1:
Как я настраиваю контент, просто скопируйте и вставьте форму здесь /questions/15196715/ispolzovanie-gssmanager-dlya-proverki-bileta-kerberos/15196728#15196728:
final Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
GSSManager gssmgr = GSSManager.getInstance();
// tell the GSSManager the Kerberos name of the service
GSSName serviceName = gssmgr.createName(this.servicePrincipal, GSSName.NT_USER_NAME);
// get the service's credentials. note that this run() method was called by Subject.doAs(),
// so the service's credentials (Service Principal Name and password) are already
// available in the Subject
GSSCredential serviceCredentials = gssmgr.createCredential(serviceName,
GSSCredential.INDEFINITE_LIFETIME, spnegoOid, GSSCredential.ACCEPT_ONLY);
// create a security context for decrypting the service ticket
GSSContext gssContext = gssmgr.createContext(serviceCredentials);
// decrypt the service ticket
System.out.println("Entering accpetSecContext...");
System.out.println( new String (Base64.encodeBase64( gssContext.acceptSecContext(this.kerberosTicket, 0,
this.kerberosTicket.length) ) ));
// get the client name from the decrypted service ticket
// note that Active Directory created the service ticket, so we can trust it
String clientName = gssContext.getSrcName().toString();
Обновление 2:
Если я настраиваю пружинную защиту на основе этого https://spring.io/blog/2009/09/28/spring-security-kerberos-spnego-extension я также получаю ту же ошибку:
java.lang.NullPointerException в org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:136) в org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:125) в java.security.AccessController.doPrivileged(собственный метод) в javax.security.auth.Subject.doAs(Subject.java:422)
private static class KerberosValidateAction implements PrivilegedExceptionAction<String> {
byte[] kerberosTicket;
public KerberosValidateAction(byte[] kerberosTicket) {
this.kerberosTicket = kerberosTicket;
}
@Override
public String run() throws Exception {
GSSContext context = GSSManager.getInstance().createContext((GSSCredential) null);
context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);
String user = context.getSrcName().toString(); // ERROR!
context.dispose();
return user;
}
}
Обновление 3:
Также попытался изменить версию Java с 1.8 до 1.7, как предлагается здесь. Сбой аутентификации домена с Kerberos. Безрезультатно.
Обновление 4:
Прежде всего. Не используйте Java 1.8 b40 и b45, они оба сломаны. И не тестируйте его на локальном ПК, он не работает (я не знаю почему).
После перехода на новейшую (b65) версию Java я получил исключение по поводу надписи (не удается найти ключ соответствующего типа для расшифровки AP REP - AES256 ...). Это я исправил с помощью Java Cryptography Extension (JCE) для Java 1.8 и заново создаю keytab с помощью /crypto AES256-SHA1
после всего этого я получил исключение:
GSSException: ошибка, не указанная на уровне GSS-API (уровень механизма: контрольная сумма не удалась) в sun.security.jgss.krb5.Krb5Context.acceptSecContext(неизвестный источник) в sun.security.jgss.GSSContextImpl.acceptSecContext(неизвестный источник) в sun.security..jgss.GSSContextImpl.acceptSecContext (Неизвестный источник) в GssServer$GssServerAction.run(GssServer.java:159) ...... еще 4 Причины: KrbException: Не удалось проверить контрольную сумму в sun.security.krb5.internal.crypto.Arptycc (Неизвестный источник) в sun.security.krb5.internal.crypto.ArcFourHmacEType.decrypt(Неизвестный источник) в sun.security.krb5.EncryptedData.decrypt(Неизвестный источник) в sun.security.krb5.KrbApReq.authenticate(Неизвестный источник в) sun.security.krb5.KrbApReq.(Неизвестный источник) at sun.security.jgss.krb5.InitSecContextToken.(Неизвестный источник)... еще 8 Причина: java.security.GeneralSecurityException: контрольная сумма не удалась в sun.security.krb5.internal.crypto.dk.ArcFourCrypto.decrypt (Неизвестный источник) в sun.security.krb5.internal.crypto.ArcFourHmac.decrypt(Unk Неизвестный источник)... еще 14
Я попробовал этот урок и другой способ создания keytabfile, но у меня все еще нет решения.
2 ответа
Я сталкивался с тем же Checksum failed
ошибка при реализации моей демонстрации сокета GSSAPI, которая является модификацией учебного кода Oracle GSSAPI. Я выполнил свой код на Linux-машине, зарегистрированной в области Kerberos FreeIPA. Я использовал ваниль krb5.conf
файл моей системы Linux. Нет ограничений на билет etype
здесь:
...
[libdefaults]
default_realm = AUTHDEMO.IT
dns_lookup_realm = true
dns_lookup_kdc = true
rdns = false
ticket_lifetime = 24h
forwardable = true
udp_preference_limit = 0
...
По умолчанию в области FreeIPA используются билеты типа 18 (AES-256).
Что касается моего приложения, у него настроен этот файл политики:
grant CodeBase "file:./app.jar" {
permission java.security.AllPermission;
};
grant CodeBase "file:./app.jar"
Principal javax.security.auth.kerberos.KerberosPrincipal
"servicename@AUTHDEMO.IT" {
permission java.net.SocketPermission "*", "accept";
permission javax.security.auth.kerberos.ServicePermission
"servicename@AUTHDEMO.IT", "accept";
};
При выполнении приложения я получил эту ошибку на стороне акцептора:
GSSException: ошибка не указана на уровне GSS-API (уровень механизма: режим шифрования AES256CTS типа с HMAC SHA1-96 не поддерживается / не включен)
В моем случае ошибка возникает на стороне акцептора GSS. В моем приложении я создаю конфигурацию Jaas программно (я буду называть это DConfig) и не использую файл конфигурации. Первое решение, которое я нашел, это использовать файлы конфигурации вместо DConfig, и проблема исчезла, она работала нормально. Временное решение, файл Jaas Config:
DemoServer {
com.sun.security.auth.module.Krb5LoginModule required
principal="servicename@AUTHDEMO.IT"
storeKey=true
debug=true; #not mandatory
};
При такой конфигурации не возникает никаких проблем на стороне принимающей стороны, и приложение смогло проверить правильность билета службы и принять соединение.
Я спросил себя.. ПОЧЕМУ?
Я проверил различия в предметах, полученных с двумя конфигурациями. В рабочем случае с файлом конфигурации субъект содержит в личных учетных данных как учетные данные хэша пароля, так и основной билет TGT. С помощью DConfig я получаю Subject только с хэшами паролей, но в личных учетных данных нет основного билета TGT.
Мое исправление
DConfig содержит те же настройки файла конфигурации, а остальные параметры являются копией Krb5LoginModule
по умолчанию, сначала я не вижу причины неправильного поведения.
настройка isInitiator = true
в сторону акцептора DConfig, решил проблему. `isInitiator = true заставил персистентный билет TGT перейти в тему.
С этим обходным путем ошибка исчезла без изменений в системе krb5.conf.
Мой цент... после входа в систему Jaas, давайте проверим ваши личные учетные данные субъекта на предмет отсутствия кредитов (вам нужен основной TGT службы в теме вашего получателя!) И в случае, если попытайтесь установить isInitiator = true
на стороне акцептора тоже.
С уважением
Кажется, что контекст не полностью установлен, когда вы пытаетесь получить SrcName. Кажется, это причина того, что ScrName будет нулевым. Согласно https://www-01.ibm.com/support/knowledgecenter/SSYKE2_7.0.0/com.ibm.java.security.api.doc/jgss/org/ietf/jgss/GSSContext.html генерирует acceptSecContext() токен, и если он не равен нулю, этот токен должен быть отправлен равноправному узлу. После вызова acceptSecContext() вы должны проверить, возвращает ли isEstablished() значение false. Если это так,
Если этот метод возвращает false, это указывает на то, что токен необходим от его однорангового узла для продолжения фазы установления контекста. Возвращаемое значение true указывает, что локальный конец контекста установлен. Для этого может потребоваться, чтобы токен был отправлен одноранговому узлу, если он создан GSS-API. На этапе установления контекста может вызываться метод isProtReady(), чтобы определить, может ли контекст использоваться для операций для каждого сообщения. Это позволяет приложениям использовать операции для каждого сообщения в контекстах, которые не полностью установлены.
То же самое объясняется более подробно в учебнике http://www.cs.mun.ca/java-api-1.5/guide/security/jgss/tutorials/BasicClientServer.html:
Метод acceptSecContext может в свою очередь вернуть токен. Если это так, получатель должен отправить этот токен инициатору, который должен затем снова вызвать initSecContext и передать ему этот токен. Каждый раз, когда initSecContext или acceptSecContext возвращает токен, приложение, вызвавшее метод, должно отправить токен своему партнеру, и этот узел должен передать токен соответствующему методу (acceptSecContext или initSecContext). Это продолжается до тех пор, пока контекст не будет полностью установлен (что является случаем, когда метод контекста isEstablished возвращает true).