问题
I'm trying to setup kerberos authentication in a Java web-app running in a Tomcat on Linux. I'm using the spring security kerberos extension. I'm using:
- jdk 1.7u75
- spring-security-kerberos 1.0.0.RELEASE
- MS Active Directory
On my local development machine (windows) everything runs fine. But after deploying the app to a linux machine authentication is no longer working. I strongly suspect that something is wrong with my Kerberos configuration :
[libdefaults]
default_realm = INT.MYCOMPANY.DE
ccache_type=4
kdc_tymesync=1
forwardable=true
proxiable=true
[realms]
INT.MYCOMPANY.DE = {
admin_server = xyz.mycompany.de
kdc = xyz.mycompany.de
}
[domain_realm]
.INT.MYCOMPANY.DE = INT.MYCOMPANY.DE
int.mycompany.de = INT.MYCOMPANY.DE
.int.mycompany.de = INT.MYCOMPANY.DE
.mycompany.de = INT.MYCOMPANY.DE
mycompany.de = INT.MYCOMPANY.DE
[logging]
#kdc = console
(server and realm name changed)
Spring security config:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="file:${externalPropertiesPath}/edlgui.properties" />
<authentication-manager alias="authenticationManager">
<authentication-provider ref="kerberosAuthenticationProvider" />
</authentication-manager>
<http use-expressions="true">
<intercept-url pattern="/login.jsp" access="permitAll" />
<intercept-url pattern="/admin/**" access="hasRole('${edl.gui.authorization.requiredrole}')" />
<form-login login-page="/login.jsp" username-parameter="username" password-parameter="password" default-target-url="/admin"/>
<logout logout-url="/logout" logout-success-url="/login.jsp" />
<http-basic />
<access-denied-handler ref="edlGuiAccessDeniedHandler"/>
</http>
<beans:bean id="edlGuiAccessDeniedHandler" class="edl.security.EdlGuiAccessDeniedHandler">
<beans:constructor-arg value="/login.jsp"/>
</beans:bean>
<beans:bean id="kerberosAuthenticationProvider" class="org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider">
<beans:property name="kerberosClient">
<beans:bean class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient">
<beans:property name="debug" value="false" />
</beans:bean>
</beans:property>
<!-- TODO replace dummy user service -->
<beans:property name="userDetailsService" ref="ldapUserDetailsService" />
</beans:bean>
<beans:bean class="org.springframework.security.kerberos.authentication.sun.GlobalSunJaasKerberosConfig">
<beans:property name="debug" value="false" />
<!-- externalPropertiesPath path = /opt/pksvc/tomcat/current/conf -->
<beans:property name="krbConfLocation" value="file:${externalPropertiesPath}/krb5.conf"/>
</beans:bean>
<!-- Get User Details via LDAP -->
<!-- It would be nice to do this via Kerberos, however that requires a keytab -->
<ldap-user-service id="ldapUserDetailsService"
server-ref="activeDirectoryLdap"
user-search-base="${edl.gui.ldap.usersearchbase}"
user-search-filter="${edl.gui.ldap.usersearchfilter}"
group-search-base="${edl.gui.ldap.groupsearchbase}"
group-role-attribute="${edl.gui.ldap.grouproleattribute}"
group-search-filter="${edl.gui.ldap.groupsearchfilter}"
user-details-class="person"/>
<ldap-server id="activeDirectoryLdap"
url="${edl.gui.ldap.url}"
manager-dn="${edl.gui.ldap.managerdn}"
manager-password="${edl.gui.ldap.managerpw}"
root="${edl.gui.ldap.root}"/>
</beans:beans>
When I try to login the only thing I see from the kerberos debug output is:
Java config name: file:/opt/pksvc/tomcat/current/conf/krb5.conf
getRealmFromDNS: trying mycompany.de
(I would expect to see 'KrbAsReq creating message' and 'KrbKdcReq send' entries)
And from spring:
2015-08-04 10:07:42.986 DEBUG o.s.security.web.FilterChainProxy - /j_spring_security_check at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-08-04 10:07:42.986 DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
2015-08-04 10:07:42.986 DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@64656737. A new one will be created.
2015-08-04 10:07:42.986 DEBUG o.s.security.web.FilterChainProxy - /j_spring_security_check at position 2 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-08-04 10:07:42.986 DEBUG o.s.security.web.FilterChainProxy - /j_spring_security_check at position 3 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2015-08-04 10:07:42.987 DEBUG o.s.security.web.FilterChainProxy - /j_spring_security_check at position 4 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2015-08-04 10:07:42.987 DEBUG o.s.s.w.a.UsernamePasswordAuthenticationFilter - Request is to process authentication
2015-08-04 10:07:42.987 DEBUG o.s.s.authentication.ProviderManager - Authentication attempt using org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider
2015-08-04 10:07:42.987 DEBUG o.s.s.k.a.sun.SunJaasKerberosClient - Trying to authenticate KieselGun with Kerberos
2015-08-04 10:07:42.993 DEBUG o.s.s.w.a.UsernamePasswordAuthenticationFilter - Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Kerberos authentication failed
2015-08-04 10:07:42.993 DEBUG o.s.s.w.a.UsernamePasswordAuthenticationFilter - Updated SecurityContextHolder to contain null Authentication
2015-08-04 10:07:42.993 DEBUG o.s.s.w.a.UsernamePasswordAuthenticationFilter - Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@72f106b0
2015-08-04 10:07:42.993 DEBUG o.s.s.w.a.SimpleUrlAuthenticationFailureHandler - Redirecting to /login.jsp
2015-08-04 10:07:42.993 DEBUG o.s.s.web.DefaultRedirectStrategy - Redirecting to '/edl-gui/login.jsp'
2015-08-04 10:07:42.993 DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2015-08-04 10:07:42.994 DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
2015-08-04 10:07:43.042 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-08-04 10:07:43.043 DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
2015-08-04 10:07:43.043 DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@64656737. A new one will be created.
2015-08-04 10:07:43.043 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 2 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-08-04 10:07:43.043 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 3 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2015-08-04 10:07:43.043 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 4 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2015-08-04 10:07:43.043 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
2015-08-04 10:07:43.043 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2015-08-04 10:07:43.044 DEBUG o.s.s.w.s.DefaultSavedRequest - pathInfo: both null (property equals)
2015-08-04 10:07:43.044 DEBUG o.s.s.w.s.DefaultSavedRequest - queryString: both null (property equals)
2015-08-04 10:07:43.044 DEBUG o.s.s.w.s.DefaultSavedRequest - requestURI: arg1=/edl-gui/admin; arg2=/edl-gui/login.jsp (property not equals)
2015-08-04 10:07:43.044 DEBUG o.s.s.w.s.HttpSessionRequestCache - saved request doesn't match
2015-08-04 10:07:43.044 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2015-08-04 10:07:43.044 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2015-08-04 10:07:43.044 DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6faa3d44: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff4c9c: RemoteIpAddress: 172.20.65.226; SessionId: F2C563CA5780A3024AE7D89390CE0AB1; Granted Authorities: ROLE_ANONYMOUS'
2015-08-04 10:07:43.044 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2015-08-04 10:07:43.044 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2015-08-04 10:07:43.045 DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2015-08-04 10:07:43.045 DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/login.jsp'; against '/login.jsp'
2015-08-04 10:07:43.045 DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /login.jsp; Attributes: [permitAll]
2015-08-04 10:07:43.045 DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@6faa3d44: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff4c9c: RemoteIpAddress: 172.20.65.226; SessionId: F2C563CA5780A3024AE7D89390CE0AB1; Granted Authorities: ROLE_ANONYMOUS
2015-08-04 10:07:43.045 DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@265c45f7, returned: 1
2015-08-04 10:07:43.045 DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Authorization successful
2015-08-04 10:07:43.045 DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - RunAsManager did not change Authentication object
2015-08-04 10:07:43.045 DEBUG o.s.security.web.FilterChainProxy - /login.jsp reached end of additional filter chain; proceeding with original chain
2015-08-04 10:07:43.046 DEBUG o.s.s.w.a.ExceptionTranslationFilter - Chain processed normally
2015-08-04 10:07:43.046 DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2015-08-04 10:07:43.046 DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
So it seems the user gets authenticated as anonymous, after which I get back to the login page since anonymous users have no access.
Can anyone tell me what's wrong with my configuration? Or how I could further analyse this?
回答1:
I'm not sure how jdk's krb implementation differ between linux and win. Obviously there are some differences because in linux jdk will try to find default /etc/krb5.conf
and there is one other default location I don't remember right now. I assume in win similar tweaks are in place for jdk. You could event temporarily rename default krb5.conf
file to be sure it's not used(and getting wrong config).
I'm shooting in dark here but let's make a random guess. I had a lot of various type of troubles when I make all those samples but eventually got all working. At some point(in linux) when I was totally lost if failures was caused by our spring-security-kerberos libs or something to do with a kerberos settings, etc, I found it to very valuable to test kerberos settings outside of a jdk. See http://docs.spring.io/spring-security-kerberos/docs/1.0.1.RELEASE/reference/htmlsingle/#troubleshooting and especially trying to connect ldapsearch
from linux into AD
. You don't need to use keytabs because kinit should allow you to get ticket from AD if settings are right.
One thing I have there is:
[realms]
EXAMPLE.ORG = {
kdc = WIN-EKBO0EQ7TS7.example.org:88
}
I believe I had this port 88
for a reason and maybe there are some different defaults linux/win jdk's if none are defined.
Other think is supported enctypes
if those are different used by AD
and what linux jdk support. This is something you should see from jdk internal krb debug logs. Also if you are able to kinit
against AD
from linux, klist
will then show key enctypes.
回答2:
I found out that in both my local environment on windows and the linux environment the krb5.conf specified in the GlobalSunJaasKerberosConfig krbConfLocation (see below) was not used. Although the debug output showed this file the changes made there had no effect. In my windows environment I had a correctly setup kerberos configuration (I still don't know where that is, I don't have a krb5.ini anywhere...) in the linux environment I did not. As a result kerberos failed in the linux environment.
I managed to workaround this by setting the environment variables java.security.krb5.realm and java.security.krb5.kdc (see https://blogs.oracle.com/wangwj/entry/kerberos_programming_on_windows). With these set kerberos authentication worked.
The krbConfLocation from this bean was not used:
<beans:bean class="org.springframework.security.kerberos.authentication.sun.GlobalSunJaasKerberosConfig">
<beans:property name="debug" value="false" />
<beans:property name="krbConfLocation" value="file:${externalPropertiesPath}/krb5.conf"/>
</beans:bean>
来源:https://stackoverflow.com/questions/31804452/how-to-configure-kerberos-on-tomcat-linux-server