tuwunel_api/client/session/
ldap.rs1use futures::FutureExt;
2use ruma::{OwnedUserId, UserId};
3use tuwunel_core::{Err, Result, debug};
4use tuwunel_service::{Services, users::Register};
5
6use super::password_login;
7
8#[tracing::instrument(skip_all, fields(%user_id), name = "ldap")]
13pub(super) async fn ldap_login(
14 services: &Services,
15 user_id: &UserId,
16 lowercased_user_id: &UserId,
17 password: &str,
18) -> Result<OwnedUserId> {
19 let bind_dn = services
20 .users
21 .ldap_bind_dn(lowercased_user_id.localpart());
22
23 let (user_dn, is_ldap_admin) = match bind_dn {
24 | Some(user_dn) => (user_dn, false),
25 | None => {
26 debug!("Searching user in LDAP");
27
28 let dns = services.users.search_ldap(user_id).await?;
29 if dns.len() >= 2 {
30 return Err!(Ldap("LDAP search returned two or more results"));
31 }
32
33 let Some((user_dn, is_admin)) = dns.first() else {
34 return password_login(services, user_id, lowercased_user_id, password).await;
35 };
36
37 (user_dn.clone(), *is_admin)
38 },
39 };
40
41 let user_id = services
42 .users
43 .auth_ldap(&user_dn, password)
44 .await
45 .map(|()| lowercased_user_id.to_owned())?;
46
47 services
48 .users
49 .check_ldap_login(lowercased_user_id)
50 .await?;
51
52 if !services.users.exists(lowercased_user_id).await {
60 services
61 .users
62 .full_register(Register {
63 user_id: Some(lowercased_user_id),
64 password: Some("*"),
65 origin: Some("ldap"),
66 ..Default::default()
67 })
68 .await?;
69 }
70
71 if !services.config.ldap.admin_filter.is_empty() {
73 let is_tuwunel_admin = services
74 .admin
75 .user_is_admin(lowercased_user_id)
76 .await;
77
78 if is_ldap_admin && !is_tuwunel_admin {
79 services
80 .admin
81 .make_user_admin(lowercased_user_id)
82 .boxed()
83 .await?;
84 } else if !is_ldap_admin && is_tuwunel_admin {
85 services
86 .admin
87 .revoke_admin(lowercased_user_id)
88 .await?;
89 }
90 }
91
92 Ok(user_id)
93}