zookeeper_client/sasl/
digest_md5.rs1use std::borrow::Cow;
2
3use rsasl::callback::{Context, Request, SessionCallback, SessionData};
4use rsasl::prelude::*;
5use rsasl::property::{AuthId, Password, Realm};
6
7use super::{Result, SaslInitiator, SaslInnerOptions, SaslOptions, SaslSession};
8
9#[derive(Clone, Debug)]
13pub struct DigestMd5SaslOptions {
14 realm: Option<Cow<'static, str>>,
15 username: Cow<'static, str>,
16 password: Cow<'static, str>,
17}
18
19impl DigestMd5SaslOptions {
20 fn realm(&self) -> Option<&str> {
21 self.realm.as_ref().map(|s| s.as_ref())
22 }
23
24 pub(crate) fn new(username: impl Into<Cow<'static, str>>, password: impl Into<Cow<'static, str>>) -> Self {
25 Self { realm: None, username: username.into(), password: password.into() }
26 }
27
28 #[cfg(test)]
30 pub fn with_realm(self, realm: impl Into<Cow<'static, str>>) -> Self {
31 Self { realm: Some(realm.into()), ..self }
32 }
33}
34
35impl From<DigestMd5SaslOptions> for SaslOptions {
36 fn from(options: DigestMd5SaslOptions) -> Self {
37 Self(SaslInnerOptions::DigestMd5(options))
38 }
39}
40
41struct DigestSessionCallback {
42 options: DigestMd5SaslOptions,
43}
44
45impl SessionCallback for DigestSessionCallback {
46 fn callback(
47 &self,
48 _session_data: &SessionData,
49 _context: &Context,
50 request: &mut Request<'_>,
51 ) -> Result<(), SessionError> {
52 if request.is::<Realm>() {
53 if let Some(realm) = self.options.realm() {
54 request.satisfy::<Realm>(realm)?;
55 }
56 } else if request.is::<AuthId>() {
57 request.satisfy::<AuthId>(&self.options.username)?;
58 } else if request.is::<Password>() {
59 request.satisfy::<Password>(self.options.password.as_bytes())?;
60 }
61 Ok(())
62 }
63}
64
65impl SaslInitiator for DigestMd5SaslOptions {
66 fn new_session(&self, _hostname: &str) -> Result<SaslSession> {
67 let callback = DigestSessionCallback { options: self.clone() };
68 let config = SASLConfig::builder().with_defaults().with_callback(callback).unwrap();
69 let client = SASLClient::new(config);
70 let session = client.start_suggested(&[Mechname::parse(b"DIGEST-MD5").unwrap()]).unwrap();
71 SaslSession::new(session)
72 }
73}