Erreur" Defective token detected " (NTLM not Kerberos) avec Kerberos / Spring Security / IE / Active Directory

nous avons de la difficulté à faire fonctionner Spring Security/Kerberos/AD pour notre application web. Notre diagnostic est que notre serveur publicitaire envoie un jeton NTLM (nous pouvons dire comme il commence par "TlRMTVNT.....") à IE et IE envoie alors ceci à notre application et c'est un échec. Notre serveur publicitaire devrait envoyer un token Kerberos/SPNEGO à IE.

"pièces mobiles" sont comme suit:

  • Spring Security 3.0 (patched)
  • Microsoft Windows Server Enterprise 2003 SP1 Active Directory
  • IE 8
  • Tomcat (tc Server 6.0)
  • Java 1.6

nous avons tout mis en place 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 comme Principal de Service (le même que le nom de la machine où réside notre application). Nous avons défini la suite options de compte:
    • désactivé 'a Utiliser pour changer le mot de passe à la prochaine ouverture de session'
    • activé le mot de passe n'expire jamais'.
    • activé 'Utilisation de Kerberos DES...'
    • handicapés, Ne nécessitent pas la pré-authentification Kerberos'
    • NOTE: Server 2003 ne présente pas les options "This account supports Kerberos AES 128 bit..." et " This account supports Kerberos AES 256 bit..."
  • utilisé " ktpass.exe " pour attribuer le nom principal du service (SPN) à ce nouvel utilisateur et exporter cette clé utilisateur vers un fichier keytab. utiliser 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 *'
  • code source Téléchargé de https://src.springframework.org/svn/se-security/trunk.
  • copié le fichier keytab du serveur publicitaire à WEB-INF / etc du code source (application).
  • Fait changement dans le fichier SunJaasKerbersoTicketValidator.java pour lire fichier keytab. (Pour résoudre le bogue dans lequel l'application ne peut pas lire le fichier keytab à partir du classpath Java) option.mettre ("keyTab", "C:se-securityspring-security-kerberosspring-security-kerberos-samplesrcmainwebappWEB-INFetcourweb.keytab");
  • configuré web.xml pour utiliser spnego.XML. contextConfigLocation / WEB-INF / spnego.XML
    • sécurité de ressort configurée (spnego.xml) pour utiliser Kerberos (SpnegoEntryPoint, SpnegoAuthenticationProcessingFilter et KerberosServiceAuthenticationProvider beans) en fournissant notre nom principal de service et l'emplacement des fichiers keytab.
    • configuré spnego.xml pour lire fichier keytab copié dans WEB-INF/etc.

lorsque nous avons démarré notre serveur TC, nous avons pu voir les choses s'initialiser correctement (i.e. sans erreur - "principes clés obtenues à partir du fichier 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:WINDOWSkrb5.ini
Debug is  true storeKey true useTicketCache false useKeyTab true doNotPrompt true ticketCache is null isInitiator false KeyTab is C:se-securityspring-security-kerberosspring-security-kerberos-samplesrcmainwebappWEB-INFetcourwebapp4.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' 

prêt à tester, nous avons ensuite activé "Windows Integrated Authentication" dans IE et nous nous sommes assurés que le domaine était listé dans la section locale du site intranet D'IE. Nous nous sommes ensuite connectés à notre application web en utilisant le nom de domaine entièrement qualifié.

Quand nous l'avons fait nous avons obtenu l'erreur suivante dans le navigateur:

500 Internal server error.

et dans le TC fichier journal du Serveur:

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 (à partir ce que nous pouvons faire) que le serveur publicitaire envoie un token NTLM (nous pouvons dire que cela commence par "TlRMTVNT.....") à IE et IE envoie alors ceci à notre application et c'est un échec.

notre serveur publicitaire devrait envoyer un jeton Kerberos/SPNEGO à IE.

autres notes:

  • notre serveur (tc server) et client (browser) sur différentes machines (virtuelles) et dans le même domaine.
29
demandé sur Anthony O. 2010-06-04 14:44:31

3 réponses

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 qui exécute tomcat, assurez-vous qu'il s'agit de machines distinctes.

de plus, vous devez vous assurer que la machine du serveur est reliée au domaine spécifié dans le domaine keytab (testdomain.notre société.co.uk) ou vous pouvez revenir à NTLM. Votre clavier peut encore fonctionner même si votre serveur est sur une machine qui n'est pas reliée au domaine (vous verrez le joli clavier décrypter que vous avez montré), mais IE peut être confus et ne pas faire la bonne chose.

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

vous pouvez créer correctement le clavier comme ceci:

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)

je n'ai pas vu que vous aviez mis en place un krb5.fichier ini. Vous aurez besoin d'avoir ce jeu correctement sur votre machine de 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 peut aussi avoir besoin de définir les propriétés suivantes (si vous essayez d'exécuter ceci à 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 l'org.codehaus.Mojo plugin 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>
26
répondu Grant Cermak 2010-08-04 22:35:39

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

7
répondu Lior Chaga 2014-05-20 13:15:06

j'ai également eu le même problème et m'a pris très longtemps pour trouver le coupable. Donc si vous avez fait tout ce qui précède et encore il utilise NTLM token au lieu de kerberos. assurez-vous que vous n'avez pas dupliquer SPN. dans mon cas, j'avais 2 comptes mappés sur le même SPN et la raison en était que j'avais déjà lancé une application web séparée sur le même serveur qui utilisait un compte de service différent mais mappé sur le même SPN qui était HTTP/

j'Espère que ça aide

5
répondu arash 2015-04-11 14:06:28