rs_sasl/
external.rs

1use crate::sasl;
2
3use anyhow::{anyhow, Result};
4
5/// The EXTERNAL mechanism name.
6pub const EXTERNAL: &str = "EXTERNAL";
7
8/// An implementation of the EXTERNAL authentication mechanism, as described in
9/// RFC 4422. Authorization identity may be left blank to indicate that the
10/// client is requesting to act as the identity associated with the
11//. authentication credentials.
12pub struct ExternalClient {
13    identity: String,
14}
15
16impl ExternalClient {
17    pub fn new(identity: String) -> Self {
18        Self {
19            identity,
20        }
21    }
22}
23
24impl sasl::Client for ExternalClient {
25    fn start(&mut self) -> Result<(String, Vec<u8>)> {
26        Ok((
27            EXTERNAL.to_string(),
28            self.identity.clone().into_bytes(),
29        ))
30    }
31
32    fn next(&mut self, _challenge: &[u8]) -> Result<Vec<u8>> {
33        Err(anyhow!(sasl::ERR_UNEXPECTED_SERVER_CHALLENGE))
34    }
35}
36
37/// ExternalAuthenticator authenticates users with the EXTERNAL mechanism. If
38/// the identity is left blank, it indicates that it is the same as the one used
39/// in the external credentials. If identity is not empty and the server doesn't
40/// support it, an error must be returned.
41pub type ExternalAuthenticator = Box<dyn Fn(&str) -> Result<()> + Send>;
42
43/// NewExternalServer creates a server implementation of the EXTERNAL
44/// authentication mechanism, as described in RFC 4422.
45pub struct ExternalServer {
46    done: bool,
47    authenticator: ExternalAuthenticator,
48}
49
50impl ExternalServer {
51    pub fn new<F>(authenticator: ExternalAuthenticator) -> Self {
52        Self {
53            done: false,
54            authenticator,
55        }
56    }
57}
58
59impl sasl::Server for ExternalServer {
60    fn next(&mut self, response: Option<&[u8]>) -> Result<(Vec<u8>, bool)> {
61        if self.done {
62            return Err(anyhow!(sasl::ERR_UNEXPECTED_CLIENT_RESPONSE));
63        }
64
65        if response.is_none() {
66            return Ok((Vec::new(), false));
67        }
68        let response = response.unwrap();
69
70        self.done = true;
71
72        if response.contains(&b'\x00') {
73            return Err(anyhow!("identity contains a NUL character"));
74        }
75
76        (self.authenticator)(std::str::from_utf8(response)?)?;
77        Ok((Vec::new(), true))
78    }
79}