I've implemented kerberos authentication with SPNEGO using spring security. Everything works fine on my computer.
I've used the exact keytab file and the krb5 configuration that worked on my computer and put it in the test environment. Both environments use tomcat 6 and I've installed the exact jdk version.
However, on the test environment I get the following:
16:27:33 WARN http-8180-1 org.springframework.security.extensions.kerberos.web.SpnegoAuthenticationProcessingFilter - Negotiate Header was invalid: Negotiate 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
org.springframework.security.authentication.BadCredentialsException: Kerberos validation not succesfull
at org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:69)
at org.springframework.security.extensions.kerberos.KerberosServiceAuthenticationProvider.authenticate(KerberosServiceAuthenticationProvider.java:86)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at org.springframework.security.extensions.kerberos.web.SpnegoAuthenticationProcessingFilter.doFilter(SpnegoAuthenticationProcessingFilter.java:131)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
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 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
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:291)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:877)
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:594)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1675)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.security.PrivilegedActionException: GSSException: Failure unspecified at GSS-API level (Mechanism level: Specified version of key is not available (44))
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:415)
at org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:67)
... 22 more
Caused by: GSSException: Failure unspecified at GSS-API level (Mechanism level: Specified version of key is not available (44))
at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:788)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285)
at sun.security.jgss.spnego.SpNegoContext.GSS_acceptSecContext(SpNegoContext.java:875)
at sun.security.jgss.spnego.SpNegoContext.acceptSecContext(SpNegoContext.java:548)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285)
at org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:146)
at org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:136)
... 25 more
Caused by: KrbException: Specified version of key is not available (44)
at sun.security.krb5.EncryptionKey.findKey(EncryptionKey.java:588)
at sun.security.krb5.KrbApReq.authenticate(KrbApReq.java:270)
at sun.security.krb5.KrbApReq.<init>(KrbApReq.java:144)
at sun.security.jgss.krb5.InitSecContextToken.<init>(InitSecContextToken.java:108)
at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:771)
... 33 more
I've tested my keytab file according to this post on the test machine and everything looks good.
My machine - windows 7 pro Test machine - windows server 2008 R2
Any apparent reason why the keytab would be valid on one machine and not on the other?
My next step would be regenerating the keytab, but that's just voodoo, and I don't like voodoo.
Thanks, Lior
EDIT:
I'm not directly using the KRB5ModuleLogin. I use spring security with kerberos extension.
Behind the scenes it's obviously using the module, but I don't know how I could configure it (maybe through the krb5.conf file).
Here is my relevant spring configuration:
<bean id="kerberosServiceAuthenticationProvider"
class="org.springframework.security.extensions.kerberos.KerberosServiceAuthenticationProvider">
<property name="ticketValidator">
<bean
class="org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator">
<property name="servicePrincipal" value="${krb.service.prinicipal}" />
<!-- Setting keyTabLocation to a classpath resource will most likely not work in a Java EE application Server -->
<!-- See the Javadoc for more information on that -->
<property name="keyTabLocation" value="${krb.keytab.location}" />
<property name="debug" value="${krb.debug}" />
</bean>
</property>
<property name="userDetailsService" ref="LDAPUserDetailsService" />
</bean>
<!-- This bean definition enables a very detailed Kerberos logging -->
<bean
class="org.springframework.security.extensions.kerberos.GlobalSunJaasKerberosConfig">
<property name="debug" value="${krb.debug}" />
<property name="krbConfLocation" value="${krb.conf.location}"/>
</bean>
And the krb5.conf injected to the GlobalSunJaasKerberosConfig is as follows:
[libdefaults]
default_realm = DOMAIN.COM
forwardable = true
proxiable = true
[realms]
DOMAIN.COM = {
kdc = controller1.domain.com
kdc = controller2.domain.com
kdc = controller3.domain.com
admin_server = controler.domain.com
default_domain = DOMAIN.COM
}
[domain_realm]
.domain.com = DOMAIN.COM
domain.com = DOMAIN.COM
[login]
krb4_convert = true
krb4_get_tickets = false
EDIT 2
I've debugged into the test server, and compared to my computer.
This is the debug info from the login context in my dev (which works):
Debug is true storeKey true useTicketCache false useKeyTab true doNotPrompt true ticketCache is null isInitiator false KeyTab is file:/C:/Eclipse/Loans_maven/http-web.keytab refreshKrb5Config is false principal is HTTP/[email protected] tryFirstPass is false useFirstPass is false storePass is false clearPass is false
>>> KeyTabInputStream, readName(): DOMAIN.COM
>>> KeyTabInputStream, readName(): HTTP
>>> KeyTabInputStream, readName(): testing.domain.com
>>> KeyTab: load() entry length: 71; type: 23
Added key: 23version: 24
Ordering keys wrt default_tkt_enctypes list
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 3 1 23 16 17 18.
principal's key obtained from the keytab
principal is HTTP/[email protected]
EncryptionKey: keyType=23 keyBytes (hex dump)=0000: 05 DF 2F D1 10 9E 3D 3B 60 F1 10 96 5F 6A F1 28 ../...=;`..._j.(
Added server's keyKerberos Principal HTTP/[email protected] Version 24key EncryptionKey: keyType=23 keyBytes (hex dump)=
0000: 05 DF 2F D1 10 9E 3D 3B 60 F1 10 96 5F 6A F1 28 ../...=;`..._j.(
[Krb5LoginModule] added Krb5Principal HTTP/[email protected] to Subject
Commit Succeeded
And this is the debug info when the login is done in the test server:
Debug is true storeKey true useTicketCache false useKeyTab true doNotPrompt true ticketCache is null isInitiator false KeyTab is file:/D:/Apps/fibi-loans/config/http-web.keytab refreshKrb5Config is false principal is HTTP/[email protected] tryFirstPass is false useFirstPass is false storePass is false clearPass is false
>>> KeyTabInputStream, readName(): DOMAIN.COM
>>> KeyTabInputStream, readName(): HTTP
>>> KeyTabInputStream, readName(): testing.domain.com
>>> KeyTab: load() entry length: 71; type: 23
Added key: 23version: 24
Ordering keys wrt default_tkt_enctypes list
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 3 1 23 16 17.
principal's key obtained from the keytab
principal is HTTP/[email protected]
EncryptionKey: keyType=23 keyBytes (hex dump)=0000: 05 DF 2F D1 10 9E 3D 3B 60 F1 10 96 5F 6A F1 28 ../...=;`..._j.(
Added server's keyKerberos Principal HTTP/[email protected] Version 24key EncryptionKey: keyType=23 keyBytes (hex dump)=
0000: 05 DF 2F D1 10 9E 3D 3B 60 F1 10 96 5F 6A F1 28 ../...=;`..._j.(
[Krb5LoginModule] added Krb5Principal HTTP/[email protected] to Subject
Commit Succeeded
As you can see, it's quite the same (except for the location of the keytab file, but as I said, the keytab file is identical) Another difference is that the dev supports enc_type 18, whereas the test does not, but this seems irrelevant, because the key type is 23 (RC4-HMAC-NT), and both support is.
So why, for goodness sake, does the test machine reject the keytab file when a user tries to login?
Java checks if the version-nummer (kvno) of the keytab-file is the same as the one in the kerberos database (LDAP server). This error comes if both nummer differ from oneother.
You can bypass this check by creating the keytab with the jdk tool ktab.exe
and its parameter -n 0
. Java will not check a keytab with knvo = 0
.
It would however be better not to use ktab.exe
at all but to produce the keytab with ktpass.exe
on the ADS-Server, which directly writes the right version-number in the file.
See this article: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6984764