Integração com o Spring Security Kerberos
1. Visão geral
Neste tutorial, forneceremos uma visão geral do Spring Security Kerberos.
Vamos escrever um cliente Kerberos em Java que se autoriza a acessar nosso serviço Kerberizado. E vamos executar nosso próprio Centro de distribuição de chaves incorporado para realizar autenticação Kerberos completa e ponta a ponta. Tudo isso, sem nenhuma infraestrutura externa necessária graças aSpring Security Kerberos.
2. Kerberos e seus benefícios
Kerberos é um protocolo de autenticação de rede criado pelo MIT na década de 1980, especificamente útil para centralizar a autenticação em uma rede.
Em 1987, o MIT o lançou para a comunidadethe Open Source e ainda está em desenvolvimento ativo. Em 2005, foi canonizado como um padrão IETF em RFC 4120.
Normalmente, Kerberos éused in corporate environments. Lá, ele protege o ambiente de forma que ouser doesn’t have to authenticate to each service separately. Essa solução arquitetônica é conhecida comoSingle Sign-on.
Simplificando, o Kerberos é um sistema de bilhética. Um usuárioauthenticates once ereceives a Ticket-granting Ticket (TGT). Then, the network infrastructure exchanges that TGT for Service Tickets. Esses tíquetes de serviço permitem que o usuário interaja com os serviços de infraestrutura, desde que o TGT seja válido, o que geralmente dura algumas horas.
Portanto, é ótimo que o usuário só faça login uma vez. Mas também há um benefício de segurança: em tal ambiente, ouser’s password is never sent over the network. Em vez disso, o Kerberos o usa como um fator para gerar outra chave secreta que será usada para criptografar e descriptografar mensagens.
Outro benefício é quewe can manage users from a central place, diz um que é apoiado por LDAP. Portanto, se desativarmos uma conta em nosso banco de dados centralizado para um determinado usuário, então iremos revogar seu acesso em nossa infraestrutura. Assim, os administradores não precisam revogar o acesso separadamente em cada serviço.
3. Ambiente Kerberizado
Então, vamos criar um ambiente para autenticação com o protocolo Kerberos. O ambiente consistirá em três aplicativos separados que serão executados simultaneamente.
Primeiro,we’ll have a Key Distribution Center que atuará como o ponto de autenticação. A seguir, escreveremos um cliente e um aplicativo de serviço que configuraremos para usar o protocolo Kerberos.
Agora, a execução do Kerberos requer um pouco de instalação e configuração. No entanto, vamos aproveitarSpring Security Kerberos, então vamos executar o Key Distribution Center programaticamente, no modo incorporado. Além disso, oMiniKdc mostrado abaixo é útil no caso de teste de integração com infraestrutura Kerberizada.
3.1. Executando um Centro de Distribuição de Chaves
Primeiro, lançaremos nosso Centro de distribuição de chaves, que emitirá os TGTs para nós:
String[] config = MiniKdcConfigBuilder.builder()
.workDir(prepareWorkDir())
.principals("client/localhost", "HTTP/localhost")
.confDir("minikdc-krb5.conf")
.keytabName("example.keytab")
.build();
MiniKdc.main(config);
Basicamente, demos aMiniKdc um conjunto de princípios e um arquivo de configuração; além disso, dissemos aMiniKdc como chamar okeytab que ele gera.
MiniKdc gerará um arquivokrb5.conf que forneceremos aos nossos aplicativos de cliente e serviço. Este arquivo contém as informações onde encontrar nosso KDC - o host e a porta para um determinado território.
MiniKdc.main inicia o KDC e deve produzir algo como:
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. Aplicativo Cliente
Nosso cliente será um aplicativo Spring Boot que está usandoRestTemplate para fazer chamadas para uma API REST externa.
Mas, vamos parause KerberosRestTemplate instead. Será necessário o keytab e o principal do cliente:
@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 é isso! KerberosRestTemplate negocia o lado do cliente do protocolo Kerberos para nós.
Então, vamos criar uma classe rápida que irá consultar alguns dados de um serviço Kerberizado, hospedado no endpointapp.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);
}
}
Então, vamos criar nosso aplicativo de serviço agora para que esta classe tenha algo para chamar!
3.3. Aplicativo de Serviço
Usaremos Spring Security, configurando-o com os beans específicos de Kerberos apropriados.
Além disso, observe que o serviço terá seu principal e usará o keytab também:
@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;
}
}
Observe que configuramos Spring Security paraSPNEGO authentication. Dessa forma, poderemos autenticar por meio do protocolo HTTP, embora também possamos atingirSPNEGO authentication with core Java.
4. Teste
Agora, vamos executar um teste de integração para mostrar queour client successfully retrieves data from an external server over the Kerberos protocol. Para executar este teste, precisamos ter nossa infraestrutura em execução, portanto,MiniKdc e nosso aplicativo de serviço devem ser iniciados.
Basicamente, usaremos nossoSampleClient do Aplicativo do Cliente para fazer uma solicitação ao nosso Aplicativo de Serviço. Vamos testar:
@Autowired
private SampleClient sampleClient;
@Test
public void givenKerberizedRestTemplate_whenServiceCall_thenSuccess() {
assertEquals("data from kerberized server", sampleClient.getData());
}
Observe que também podemos provar queKerberizedRestTemplate é importante acessando o serviço sem ele:
@Test
public void givenRestTemplate_whenServiceCall_thenFail() {
sampleClient.setRestTemplate(new RestTemplate());
assertThrows(RestClientException.class, sampleClient::getData);
}
Como observação lateral, há uma chance deour second test could re-use the ticket already stored in the credential cache. Isso aconteceria devido à negociação SPNEGO automática usada emHttpUrlConnection.
Como resultado,the data might actually return, invalidating our test. Dependendo de nossas necessidades, então, podemos desativar o uso do cache de tíquetes por meio da propriedade do sistemahttp.use.global.creds=false.
5. Conclusão
Neste tutorial,we explored Kerberos for centralized user managemente Spring Security suporta o protocolo Kerberos e o mecanismo de autenticação SPNEGO.
UsamosMiniKdc para criar um KDC embutido e também criamos um cliente e servidor Kerberizados muito simples. Essa configuração foi útil para exploração e especialmente útil quando criamos um teste de integração para testar as coisas.
Agora, nós apenas arranhamos a superfície. Para se aprofundar, verifique o Kerberoswiki page ouits RFC. Além disso, oofficial documentation page será útil. Fora isso, para ver como as coisas podem ser feitas no núcleo do java, ofollowing Oracle’s tutorial mostra em detalhes.
Como de costume, o código pode ser encontrado em nossa páginaGitHub.