Skip to content

Instantly share code, notes, and snippets.

@tobecwb
Created October 16, 2019 12:59
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save tobecwb/9d3c0664ef000450de741582358cf758 to your computer and use it in GitHub Desktop.
Save tobecwb/9d3c0664ef000450de741582358cf758 to your computer and use it in GitHub Desktop.
Kerberos Login with Spring Boot

This documentation show how to configure Spring Boot 2 to authenticate with Kerberos (here, I'm using Windows AD).

Refs:


Setting the user on AD: First of, you must create a valid user on AD. Don't forget to disable the option which force user to change his password on first logon.

After create the user, you must configure user in KDC.


Creating a keytab file:

To configure user in KDC, you will use the ktpass command. This command is available on Windows Server (same server with AD).

According with T-Heron's answer on Stackoverflow, it's not necessary use the setspn command, and in my tests, this is true. So, the only command necessary is ktpass. This must be executed on AD server.

Execute the following command to configure the user and generate a keytab file: ktpass -out outputfile.keytab -princ HTTP/[fqdn]@[domain] -mapUser [user] -mapOp set -pass [password] -crypto ALL -pType KRB5_NT_PRINCIPAL

Where:

  • [fqdn]: full qualified domain name. Must be the name, not IP. Example: server001.domain.intranet.com
  • [domain]: domain name. Example: domain.intranet.com
  • [user]: login name of user
  • [password]: password of the user

Example: Domain: domain.intranet.com Username: user001 Password: secret123 Hostname of the service: server001

ktpass -out keys.keytab -princ HTTP/server001.domain.intranet.com@doman.intranet.com -mapUser user001 -mapOp set -pass secret123 -crypto ALL -pType KRB5_NT_PRINCIPAL

It's recommended that the service that will use the Kerberos authentication be on a different host than Windows AD.


Configure Chrome and Internet Explorer to authenticate via Kerberos:

On Internet Explorer, check the Security Tab on Options, and on Intranet Zone, add the hostname of service as trusted site. Chrome will get the configuration from Internet Explorer.

Check example below to see how to use Kerberos Authentication with Spring Boot.


You must navigate with the full qualified host name...

http://localhost, http://server001, http://127.0.0.1 will not work! Must be something like http://server001.domain.intranet.com

import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public class DummyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
System.out.println(s);
return new User(s, "notUsed", true, true, true, true, AuthorityUtils.createAuthorityList("ROLE_USER", "ROLE_ADMIN"));
}
}
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.security.Principal;
@Controller
@RequestMapping(value = "/")
public class MainController {
@GetMapping(value = "/")
@ResponseBody
public String foo(Principal principal) {
if (principal != null) {
return String.format("Hello %s", principal.getName());
} else {
return "Oops";
}
}
}
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.kerberos</groupId>
<artifactId>spring-security-kerberos-web</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
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.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.kerberos.authentication.KerberosAuthenticationProvider;
import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator;
import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter;
import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(spnegoEntryPoint())
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.logout()
.permitAll()
.and()
.addFilterBefore(
spnegoAuthenticationProcessingFilter(),
BasicAuthenticationFilter.class);
}
@Bean
public SpnegoEntryPoint spnegoEntryPoint() {
return new SpnegoEntryPoint("/");
}
@Bean
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter() {
SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
try {
AuthenticationManager authenticationManager = authenticationManagerBean();
filter.setAuthenticationManager(authenticationManager);
} catch (Exception e) {
e.printStackTrace();
}
return filter;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(kerberosAuthenticationProvider())
.authenticationProvider(kerberosServiceAuthenticationProvider());
}
@Bean
public KerberosAuthenticationProvider kerberosAuthenticationProvider() {
KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider();
SunJaasKerberosClient client = new SunJaasKerberosClient();
client.setDebug(true);
provider.setKerberosClient(client);
provider.setUserDetailsService(dummyUserDetailsService());
return provider;
}
@Bean
public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
provider.setTicketValidator(sunJaasKerberosTicketValidator());
provider.setUserDetailsService(dummyUserDetailsService());
return provider;
}
@Bean
public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
ticketValidator.setServicePrincipal("HTTP/server001.domain.intranet.com@domain.intranet.com");
ticketValidator.setKeyTabLocation(new FileSystemResource("C:\\temp\\keys.keytab"));
ticketValidator.setDebug(true);
return ticketValidator;
}
@Bean
public DummyUserDetailsService dummyUserDetailsService() {
return new DummyUserDetailsService();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment