Reputation: 21
I wanted to know how to use Spring Security Kerberos with Spring Boot 2.0.
We are currently trying to get the SPNego filter to work.
This is the error:
o.s.s.k.w.a.SpnegoAuthenticationProcessingFilter : Negotiate Header was invalid: Negotiate YHoGBisGAQUFAqBwMG6gMDAuBgorBgEEAYI3AgIKBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICHqI6BDhOVExNU1NQAAEAAACXsgjiAwADADUAAAANAA0AKAAAAAYBsR0AAAAPSU5CT01WRDgxMTAzMURCRw==
org.springframework.security.authentication.BadCredentialsException: GSSContext name of the context initiator is null
at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:173)
at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:153)
at java.security.AccessController.doPrivileged(Native Method)
Currently we are trying to authenticate only a single endpoint (/protected
), but we need to secure all the endpoints using kerberos authentication.
This is the web security config(same code is working with Spring Boot 1.5.13.RELEASE but not with Spring Boot 2.0.3.RELEASE):
package com.findwise.kerberos.config;
import com.findwise.kerberos.localhost.LocalhostAuthFilter;
import com.findwise.kerberos.localhost.LocalhostAuthProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator;
import org.springframework.security.kerberos.client.config.SunJaasKrb5LoginConfig;
import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter;
import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint;
import org.springframework.security.ldap.userdetails.LdapUserDetailsService;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import java.util.Collection;
/**
* SpringSecurityConfig:
* <p>
* This is our main security configuration - It follows very closely the
* examples provided by Spring.IO - Spring Security Kerberos.
*
* @author Peter Gylling - email: [email protected]
* @link http://docs.spring.io/spring-security-kerberos/docs/current/reference/htmlsingle/
*/
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${app.service-principal}")
private String servicePrincipal;
@Value("${app.keytab-location}")
private String keytabLocation;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.exceptionHandling()
.authenticationEntryPoint(spnegoEntryPoint())
.and().authorizeRequests().anyRequest().authenticated()
.and().addFilterBefore( spnegoAuthenticationProcessingFilter(authenticationManagerBean()),
BasicAuthenticationFilter.class);
}
/**
* This ensures a global configuration for the security of the application.
*
* @param auth
* @param kerbServiceProvider
*/
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth,
LocalhostAuthProvider localhostAuthProvider,
KerberosServiceAuthenticationProvider kerbServiceProvider) {
auth
.authenticationProvider(localhostAuthProvider)
.authenticationProvider(kerbServiceProvider);
}
/**
* Provide the default Spring Authentication Manager bean.
* This is used by the SpnegoAuthenticationProcessingFilter as
* part of the configuration.
*
* @return
* @throws Exception
* @see SpnegoAuthenticationProcessingFilter
*/
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* LocalhostAuthProvider:
* Provided with the username from the LocalAuthFilter the LocalhostAuthProvider
* calls Ldap and extracts the roles of the current user.
*
* @return a configured localhost auth provider
*/
@Bean
public LocalhostAuthProvider localhostAuthProvider() {
LocalhostAuthProvider localhostAuthProvider = new LocalhostAuthProvider();
localhostAuthProvider.setUserDetailsService(new KerberosUserDetailsService());
return localhostAuthProvider;
}
/**
* LocalhostAuthFilter:
* Graps the SPNEGO request before the Kerberos based SPNEGO authentication filter
* and shortcuts the system to allow for local users. (The developer use cae).
*
* @param authenticationManager - Standard Spring Security
* @return a configured LocalHostAuth filter.
*/
@Bean
public LocalhostAuthFilter localhostAuthFilter(AuthenticationManager authenticationManager) {
LocalhostAuthFilter localhostAuthFilter = new LocalhostAuthFilter();
localhostAuthFilter.setAuthenticationManager(authenticationManager);
return localhostAuthFilter;
}
/**
* Setup SpnegoEntryPoint to point to the login
* page provided by the login.jsp page.
*
* @return
*/
@Bean
public SpnegoEntryPoint spnegoEntryPoint() {
return new SpnegoEntryPoint("/protected");
}
/**
* SpnegoAuthenticationProcessingFilter:
* <p>
* This is your friendly SSO filter, that kindly automatically
* logs the user in if the Browser provides the actual credentials
*
* @param authenticationManager - with BeanIds.AUTHENTICATION_MANAGER
* @return
* @See AuthenticationManager
*/
@Bean
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(
AuthenticationManager authenticationManager) {
SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
filter.setAuthenticationManager(authenticationManager);
return filter;
}
/**
* KerberosServiceAuthenticationProvider:
* <p>
* This bean is needed by the global AuthenticationManager bean as the only
* accepted authentication providers.
* <p>
* To actually provide Spring Security with the required user details the
* LdapUserDetailsService is provided to the service auth provider.
* <p>
* The Ldap service will not be used until the TicketValidator has granted
* general access.
*
* @return - A configured Kerberos Service Auth Provider
* @see SunJaasKerberosTicketValidator
* @see LdapUserDetailsService
*/
@Bean
public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
provider.setTicketValidator(sunJaasKerberosTicketValidator());
provider.setUserDetailsService(new KerberosUserDetailsService());
return provider;
}
/**
* SunJaasKerberosTicketValidator
* <p>
* This bean will on behalf of the web application validate the visiting users provided
* Kerberos Ticket. This will not kick in if the underlying JAAS and KRB5 configuration is
* not working as expected.
* <p>
* Find the values of the servicePrincipal and keytabLocation in application.properties
*
* @return - A Kerberos Ticket Validator
* @see KerberosGlobalConfig
*/
@Bean
public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
ticketValidator.setServicePrincipal(servicePrincipal);
ticketValidator.setKeyTabLocation(new FileSystemResource(keytabLocation));
ticketValidator.setDebug(true);
return ticketValidator;
}
/**
* SunJaasKrb5LoginConfig
* <p>
* This is what you would previously find in a JAAS Conf file.
* <p>
* Find the servicePrincipal and keytabLocation is application.properties
*
* @return a configured JAAS login
* @see SunJaasKrb5LoginConfig
*/
@Bean
public SunJaasKrb5LoginConfig loginConfig() {
SunJaasKrb5LoginConfig loginConfig = new SunJaasKrb5LoginConfig();
loginConfig.setKeyTabLocation(new FileSystemResource(keytabLocation));
loginConfig.setServicePrincipal(servicePrincipal);
loginConfig.setDebug(true);
loginConfig.setIsInitiator(true);
loginConfig.setUseTicketCache(true);
return loginConfig;
}
protected static class KerberosUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(final String s) throws UsernameNotFoundException {
return new UserDetails() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return null;
}
@Override
public String getUsername() {
return s;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
};
}
}
}
Upvotes: 0
Views: 10911
Reputation: 21
Kerberos service principal didn't setup properly. Now its working fine.
Basic configuration steps :
1) Krb5 conf should be loaded properly (it contains KDC and realm related information).
2) Service principal (HTTP/xyz) must be created and keytab should be provided as a configuration.
3) If you are calling any rest service via client program then you need to provide user principal and keytab, or you can use local Kerberos cache (krb5_123x).
Upvotes: 2