1.SASL概述
SASL是一个互联网标准,它制定了一个鉴权协议,且在client和server之间建立连接。SASL定义了鉴权数据如何交换,但是并没有制定数据的内容。它是一个鉴权机制框架。
简单身份验证和安全层 (SASL) 指定了一种挑战-响应协议,使用该协议在客户端和服务器之间交换数据,从而实现身份验证和(可选)建立一个可承载后续通信的安全层。它与基于连接的协议,如 LDAPv3 或 IMAPv4 一起使用。RFC 2222 中描述了 SASL。
SASL通过LDAP v3和IMAP v4协议来确保鉴权是可插拔的。而不是硬编码一个鉴权方法到协议。
2.Java SASL的实现
SASL是一种challange-response协议,server发布challenge到client,而client基于challange发送response。这种交换直到server被满足且不再发布challenge。challenge和response是任意长度的二进制标记,封装协议诸如LDAP、IMAP指定了这些标记如何被编码和交换的。例如LDAP指定了SASL标记被封装在LDAP request和response内。
Java SASL根据这种应答和使用方式已经模板化了,SaslClient和SaslServer接口,分别代表了client-side和server-side的机制(mechanism)。应用程序通过代表challenge和response的字节数组,使用这种机制交互。
Java SASL机制的实现主要分为以下三个步骤。
2.1.创建SASL机制
需要分别创建服务端机制和客户端机制。
2.1.1.server-side机制
不断发布challenge,处理response直到被满足。创建方式如下:
SaslServer ss = Sasl.createSaslServer(mechanism, protocol, myName, props, callbackHandler);
基本的服务端机制有:CRAM-MD5、DIGEST-MD5、GSSAPI。
前四个是java原生提供的SaslServer。
2.1.2.client-side机制
不断评估challenge,且发布response直到server满足。创建方式如下:
String[] mechanisms = new String[]{"DIGEST-MD5", "PLAIN"};
SaslClient sc = Sasl.createSaslClient(mechanisms, authzid, protocol, serverName, props, callbackHandler);
基本的客户端机制有:PLAIN、CRAM-MD5、DIGEST-MD5、GSSAPI、以及其他外部机制。
java中对SaslClient有通用的接口定义,如果需要自定义SaslClient,需要实现此接口。
2.2.传递输入信息到机制中
Java SASL是一个通用的框架,它必须能容纳多种不同类型的机制,每个机制需要用输入来初始化,且需要输入做进一步的事情。API提供了三种application传递input给机制的方式。
(1)普通输入参数:应用程序使用预定义参数来提供信息。对于sasl客户端机制,输入参数是授权ID、协议ID和server名称。对于sasl服务端机制,输入参数是协议id和server名称。
(2)属性参数:Java sasl api定义了一些标准属性,如 quality-of-protection, cipher strength和maximum buffer size。此参数可以以非标准属性(相对于特定机制)使用。
(3)Callbacks:使用回调handler参数来提供输入(不能被预定义)。当机制需要输入数据时,它使用callback提供数据。
2.3.使用机制
一旦应用程序创建一个机制,它使用此机制来获取sasl tokens做点交换,客户端通过协议指示给server。有些协议允许客户端使用带可选的初始response请求。客户端应用程序不断循环使用机制来取得从server获得challenge的response,回送给server,直到机制或应用程序协议表明授权完成或机制不能获得challenge。
2.3.1.客户端如何使用机制
客户端代码例如下所示:
// 初始化的response信息
byte[] response = (sc.hasInitialResponse() ? sc.evaluateChallenge(new byte[]) : null);
String mechanism = sc.getName();
// 把初始化的response信息发送到服务端
send(mechanism, response);
// 接收服务端响应信息
msg = receive();
// 只有当客户端未结束,且收到的消息状态为CONTINUE或SUCCESS才继续
while (!sc.isComplete() && (msg.status == CONTINUE || msg.status == SUCCESS)) {
// 对服务端的challenge进行评估,提取出下一次需要发送到服务端的response信息
response = sc.evaluateChallenge(msg.contents);
if (msg.status == SUCCESS) {
// 表示完成,服务端不再继续接收SASL数据
if (response != null) {
throw new IOException("Protocol error: attempting to send response after completion");
}
break;
} else {
// 表示继续
send(mechanism, response);
msg = receive();
}
}
主要是向evaluateChallenge,并把Response信息发送给SaslServer。
2.3.2.服务端如何使用机制
服务端代码例如下所示:
// 读取包含mechanism名称和初始化response信息的请求信息
msg.receive();
// 创建SaslServer执行认证
SaslServer ss = Sasl.createSaslServer(msg.mechanism, protocol, myName, props, callbackHandler);
// 认证过程,直到结束
while (!ss.isComplete()) {
try {
// 评估请求的response信息,得到challenge信息
byte[] challenge = ss.evaluateResponse(msg.contents);
if (ss.isComplete()) {
// 服务端已结束,则向SaslClient发送认证成功信息
send(mechanism, challenge, SUCCESS);
} else {
// 服务端未结束,则向SaslClient发送认证继续信息
send(mechanism, challenge, CONTINUE);
msg.receive();
}
} catch (SaslException e) {
// 发送认证失败信息
send(ERROR);
sc.dispose();
break;
}
}
主要是evaluateResponse,并把challenge信息发回给SaslClient。