kerberos authentication

this is roughly how it works:

  1. client (C) request for a web service (S), which is secured by kerberos; the web service (S) respond back with negotiate, which modern browser would support
  2. receiving the `negotiate` response, the client (C) would send KDC that it’s requesting access for web service (S)
  3. there are few rounds between the client (C) and KDC, for exchanging the request (encrypted by C’s key/password); then KDC decrypt using C’s key, and send back a TGT, encrypted by KDC/TS’s key; client (C) then send this request encrypted by TS’s key to TS with TGT; TS then give back a ticket, which is secured by web service (S)’s encryption key
  4. with the ticket, client (C) send to web service (S), (S) then decrypt the message successfully with its own key, hence verifies/authenticate the client (C)

as for the set up, this is roughly how it looks like

  • set up keberos account for client(C) which is likely a user
this is done on KDC (Windows AD).
  • set up keberos service account for web service (S) which likely is service account
this is done on KDC (Windows AD).
  • register a SPN, map to S’s kerberos
this is done on KDC (Windows AD).
To verify the spn:
setspn -L <service_account>
  • set up a keytab for S (service account), and make it accessible by web service
    • when C send over the ticket encrypted by S’ key, the web service (S) should be able to decrypt it using the keytab above
this can either be done from windows server with ktpass:
ktpass -out outputfile.keytab -princ HTTP/[fqdn]@[domain] -mapUser [user] -mapOp set -pass [password] -crypto ALL -pType KRB5_NT_PRINCIPAL

or on Unix Server with ktutil
ktuil: addent -password -p <service_account>@DOMAIN -s <salt> -k <version> -e aes256-cts
ktutil: wkt <account>.keytab


to verify the keytab
klist -kt <account>.keytab ---> this shows the entry in the keytab
kinit -kt <account>.keytab <account> --> this verifies the login
klist ---> after kinit, this should return the ticket from KDC

sample:

step 2:

  • Log in to the computer as a domain administrator or a user who is a member of the built-in Account Operators domain group.
  • Open the Active Directory Users and Computers MMC snap-in.
  • Create an ordinary user account with the following properties:
    • Use the same identifier in the Full name and User logon name (pre‐Windows 2000) fields.Note: Use only lowercase characters and make sure that there are no spaces in these fields.
    • Select the Password never expires check box.
    • Clear the User must change password at next logon check box.
    • If you want to use the crypto algorithm aes128-sha1 or aes256-sha1 the account option This account supports Kerberos AES 128 bit encryption or This account supports Kerberos AES 256 bit encryption must also be selected.
    • \

step 3:

  • Log in to the computer as a domain administrator or a user who is a member of the built-in Account Operators domain group.
  • From the Microsoft Support Tools package, use the setspn.exe command-line tool to register two SPNs for the Kerberos service account:
    • Execute the following two commands, replacing the variables as indicated in the table below the commands:> setspn -S HTTP/<fully qualified hostname>[:<port>] <service account name> > setspn -S HTTP/<hostname>[:<port>] <service account name>If the Spotfire Server is not listening on the default HTTP port 80 or the default HTTPS port 443, you should execute the setspn commands both with and without the port specified:> setspn -S HTTP/<fully qualified hostname>[:<port>] <service account name> > setspn -S HTTP/<hostname>[:<port>] <service account name> > setspn -S HTTP/<fully qualified hostname> <service account name> > setspn -S HTTP/<hostname> <service account name>

https://docs.tibco.com/pub/spotfire_server/7.8.0/doc/html/TIB_sfire_server_tsas_admin_help/GUID-3391E621-6DE0-4A93-AA3E-2EE6F2633545.html

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>
view raw pom.xml hosted with ❤ by GitHub
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();
}
}

it should work with above steps done, and should work with Windows (service running out windows box). However, there is a TRICK of the TRICK, for Unix (service running out of Unix) to work, the SPN should include an entry for the real server

so, when list spn

SETSPN -L <account>

this should return entries not only with the cname, but also with the REAL server

so on windows server/AD side, for the SPN set up, these should be done

setspn -S HTTP/<service_name/CNAME>.DOMAIN <service_account>   --> this is enough for windows to work
setspn -S HTTP/<REAL_SERVER_NAME>.DOMAIN <service_account>    ----> this is important for unix to work

Seems like the cause for above issue, there could be different setting for the reverse dns setup.

This is the set up in my Unix box, where reverse dns is disabled, this probably however likely is enabled in Windows AD.

https://web.mit.edu/kerberos/krb5-1.12/doc/admin/princ_dns.html

https://www.tarlogic.com/blog/how-kerberos-works/
https://en.wikipedia.org/wiki/Kerberos_%28protocol%29

https://www.baeldung.com/spring-security-kerberos

https://www.baeldung.com/spring-security-kerberos-integration

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s