Intégration Spring Security Kerberos avec MiniKdc

Haut de sécurité

Je viens d'annoncer le nouveau cours Learn Spring Security, y compris le matériel complet axé sur la nouvelle pile OAuth2 dans Spring Security 5:

>> VOIR LE COURS

1. Vue d'ensemble

Dans ce didacticiel, nous fournirons une vue d'ensemble de Spring Security Kerberos.

Nous allons écrire un client Kerberos en Java qui s'autorise à accéder à notre service Kerberos. Et nous exécuterons notre propre centre de distribution de clés intégré pour effectuer une authentification Kerberos complète et de bout en bout. Tout cela, sans aucune infrastructure externe requise grâce à Spring Security Kerberos.

2. Kerberos et ses avantages

Kerberos est un protocole d'authentification réseau créé par le MIT dans les années 1980, particulièrement utile pour centraliser l'authentification sur un réseau.

En 1987, le MIT l'a publié à la communauté Open Source et il est toujours en développement actif. En 2005, il a été canonisé en tant que norme IETF sousRFC 4120.

Habituellement, Kerberos est utilisé dans les environnements d'entreprise . Là-dedans, il sécurise l'environnement de manière à ce que l' utilisateur n'ait pas à s'authentifier séparément auprès de chaque service . Cette solution architecturale est connue sous le nom de Single Sign-on .

En termes simples, Kerberos est un système de billetterie. Un utilisateur s'authentifie une fois et reçoit un ticket d'octroi de tickets (TGT). Ensuite, l'infrastructure réseau échange ce TGT contre des tickets de service. Ces tickets de service permettent à l'utilisateur d'interagir avec les services d'infrastructure, à condition que le TGT soit valide, ce qui dure généralement quelques heures.

C'est donc formidable que l'utilisateur ne se connecte qu'en une seule fois. Mais il y a aussi un avantage de sécurité: dans un tel environnement, le mot de passe de l'utilisateur n'est jamais envoyé sur le réseau . Au lieu de cela, Kerberos l'utilise comme facteur pour générer une autre clé secrète qui sera utilisée pour le chiffrement et le déchiffrement des messages.

Un autre avantage est que nous pouvons gérer les utilisateurs à partir d'un emplacement central, disons celui qui est soutenu par LDAP. Par conséquent, si nous désactivons un compte dans notre base de données centralisée pour un utilisateur donné, nous révoquerons son accès dans notre infrastructure. Ainsi, les administrateurs n'ont pas à révoquer l'accès séparément dans chaque service.

L'introduction à l'authentification SPNEGO / Kerberos dans Spring fournit une vue d'ensemble approfondie de la technologie.

3. Environnement Kerberisé

Alors, créons un environnement pour l'authentification avec le protocole Kerberos. L'environnement sera composé de trois applications distinctes qui s'exécuteront simultanément.

Tout d'abord, nous aurons un centre de distribution de clés qui servira de point d'authentification. Ensuite, nous allons écrire un client et une application de service que nous configurerons pour utiliser le protocole Kerberos.

Désormais, exécuter Kerberos nécessite un peu d'installation et de configuration. Cependant, nous tirerons parti de Spring Security Kerberos, nous allons donc exécuter le centre de distribution de clés par programme, en mode intégré. En outre, le MiniKdc illustré ci-dessous est utile en cas de test d'intégration avec une infrastructure Kerberisée.

3.1. Exécution d'un centre de distribution de clés

Tout d'abord, nous allons lancer notre centre de distribution de clés, qui émettra les TGT pour nous:

String[] config = MiniKdcConfigBuilder.builder() .workDir(prepareWorkDir()) .principals("client/localhost", "HTTP/localhost") .confDir("minikdc-krb5.conf") .keytabName("example.keytab") .build(); MiniKdc.main(config);

Fondamentalement, nous avons donné à MiniKdc un ensemble de principes et un fichier de configuration; De plus, nous avons dit à MiniKdc comment appeler le keytab qu'il génère.

MiniKdc générera un fichier krb5.conf que nous fournirons à nos applications client et service. Ce fichier contient les informations où trouver notre KDC - l'hôte et le port d'un royaume donné.

MiniKdc.main démarre le KDC et devrait afficher quelque chose comme:

Standalone MiniKdc Running --------------------------------------------------- Realm : EXAMPLE.COM Running at : localhost:localhost krb5conf : .\spring-security-sso\spring-security-sso-kerberos\krb-test-workdir\krb5.conf created keytab : .\spring-security-sso\spring-security-sso-kerberos\krb-test-workdir\example.keytab with principals : [client/localhost, HTTP/localhost]

3.2. Application client

