Kerberos – 使用HMAC无法找到适当类型的密钥来解密AP REP-RC4

我正在尝试使用Kerberos / SpNego为Java WebApp设置SSO。 我在用着:

  • Java 1.7u67
  • org.springframework.security.kerberos 1.0.0.RELEASE
  • 活动目录
  • Linux上的Tomcat 7

克服了如何在Tomcat / linux服务器上配置kerberos中描述的问题? ,我现在坚持以下错误:

org.springframework.security.authentication.BadCredentialsException: Kerberos validation not succesful at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:70) ~[spring-security-kerberos-core-1.0.0.RELEASE.jar:1.0.0.RELEASE] at org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider.authenticate(KerberosServiceAuthenticationProvider.java:64) ~[spring-security-kerberos-core-1.0.0.RELEASE.jar:1.0.0.RELEASE] at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156) ~[spring-security-core-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter.doFilter(SpnegoAuthenticationProcessingFilter.java:145) ~[spring-security-kerberos-web-1.0.0.RELEASE.jar:1.0.0.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.55] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.55] at org.lightadmin.core.view.TilesContainerEnrichmentFilter.doFilterInternal(TilesContainerEnrichmentFilter.java:40) [lightadmin-1.2.0.RC1.jar:1.2.0.RC1] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.55] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.55] at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.55] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.55] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) [catalina.jar:7.0.55] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [catalina.jar:7.0.55] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) [catalina.jar:7.0.55] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) [catalina.jar:7.0.55] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) [catalina.jar:7.0.55] at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) [catalina.jar:7.0.55] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [catalina.jar:7.0.55] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) [catalina.jar:7.0.55] at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070) [tomcat-coyote.jar:7.0.55] at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611) [tomcat-coyote.jar:7.0.55] at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316) [tomcat-coyote.jar:7.0.55] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_67] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_67] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-coyote.jar:7.0.55] at java.lang.Thread.run(Thread.java:745) [na:1.7.0_67] Caused by: java.security.PrivilegedActionException: null at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_67] at javax.security.auth.Subject.doAs(Subject.java:415) ~[na:1.7.0_67] at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:67) ~[spring-security-kerberos-core-1.0.0.RELEASE.jar:1.0.0.RELEASE] ... 42 common frames omitted Caused by: org.ietf.jgss.GSSException: Failure unspecified at GSS-API level (Mechanism level: Invalid argument (400) - Cannot find key of appropriate type to decrypt AP REP - RC4 with HMAC) at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:788) ~[na:1.7.0_67] at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342) ~[na:1.7.0_67] at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285) ~[na:1.7.0_67] at sun.security.jgss.spnego.SpNegoContext.GSS_acceptSecContext(SpNegoContext.java:875) ~[na:1.7.0_67] at sun.security.jgss.spnego.SpNegoContext.acceptSecContext(SpNegoContext.java:548) ~[na:1.7.0_67] at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342) ~[na:1.7.0_67] at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285) ~[na:1.7.0_67] at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:162) ~[spring-security-kerberos-core-1.0.0.RELEASE.jar:1.0.0.RELEASE] at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:152) ~[spring-security-kerberos-core-1.0.0.RELEASE.jar:1.0.0.RELEASE] ... 45 common frames omitted Caused by: sun.security.krb5.KrbException: Invalid argument (400) - Cannot find key of appropriate type to decrypt AP REP - RC4 with HMAC at sun.security.krb5.KrbApReq.authenticate(KrbApReq.java:273) ~[na:1.7.0_67] at sun.security.krb5.KrbApReq.(KrbApReq.java:144) ~[na:1.7.0_67] at sun.security.jgss.krb5.InitSecContextToken.(InitSecContextToken.java:108) ~[na:1.7.0_67] at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:771) ~[na:1.7.0_67] ... 53 common frames omitted 

