1. Overview
1.概述
In this tutorial, we’ll go through the basics of Simple Authentication and Security Layer (SASL). We’ll understand how Java supports adopting SASL for securing communication.
在本教程中,我们将了解简单认证和安全层(SASL)的基本知识。我们将了解Java如何支持采用SASL来保证通信安全。
In the process, we’ll use simple client and server communication, securing it with SASL.
在这个过程中,我们将使用简单的客户端和服务器通信,用SASL来保证其安全性。
2. What Is SASL?
2.什么是SASL?
SASL is a framework for authentication and data security in Internet protocols. It aims to decouple internet protocols from specific authentication mechanisms. We’ll better understand parts of this definition as we go along.
SASL是互联网协议中的认证和数据安全框架。它的目的是使互联网协议与特定的认证机制脱钩。随着我们的深入,我们将更好地理解这一定义的部分内容。
The need for security in communication is implicit. Let’s try to understand this in the context of client and server communication. Typically client and server exchange data over the network. It is imperative that both parties can trust each other and send data securely.
通信中对安全的需求是隐含的。让我们试着在客户和服务器通信的背景下理解这一点。通常,客户端和服务器通过网络交换数据。当务之急是双方能够相互信任并安全地发送数据。
2.1. Where Does SASL Fit In?
2.1.SASL适合在哪里?
In an application, we may use SMTP to send emails and use LDAP to access directory services. But each of these protocols may support another authentication mechanism, like Digest-MD5 or Kerberos.
在一个应用程序中,我们可能使用SMTP来发送电子邮件,使用LDAP来访问目录服务。但这些协议中的每一个都可能支持另一种认证机制,如Digest-MD5或Kerberos。
What if there was a way for protocols to swap authentication mechanisms more declaratively? This is exactly where SASL comes into the picture. Protocols supporting SASL can invariably support any of the SASL mechanisms.
如果有一种方法可以让协议更明确地交换认证机制,会怎么样呢?这正是SASL出现的地方。支持SASL的协议可以无一例外地支持任何SASL机制。
Hence, applications can negotiate a suitable mechanism and adopt that for authentication and secure communication.
因此,应用程序可以协商一个合适的机制,并采用该机制进行认证和安全通信。
2.2. How Does SASL Work?
2.2.SASL如何工作?
Now, that we’ve seen where SASL fits in the overall scheme of security, let’s understand how it works.
现在,我们已经看到了SASL在整个安全计划中的位置,让我们了解它是如何工作的。
SASL is a challenge-response framework. Here, the server issues a challenge to the client, and the client sends a response based on the challenge. The challenge and response are byte arrays of arbitrary length and, hence, can carry any mechanism-specific data.
SASL是一个挑战-响应框架。在这里,服务器向客户端发出挑战,而客户端根据挑战发送响应。挑战和响应是任意长度的字节数组,因此,可以携带任何机制特定的数据。
This exchange can continue for multiple iterations and finally ends when the server issues no further challenge.
这个交换可以持续多个迭代,最后在服务器不再发出挑战时结束。
Furthermore, the client and server can negotiate a security layer post-authentication. All subsequent communication can then leverage this security layer. However, note that some of the mechanisms may only support authentication.
此外,客户和服务器可以在认证后协商一个安全层。然后,所有后续的通信都可以利用这个安全层。然而,请注意,有些机制可能只支持认证。
It’s important to understand here that SASL only provides a framework for the exchange of challenge and response data. It does not mention anything about the data itself or how they are exchanged. Those details are left for the applications adopting to use SASL.
在此必须了解,SASL只提供了一个交换挑战和响应数据的框架。它没有提到任何关于数据本身或如何交换的信息。这些细节是留给采用SASL的应用程序的。
3. SASL Support in Java
3.Java中的SASL支持
There are APIs in Java that support developing both client-side and server-side applications with SASL. The API is not dependent on the actual mechanisms themselves. Applications using Java SASL API can select a mechanism based on security features required.
在Java中有一些API,支持用SASL开发客户端和服务器端应用程序。该API不依赖于实际机制本身。使用Java SASL API的应用程序可以根据所需的安全功能选择一种机制。
3.1. Java SASL API
3.1. Java SASL API
The key interfaces to notice, as part of the package “javax.security.sasl”, are SaslServer and SaslClient.
作为 “javax.security.sasl “包的一部分,需要注意的关键接口是SaslServer和SaslClient。
SaslServer represents the server-side mechanism of SASL.
SaslServer代表SASL的服务器端机制。
Let’s see how we can instantiate a SaslServer:
让我们看看如何实例化一个SaslServer。
SaslServer ss = Sasl.createSaslServer(
mechanism,
protocol,
serverName,
props,
callbackHandler);
We are using the factory class Sasl to instantiate SaslServer. The method createSaslServer accepts several parameters:
我们正在使用工厂类Sasl来实例化SaslServer。该方法createSaslServer接受几个参数。
- mechanism – the IANA registered name of a SASL supported mechanism
- protocol – the name of the protocol for which authentication is being done
- serverName – the fully qualified hostname of the server
- props – a set of properties used to configure the authentication exchange
- callbackHandler – a callback handler to be used by the selected mechanism to get further information
Out of the above, only the first two are mandatory, and the rest are nullable.
在上述内容中,只有前两个是强制性的,其余的都是可忽略的。
SaslClient represents the client-side mechanism of SASL. Let’s see how can we instantiate a SaslClient:
SaslClient代表SASL的客户端机制。让我们看看如何实例化一个SaslClient。
SaslClient sc = Sasl.createSaslClient(
mechanisms,
authorizationId,
protocol,
serverName,
props,
callbackHandler);
Here again, we’re using the factory class Sasl to instantiate our SaslClient. The list of parameters which createSaslClient accepts is pretty much the same as before.
这里,我们再次使用工厂类Sasl来实例化我们的SaslClient。createSaslClient所接受的参数列表与之前的基本相同。
However, there are some subtle differences:
然而,也有一些微妙的差别。
- mechanisms – here, this is a list of mechanisms to try from
- authorizationId – this is a protocol-dependent identification to be used for authorization
The rest of the parameters are similar in meaning and their optionality.
其余的参数在含义上和它们的可选择性上都是相似的。
3.2. Java SASL Security Provider
3.2.Java SASL安全提供者
Beneath the Java SASL API are the actual mechanisms that provide the security features. The implementation of these mechanisms is provided by security providers registered with the Java Cryptography Architecture (JCA).
在Java SASL API下面是提供安全功能的实际机制。这些机制的实现是由在Java Cryptography Architecture (JCA)上注册的安全提供商提供。
There can be multiple security providers registered with the JCA. Each of these may support one or more of the SASL mechanisms.
可以有多个安全提供者在JCA注册。其中每个可能支持一个或多个SASL机制。
Java ships with SunSASL as a security provider, which gets registered as a JCA provider by default. However, this may be removed or reordered with any other available providers.
Java在出厂时将SunSASL作为一个安全提供者,它被默认注册为JCA提供者。然而,这可以被删除或与任何其他可用的提供者重新排序。
Moreover, it is always possible to provide a custom security provider. This will require us to implement the interfaces SaslClient and SaslServer. In doing so, we may implement our custom security mechanism as well!
此外,我们总是可以提供一个自定义的安全提供者。这将要求我们实现接口SaslClient和SaslServer。在这样做的过程中,我们也可以实现我们的自定义安全机制!
4. SASL Through an Example
4.通过实例介绍SASL
Now that we’ve seen how to create a SaslServer and a SaslClient, it’s time to understand how to use them. We’ll be developing client and server components. These will exchange challenge and response iteratively to achieve authentication. We’ll make use of the DIGEST-MD5 mechanism in our simple example here.
现在我们已经看到了如何创建一个SaslServer和一个SaslClient,是时候了解如何使用它们了。我们将开发客户端和服务器组件。这些组件将反复交换挑战和响应以实现认证。我们将在这里的简单例子中使用DIGEST-MD5机制。
4.1. Client and Server CallbackHandler
4.1 客户端和服务器CallbackHandler
As we saw earlier, we need to provide implementations of CallbackHandler to SaslServer and SaslClient. Now, CallbackHandler is a simple interface that defines a single method — handle. This method accepts an array of Callback.
正如我们之前看到的,我们需要为SaslServer和SaslClient提供CallbackHandler的实现。现在,CallbackHandler是一个简单的接口,定义了一个方法–handle。这个方法接受一个Callback的数组。
Here, Callback presents a way for the security mechanism to collect authentication data from the calling application. For instance, a security mechanism may require a username and password. There are quite a few Callback implementations like NameCallback and PasswordCallback available for use.
这里,Callback为安全机制提供了一种从调用应用程序收集认证数据的方式。例如,一个安全机制可能需要一个用户名和密码。有相当多的Callback实现,如NameCallback和PasswordCallback可供使用。
Let’s see how we can define a CallbackHandler for the server, to begin with:
让我们看看我们如何为服务器定义一个CallbackHandler,首先。
public class ServerCallbackHandler implements CallbackHandler {
@Override
public void handle(Callback[] cbs) throws IOException, UnsupportedCallbackException {
for (Callback cb : cbs) {
if (cb instanceof AuthorizeCallback) {
AuthorizeCallback ac = (AuthorizeCallback) cb;
//Perform application-specific authorization action
ac.setAuthorized(true);
} else if (cb instanceof NameCallback) {
NameCallback nc = (NameCallback) cb;
//Collect username in application-specific manner
nc.setName("username");
} else if (cb instanceof PasswordCallback) {
PasswordCallback pc = (PasswordCallback) cb;
//Collect password in application-specific manner
pc.setPassword("password".toCharArray());
} else if (cb instanceof RealmCallback) {
RealmCallback rc = (RealmCallback) cb;
//Collect realm data in application-specific manner
rc.setText("myServer");
}
}
}
}
Now, let’s see our client-side of the Callbackhandler:
现在,让我们看看客户端的Callbackhandler。
public class ClientCallbackHandler implements CallbackHandler {
@Override
public void handle(Callback[] cbs) throws IOException, UnsupportedCallbackException {
for (Callback cb : cbs) {
if (cb instanceof NameCallback) {
NameCallback nc = (NameCallback) cb;
//Collect username in application-specific manner
nc.setName("username");
} else if (cb instanceof PasswordCallback) {
PasswordCallback pc = (PasswordCallback) cb;
//Collect password in application-specific manner
pc.setPassword("password".toCharArray());
} else if (cb instanceof RealmCallback) {
RealmCallback rc = (RealmCallback) cb;
//Collect realm data in application-specific manner
rc.setText("myServer");
}
}
}
}
To clarify, we’re looping through the Callback array and handling only specific ones. The ones that we have to handle is specific to the mechanism in use, which is DIGEST-MD5 here.
澄清一下,我们正在浏览回调数组,只处理特定的。我们必须处理的是特定的机制,在这里是DIGEST-MD5。
4.2. SASL Authentication
4.2.SASL认证
So, we’ve written our client and server CallbackHandler. We’ve also instantiated SaslClient and SaslServer for DIGEST-MD5 mechanism.
所以,我们已经编写了我们的客户端和服务器CallbackHandler。我们还为DIGEST-MD5机制实例化了SaslClient和SaslServer。
Now is the time to see them in action:
现在是看他们行动的时候了。
@Test
public void givenHandlers_whenStarted_thenAutenticationWorks() throws SaslException {
byte[] challenge;
byte[] response;
challenge = saslServer.evaluateResponse(new byte[0]);
response = saslClient.evaluateChallenge(challenge);
challenge = saslServer.evaluateResponse(response);
response = saslClient.evaluateChallenge(challenge);
assertTrue(saslServer.isComplete());
assertTrue(saslClient.isComplete());
}
Let’s try to understand what is happening here:
让我们试着理解这里发生了什么。
- First, our client gets the default challenge from the server
- The client then evaluates the challenge and prepares a response
- This challenge-response exchange continues for one more cycle
- In the process, the client and server make use of callback handlers to collect any additional data as needed by the mechanism
- This concludes our authentication here, but in reality, it can iterate over multiple cycles
A typical exchange of challenge and response byte arrays happens over the network. But, here for simplicity, we’ve assumed local communication.
挑战和响应字节数组的典型的交换发生在网络上。但是,在这里为了简单起见,我们假设是本地通信。
4.3. SASL Secure Communication
4.3.SASL安全通信
As we discussed earlier, SASL is a framework capable of supporting secure communication beyond just authentication. However, this is only possible if the underlying mechanism supports it.
正如我们之前所讨论的,SASL是一个能够支持安全通信的框架,不仅仅是认证。然而,这只有在底层机制支持的情况下才有可能。
Firstly, let’s first check if we have been able to negotiate a secure communication:
首先,让我们先检查一下我们是否已经能够进行安全通信的谈判。
String qop = (String) saslClient.getNegotiatedProperty(Sasl.QOP);
assertEquals("auth-conf", qop);
Here, QOP stands for the quality of protection. This is something that the client and server negotiate during authentication. A value of “auth-int” indicates authentication and integrity. While, a value of “auth-conf” indicates authentication, integrity, and confidentiality.
这里,QOP代表保护的质量。这是客户和服务器在认证过程中协商的事情。值为 “auth-int “表示认证和完整性。而 “auth-conf “的值则表示认证、完整性和保密性。
Once we have a security layer, we can leverage that to secure our communication.
一旦我们有了安全层,我们就可以利用它来保障我们的通信。
Let’s see how we can secure outgoing communication in the client:
让我们看看如何确保客户端的外发通信。
byte[] outgoing = "Baeldung".getBytes();
byte[] secureOutgoing = saslClient.wrap(outgoing, 0, outgoing.length);
// Send secureOutgoing to the server over the network
And, similarly, the server can process incoming communication:
而且,同样地,服务器可以处理传入的通信。
// Receive secureIncoming from the client over the network
byte[] incoming = saslServer.unwrap(secureIncoming, 0, netIn.length);
assertEquals("Baeldung", new String(incoming, StandardCharsets.UTF_8));
5. SASL in the Real World
5.真实世界中的SASL
So, we now have a fair understanding of what SASL is and how to use it in Java. But, typically, that’s not what we’ll end up using SASL for, at least in our daily routine.
因此,我们现在对SASL是什么以及如何在Java中使用它有了相当的了解。但是,通常情况下,这并不是我们最终要使用SASL的目的,至少在我们的日常工作中。
As we saw earlier, SASL is primarily meant for protocols like LDAP and SMTP. Although, more and more applications and coming on board with SASL — for instance, Kafka. So, how do we use SASL to authenticate with such services?
正如我们之前所看到的,SASL主要用于LDAP和SMTP等协议。虽然,越来越多的应用程序开始使用SASL,例如Kafka。那么,我们如何使用SASL对这些服务进行认证呢?
Let’s suppose we’ve configured Kafka Broker for SASL with PLAIN as the mechanism of choice. PLAIN simply means that it authenticates using a combination of username and password in plain text.
假设我们为Kafka Broker配置了SASL,并选择PLAIN作为机制。PLAIN只是意味着它使用纯文本的用户名和密码的组合进行认证。
Let’s now see how can we configure a Java client to use SASL/PLAIN to authenticate against the Kafka Broker.
现在让我们看看如何配置一个Java客户端来使用SASL/PLAIN来对Kafka Broker进行认证。
We begin by providing a simple JAAS configuration, “kafka_jaas.conf”:
我们首先提供一个简单的JAAS配置,”kafka_jaas.conf”。
KafkaClient {
org.apache.kafka.common.security.plain.PlainLoginModule required
username="username"
password="password";
};
We make use of this JAAS configuration while starting the JVM:
我们在启动JVM时利用了这个JAAS配置。
-Djava.security.auth.login.config=kafka_jaas.conf
Finally, we have to add a few properties to pass to our producer and consumer instances:
最后,我们必须添加一些属性来传递给我们的生产者和消费者实例。
security.protocol=SASL_SSL
sasl.mechanism=PLAIN
That’s all there is to it. This is just a small part of Kafka client configurations, though. Apart from PLAIN, Kafka also supports GSSAPI/Kerberos for authentication.
这就是它的全部内容。不过这只是Kafka客户端配置的一小部分。除了PLAIN之外,Kafka还支持GSSAPI/Kerberos的认证。
6. SASL in Comparision
6.比较中的SASL
Although SASL is quite effective in providing a mechanism-neutral way of authenticating and securing client and server communication. However, SASL is not the only solution available in this regard.
尽管SASL在提供一种机制中立的方法来验证和保护客户和服务器通信方面相当有效。然而,SASL并不是这方面的唯一解决方案。
Java itself provides other mechanisms to achieve this objective. We’ll briefly discuss them and understand how they fare against SASL:
Java本身提供了其他机制来实现这一目标。我们将简要地讨论它们,并了解它们与SASL的对比情况。
- Java Secure Socket Extension (JSSE): JSSE is a set of packages in Java that implements Secure Sockets Layer (SSL) for Java. It provides data encryption, client and server authentication, and message integrity. Unlike SASL, JSSE relies on a Public Key Infrastructure (PKI) to work. Hence, SASL works out to be more flexible and lightweight than JSSE.
- Java GSS API (JGSS): JGGS is the Java language binding for Generic Security Service Application Programming Interface (GSS-API). GSS-API is an IETF standard for applications to access security services. In Java, under GSS-API, Kerberos is the only mechanism supported. Kerberos again requires a Kerberised infrastructure to work. Compared to SASL, here yet, choices are limited and heavyweight.
Overall, SASL is a very lightweight framework and offers a wide variety of security features through pluggable mechanisms. Applications adopting SASL have a lot of choices in implementing the right set of security features, depending upon the need.
总的来说,SASL是一个非常轻量级的框架,并通过可插拔机制提供各种安全功能。采用SASL的应用程序在实现正确的安全功能集方面有很多选择,这取决于需求。
7. Conclusion
7.结语
To sum up, in this tutorial, we understood the basics of the SASL framework, which provides authentication and secure communication. We also discussed the APIs available in Java for implementing the client- and server-side of SASL.
总而言之,在本教程中,我们了解了SASL框架的基本知识,它提供了认证和安全通信。我们还讨论了Java中可用于实现SASL客户端和服务器端的API。
We saw how to use a security mechanism through a JCA provider. Finally, we also talked about the usage of SASL in working with different protocols and applications.
我们看到了如何通过JCA提供者使用安全机制。最后,我们还谈到了SASL在不同协议和应用中的使用。
As always, the code can be found over on GitHub.
一如既往,代码可以在GitHub上找到over。