Ошибка "Обнаружен дефектный токен" (NTLM, а не Kerberos) с Kerberos/Spring Security/IE/Active Directory

У нас проблемы с настройкой Spring Security/Kerberos/AD для нашего веб-приложения. Наш диагноз состоит в том, что наш сервер AD отправляет токен NTLM (мы можем сказать, что он начинается с "TlRMTVNT.....") в IE, а затем IE отправляет это в наше приложение, и это не удается. Наш сервер AD должен отправлять маркер Kerberos/SPNEGO в IE.

"Движущиеся части" следующие:

  • Spring Security 3.0 (исправлено)
  • Microsoft Windows Server Enterprise 2003 с пакетом обновления 1 (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

Это связано с:

  • Создание обычного пользователя в качестве субъекта службы (совпадает с именем компьютера, на котором находится наше приложение). Мы устанавливаем следующие параметры учетной записи:
    • отключено "Использовать необходимо сменить пароль при следующем входе в систему"
    • включен "пароль никогда не истекает"
    • включен 'Использовать Kerberos DES…'
    • отключено "Не требовать предварительной аутентификации Kerberos"
    • ПРИМЕЧАНИЕ. В Server 2003 отсутствуют параметры "Эта учетная запись поддерживает Kerberos AES 128-разрядный..." и "Эта учетная запись поддерживает Kerberos AES 256-разрядный..."
  • Использовал "ktpass.exe", чтобы назначить имя участника-службы (SPN) этому новому пользователю и экспортировать этот ключ пользователя в файл keytab. используя 'ktpass /out ourweb.keytab /mapuser ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK /princ HTTP/ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK /pass *"
  • Загруженный исходный код с https://src.springframework.org/svn/se-security/trunk.
  • Скопировал файл keytab с сервера AD в WEB-INF/etc с исходным кодом (приложение).
  • Внесены изменения в файл SunJaasKerbersoTicketValidator.java для чтения файла keytab. (Чтобы устранить ошибку, из-за которой приложение не может прочитать файл keytab из пути к классам Java) options.put("keyTab", "C:\se-security\spring-security-kerberos\spring-security-kerberos-sample) \ SRC \ главной \ WebApp\WEB-INF\ и т.д. \ourweb.keytab");
  • Настроил web.xml для использования spnego.xml. contextConfigLocation /WEB-INF/spnego.xml
    • Настроил Spring Security (spnego.xml) для использования компонентов Kerberos (SpnegoEntryPoint, SpnegoAuthenticationProcessingFilter и KerberosServiceAuthenticationProvider), предоставив нашему сервису имя участника и местоположение файла keytab.
    • Настроил spnego.xml для чтения файла keytab, скопированного в WEB-INF/etc.

Когда мы запустили наш сервер TC, мы могли видеть, что вещи хорошо инициализируются (то есть без ошибок - "ключ принципов, полученный из таблицы ключей"):

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's key obtained from the keytab
principal is HTTP/ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK
EncryptionKey: keyType=1 keyBytes (hex dump)=0000: 91 01 43 E3 02 A8 B9 83   
Added server's keyKerberos Principal HTTP/ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UKKey Version 2key EncryptionKey: keyType=1 keyBytes (hex dump)=
0000: 91 01 43 E3 02 A8 B9 83   

[Krb5LoginModule] added Krb5Principal  HTTP/ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK 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-сервер) и клиент (браузер) находятся на разных (виртуальных) машинах и в одном домене.

4 ответа

Решение

Это может произойти, если вы используете клиент и сервер на одном компьютере. Когда вы используете IE для связи с машиной, на которой запущен tomcat, убедитесь, что это разные машины.

Кроме того, вам необходимо убедиться, что серверный компьютер подключен к домену, указанному в таблице ключей (testdomain.ourcompany.co.uk), или вы можете вернуться к NTLM. Ваша таблица ключей все еще может работать, даже если ваш сервер находится на компьютере, не присоединенном к домену (вы увидите, что расшифровка ключевой таблицы показана на рисунке), но IE может запутаться и не делать все правильно.

AD действительно любит говорить на arcfour-hmac для Server 2003, поэтому вам нужно убедиться, что вы правильно настроили это в своем файле krb5.ini.

Вы можете правильно создать таблицу ключей следующим образом:

C:\>ktpass -princ HTTP/ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK -mapuser ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK -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/ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK to ourweb.testdomain.ourcompany.co.uk.
Key created.
Output keytab to ourweb.keytab:
Keytab version: 0x502
keysize 75 HTTP/ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK 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>

Я также столкнулся с этой проблемой. Для тех неудачников, у которых в будущем возникнет эта проблема, другой причиной этой проблемы является доступ к серверу по ip вместо записи A (имя хоста)

У меня тоже была такая же проблема, и мне потребовалось очень много времени, чтобы найти виновного. Так что, если вы сделали все вышеперечисленное и до сих пор он использует токен NTLM вместо kerberos. убедитесь, что у вас нет дубликата SPN. в моем случае у меня было 2 учетных записи, сопоставленных одному и тому же имени участника-службы, и причина была в том, что я ранее запустил отдельное веб-приложение на том же сервере, который использовал другую учетную запись службы, но сопоставил с тем же именем участника-службы, которое было HTTP

Надеюсь, поможет

Итак, в моем случае я установил две машины:

  • Win-Root - 192.168.1.100 - Мой тестовый контроллер домена
  • Win-Child - 192.168.1.200 - Сервер, на котором будет запущена служба Tomcat, защищенная Kerberos.

Затем я установил доменные службы Active Directory на Win-Root и повысил его до контроллера домена (включает DNS). Имя домена Netbios =, FQDN= fusionis.life.

Затем я вошел в Win-Child и установил DNS-сервер на 192.168.1.100, затем присоединился к домену FUSIONIS.

Затем я зашел в настройки Win-Root DNS и добавил зону прямого просмотра для fusion.fusoinis.life.

Затем я включил аутентификацию Kerberos для своего приложения tomcat на http://fusion.fusionis.life:8080.

Я вошел в Win-Child, чтобы проверить это.

Но я продолжал получать (Mechanism level: GSSHeader did not find the right tag).

После часа почесывания головы я понял ... Я случайно вошел в систему как локальный аккаунт! Другими словами, whoamiвернул "WIN-23523х253 \ Администратор". Я совершенно забыл войти в систему как учетная запись домена на сервере Win-Child.

Затем я вошел в fusionis\testuser и все заработало как положено.

Извлеченный урок: убедитесь, что вы случайно не вошли в систему под учетной записью вне домена!

Другие вопросы по тегам