Introduction to SPNEGO/Kerberos Authentication in Spring – Spring中的SPNEGO/Kerberos认证介绍

最后修改: 2019年 4月 24日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll understand the basics of the Kerberos authentication protocol. We’ll also cover the need for SPNEGO in connection with Kerberos.

在本教程中,我们将了解Kerberos认证协议的基本内容。我们还将介绍与Kerberos有关的SPNEGO>的必要性。

Finally, we’ll see how to make use of the Spring Security Kerberos extension to create applications enabled for Kerberos with SPNEGO.

最后,我们将看到如何利用Spring Security Kerberos扩展来创建支持SPNEGO的Kerberos的应用程序。

Before we proceed, it’s worthwhile to note that this tutorial will introduce many new terms for those uninitiated in this area. Hence, we’ll spend some time up front to cover the grounds.

在我们继续之前,值得注意的是,本教程将为那些不熟悉这一领域的人介绍许多新术语。因此,我们将在前面花一些时间来介绍这些内容。

2. Understanding Kerberos

2 了解Kerberos

Kerberos is a Network Authentication Protocol developed at Massachusetts Institute of Technology (MIT) in the early eighties. As you may realize, this is relatively old and has stood the test of time. Windows Server widely supports Kerberos as an authentication mechanism and has even made it the default authentication option.

Kerberos是麻省理工学院(MIT)在八十年代初开发的网络认证协议。正如您可能意识到的那样,这相对来说是比较古老的,而且经受住了时间的考验。Windows服务器广泛支持Kerberos作为一种认证机制,甚至将其作为默认的认证选项。

Technically, Kerberos is a ticket-based authentication protocol that allows nodes in a computer network to identify themselves to each other.

从技术上讲,Kerberos是一个基于票据的认证协议,它允许计算机网络中的节点相互识别。

2.1. Simple Use Case for Kerberos

2.1.Kerberos的简单用例

Let’s draw up a hypothetical situation to demonstrate this.

让我们拟定一个假设的情况来证明这一点。

Suppose that a user, through his mail client on his machine, needs to pull his emails from a mail server on another machine on the same network. There is an obvious need for authentication here. The mail client and mail server must be able to identify and trust each other for them to communicate securely.

假设一个用户,通过他的机器上的邮件客户端,需要从同一网络上的另一台机器上的邮件服务器上提取他的邮件。这里显然需要进行认证。邮件客户端和邮件服务器必须能够识别和信任对方,以便他们能够安全地进行通信。

How can Kerberos help us here? Kerberos introduces a third party called Key Distribution Centre (KDC), which has a mutual trust with each node in the network. Let’s see how this can work in our case:

Kerberos在这里如何帮助我们?Kerberos 引入了一个叫做密钥分发中心(KDC)的第三方,它与网络中的每个节点都有相互信任。让我们看看这在我们的案例中是如何工作的。

Kerberos Protocol

2.2. Key Aspects of Kerberos Protocol

2.2.Kerberos协议的关键方面

While this may sound esoteric, this is quite simple and creative in securing communication over an unsecured network. Some of the problems presented here are quite taken for granted in the era of TLS everywhere!

虽然这听起来很深奥,但在保证不安全网络的通信安全方面,这是相当简单和有创意的。在TLS无处不在的时代,这里提出的一些问题是相当理所当然的!

While a detailed discussion of the Kerberos Protocol is not possible here, let’s go through some salient aspects:

虽然这里不可能对Kerberos协议进行详细的讨论,但让我们来看看一些突出的方面。

  • Trust between nodes (client and server) and KDC is assumed to exist here over the same realm
  • Password is never exchanged over the network
  • Trust between the client and server is implied based on the fact that they can decrypt messages with a key shared only with the KDC
  • Trust between the client and the server is mutual
  • The client can cache tickets for repeated use until the expiry, providing a single sign-on experience
  • Authenticator Messages are based on the timestamp and thus are good only for one-time use
  • All three parties here must have a relatively synchronized time

While this just scratches the surface of this beautiful authentication protocol, it is sufficient to get us going with our tutorial.

虽然这只是触及了这个美丽的认证协议的表面,但它足以让我们的教程进行下去。

3. Understanding SPNEGO

3.了解SPNEGO

