ldap_rs/
options.rs

1//! LDAP connection options
2
3#[cfg(feature = "tls-native-tls")]
4pub use native_tls;
5
6#[cfg(feature = "tls-rustls")]
7pub use {rustls, rustls_pki_types};
8
9#[cfg(tls)]
10pub use tls::TlsOptions;
11
12#[cfg(tls)]
13pub(crate) use tls::{TlsBackend, TlsKind};
14
15#[cfg(tls)]
16mod tls {
17    #[cfg(feature = "tls-native-tls")]
18    use native_tls::TlsConnector;
19
20    #[cfg(feature = "tls-rustls")]
21    pub use rustls::ClientConfig;
22
23    #[derive(Clone, Copy, Debug, Default, PartialEq)]
24    pub enum TlsKind {
25        #[default]
26        Plain,
27        Tls,
28        StartTls,
29    }
30
31    #[derive(Debug)]
32    pub enum TlsBackend {
33        #[cfg(feature = "tls-native-tls")]
34        Native(TlsConnector),
35        #[cfg(feature = "tls-rustls")]
36        Rustls(ClientConfig),
37    }
38
39    impl Default for TlsBackend {
40        #[cfg(feature = "tls-native-tls")]
41        fn default() -> Self {
42            Self::Native(TlsConnector::new().unwrap())
43        }
44
45        #[cfg(all(feature = "tls-rustls", not(feature = "tls-native-tls")))]
46        fn default() -> Self {
47            pub static CA_CERTS: once_cell::sync::Lazy<rustls::RootCertStore> = once_cell::sync::Lazy::new(|| {
48                let certs = rustls_native_certs::load_native_certs()
49                    .certs
50                    .into_iter()
51                    .map(|c| c)
52                    .collect::<Vec<_>>();
53                let mut store = rustls::RootCertStore::empty();
54                store.add_parsable_certificates(certs);
55                store
56            });
57
58            Self::Rustls(
59                ClientConfig::builder()
60                    .with_root_certificates(CA_CERTS.clone())
61                    .with_no_client_auth(),
62            )
63        }
64    }
65
66    /// TLS options
67    #[derive(Default, Debug)]
68    pub struct TlsOptions {
69        pub(crate) backend: Option<TlsBackend>,
70        pub(crate) kind: TlsKind,
71        pub(crate) domain_name: Option<String>,
72    }
73
74    impl TlsOptions {
75        fn new(kind: TlsKind) -> Self {
76            Self {
77                backend: None,
78                kind,
79                domain_name: None,
80            }
81        }
82
83        /// Connect using TLS transport
84        pub fn tls() -> Self {
85            Self::new(TlsKind::Tls)
86        }
87
88        /// Connect using STARTTLS negotiation
89        pub fn start_tls() -> Self {
90            Self::new(TlsKind::StartTls)
91        }
92
93        #[cfg(feature = "tls-rustls")]
94        /// Configure rustls backend with a given ClientConfig
95        pub fn client_config(mut self, client_config: ClientConfig) -> Self {
96            self.backend = Some(TlsBackend::Rustls(client_config));
97            self
98        }
99
100        #[cfg(feature = "tls-native-tls")]
101        /// Configure native-tls backend with a given TlsConnector
102        pub fn tls_connector(mut self, tls_connector: TlsConnector) -> Self {
103            self.backend = Some(TlsBackend::Native(tls_connector));
104            self
105        }
106
107        /// Specify custom domain name to use for SNI match. The default is the connection host name
108        pub fn domain_name<S: AsRef<str>>(mut self, domain_name: S) -> Self {
109            self.domain_name = Some(domain_name.as_ref().to_owned());
110            self
111        }
112    }
113}