zookeeper_client/sasl/
gssapi.rs1use std::borrow::Cow;
2
3use rsasl::callback::{Context, Request, SessionCallback, SessionData};
4use rsasl::mechanisms::gssapi::properties::GssService;
5use rsasl::prelude::*;
6use rsasl::property::Hostname;
7
8use super::{Result, SaslInitiator, SaslInnerOptions, SaslOptions, SaslSession};
9
10impl From<GssapiSaslOptions> for SaslOptions {
11 fn from(options: GssapiSaslOptions) -> Self {
12 Self(SaslInnerOptions::Gssapi(options))
13 }
14}
15
16#[derive(Clone, Debug)]
20pub struct GssapiSaslOptions {
21 username: Cow<'static, str>,
22 hostname: Option<Cow<'static, str>>,
23}
24
25impl GssapiSaslOptions {
26 pub(crate) fn new() -> Self {
27 Self { username: Cow::from("zookeeper"), hostname: None }
28 }
29
30 pub fn with_username(self, username: impl Into<Cow<'static, str>>) -> Self {
37 Self { username: username.into(), ..self }
38 }
39
40 pub fn with_hostname(self, hostname: impl Into<Cow<'static, str>>) -> Self {
44 Self { hostname: Some(hostname.into()), ..self }
45 }
46
47 fn hostname_or(&self, hostname: &str) -> Cow<'static, str> {
48 match self.hostname.as_ref() {
49 None => Cow::Owned(hostname.to_string()),
50 Some(hostname) => hostname.clone(),
51 }
52 }
53}
54
55impl SaslInitiator for GssapiSaslOptions {
56 fn new_session(&self, hostname: &str) -> Result<SaslSession> {
57 struct GssapiOptionsProvider {
58 username: Cow<'static, str>,
59 hostname: Cow<'static, str>,
60 }
61 impl SessionCallback for GssapiOptionsProvider {
62 fn callback(
63 &self,
64 _session_data: &SessionData,
65 _context: &Context,
66 request: &mut Request<'_>,
67 ) -> Result<(), SessionError> {
68 if request.is::<Hostname>() {
69 request.satisfy::<Hostname>(&self.hostname)?;
70 } else if request.is::<GssService>() {
71 request.satisfy::<GssService>(&self.username)?;
72 }
73 Ok(())
74 }
75 }
76 let provider = GssapiOptionsProvider { username: self.username.clone(), hostname: self.hostname_or(hostname) };
77 let config = SASLConfig::builder().with_defaults().with_callback(provider).unwrap();
78 let client = SASLClient::new(config);
79 let session = client.start_suggested(&[Mechname::parse(b"GSSAPI").unwrap()]).unwrap();
80 SaslSession::new(session)
81 }
82}