SPNEGO stands for Simple and Protected GSS-API Negotiation Mechanism. Quite a name! Let’s first see what GSS-API stands for. The Generic Security Service Application Program Interface (GSS-API) is nothing but an IETF standard for client and server to communicate in a secure and vendor-agnostic manner.

SPNEGO代表Simple and Protected GSS-API Negotiation Mechanism。相当不错的名字!让我们先看看GSS-API代表什么。通用安全服务应用程序接口(GSS-API)只不过是一个IETF标准,用于客户端和服务器以安全的、与厂商无关的方式进行通信。

SPNEGO is a part of the GSS-API for client and server to negotiate the choice of security mechanism to use, for instance, Kerberos or NTLM.

SPNEGO是GSS-API的一部分,用于客户端和服务器协商选择使用的安全机制,例如,Kerberos或NTLM。

4. Why Do We Need SPNEGO With Kerberos?

4.为什么我们需要SPNEGO与Kerberos?

As we saw in the previous section, Kerberos is a pure Network Authentication Protocol operating primarily in the transport layer (TCP/UDP). While this is good for many use cases, this falls short of requirements for the modern web. If we have an application that operates on a higher abstraction, like HTTP, it is not possible to use Kerberos directly.

正如我们在上一节中所看到的,Kerberos 是一个纯粹的网络认证协议,主要在传输层 (TCP/UDP) 运行。虽然这对许多用例来说是好的,但这并不符合现代网络的要求。如果我们有一个在更高的抽象上操作的应用程序,比如 HTTP,就不可能直接使用 Kerberos。

This is where SPNEGO comes to our help. In the case of a web application, communication primarily happens between a web browser like Chrome and a web server like Tomcat hosting the web application over HTTP. If enabled, they can negotiate Kerberos as a security mechanism through SPNEGO and exchange tickets as SPNEGO tokens over HTTP.

这就是SPNEGO来帮助我们的地方。就网络应用而言,通信主要发生在Chrome等网络浏览器和Tomcat等通过HTTP托管网络应用的网络服务器之间。如果启用,它们可以通过SPNEGO协商Kerberos作为一种安全机制,并通过HTTP交换票据作为SPNEGO令牌

So how does this change our scenario mentioned earlier? Let’s replace our simple mail client with a web browser and mail server with a web application:

那么,这如何改变我们前面提到的情景呢?让我们把简单的邮件客户端换成一个网络浏览器,把邮件服务器换成一个网络应用。

Kerberos with SPNEGO

So, not much has changed in this compared to our previous diagram except that the communication between client and server happens explicitly over HTTP now. Let’s understand this better:

因此,与我们之前的图相比,除了客户端和服务器之间的通信现在明确地通过HTTP发生之外,这里面没有什么变化。让我们更好地理解这一点。

  • The client machine authenticates against the KDC and caches the TGT
  • Web browser on the client machine is configured to use SPNEGO and Kerberos
  • The web application is also configured to support SPNEGO and Kerberos
  • Web application throws a “Negotiate” challenge to web browser trying to access a protected resource
  • Service Ticket is wrapped as SPNEGO token and exchanged as an HTTP header

5. Requirements

5.要求

Before we can proceed to develop a web application that supports Kerberos authentication mode, we must gather some basic setup. Let’s go through these tasks quickly.

在我们继续开发一个支持Kerberos认证模式的网络应用程序之前,我们必须收集一些基本设置。让我们快速浏览一下这些任务。

5.1. Setting up KDC

5.1.设置 KDC

Setting up a Kerberos environment for production use is beyond the scope of this tutorial. This is unfortunately not a trivial task and fragile as well. There are several options available to get an implementation of Kerberos, both open source and commercial versions:

建立一个用于生产的 Kerberos 环境已经超出了本教程的范围。不幸的是,这不是一项简单的任务,而且也很脆弱。有几个选择可以获得Kerberos的实现,包括开源和商业版本。

The actual set-up of KDC and related infrastructure is dependent on the provider and should be followed from their respective documentation. However, Apache Kerby can be run inside a Docker container, which makes it platform-neutral.

KDC 和相关基础设施的实际设置取决于提供商,应遵循其各自的文档。然而,Apache Kerby 可以在 Docker 容器内运行,这使其不受平台影响。

5.2. Setting up Users in KDC

5.2.在 KDC 中设置用户

