13个不稳定版本

使用旧的Rust 2015

0.6.0 2021年2月21日
0.5.0 2020年2月3日
0.4.0 2018年8月5日
0.3.0 2018年5月23日
0.1.0 2016年8月24日

#223 in 身份验证

Download history 287/week @ 2024-03-03 272/week @ 2024-03-10 265/week @ 2024-03-17 225/week @ 2024-03-24 349/week @ 2024-03-31 326/week @ 2024-04-07 235/week @ 2024-04-14 245/week @ 2024-04-21 200/week @ 2024-04-28 321/week @ 2024-05-05 201/week @ 2024-05-12 187/week @ 2024-05-19 191/week @ 2024-05-26 154/week @ 2024-06-02 189/week @ 2024-06-09 186/week @ 2024-06-16

737 每月下载次数
7 个Crate中(4个直接使用)

MIT 许可证

45KB
661

加盐挑战响应认证机制(SCRAM)

本实现根据RFC5802和RFC7677提供了SCRAM-SHA-256机制的客户端和服务器。它不支持通道绑定。

阅读文档。

限制

强制的SCRAM-SHA-1认证机制目前尚未实现。这也适用于*-PLUS变体,因为该库不支持通道绑定。如果您愿意为它们做出贡献或维护,我将非常感激。

用法

客户端

以下是一个典型用例。有关方法的详细说明,请考虑其文档。在生产代码中,您应该用适当的错误处理来替换解包。

首先,必须使用以下任一方法提供用户和密码:使用ClientFirst::newClientFirst::with_rng。这些方法返回一个SCRAM状态,您可以使用它来计算第一个客户端消息。

服务器和客户端使用SCRAM机制交换四个消息。每种消息都有一个Rust类型。在不同的类型上调用client_firsthandle_server_firstclient_finalhandle_server_final方法可以逐步推进SCRAM握手。计算客户端消息永远不会失败,但处理服务器消息可能会导致失败。

use scram::ScramClient;

// This function represents your I/O implementation.
fn send_and_receive(message: &str) -> String {
    unimplemented!()
}

// Create a SCRAM state from the credentials.
let scram = ScramClient::new("user", "password", None);

// Get the client message and reassign the SCRAM state.
let (scram, client_first) = scram.client_first();

// Send the client first message and receive the servers reply.
let server_first = send_and_receive(&client_first);

// Process the reply and again reassign the SCRAM state. You can add error handling to
// abort the authentication attempt.
let scram = scram.handle_server_first(&server_first).unwrap();

// Get the client final message and reassign the SCRAM state.
let (scram, client_final) = scram.client_final();

// Send the client final message and receive the servers reply.
let server_final = send_and_receive(&client_final);

// Process the last message. Any error returned means that the authentication attempt
// wasn't successful.
let () = scram.handle_server_final(&server_final).unwrap();

服务器

服务器用于响应来自客户端的挑战。以下是一个使用默认提供者的典型用法模式。在生产中,您将实现一个AuthenticationProvider,可以根据用户名查找凭据。

服务器和客户端使用SCRAM机制交换四条消息。每个消息都有一个rust类型。调用handle_client_first()server_first()handle_client_final()server_final()这些不同类型的函数,可以逐步推进SCRAM握手过程。计算服务器消息永远不会失败(除非nonce的随机数源失败),但处理客户端消息可能导致失败。

如果认证失败,最后一步不会返回错误,但会返回一个AuthenticationStatus,你可以用它来确定认证是否成功。

use scram::{ScramServer, AuthenticationStatus, AuthenticationProvider, PasswordInfo};

// Create a dummy authentication provider
struct ExampleProvider;
impl AuthenticationProvider for ExampleProvider {
    // Here you would look up password information for the the given username
    fn get_password_for(&self, username: &str) -> Option<PasswordInfo> {
       unimplemented!()
    }

}
// These functions represent your I/O implementation.
# #[allow(unused_variables)]
fn receive() -> String {
    unimplemented!()
}
# #[allow(unused_variables)]
fn send(message: &str) {
    unimplemented!()
}

// Create a new ScramServer using the example authenication provider
let scram_server = ScramServer::new(ExampleProvider{});

// Receive a message from the client
let client_first = receive();

// Create a SCRAM state from the client's first message
let scram_server = scram_server.handle_client_first(&client_first).unwrap();
// Craft a response to the client's message and advance the SCRAM state
// We could use our own source of randomness here, with `server_first_with_rng()`
let (scram_server, server_first) = scram_server.server_first();
// Send our message to the client and read the response
send(&server_first);
let client_final = receive();

// Process the client's challenge and re-assign the SCRAM state.  This could fail if the
// message was poorly formatted
let scram_server = scram_server.handle_client_final(&client_final).unwrap();

// Prepare the final message and get the authentication status
let(status, server_final) = scram_server.server_final();
// Send our final message to the client
send(&server_final);

// Check if the client successfully authenticated
assert_eq!(status, AuthenticationStatus::Authenticated);

依赖项

~7.5MB
~229K SLoC