Integrazione di Spring Security Kerberos con MiniKdc

Top di sicurezza

Ho appena annunciato il nuovo corso Learn Spring Security, incluso il materiale completo incentrato sul nuovo stack OAuth2 in Spring Security 5:

>> SCOPRI IL CORSO

1. Panoramica

In questo tutorial, forniremo una panoramica di Spring Security Kerberos.

Scriveremo un client Kerberos in Java che si autorizza ad accedere al nostro servizio Kerberizzato. Inoltre, eseguiremo il nostro Centro di distribuzione delle chiavi incorporato per eseguire l'autenticazione Kerberos completa e end-to-end. Tutto ciò, senza alcuna infrastruttura esterna richiesta grazie a Spring Security Kerberos.

2. Kerberos e i suoi vantaggi

Kerberos è un protocollo di autenticazione di rete creato dal MIT negli anni '80, particolarmente utile per centralizzare l'autenticazione su una rete.

Nel 1987, il MIT lo ha rilasciato alla comunità Open Source ed è ancora in fase di sviluppo attivo. Nel 2005 è stato canonizzato come standard IETF sottoRFC 4120.

Di solito, Kerberos viene utilizzato negli ambienti aziendali . Lì, protegge l'ambiente in modo tale che l' utente non debba autenticarsi a ciascun servizio separatamente . Questa soluzione architettonica è nota come Single Sign-on .

In poche parole, Kerberos è un sistema di ticketing. Un utente si autentica una volta e riceve un Ticket-granting Ticket (TGT). Quindi, l'infrastruttura di rete scambia quel TGT per i ticket di servizio. Questi ticket di servizio consentono all'utente di interagire con i servizi dell'infrastruttura, a condizione che il TGT sia valido, che di solito è per un paio d'ore.

Quindi, è fantastico che l'utente acceda solo in una volta. Ma c'è anche un vantaggio in termini di sicurezza: in un ambiente del genere, la password dell'utente non viene mai inviata in rete . Invece, Kerberos lo utilizza come fattore per generare un'altra chiave segreta che verrà utilizzata per la crittografia e la decrittografia dei messaggi.

Un altro vantaggio è che possiamo gestire gli utenti da una posizione centrale, ad esempio supportata da LDAP. Pertanto, se disabilitiamo un account nel nostro database centralizzato per un dato utente, revocheremo il suo accesso nella nostra infrastruttura. Pertanto, gli amministratori non devono revocare l'accesso separatamente a ciascun servizio.

L'introduzione all'autenticazione SPNEGO / Kerberos in primavera fornisce una panoramica approfondita della tecnologia.

3. Ambiente Kerberizzato

Quindi, creiamo un ambiente per l'autenticazione con il protocollo Kerberos. L'ambiente sarà costituito da tre applicazioni separate che verranno eseguite contemporaneamente.

Innanzitutto, avremo un centro di distribuzione delle chiavi che fungerà da punto di autenticazione. Successivamente, scriveremo un client e un'applicazione di servizio che configureremo per utilizzare il protocollo Kerberos.

Ora, l'esecuzione di Kerberos richiede un po 'di installazione e configurazione. Tuttavia, sfrutteremo Spring Security Kerberos, quindi eseguiremo il Key Distribution Center a livello di programmazione, in modalità incorporata. Inoltre, il MiniKdc mostrato di seguito è utile in caso di test di integrazione con l'infrastruttura Kerberizzata.

3.1. Esecuzione di un centro di distribuzione delle chiavi

Innanzitutto, lanceremo il nostro Key Distribution Center, che emetterà i TGT per noi:

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

Fondamentalmente, abbiamo fornito a MiniKdc una serie di principali e un file di configurazione; inoltre, abbiamo detto a MiniKdc come chiamare il keytab che genera.

MiniKdc genererà un file krb5.conf che forniremo alle nostre applicazioni client e di servizio. Questo file contiene le informazioni su dove trovare il nostro KDC: l'host e la porta per un determinato regno.

MiniKdc.main avvia il KDC e dovrebbe produrre qualcosa come:

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. Applicazione client

Il nostro client sarà un'applicazione Spring Boot che utilizza un RestTemplate per effettuare chiamate a un'API REST esterna.

Ma, stiamo andando a utilizzare KerberosRestTemplate invece . Avrà bisogno della keytab e del principale del 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); } }

E questo è tutto! KerberosRestTemplate negozia per noi il lato client del protocollo Kerberos.

Quindi, creiamo una classe veloce che interrogherà alcuni dati da un servizio Kerberized, ospitato nell'endpoint 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); } }

Quindi, creiamo ora la nostra applicazione di servizio in modo che questa classe abbia qualcosa da chiamare!

3.3. Applicazione di servizio

Useremo Spring Security, configurandolo con i bean specifici di Kerberos appropriati.

Inoltre, tieni presente che il servizio avrà il suo principale e utilizzerà anche la 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; } }

Tieni presente che abbiamo configurato Spring Security per l'autenticazione SPNEGO. In questo modo, saremo in grado di autenticarci tramite il protocollo HTTP, sebbene possiamo anche ottenere l'autenticazione SPNEGO con Java core.

4. Test

Ora eseguiremo un test di integrazione per mostrare che il nostro client recupera correttamente i dati da un server esterno tramite il protocollo Kerberos . Per eseguire questo test, dobbiamo avere la nostra infrastruttura in esecuzione, quindi MiniKdc e la nostra applicazione di servizio devono essere entrambi avviati.

Fondamentalmente, useremo il nostro SampleClient dall'applicazione client per effettuare una richiesta alla nostra applicazione di servizio. Proviamolo:

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

Nota che possiamo anche provare che KerberizedRestTemplate è importante colpendo il servizio senza di esso:

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

Come nota a margine, c'è la possibilità che il nostro secondo test possa riutilizzare il ticket già memorizzato nella cache delle credenziali . Ciò accadrebbe a causa della negoziazione SPNEGO automatica utilizzata in HttpUrlConnection .

Di conseguenza, i dati potrebbero effettivamente tornare, invalidando il nostro test. A seconda delle nostre esigenze, quindi, possiamo disabilitare l'utilizzo della cache dei ticket tramite la proprietà di sistema http.use.global.creds = false.

5. conclusione

In questo tutorial, abbiamo esplorato Kerberos per la gestione centralizzata degli utenti e come Spring Security supporta il protocollo Kerberos e il meccanismo di autenticazione SPNEGO.

Abbiamo utilizzato MiniKdc per supportare un KDC incorporato e abbiamo anche creato un client e un server Kerberizzati molto semplici. Questa configurazione è stata utile per l'esplorazione e particolarmente utile quando abbiamo creato un test di integrazione per testare le cose.

Ora, abbiamo appena graffiato la superficie. Per approfondire, controlla la pagina wiki Kerberos o la sua RFC. Inoltre, la pagina della documentazione ufficiale sarà utile. Oltre a questo, per vedere come si potrebbero fare le cose nel core java, il seguente tutorial di Oracle lo mostra in dettaglio.

Come al solito, il codice può essere trovato sulla nostra pagina GitHub.

Fondo di sicurezza

Ho appena annunciato il nuovo corso Learn Spring Security, incluso il materiale completo incentrato sul nuovo stack OAuth2 in Spring Security 5:

>> SCOPRI IL CORSO