We need to set up two users — or, as they call it, principals — in KDC. We can use the “kadmin” command-line tool for this purpose. Let’s suppose we’ve created a realm called “baeldung.com” in the KDC database and logged in to “kadmin” with a user having admin privileges.

我们需要在KDC中设置两个用户–或者,他们称之为负责人–。我们可以使用 “kadmin “命令行工具来实现这一目的。假设我们在 KDC 数据库中创建了一个名为 “baeldung.com “的领域,并以具有管理权限的用户登录到 “kadmin”。

We’ll create our first user, whom we wish to authenticate from a web browser, with:

我们将创建我们的第一个用户,我们希望通过网络浏览器来验证他。

$ kadmin: addprinc -randkey kchandrakant -pw password
Principal "kchandrakant@baeldung.com" created.

We’ll also need to register our web application with the KDC:

我们还需要在KDC上注册我们的网络应用。

$ kadmin: addprinc -randkey HTTP/demo.kerberos.baeldung.com@baeldung.com -pw password
Principal "HTTP/demo.kerberos.baeldung.com@baeldung.com" created.

Note the convention for naming the principal here, as this must match the domain on which the application is accessible from the web browser. The web browser automatically tries to create a Service Principal Name (SPN) with this convention when presented with a “Negotiate” challenge.

请注意这里命名委托人的惯例,因为这必须与Web浏览器可以访问的应用程序的域相匹配。当遇到 “协商 “挑战时,网络浏览器会自动尝试用这个惯例创建一个服务主名称(SPN)

We also need to export this as a keytab file to make it available to the web application:

我们还需要将其导出为keytab文件,使其对网络应用可用。

$ kadmin: ktadd -k baeldung.keytab HTTP/demo.kerberos.baeldung.com@baeldung.com

This should give us a file named “baeldung.keytab”.

这应该给我们一个名为 “baeldung.keytab “的文件。

5.3. Browser Configuration

5.3.浏览器配置

We need to enable the web browser that we use to access a protected resource on the web application for the “Negotiate” authentication scheme. Fortunately, most of the modern web browsers like Chrome support “Negotiate” as an authentication scheme by default.

我们需要启用我们用来访问网络应用程序上受保护资源的网络浏览器的 “协商 “认证方案。幸运的是,大多数现代网络浏览器,如Chrome,都默认支持 “协商 “作为一种认证方案。

Additionally, we can configure the browser to provide “Integrated Authentication”. In this mode, when presented with the “Negotiate” challenge, the browser tries to make use of the cached credentials in the host machine, which has already been logged into a KDC principal. However, we’ll not use this mode in here to keep things explicit.

此外,我们还可以将浏览器配置为提供 “综合认证”。在这种模式下,当遇到 “协商 “挑战时,浏览器会尝试使用主机中的缓存凭证,这些凭证已经登录到了KDC主账户。然而,我们在这里不使用这种模式,以保持事情的明确性。

5.4. Domain Configuration

5.4.域配置

It is understandable that we may not have actual domains to test our web application. But sadly, we can’t use localhost or 127.0.0.1 or any other IP address with Kerberos authentication. There is, however, an easy solution to this, which involves setting up entries in the “hosts” file like:

可以理解的是,我们可能没有实际的域名来测试我们的网络应用。但遗憾的是,我们不能使用localhost或127.0.0.1或任何其他带有Kerberos认证的IP地址。然而,有一个简单的解决方案,这涉及到在 “hosts “文件中设置条目,比如。

demo.kerberos.bealdung.com 127.0.0.1

6. Spring to Our Rescue!

6.Spring来拯救我们!

Finally, as we’ve got the basics clear, it is time to test the theory. But, won’t it be cumbersome to create a web application supporting SPNEGO and Kerberos? Not if we use Spring. Spring has a Kerberos Extension as part of Spring Security that supports SPNEGO with Kerberos seamlessly.

最后,由于我们已经清楚了基础知识,是时候测试一下这个理论了。但是,创建一个支持SPNEGO和Kerberos的Web应用不是很麻烦吗?如果我们使用Spring就不会。Spring有一个Kerberos扩展,作为Spring Security的一部分,可以无缝地支持SPNEGO与Kerberos

