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