javax.security.sasl

接口
异常
public interface SaslClient

以客户端的身份执行 SASL 验证。

为了执行具体 SASL 机制所定义的验证,协议库(例如用于 LDAP 的库)要获得此类的一个实例。调用 SaslClient 实例的方法可处理 challenge,并创建与 SaslClient 所实现的 SASL 机制相对应的响应。随着验证的进行,该实例会封装 SASL 客户端的验证交换状态。

以下是 LDAP 库如何使用 SaslClient 的一个示例。它首先获得 SaslClient 的一个实例:

 SaslClient sc = Sasl.createSaslClient(mechanisms,
     authorizationId, protocol, serverName, props, callbackHandler);
然后它可继续使用该客户端进行验证。例如,LDAP 库可能按如下方式使用该客户端:
 // Get initial response and send to server
 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) {
         // we're done; don't expect to send another BIND
         if (response != null) {
               throw new SaslException(
                   "Protocol error: attempting to send response after completion");
           }
         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"))) {

      // Use SaslClient.wrap() and SaslClient.unwrap() for future
      // communication with server
        ldap.in = new SecureInputStream(sc, ldap.in);
        ldap.out = new SecureOutputStream(sc, ldap.out);
    }
 }
如果该机制有初始响应,则库可调用带有空 challenge 的 evaluateChallenge() 来获得该初始响应。诸如 IMAP4 等此类协议在其送往服务器的第一个验证命令中不包括初始响应,所以可无需首先调用 hasInitialResponse()evaluateChallenge() 即可发起验证。当服务器响应该命令时,它会发送初始 challenge。对于客户端首先发送数据的 SASL 机制而言,服务器应该发出一个没有数据的 challenge。然后,这会导致带有空 challenge 的 evaluateChallenge() 调用(在客户端上)。

从以下版本开始:
1.5
另请参见:
Sasl, SaslClientFactory

方法摘要
 void dispose()
          处置 SaslClient 可能使用的所有系统资源或安全敏感信息。
 byte[] evaluateChallenge(byte[] challenge)
          评估 challenge 数据并生成一个响应。
 String getMechanismName()
          返回此 SASL 客户端的 IANA 注册机制名。
 Object getNegotiatedProperty(String propName)
          获取已协商的属性。
 boolean hasInitialResponse()
          确定此机制是否具有可选的初始响应。
 boolean isComplete()
          确定验证交换是否已完成。
 byte[] unwrap(byte[] incoming, int offset, int len)
          解包接收自服务器的 byte 数组。
 byte[] wrap(byte[] outgoing, int offset, int len)
          包装要发送到服务器的 byte 数组。
 

方法详细信息

getMechanismName

String getMechanismName()
返回此 SASL 客户端的 IANA 注册机制名。(例如 "CRAM-MD5"、"GSSAPI")。

返回:
表示 IANA 注册机制名的非 null 字符串。

hasInitialResponse

boolean hasInitialResponse()
确定此机制是否具有可选的初始响应。如果为 true,则调用者应该调用带有空数组的 evaluateChallenge() 以获得初始响应。

返回:
如果此机制具有初始响应,则返回 true。

evaluateChallenge

byte[] evaluateChallenge(byte[] challenge)
                         throws SaslException
评估 challenge 数据并生成一个响应。如果在验证处理期间接收到服务器的 challenge,则调用此方法来准备要提交给服务器的下一个合适响应。

参数:
challenge - 服务器发送的非 null challenge。该 challenge 数组的长度可以为零。
返回:
要发送给服务器的响应,可能为 null。如果 challenge 随附一个 "SUCCESS" 状态并且它只包含客户端更新其状态的数据,而没有需要送到服务器的响应,则返回 null。如果客户端要发送没有数据的响应,则该响应是一个零长度的 byte 数组。
抛出:
SaslException - 如果处理 challenge 或生成响应时发生错误。

isComplete

boolean isComplete()
确定验证交换是否已完成。可在任何时间调用此方法,但是通常在调用者接收到服务器关于交换已完成的指示(以特定于协议的方式通知)前不会调用此方法。

返回:
如果验证交换已完成,则返回 true;否则返回 false。

unwrap

byte[] unwrap(byte[] incoming,
              int offset,
              int len)
              throws SaslException
解包接收自服务器的 byte 数组。仅在验证交换已完成(即 isComplete() 返回 true)后,并且仅在验证交换已经协商将完整性和/或机密性作为保护级别时才调用此方法;否则会抛出 IllegalStateException

incoming 是 SASL 缓冲区的内容(在 RFC 2222 中定义),没有表示长度的前导 4 个八位组字段。offsetlen 指定了要使用的 incoming 部分。

参数:
incoming - 非 null 的 byte 数组,包含取自服务器的已编码字节。
offset - 所用字节在 incoming 中的开始位置。
len - 要使用的 incoming 中的字节数。
返回:
包含已解码字节的非 null byte 数组。
抛出:
SaslException - 如果无法成功解包 incoming
IllegalStateException - 如果验证交换未完成,如果协商的保护级别既没有完整性,也没有机密性。

wrap

byte[] wrap(byte[] outgoing,
            int offset,
            int len)
            throws SaslException
包装要发送到服务器的 byte 数组。仅在验证交换已完成(即 isComplete() 返回 true)后,并且仅在验证交换已经协商将完整性和/或机密性作为保护级别时才调用此方法;否则会抛出 IllegalStateException

此方法的结果会组成 SASL 缓冲区的内容(在 RFC 2222 中定义),没有表示长度的前导 4 个八位组字段。offsetlen 指定了要使用的 outgoing 部分。

参数:
outgoing - 非 null 的 byte 数组,包含要编码的字节。
offset - 所用字节在 outgoing 中的开始位置。
len - 要使用的 outgoing 中的字节数。
返回:
包含已编码字节的非 null byte 数组。
抛出:
SaslException - 如果无法成功包装 outgoing
IllegalStateException - 如果验证交换未完成,如果协商的保护级别既没有完整性,也没有机密性。

getNegotiatedProperty

Object getNegotiatedProperty(String propName)
获取已协商的属性。仅在验证交换已完成后(即 isComplete() 返回 true 时)才调用此方法;否则会抛出 IllegalStateException

参数:
propName - 非 null 的属性名。
返回:
已协商的属性的值。如果为 null,则未协商该属性,或者该属性不适用于此机制。
抛出:
IllegalStateException - 如果未完成此验证交换。

dispose

void dispose()
             throws SaslException
处置 SaslClient 可能使用的所有系统资源或安全敏感信息。调用此方法会使 SaslClient 实例失效。此方法是幂等的。

抛出:
SaslException - 如果释放资源时遇到问题。