Almost all we have to do is just configurations in Spring Security to enable SPNEGO with Kerberos. We’ll use Java-style configurations here, but an XML configuration can be set up as easily.

我们所要做的几乎只是在Spring Security中进行配置,以启用带有Kerberos的SPNEGO。我们将在这里使用Java风格的配置,但XML配置也可以轻松设置。

6.1. Maven Dependencies

6.1.Maven的依赖性

The first thing we have to set up are the dependencies:

我们要设置的第一件事是依赖性。

<dependency>
    <groupId>org.springframework.security.kerberos</groupId>
    <artifactId>spring-security-kerberos-web</artifactId>
    <version>${kerberos.extension.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.security.kerberos</groupId>
    <artifactId>spring-security-kerberos-client</artifactId>
    <version>${kerberos.extension.version}</version>
</dependency>

These dependencies are available for download from Maven Central.

这些依赖项可从Maven Central下载。

6.2. SPNEGO Configurations

6.2.SPNEGO配置

Firstly, SPNEGO is integrated into Spring Security as a Filter in HTTPSecurity:

首先,SPNEGO作为HTTPSecurity中的Filter被整合到Spring Security中。

 @Override
 public void configure(HttpSecurity http) throws Exception {
     AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
     http.addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManager),
         BasicAuthenticationFilter.class);
}

This only shows the part required to configure SPNEGO Filter and is not a complete HTTPSecurity configuration, which should be configured as per application security requirements.

这只显示了配置SPNEGOFilter所需的部分,而不是完整的HTPSecurity配置,应根据应用安全要求进行配置。

Next, we need to provide the SPNEGO Filter as Bean:

接下来,我们需要提供SPNEGO Filter作为Bean

@Bean
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(
  AuthenticationManager authenticationManager) {
    SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
    filter.setAuthenticationManager(authenticationManager);
    return filter;
}

6.3. Kerberos Configurations

6.3.Kerberos配置

In addition, We can configure Kerberos by adding AuthenticationProvider to AuthenticationManagerBuilder in Spring Security:

此外,我们可以通过在Spring Security的AuthenticationProvider中加入AuthenticationManagerBuilder来配置Kerberos。

 @Bean
 public AuthenticationManager authManager(HttpSecurity http) throws Exception {
     return http.getSharedObject(AuthenticationManagerBuilder.class)
         .authenticationProvider(kerberosAuthenticationProvider())
         .authenticationProvider(kerberosServiceAuthenticationProvider())
         .build();
 }

The first thing we have to provide is a KerberosAuthenticationProvider as a Bean. This is an implementation of AuthenticationProvider, and this is where we set SunJaasKerberosClient as a KerberosClient:

我们首先要提供的是一个KerberosAuthenticationProvider作为一个Bean。这是AuthenticationProvider的一个实现,在这里我们将SunJaasKerberosClient设置为KerberosClient

@Bean
public KerberosAuthenticationProvider kerberosAuthenticationProvider() {
    KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider();
    SunJaasKerberosClient client = new SunJaasKerberosClient();
    provider.setKerberosClient(client);
    provider.setUserDetailsService(userDetailsService());
    return provider;
}

Next, we also have to provide a KerberosServiceAuthenticationProvider as a Bean. This is the class that validates Kerberos Service Tickets or SPNEGO Tokens:

接下来,我们还必须提供一个KerberosServiceAuthenticationProvider作为Bean。这是一个验证Kerberos服务券或SPNEGO令牌的类。

@Bean
public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
    KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
    provider.setTicketValidator(sunJaasKerberosTicketValidator());
    provider.setUserDetailsService(userDetailsService());
    return provider;
}

Lastly, we need to provide a SunJaasKerberosTicketValidator as a Bean. This is an implementation of KerberosTicketValidator and uses SUN JAAS Login Module:

最后,我们需要提供一个SunJaasKerberosTicketValidator作为一个Bean。这是对KerberosTicketValidator的实现,并使用SUN JAAS登录模块。

@Bean
public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
    SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
    ticketValidator.setServicePrincipal("HTTP/demo.kerberos.bealdung.com@baeldung.com");
    ticketValidator.setKeyTabLocation(new FileSystemResource("baeldung.keytab"));
    return ticketValidator;
}

6.4. User Details

6.4.用户详情

