查看原文
其他

Spring 安全框架Kerberos 集成

stphenZkang SpringForAll社区 2021-05-27

1.概述

在本教程中,我们将概述Spring的安全框架Kerberos。

我们将用Java编写一个Kerberos客户端,它授权自己访问Kerberos化的服务。我们将运行我们自己的嵌入式密钥分发中心来执行完整的端到端Kerberos身份验证。由于 Spring Security Kerberos,所有这些都不需要任何外部基础设施。

2. Kerberos及其优点

Kerberos是MIT在上世纪80年代创建的一种网络身份验证协议,特别适用于在网络上集中身份验证。

1987年,MIT将其发布给 开源社区 ,目前它仍在积极开发中。2005年,它被规范化为IETF标准 RFC 4120里。

通常,Kerberos用于企业环境。在那里,它以一种用户不必分别对每个服务进行身份验证的方式来确保环境安全。这种体系结构解决方案称为单点登录

简单地说,Kerberos是一个票务系统。用户进行一次身份验证,然后收到一个授予票证的票证(TGT)。然后,网络基础设施交换TGT以获得服务票。只要TGT有效,这些服务票证允许用户与基础设施服务进行交互,这通常需要几个小时。

所以,用户只需要一次登录就可以了。但也有一个安全好处:在这样的环境中,用户的密码永远不会通过网络发送。相反,Kerberos使用它作为生成另一个密钥的因素,该密钥将用于消息加密和解密。

另一个好处是,我们可以从一个中心位置管理用户,比如一个由LDAP支持的位置。因此,如果我们为给定的用户禁用集中数据库中的帐户,那么我们将撤销他在基础设施中的访问。因此,管理员不必在每个服务中分别撤销访问。

3.使用kerberos环境

因此,让我们创建一个使用Kerberos协议进行身份验证的环境。该环境将由三个同时运行的独立应用程序组成。

首先,我们将有一个密钥分发中心作为身份验证点。接下来,我们将编写一个客户端和一个服务应用程序,并将其配置为使用Kerberos协议。

现在,运行Kerberos需要进行一些安装和配置。但是,我们将利用 Spring Security Kerberos,,因此我们将以嵌入式模式以编程方式运行密钥分发中心。此外,在使用kerberos基础设施进行集成测试时,下面所示的MiniKdc非常有用。

3.1. 启动密钥分发中心

首先,我们将启动我们的密钥分发中心,它将为我们发出TGTs :

  1. String[] config = MiniKdcConfigBuilder.builder()

  2. .workDir(prepareWorkDir())

  3. .principals("client/localhost", "HTTP/localhost")

  4. .confDir("minikdc-krb5.conf")

  5. .keytabName("example.keytab")

  6. .build();


  7. MiniKdc.main(config);

基本上,我们已经给了MiniKdc一组主体和一个配置文件;此外,我们还告诉MiniKdc 如何调用它生成的keytab

MiniKdc将生成一个krb5.conf文件,我们将提供给客户端和服务应用程序。该文件包含在何处找到我们的 KDC 的信息—给定领域的主机和端口。

MiniKdc.main 启动KDC,应该输出如下内容:

  1. Standalone MiniKdc Running

  2. ---------------------------------------------------

  3. Realm : EXAMPLE.COM

  4. Running at : localhost:localhost

  5. krb5conf : .\spring-security-sso\spring-security-sso-kerberos\krb-test-workdir\krb5.conf


  6. created keytab : .\spring-security-sso\spring-security-sso-kerberos\krb-test-workdir\example.keytab

  7. with principals : [client/localhost, HTTP/localhost]

3.2. 客户端程序

我们的客户端将是一个Spring Boot应用程序,它使用RestTemplate 来调用外部的REST API。

但是,我们将使用 KerberosRestTemplate 代替。它需要 keytab 和客户端的主体:

  1. @Configuration

  2. public class KerberosConfig {


  3. @Value("${app.user-principal:client/localhost}")

  4. private String principal;


  5. @Value("${app.keytab-location}")

  6. private String keytabLocation;


  7. @Bean

  8. public RestTemplate restTemplate() {

  9. return new KerberosRestTemplate(keytabLocation, principal);

  10. }

  11. }

这就是它! KerberosRestTemplate为我们协商Kerberos协议的客户端。

因此,让我们快速创建一个类,它将从kerberos化的服务中查询一些数据,该服务位于端点app.access-url:

  1. @Service

  2. class SampleClient {


  3. @Value("${app.access-url}")

  4. private String endpoint;


  5. private RestTemplate restTemplate;


  6. // constructor, getter, setter


  7. String getData() {

  8. return restTemplate.getForObject(endpoint, String.class);

  9. }

  10. }

