web-dev-qa-db-fra.com

Erreur "Jeton défectueux détecté" (NTLM et non Kerberos) avec Kerberos / Spring Security / IE / Active Directory

Nous avons du mal à faire fonctionner Spring Security/Kerberos/AD pour notre application Web. Notre diagnostic est que notre serveur AD envoie un token NTLM (on peut dire comme il commence par "TlRMTVNT .....") à IE et IE envoie alors ceci à notre application et il échoue. Notre serveur AD devrait envoyer un jeton Kerberos/SPNEGO à IE.

Les "pièces mobiles" sont les suivantes:

  • Spring Security 3.0 (corrigé)
  • Active Directory Microsoft Windows Server Entreprise 2003 SP1
  • IE 8
  • Tomcat (serveur TC 6.0)
  • Java 1.6

Nous avons tout configuré comme détaillé dans les instructions ici:

https://spring.io/blog/2009/09/28/spring-security-kerberos-spnego-extension

Cela impliquait:

  • Création d'un utilisateur normal en tant que principal du service (le même que le nom de la machine où réside notre application). Nous définissons les options de compte suivantes:
    • désactivé 'Utiliser doit changer le mot de passe à la prochaine connexion'
    • activé 'le mot de passe n'expire jamais'
    • activé 'Utiliser Kerberos DES…'
    • désactivé 'Ne nécessite pas de pré-authentification Kerberos'
    • REMARQUE: Server 2003 ne présente pas les options "Ce compte prend en charge Kerberos AES 128 bits…" et "Ce compte prend en charge Kerberos AES 256 bits…"
  • "Ktpass.exe" a été utilisé pour attribuer le nom principal du service (SPN) à ce nouvel utilisateur et exporter cette clé utilisateur vers un fichier keytab. en utilisant 'ktpass/out ourweb.keytab/mapuser [email protected]/princ HTTP/[email protected]/pass * '
  • Code source téléchargé depuis https://src.springframework.org/svn/se-security/trunk .
  • Copie du fichier keytab du serveur AD vers WEB-INF/etc du code source (application).
  • Modification du fichier SunJaasKerbersoTicketValidator.Java pour lire le fichier keytab. (Pour résoudre le bogue dans lequel l'application ne peut pas lire le fichier keytab à partir de 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 configuré pour utiliser spnego.xml. contextConfigLocation /WEB-INF/spnego.xml
    • Configuration de Spring Security (spnego.xml) pour utiliser Kerberos (beans SpnegoEntryPoint, SpnegoAuthenticationProcessingFilter et KerberosServiceAuthenticationProvider) en fournissant le nom principal de notre service et l'emplacement du fichier keytab.
    • Configuration de spnego.xml pour lire le fichier keytab copié dans WEB-INF/etc.

Lorsque nous avons démarré notre serveur TC, nous pouvions voir les choses s’initialiser correctement (c’est-à-dire sans erreur - "principes clés obtenus à partir du 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's 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'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/[email protected] to Subject Commit Succeeded 

Finished creating instance of bean 'org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator#10fa4b8' 

Prêt à tester, nous avons ensuite activé "l'authentification intégrée Windows" dans IE et nous nous sommes assurés que le domaine était répertorié dans la section du site intranet local d'IE. Nous nous sommes ensuite connectés à notre application Web à l'aide du domaine pleinement qualifié. Nom.

Lorsque nous l'avons fait, nous avons eu les erreurs suivantes dans le navigateur:

500 Internal server error.

et dans le fichier journal du serveur 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

Il semble (d'après ce que nous pouvons comprendre) que le serveur AD envoie un jeton NTLM (nous pouvons dire qu'il commence par "TlRMTVNT .....") à IE et IE envoie alors ceci à notre application et il échoue.

Notre serveur AD devrait envoyer un jeton Kerberos/SPNEGO à IE.

Autres notes:

  • Notre serveur (serveur tc) et client (navigateur) sont sur des machines (virtuelles) différentes et dans le même domaine.
30

Cela peut se produire lorsque vous exécutez le client et le serveur sur la même machine. Lorsque vous utilisez IE pour parler à la machine exécutant Tomcat, assurez-vous qu'il s'agit de machines distinctes.

De plus, vous devez vous assurer que la machine serveur est jointe au domaine spécifié dans le keytab (testdomain.ourcompany.co.uk) ou vous pouvez revenir à NTLM. Votre keytab peut toujours fonctionner même si votre serveur est sur une machine non jointe au domaine (vous verrez le keytab de Nice décrypter que vous avez montré), mais IE peut être confus et ne pas faire le chose correcte.

AD n'aime vraiment parler arcfour-hmac que pour Server 2003, vous devez donc vous assurer que vous l'avez configuré correctement dans votre fichier krb5.ini.

Vous pouvez créer correctement le keytab comme ceci:

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)

Je n'ai pas vu que vous aviez créé un fichier krb5.ini. Vous devrez l'avoir défini correctement sur votre machine serveur (emplacement par défaut 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
}

Vous devrez peut-être également définir les propriétés suivantes (si vous essayez de l'exécuter à partir d'un 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>

J'utilisais le plugin org.codehaus.mojo pour maven qui les définit dans le fichier pom comme ceci:

<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>
29
Grant Cermak

J'ai également rencontré ce problème. Pour les personnes malchanceuses qui auront ce problème à l'avenir, une autre cause de ce problème est d'accéder au serveur par ip au lieu de son enregistrement A (nom d'hôte)

7
Lior Chaga

J'ai également eu le même problème et il m'a fallu très très longtemps pour trouver le coupable. Donc, si vous avez fait tout ce qui précède et qu'il utilise toujours un jeton NTLM au lieu de kerberos. assurez-vous que vous n'avez pas de SPN en double. dans mon cas, j'avais 2 comptes mappés sur le même SPN et la raison était que j'avais précédemment exécuté une application Web distincte sur le même serveur qui utilisait un compte de service différent mais mappé au même SPN qui était HTTP /

J'espère que ça aide

5
arash