We’ve seen references to a UserDetailsService in our AuthenticationProvider earlier, so why do we need it? Well, as we’ve come to know Kerberos, it is purely an authentication mechanism that is ticket-based.

我们已经在前面的AuthenticationProvider中看到了对UserDetailsService的引用,那么我们为什么需要它?嗯,正如我们对Kerberos的了解,它纯粹是一种基于票据的认证机制。

So, while it’s able to identify the user, it doesn’t provide other details related to the user, like their authorizations. We need a valid UserDetailsService provided to our AuthenticationProvider to fill this gap.

因此,虽然它能够识别用户,但它并不提供与用户相关的其他细节,比如他们的授权。我们需要一个有效的UserDetailsService提供给我们的AuthenticationProvider来填补这个空白。

6.5. Running the Application

6.5.运行应用程序

This is pretty much what we need to set up a web application with Spring Security enabled for SPNEGO with Kerberos. When we boot up the web application and access any page therein, the web browser should prompt for username and password, prepare a SPNEGO token with Service Ticket, and send it to the application.

这几乎就是我们为SPNEGO和Kerberos启用Spring Security的网络应用程序所需要的。当我们启动Web应用程序并访问其中的任何页面时,Web浏览器应该提示用户名和密码,用服务票准备一个SPNEGO令牌,并将其发送到应用程序。

The application should be able to process it using the credentials in the keytab file and respond with successful authentication.

应用程序应该能够使用keytab文件中的凭证来处理它,并响应成功的认证。

However, as we saw earlier, setting up a working Kerberos environment is complicated and quite brittle. If things don’t work as expected, it’s worthwhile to check all the steps again. A simple mistake like mismatch in the domain name can lead to failure with error messages that aren’t particularly helpful.

然而,正如我们前面所看到的,建立一个有效的 Kerberos 环境是很复杂的,也是很脆的。如果事情没有按预期进行,值得再次检查所有的步骤。一个简单的错误,如域名不匹配,就会导致失败,而且错误信息并不特别有用。

7. Practical Use of SPNEGO and Kerberos

7.SPNEGO和Kerberos的实际使用

Now that we’ve seen how Kerberos authentication works and how we can use SPNEGO with Kerberos in web applications, we may question the need for it. While this makes complete sense to use it as an SSO mechanism within an enterprise network, why should we use this in web applications?

现在我们已经看到了Kerberos认证是如何工作的,以及我们如何在Web应用中使用SPNEGO和Kerberos,我们可能会质疑它的必要性。虽然在企业网络中使用它作为SSO机制是完全合理的,但为什么我们要在网络应用中使用它呢?

Well, for one, even after so many years, Kerberos is still very actively used within enterprise applications, especially Windows-based applications. If an organization has several internal and external web applications, it does make sense to extend the same SSO infrastructure to cover them all. This makes it much easier for administrators and users of an organization to have a seamless experience through disparate applications.

好吧,首先,即使过了这么多年,Kerberos仍然在企业应用中被非常积极地使用,特别是基于Windows的应用。如果一个组织有几个内部和外部的网络应用,那么将相同的SSO基础设施扩展到所有这些应用是有意义的。这使得一个组织的管理员和用户更容易通过不同的应用程序获得无缝体验。

8. Conclusion

8.结语

To sum up, in this tutorial, we understood the basics of Kerberos authentication protocol. We also discussed SPNEGO as part of GSS-API and how we can use it to facilitate Kerberos-based authentication in a web application over HTTP. Furthermore, we tried to build a small web application leveraging Spring Security’s built-in support for SPNEGO with Kerberos.

总而言之,在本教程中,我们了解了Kerberos认证协议的基本知识。我们还讨论了作为GSS-API一部分的SPNEGO,以及我们如何使用它来促进HTTP上的Web应用中基于Kerberos的认证。此外,我们还尝试建立了一个小型Web应用,利用Spring Security内置的对SPNEGO和Kerberos的支持。

This tutorial just provides a quick sneak peek of a powerful and time tested authentication mechanism. There is quite a wealth of information available for us to learn more and possibly appreciate even more!

本教程只是对一个强大的、经过时间考验的认证机制提供了一个快速的偷窥。有相当丰富的信息可供我们学习,并可能欣赏到更多的信息!

As always, the code can be found over on GitHub.

一如既往,代码可以在GitHub上找到