1pub mod config;
2
3use deadpool::managed::{Metrics, RecycleError, RecycleResult};
4use deadpool::{managed, Runtime};
5use ldap3::{Ldap, LdapConnAsync, LdapError};
6
7use crate::config::{Config, LdapConfigError};
8
9deadpool::managed_reexports!(
10 "ldap",
11 Manager,
12 managed::Object<Manager>,
13 LdapError,
14 LdapConfigError
15);
16
17pub struct Manager {
18 pub url: String,
20 pub bind_dn: Option<String>,
22 pub bind_password: Option<String>,
24 pub runtime: Runtime,
26}
27
28impl Manager {
29 #[must_use]
30 pub fn from_config(config: &Config, runtime: Runtime) -> Self {
31 Self {
32 url: config.url.clone(),
33 bind_dn: config.bind_dn.clone(),
34 bind_password: config.bind_password.clone(),
35 runtime,
36 }
37 }
38}
39
40pub type LdapConnection = Ldap;
41
42impl managed::Manager for Manager {
43 type Type = LdapConnection;
44 type Error = LdapError;
45
46 async fn create(&self) -> Result<LdapConnection, LdapError> {
48 let (conn, mut ldap) = LdapConnAsync::new(&self.url).await?;
49 match self.runtime {
50 #[cfg(feature = "rt_tokio_1")]
51 Runtime::Tokio1 => {
52 tokio::spawn(async move { conn.drive().await });
53 }
54 #[cfg(feature = "rt_async-std_1")]
55 Runtime::AsyncStd1 => {
56 async_std::task::spawn(async move { conn.drive().await });
57 }
58 #[allow(unreachable_patterns)]
59 _ => unreachable!(),
60 };
61 if let (Some(bind_dn), Some(bind_password)) = (&self.bind_dn, &self.bind_password) {
62 ldap.simple_bind(bind_dn, bind_password).await?.success()?;
63 }
64 Ok(ldap)
65 }
66
67 async fn recycle(&self, ldap: &mut LdapConnection, _: &Metrics) -> RecycleResult<LdapError> {
69 if let (Some(bind_dn), Some(bind_password)) = (&self.bind_dn, &self.bind_password) {
71 ldap.simple_bind(bind_dn, bind_password).await?.success()?;
72 }
73 if ldap.is_closed() {
75 Err(RecycleError::message("ldap connection is closed"))
76 } else {
77 Ok(())
78 }
79 }
80}
81
82#[tokio::test]
83async fn test_ldap() {
84 let cfg = Config {
85 url: "ldap://127.0.0.1:389".to_string(),
86 bind_dn: Some("cn=admin,dc=demo,dc=com".to_string()),
87 bind_password: Some("123456".to_string()),
88 pool: None,
89 };
90 let pool = cfg.create_pool(Runtime::Tokio1).unwrap();
91 let mut a = pool.get().await.unwrap();
92 a.simple_bind("admin", "123456").await.unwrap();
93}