Add direct bind support

This commit is contained in:
RatCornu
2025-04-25 21:12:03 +02:00
committed by Jason Volk
parent c11c5e61c9
commit 6160f90b8c
3 changed files with 38 additions and 34 deletions

View File

@@ -91,16 +91,23 @@ async fn ldap_login(
lowercased_user_id: &UserId,
password: &str,
) -> Result<OwnedUserId> {
debug!("Searching user in LDAP");
let user_dn = match services.config.ldap.bind_dn.as_ref() {
| Some(bind_dn) if bind_dn.contains("{username}") =>
bind_dn.replace("{username}", lowercased_user_id.localpart()),
| _ => {
debug!("Searching user in LDAP");
let dns = services.users.search_ldap(user_id).await?;
let dns = services.users.search_ldap(user_id).await?;
if dns.len() >= 2 {
return Err!(Ldap("LDAP search returned two or more results"));
}
if dns.len() >= 2 {
return Err!(Ldap("LDAP search returned two or more results"));
}
let Some(user_dn) = dns.first() else {
return password_login(services, user_id, lowercased_user_id, password).await;
};
let Some(user_dn) = dns.first() else {
return password_login(services, user_id, lowercased_user_id, password).await;
user_dn.clone()
},
};
// LDAP users are automatically created on first login attempt. This is a very
@@ -111,16 +118,16 @@ async fn ldap_login(
// password is reserved for deactivated accounts. The tuwunel password field
// will never be read to login a LDAP user so it's not an issue.
if !services.users.exists(lowercased_user_id).await {
debug!("Creating user {lowercased_user_id} from LDAP");
services
.users
.create(lowercased_user_id, Some("*"), Some("ldap"))
.await?;
}
debug!("{user_dn:?} {password:?}");
services
.users
.auth_ldap(user_dn, password)
.auth_ldap(&user_dn, password)
.await
.map(|()| lowercased_user_id.to_owned())
}

View File

@@ -1805,14 +1805,7 @@ pub struct Config {
#[serde(default)]
pub blurhashing: BlurhashConfig,
#[cfg(not(doctest))]
/// Examples:
///
/// - No LDAP login (default):
///
/// ldap = "none"
///
/// default: "none"
// external structure; separate section
pub ldap: LdapConfig,
#[serde(flatten)]
@@ -1911,12 +1904,6 @@ pub struct LdapConfig {
#[serde(deserialize_with = "crate::utils::deserialize_from_str")]
pub uri: Url,
/// Whether to use StartTLS to bind to the LDAP server.
///
/// example: true
#[serde(default)]
pub start_tls: bool,
/// Root of the searches.
///
/// example: "ou=users,dc=example,dc=org"
@@ -1925,7 +1912,13 @@ pub struct LdapConfig {
/// Bind DN if anonymous search is not enabled.
///
/// example: "cn=ldap-reader,dc=example,dc=org"
/// You can use the variable `{username}` that will be replaced by the
/// entered username. In such case, the password used to bind will be the
/// one provided for the login and not the one given by
/// `bind_password_file`.
///
/// example: "cn=ldap-reader,dc=example,dc=org" or
/// "cn={username},ou=users,dc=example,dc=org"
#[serde(default)]
pub bind_dn: Option<String>,
@@ -1955,12 +1948,16 @@ pub struct LdapConfig {
/// Attribute containing the mail of the user.
///
/// example: "mail"
///
/// default: "mail"
#[serde(default = "default_ldap_mail_attribute")]
pub mail_attribute: String,
/// Attribute containing the distinguished name of the user.
///
/// example: "givenName" or "sn"
///
/// default: "givenName"
#[serde(default = "default_ldap_name_attribute")]
pub name_attribute: String,
}
@@ -2359,4 +2356,4 @@ fn default_ldap_uid_attribute() -> String { String::from("uid") }
fn default_ldap_mail_attribute() -> String { String::from("mail") }
fn default_ldap_name_attribute() -> String { String::from("name") }
fn default_ldap_name_attribute() -> String { String::from("givenName") }

View File

@@ -1641,12 +1641,6 @@
#
#uri =
# Whether to use StartTLS to bind to the LDAP server.
#
# example: true
#
#start_tls = false
# Root of the searches.
#
# example: "ou=users,dc=example,dc=org"
@@ -1655,7 +1649,13 @@
# Bind DN if anonymous search is not enabled.
#
# example: "cn=ldap-reader,dc=example,dc=org"
# You can use the variable `{username}` that will be replaced by the
# entered username. In such case, the password used to bind will be the
# one provided for the login and not the one given by
# `bind_password_file`.
#
# example: "cn=ldap-reader,dc=example,dc=org" or
# "cn={username},ou=users,dc=example,dc=org"
#
#bind_dn = false
@@ -1682,10 +1682,10 @@
#
# example: "mail"
#
#mail_attribute =
#mail_attribute = "mail"
# Attribute containing the distinguished name of the user.
#
# example: "givenName" or "sn"
#
#name_attribute =
#name_attribute = "givenName"