所以,现在让我们创建我们的服务应用程序,这样这个类就可以调用一些东西了!

3.3. 服务端程序

我们将使用Spring Security,使用与kerberos相关的特定bean对其进行配置。

此外,请注意,该服务将有其主体,并使用keytab:

  1. @Configuration

  2. @EnableWebSecurity

  3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


  4. @Value("${app.service-principal:HTTP/localhost}")

  5. private String servicePrincipal;


  6. @Value("${app.keytab-location}")

  7. private String keytabLocation;


  8. @Override

  9. protected void configure(HttpSecurity http) throws Exception {

  10. http

  11. .authorizeRequests()

  12. .antMatchers("/", "/home").permitAll()

  13. .anyRequest().authenticated()

  14. .and()

  15. .exceptionHandling()

  16. .authenticationEntryPoint(spnegoEntryPoint())

  17. .and()

  18. .formLogin()

  19. .loginPage("/login").permitAll()

  20. .and()

  21. .logout().permitAll()

  22. .and()

  23. .addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()),

  24. BasicAuthenticationFilter.class);

  25. }


  26. @Override

  27. protected void configure(AuthenticationManagerBuilder auth) throws Exception {

  28. auth

  29. .authenticationProvider(kerberosAuthenticationProvider())

  30. .authenticationProvider(kerberosServiceAuthenticationProvider());

  31. }


  32. @Bean

  33. public KerberosAuthenticationProvider kerberosAuthenticationProvider() {

  34. KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider();

  35. // provider configuration

  36. return provider;

  37. }


  38. @Bean

  39. public SpnegoEntryPoint spnegoEntryPoint() {

  40. return new SpnegoEntryPoint("/login");

  41. }


  42. @Bean

  43. public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(

  44. AuthenticationManager authenticationManager) {

  45. SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();

  46. // filter configuration

  47. return filter;

  48. }


  49. @Bean

  50. public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {

  51. KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();

  52. // auth provider configuration

  53. return provider;

  54. }


  55. @Bean

  56. public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {

  57. SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();

  58. // validator configuration

  59. return ticketValidator;

  60. }

  61. }

注意,我们已经为SPNEGO 身份验证配置了Spring Security。通过这种方式,我们将能够通过HTTP协议进行身份验证,不过我们也可以使用core Java实现SPNEGO身份验证。

4. 测试

现在,我们将运行一个集成测试,以显示客户端通过Kerberos协议成功地从外部服务器检索数据。要运行此测试,我们需要运行基础设施,因此必须同时启动MiniKdc 和服务应用程序。

基本上,我们将使用来自客户端应用程序的SampleClient向服务应用程序发出请求。让我们来测试一下:

  1. @Autowired

  2. private SampleClient sampleClient;


  3. @Test

  4. public void givenKerberizedRestTemplate_whenServiceCall_thenSuccess() {

  5. assertEquals("data from kerberized server", sampleClient.getData());

  6. }

注意,我们还可以通过不使用KerberizedRestTemplate而使用该服务来证明KerberizedRestTemplate是重要的:

  1. @Test

  2. public void givenRestTemplate_whenServiceCall_thenFail() {

  3. sampleClient.setRestTemplate(new RestTemplate());

  4. assertThrows(RestClientException.class, sampleClient::getData);

  5. }

换句话说,我们的第二个测试有可能重用已经存储在凭据缓存中的票据。这将由于HttpUrlConnection中使用的自动 SPNEGO 协商而发生。

结果,数据实际上可能返回,使我们的测试无效。然后,根据我们的需要,我们可以通过系统属性http.use.global.creds=false.禁用票据缓存的使用。

5. 结论

在本教程中,我们探讨了Kerberos用于集中用户管理,以及Spring Security如何支持Kerberos协议和SPNEGO身份验证机制。

我们使用MiniKdc 来支持嵌入式KDC,并创建了一个非常简单的kerberos化客户端和服务器。这个设置对于探索非常方便,尤其是当我们创建一个集成测试来测试东西时。

现在,我们只了解了皮毛。要深入了解,请查看Kerberos wiki 页面 或它的RFC。此外,官方文档页面也很有用。除此之外,为了了解如何在core java中实现这些功能,下面的Oracle教程 将详细介绍。

和往常一样,代码可以在我们的GitHub页面上找到。

原文链接:https://www.baeldung.com/spring-security-kerberos-integration

作者:Denis Szczukocki

译者:康仔

推荐:Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现

上一篇:Java中的变量隐藏和阴影





 关注公众号

点击原文阅读更多


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存