Notre client sera une application Spring Boot qui utilise un RestTemplate pour passer des appels vers une API REST externe.

Mais nous allons utiliser KerberosRestTemplate à la place . Il aura besoin du keytab et du principal du client:

@Configuration public class KerberosConfig { @Value("${app.user-principal:client/localhost}") private String principal; @Value("${app.keytab-location}") private String keytabLocation; @Bean public RestTemplate restTemplate() { return new KerberosRestTemplate(keytabLocation, principal); } }

Et c'est tout! KerberosRestTemplate négocie pour nous le côté client du protocole Kerberos.

Alors, créons une classe rapide qui interrogera certaines données d'un service Kerberisé, hébergé sur le point de terminaison app.access-url :

@Service class SampleClient { @Value("${app.access-url}") private String endpoint; private RestTemplate restTemplate; // constructor, getter, setter String getData() { return restTemplate.getForObject(endpoint, String.class); } }

Alors, créons notre application de service maintenant pour que cette classe ait quelque chose à appeler!

3.3. Application de service

Nous utiliserons Spring Security, en le configurant avec les beans spécifiques à Kerberos appropriés.

Notez également que le service aura son principal et utilisera également le keytab:

@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Value("${app.service-principal:HTTP/localhost}") private String servicePrincipal; @Value("${app.keytab-location}") private String keytabLocation; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/", "/home").permitAll() .anyRequest().authenticated() .and() .exceptionHandling() .authenticationEntryPoint(spnegoEntryPoint()) .and() .formLogin() .loginPage("/login").permitAll() .and() .logout().permitAll() .and() .addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()), BasicAuthenticationFilter.class); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .authenticationProvider(kerberosAuthenticationProvider()) .authenticationProvider(kerberosServiceAuthenticationProvider()); } @Bean public KerberosAuthenticationProvider kerberosAuthenticationProvider() { KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider(); // provider configuration return provider; } @Bean public SpnegoEntryPoint spnegoEntryPoint() { return new SpnegoEntryPoint("/login"); } @Bean public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter( AuthenticationManager authenticationManager) { SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter(); // filter configuration return filter; } @Bean public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() { KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider(); // auth provider configuration return provider; } @Bean public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() { SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator(); // validator configuration return ticketValidator; } }

Notez que nous avons configuré Spring Security pour l'authentification SPNEGO. De cette façon, nous pourrons nous authentifier via le protocole HTTP, bien que nous puissions également réaliser l'authentification SPNEGO avec le noyau Java.

4. Test

Nous allons maintenant exécuter un test d'intégration pour montrer que notre client récupère avec succès les données d'un serveur externe via le protocole Kerberos . Pour exécuter ce test, nous devons avoir notre infrastructure en cours d'exécution, donc MiniKdc et notre application de service doivent tous deux être démarrés.

Fondamentalement, nous utiliserons notre SampleClient de l'application cliente pour faire une demande à notre application de service. Testons-le:

@Autowired private SampleClient sampleClient; @Test public void givenKerberizedRestTemplate_whenServiceCall_thenSuccess() { assertEquals("data from kerberized server", sampleClient.getData()); }

Notez que nous pouvons également prouver que le KerberizedRestTemplate est important en frappant le service sans lui:

@Test public void givenRestTemplate_whenServiceCall_thenFail() { sampleClient.setRestTemplate(new RestTemplate()); assertThrows(RestClientException.class, sampleClient::getData); }

As a side note, there's a chance our second test could re-use the ticket already stored in the credential cache. This would happen due to the automatic SPNEGO negotiation used in HttpUrlConnection.

As a result, the data might actually return, invalidating our test. Depending on our needs, then, we can disable ticket cache usage through the system property http.use.global.creds=false.

5. Conclusion

In this tutorial, we explored Kerberos for centralized user management and how Spring Security supports the Kerberos protocol and SPNEGO authentication mechanism.

Nous avons utilisé MiniKdc pour mettre en place un KDC intégré et avons également créé un client et un serveur Kerberized très simples. Cette configuration était pratique pour l'exploration et particulièrement pratique lorsque nous avons créé un test d'intégration pour tester les choses.

Maintenant, nous venons de gratter la surface. Pour aller plus loin, consultez la page wiki Kerberos ou sa RFC. De plus, la page de documentation officielle sera utile. En dehors de cela, pour voir comment les choses pourraient être faites dans le noyau Java, le didacticiel Oracle suivant le montre en détail.

Comme d'habitude, le code se trouve sur notre page GitHub.

Fond de sécurité

Je viens d'annoncer le nouveau cours Learn Spring Security, y compris le matériel complet axé sur la nouvelle pile OAuth2 dans Spring Security 5:

>> VOIR LE COURS