但是,似乎密钥应该存在,因为在应用程序启动时,我得到了以下调试:

  Debug is true storeKey true useTicketCache false useKeyTab true doNotPrompt true ticketCache is null isInitiator false KeyTab is /opt/pksvc/tomcat_edl/current/conf/TestSpnego.keytab refreshKrb5Config is false principal is TestSpnego@MYREALM.DE tryFirstPass is false useFirstPass is false storePass is false clearPass is false principal is TestSpnego@MYREALM.DE Will use keytab >>> KeyTabInputStream, readName(): MYREALM.DE >>> KeyTabInputStream, readName(): HTTP >>> KeyTabInputStream, readName(): lxdetstpksvc01.mydomain.de >>> KeyTab: load() entry length: 83; type: 23 Ordering keys wrt default_tkt_enctypes list Java config name: /opt/pksvc/tomcat_edl/current/conf/krb5.conf Loaded from Java config default etypes for default_tkt_enctypes: 23. Commit Succeeded 

所以enctype 23 =带有HMAC的RC4是KeyTab条目的类型和默认的enctype。 我还可以看到浏览器发送带有此enctype的标记(我从以下内容中删除了二进制文件):

 Ticket TicketType{TktVno=5,Realm=MYREALM.DE,Sname=HTTP/lxdetstpksvc01.mydomain.de,EncPart=EncryptedData{Etype=23,Kvno=4,Cipher=binary[... 352 16728 KerberosV5.TicketType Authenticator EncryptedData{Etype=23,Kvno=nothing,Cipher=binary[... 17080 2872 KerberosV5.EncryptedData 

所以一切似乎都是encytpe 23(RC4与HMAC)。 当我查看代码时,我发现KrbApReq使用的sun.security.krb5.EncryptionKey(它在上面的堆栈中抛出错误)确实不仅要比较enctype,还要比较版本。 所以我想这就是我的情况一定是错的。 在上面的票证中,对于EncryptedData是Kvno = 4,对于Authenticator EncryptedData,它是Kvno = nothing。 这些匹配吗?

我该如何解决这个问题? 这是否受到keytab生成的影响?

原来上面的错误是由两个问题引起的:

  1. 弹簧配置中的服务主体是错误的。 它是lxdetstpksvc01.mydomain.de@MYREALM.DE,但是HTTP /lxdetstpksvc01.mydomain.de@MYREALM.DE是正确的。

  2. keytab中的Kvno与存储在活动目录中的Kvno不同。 如https://tomcat.apache.org/tomcat-7.0-doc/windows-auth-howto.html所述,Active Directory在每次执行ktpass时都会提升Kvno​​。 但是我无法在AD中找到它的值(msDS-KeyVersionNumber),只能从请求中获取它。

总结了“无法找到适当类型的密钥以解密…”错误可能是由以下问题之一引起的:

  1. Spring安全配置中的服务原则与keytab(来自ktpass的param / princ)的服务原则不同。
  2. AD发送票证的enctype没有密钥(来自ktpass的param / crypto,并在krb5.conf / allowed_enctypes + default_tkt_enctypes中设置)。
  3. 票证中的Kvno与keytab中的Kvno不同(来自ktpass的param / kvno)。
  4. keytab的路径是错误的(参见Xavier Portebois的回答)
  5. 该进程无权读取密钥表(请参阅user7610的评论)

我们还得到了一个Invalid argument (400) - Cannot find key of appropriate type to decrypt ...错误。

如果keytab的路径错误,可以简单地抛出这个 (在我们的例子中,我们忘记了我们在那里有一个docker卷映射)。

因此,请确保keytab路径是正确的,因为这可能会触发这个奇怪的exception。

如果您使用Active Directory作为KDC并且keytab用户配置为与keytab使用的加密设置不同的加密设置,也会引发此问题。 在我的情况下,AES 128已配置,我期待AES 256. AD中的配置的简单更改解决了这个问题。

在我的例子中,服务器的jaas配置文件需要将参数“storeKey”设置为true。