"Ошибка обнаруженного дефекта" (NTLM не Kerberos) с Kerberos/Spring Безопасность /IE/Active Directory
У нас возникли проблемы с получением Spring Security/Kerberos/AD для работы в нашем веб-приложении. Наш диагноз заключается в том, что наш сервер AD отправляет токен NTLM (мы можем сказать, что он начинается с "TlRMTVNT....." ) в IE и IE затем отправляет это в наше приложение, и он не работает. Наш сервер AD должен отправлять токен Kerberos/SPNEGO в IE.
"движущиеся части":
- Spring Безопасность 3.0 (исправлено)
- Microsoft Windows Server Enterprise 2003 SP1 Active Directory
- IE 8
- Tomcat (TC Server 6.0)
- Java 1.6
Мы установили все, как описано в инструкциях здесь:
https://spring.io/blog/2009/09/28/spring-security-kerberos-spnego-extension
Это включает в себя:
- Создание обычного пользователя в качестве Принципа Сервиса (то же, что и имя машины, где находится наше приложение). Мы устанавливаем следующие параметры учетной записи:
- disabled 'Использование должно изменить пароль при следующем входе в систему
- enabled 'password never expires'
- enabled 'Использовать Kerberos DES...'
- disabled 'Не требуется предварительная аутентификация Kerberos
- ПРИМЕЧАНИЕ. Сервер 2003 не представляет "Эта учетная запись поддерживает Kerberos AES 128 бит..." и "Эта учетная запись поддерживает параметры Kerberos AES 256 бит...".
- Используется "ktpass.exe" для присвоения имени участника-службы (SPN) этому новому пользователю и экспорта этого ключа пользователя в файл keytab. с помощью
'ktpass/out ourweb.keytab/mapuser [email protected]/princ HTTP/[email protected]/pass *
- Загруженный исходный код https://src.springframework.org/svn/se-security/trunk.
- Скопировал файл keytab с сервера AD на WEB-INF/etc из исходного кода (приложения).
- Сделано изменение файла SunJaasKerbersoTicketValidator.java для чтения файла keytab. (Чтобы устранить ошибку, в которой приложение не может прочитать файл keytab из пути Java classpath)
options.put( "keyTab", "C:\se-security\ spring -security-kerberos\spring -security-kerberos-sample\src\main\webapp\WEB-INF\etc\ourweb.keytab" );
- Настроить web.xml для использования spnego.xml. contextConfigLocation /WEB -INF/spnego.xml
- Конфигурировано Spring Безопасность (spnego.xml) для использования Kerberos (SpnegoEntryPoint, SpnegoAuthenticationProcessingFilter и KerberosServiceAuthenticationProvider beans), предоставляя наше служебное имя и имя файла keytab.
- Конфигурированный spnego.xml для чтения файла keytab, скопированного в WEB-INF/и т.д.
Когда мы запустили наш TC-сервер, мы увидели, что элементы, инициализирующие красиво (т.е. без ошибок - "ключ принципа", полученный из keytab):
Creating instance of bean 'org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator#10fa4b8'
Invoking afterPropertiesSet() on bean with name 'org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator#10fa4b8'
Config name: C:\WINDOWS\krb5.ini
Debug is true storeKey true useTicketCache false useKeyTab true doNotPrompt true ticketCache is null isInitiator false KeyTab is C:\se-security\spring-security-kerberos\spring-security-kerberos-sample\src\main\webapp\WEB-INF\etc\ourwebapp4.keytab refreshKrb5Config is false principal is HTTP/ourwebappweb4.testdomain.ourcompany.co.uk tryFirstPass is false useFirstPass is false storePass is false clearPass is false
>>> KeyTabInputStream, readName(): TESTDOMAIN.OURCOMPANY.CO.UK
>>> KeyTabInputStream, readName(): HTTP
>>> KeyTabInputStream, readName(): ourweb
>>> KeyTab: load() entry length: 78; type: 1
>>> KeyTabInputStream, readName(): TESTDOMAIN.OURCOMPANY.CO.UK
>>> KeyTabInputStream, readName(): HTTP
>>> KeyTabInputStream, readName(): ourweb.testdomain.ourcompany.co.uk
>>> KeyTab: load() entry length: 113; type: 1
Added key: 1version: 2
Ordering keys wrt default_tkt_enctypes list
default etypes for default_tkt_enctypes: 1.
0: EncryptionKey: keyType=1 kvno=2 keyValue (hex dump)=
0000: 91 01 43 E3 02 A8 B9 83
principal key obtained from the keytab
principal is HTTP/[email protected]
EncryptionKey: keyType=1 keyBytes (hex dump)=0000: 91 01 43 E3 02 A8 B9 83
Added server keyKerberos Principal HTTP/[email protected]y Version 2key EncryptionKey: keyType=1 keyBytes (hex dump)=
0000: 91 01 43 E3 02 A8 B9 83
[Krb5LoginModule] added Krb5Principal HTTP/[email protected] to Subject Commit Succeeded
Finished creating instance of bean 'org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator#10fa4b8'
Готовый к тестированию, мы включили "Интегрированную проверку подлинности Windows" в IE и удостоверились, что домен был указан в разделе сайта локальной сети IE. Затем мы подключились к нашему веб-приложению, используя полное доменное имя.
Когда мы это сделали, мы получили следующие ошибки в браузере:
500 Internal server error.
и в файле журнала сервера TC:
Negotiate Header was invalid: Negotiate TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFASgKAAAADw==
org.springframework.security.authentication.BadCredentialsException: Kerberos validation not succesfull
at org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:74)
at org.springframework.security.extensions.kerberos.KerberosServiceAuthenticationProvider.authenticate(KerberosServiceAuthenticationProvider.java:92)
at org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:120)
at org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:48)
at org.springframework.security.extensions.kerberos.web.SpnegoAuthenticationProcessingFilter.doFilter(SpnegoAuthenticationProcessingFilter.java:132)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:149)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at com.springsource.metrics.collection.web.HttpRequestMetricCollectionValve.invoke(HttpRequestMetricCollectionValve.java:44)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:379)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.security.PrivilegedActionException: GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:396)
at org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:72)
... 25 more
Caused by: GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
at sun.security.jgss.GSSHeader.<init>(GSSHeader.java:80)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:287)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:267)
at org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:161)
at org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:1)
... 28 more
SecurityContextHolder now cleared, as request processing completed
Кажется (из того, что мы можем понять), что сервер AD отправляет токен NTLM (мы можем сказать, что он начинается с "TlRMTVNT....." ) в IE и IE затем отправляет это в наше приложение и он не работает.
Наш сервер AD должен отправлять токен Kerberos/SPNEGO в IE.
Другие примечания:
- Наш сервер (tc-сервер) и клиент (браузер) находятся на разных (виртуальных) машинах и в том же домене.
Ответы
Ответ 1
Это может произойти, если вы запускаете клиент и сервер на одном компьютере. Когда вы используете IE для общения с машиной, работающей с tomcat, убедитесь, что это разные машины.
Кроме того, вам необходимо убедиться, что серверный сервер подключен к домену, указанному в keytab (testdomain.ourcompany.co.uk), или вы можете вернуться к NTLM. Ваш keytab все еще может работать, даже если ваш сервер находится на машине, не подключенной к домену (вы увидите хороший расшифрованный keytab, который вы показали), но IE может запутаться и не сделать правильную вещь.
AD действительно очень любит говорить arcfour-hmac для Server 2003, поэтому вам нужно убедиться, что вы правильно установили его в файле krb5.ini.
Вы можете правильно создать keytab следующим образом:
C:\>ktpass -princ HTTP/[email protected] -mapuser [email protected] -crypto RC4-HMAC-NT -ptype K
RB5_NT_PRINCIPAL -pass * -out ourweb.keytab
Targeting domain controller: test-dc.ourcompany.co.uk
Using legacy password setting method
Successfully mapped HTTP/[email protected] to ourweb.testdomain.ourcompany.co.uk.
Key created.
Output keytab to ourweb.keytab:
Keytab version: 0x502
keysize 75 HTTP/[email protected] ptype 1 (KRB5_NT_PRINCIPAL)
vno 3 etype 0x17 (RC4-HMAC) keylength 16 (0x0fd0e500225c4fca9a63a9998b17ca32)
Я не видел, что вы создали файл krb5.ini. Вам нужно будет правильно установить это на своей серверной машине (местоположение по умолчанию C:\WINDOWS\krb5.ini):
[domain_realm]
.testdomain.ourcompany.co.uk = TESTDOMAIN.OURCOMPANY.CO.UK
testdomain.ourcompany.co.uk = TESTDOMAIN.OURCOMPANY.CO.UK
[libdefaults]
default_realm = TESTDOMAIN.OURCOMPANY.CO.UK
permitted_enctypes = aes128-cts aes256-cts arcfour-hmac-md5
default_tgs_enctypes = aes128-cts aes256-cts arcfour-hmac-md5
default_tkt_enctypes = aes128-cts aes256-cts arcfour-hmac-md5
[realms]
VERDAD.LOCAL = {
kdc = test-dc.ourcompany.co.uk
admin_server = test-dc.ourcompany.co.uk
default_domain = TESTDOMAIN.OURCOMPANY.CO.UK
}
Вам также может потребоваться установить следующие свойства (если вы пытаетесь запустить это из среды IDE):
<systemProperties>
<java.security.krb5.kdc>test-dc.ourcompany.co.uk</java.security.krb5.kdc>
<java.security.krb5.realm>TESTDOMAIN.OURCOMPANY.CO.UK</java.security.krb5.realm>
</systemProperties>
Я использовал плагин org.codehaus.mojo для maven, который устанавливает их в файле pom следующим образом:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<configuration>
<server>tomcat-development-server</server>
<port>8080</port>
<path>/SecurityTest</path>
<systemProperties>
<java.security.krb5.kdc>test-dc.ourcompany.co.uk</java.security.krb5.kdc
<java.security.krb5.realm>TESTDOMAIN.OURCOMPANY.CO.UK</java.security.krb5.realm>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
Ответ 2
Я также столкнулся с этой проблемой.
Для тех, кому не повезло, у кого будет эта проблема в будущем, другой причиной этой проблемы является обращение к серверу с помощью ip вместо него. Запись (имя хоста)
Ответ 3
У меня также была такая же проблема, и я очень долго искал преступника. Поэтому, если вы сделали все вышеописанное и все еще используете токен NTLM вместо kerberos. убедитесь, что у вас нет дубликата SPN. в моем случае у меня было 2 аккаунта, сопоставленных с одним SPN, и причина в том, что я ранее запускал отдельное веб-приложение на том же сервере, которое использовало другую учетную запись службы, но сопоставлено с тем же SPN, что и HTTP/
Надеюсь, что это поможет