public interface SaslClient
作为客户端执行SASL身份验证。
诸如LDAP之类的协议库会获取此类的实例,以执行特定SASL机制定义的身份验证。在SaslClient
实例上调用方法会处理挑战并根据SaslClient
实现的SASL机制创建响应。随着身份验证的进行,该实例封装了SASL客户端身份验证交换的状态。
以下是LDAP库可能如何使用SaslClient
的示例。首先获取SaslClient
的实例:
然后可以继续使用客户端进行身份验证。例如,LDAP库可能会如下使用客户端:SaslClient sc = Sasl.createSaslClient(mechanisms, authorizationId, protocol, serverName, props, callbackHandler);
如果机制具有初始响应,库将使用空挑战调用// 获取初始响应并发送给服务器 byte[] response = (sc.hasInitialResponse() ? sc.evaluateChallenge(new byte[0]) : null); LdapResult res = ldap.sendBindRequest(dn, sc.getName(), response); while (!sc.isComplete() && (res.status == SASL_BIND_IN_PROGRESS || res.status == SUCCESS)) { response = sc.evaluateChallenge(res.getBytes()); if (res.status == SUCCESS) { // 我们完成了;不希望在完成后发送另一个绑定 if (response != null) { throw new SaslException( "协议错误:尝试在完成后发送响应"); } break; } res = ldap.sendBindRequest(dn, sc.getName(), response); } if (sc.isComplete() && res.status == SUCCESS) { String qop = (String) sc.getNegotiatedProperty(Sasl.QOP); if (qop != null && (qop.equalsIgnoreCase("auth-int") || qop.equalsIgnoreCase("auth-conf"))) { // 使用SaslClient.wrap()和SaslClient.unwrap()进行未来 // 与服务器的通信 ldap.in = new SecureInputStream(sc, ldap.in); ldap.out = new SecureOutputStream(sc, ldap.out); } }
evaluateChallenge()
以获取初始响应。诸如IMAP4之类的协议,在向服务器发送第一个身份验证命令时不包含初始响应,会在首次调用hasInitialResponse()
或evaluateChallenge()
之前启动身份验证。当服务器响应命令时,它会发送初始挑战。对于客户端首先发送数据的SASL机制,服务器应该发出不带数据的挑战。这将导致(在客户端上)使用空挑战调用evaluateChallenge()
。
- 自版本:
- 1.5
- 参见:
-
Method Summary
Modifier and TypeMethodDescriptionvoid
dispose()
处置SaslClient可能正在使用的任何系统资源或安全敏感信息。byte[]
evaluateChallenge
(byte[] challenge) 评估挑战数据并生成响应。返回此SASL客户端的IANA注册机制名称。getNegotiatedProperty
(String propName) 检索协商的属性。boolean
确定此机制是否具有可选的初始响应。boolean
确定身份验证交换是否已完成。byte[]
unwrap
(byte[] incoming, int offset, int len) 从服务器接收的字节数组进行解包。byte[]
wrap
(byte[] outgoing, int offset, int len) 将要发送到服务器的字节数组进行包装。
-
Method Details
-
getMechanismName
String getMechanismName()返回此SASL客户端的IANA注册机制名称。(例如:"CRAM-MD5","GSSAPI")。- 返回:
- 代表IANA注册机制名称的非空字符串。
-
hasInitialResponse
boolean hasInitialResponse()确定此机制是否具有可选的初始响应。如果为true,则调用者应使用空数组调用evaluateChallenge()
以获取初始响应。- 返回:
- 如果此机制具有初始响应,则为true。
-
evaluateChallenge
评估挑战数据并生成响应。如果在身份验证过程中从服务器接收到挑战,则调用此方法准备适当的下一个响应提交给服务器。- 参数:
-
challenge
- 从服务器发送的非空挑战。挑战数组可能长度为零。 - 返回:
- 发送到服务器的可能为null的响应。如果挑战伴随“SUCCESS”状态且挑战仅包含客户端更新其状态所需的数据而无需发送响应到服务器,则为null。如果客户端需要发送不带数据的响应,则响应是零长度的字节数组。
- 抛出:
-
SaslException
- 如果处理挑战或生成响应时发生错误。
-
isComplete
boolean isComplete()确定身份验证交换是否已完成。可以随时调用此方法,但通常在调用者从服务器(以协议特定的方式)收到交换已完成的指示之前不会调用。- 返回:
- 如果身份验证交换已完成,则为true;否则为false。
-
unwrap
从服务器接收的字节数组进行解包。只能在身份验证交换完成后调用此方法(即,当isComplete()
返回true时),并且仅当身份验证交换已协商完整性和/或隐私作为保护质量时才能调用;否则,将抛出IllegalStateException
。incoming
是RFC 2222中定义的SASL缓冲区的内容,不包括表示长度的前导四个八位组字段。offset
和len
指定要使用的incoming
部分。- 参数:
-
incoming
- 包含来自服务器的编码字节的非空字节数组。 -
offset
- 要使用的incoming
中的字节的起始位置。 -
len
- 要使用的incoming
中的字节数。 - 返回:
- 包含解码字节的非空字节数组。
- 抛出:
-
SaslException
- 如果无法成功解包incoming
。 -
IllegalStateException
- 如果身份验证交换尚未完成,或者协商的保护质量既没有完整性也没有隐私。
-
wrap
将要发送到服务器的字节数组进行包装。只能在身份验证交换完成后调用此方法(即,当isComplete()
返回true时),并且仅当身份验证交换已协商完整性和/或隐私作为保护质量时才能调用;否则,将抛出IllegalStateException
。此方法的结果将组成RFC 2222中定义的SASL缓冲区的内容,不包括表示长度的前导四个八位组字段。
offset
和len
指定要使用的outgoing
部分。- 参数:
-
outgoing
- 包含要编码的字节的非空字节数组。 -
offset
- 要使用的outgoing
中的字节的起始位置。 -
len
- 要使用的outgoing
中的字节数。 - 返回:
- 包含编码字节的非空字节数组。
- 抛出:
-
SaslException
- 如果无法成功包装outgoing
。 -
IllegalStateException
- 如果身份验证交换尚未完成,或者协商的保护质量既没有完整性也没有隐私。
-
getNegotiatedProperty
检索协商的属性。只能在身份验证交换完成后调用此方法(即,当isComplete()
返回true时);否则,将抛出IllegalStateException
。Sasl
类包括几个众所周知的属性名称(例如,Sasl.QOP
)。SASL提供程序可以支持其他特定于供应商和/或机制的属性。- 参数:
-
propName
- 非空属性名称。 - 返回:
- 协商属性的值。如果为null,则未协商该属性或该属性不适用于此机制。
- 抛出:
-
IllegalStateException
- 如果此身份验证交换尚未完成
-
dispose
处置SaslClient可能正在使用的任何系统资源或安全敏感信息。调用此方法会使SaslClient实例无效。此方法是幂等的。- 抛出:
-
SaslException
- 如果在处理资源时遇到问题。
-