SASL简述


发布于 2024-04-06 / 78 阅读 / 0 评论 /
SASL是Simple Authentication and Security Layer的简称,简单身份验证和安全层。

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。

Mechanism

SaslServer

说明

GSSAPI

com.sun.security.sasl.gsskerb.GssKrb5Server

CRAM-MD5

com.sun.security.sasl.CramMD5Server

DIGEST-MD5

com.sun.security.sasl.digest.DigestMD5Server

PLAIN

com.sun.security.sasl.PlainSaslServer

SCRAM

org.apache.kafka.common.security.scram.internals.ScramSaslServer

Kafka自定义机制

OAUTHBEARER

org.apache.kafka.common.security.oauthbearer.internals.OAuthBearerSaslServer

Kafka自定义机制

前四个是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、以及其他外部机制。

Mechanism

SaslClient

说明

GSSAPI

com.sun.security.sasl.gsskerb.GssKrb5Client

CRAM-MD5

com.sun.security.sasl.CramMD5Client

DIGEST-MD5

com.sun.security.sasl.digest.DigestMD5Client

PLAIN

com.sun.security.sasl.PlainClient

SCRAM

org.apache.kafka.common.security.scram.internals.ScramSaslClient

Kafka自定义机制

OAUTHBEARER

org.apache.kafka.common.security.oauthbearer.internals.OAuthBearerSaslClient

Kafka自定义机制

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。