mongodb/client/auth/
plain.rs

1use crate::{
2    client::{
3        auth::{
4            sasl::{SaslResponse, SaslStart},
5            AuthMechanism,
6            Credential,
7        },
8        options::ServerApi,
9    },
10    cmap::Connection,
11    error::{Error, Result},
12};
13
14pub(crate) async fn authenticate_stream(
15    conn: &mut Connection,
16    credential: &Credential,
17    server_api: Option<&ServerApi>,
18) -> Result<()> {
19    let source = credential.source.as_deref().unwrap_or("$external");
20    let username = credential
21        .username
22        .as_ref()
23        .ok_or_else(|| Error::authentication_error("PLAIN", "no username supplied"))?;
24
25    let password = credential
26        .password
27        .as_ref()
28        .ok_or_else(|| Error::authentication_error("PLAIN", "no password supplied"))?;
29
30    let sasl_start = SaslStart::new(
31        source.into(),
32        AuthMechanism::Plain,
33        payload_bytes(username, password),
34        server_api.cloned(),
35    )
36    .into_command();
37
38    let response = conn.send_message(sasl_start).await?;
39    let sasl_response = SaslResponse::parse("PLAIN", response.auth_response_body("PLAIN")?)?;
40
41    if !sasl_response.done {
42        return Err(Error::invalid_authentication_response("PLAIN"));
43    }
44
45    Ok(())
46}
47
48fn payload_bytes(username: &str, password: &str) -> Vec<u8> {
49    let mut bytes = vec![0];
50    bytes.extend(username.as_bytes());
51
52    bytes.push(0);
53    bytes.extend(password.as_bytes());
54
55    bytes
56}