LDAP support #921

Open
RatCornu wants to merge 8 commits from RatCornu/continuwuity:ldap into main
First-time contributor

Hi!

I implemented few monthes ago LDAP login for tuwunel and I discovered after this. I would like to add the LDAP feature here to: I tried to stick as much as possible with continuwuity code style starting from the tuwunel implementation, but I'm not sure if everything is alright: I'll change everything needed to comply to your standards.

I tested basic login on a real LDAP server with cURL and it works. As the implementation is litteraly the same as in tuwunel, I would expect other features to work as inteded.

Closes #691.

Hi! I implemented few monthes ago LDAP login for tuwunel and I discovered after this. I would like to add the LDAP feature here to: I tried to stick as much as possible with continuwuity code style starting from the tuwunel implementation, but I'm not sure if everything is alright: I'll change everything needed to comply to your standards. I tested basic login on a real LDAP server with cURL and it works. As the implementation is litteraly the same as in tuwunel, I would expect other features to work as inteded. Closes #691.
RatCornu added 1 commit 2025-08-09 23:07:59 +00:00
feat: ldap login
Some checks failed
Checks / Prefligit / prefligit (pull_request) Successful in 23s
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
1b9682e464
nex added the
Enhancement
Matrix/Administration
Matrix/Auth
labels 2025-08-09 23:45:24 +00:00
Owner

Hey, great to see you! Thanks for the PR - looks like the preflight checks ran fine, so your style was perfectly fine. I'll just give this a quick test later (hopefully tomorrow), then should be good to get it merged :)

Hey, great to see you! Thanks for the PR - looks like the preflight checks ran fine, so your style was perfectly fine. I'll just give this a quick test later (hopefully tomorrow), then should be good to get it merged :)
Author
First-time contributor

Nice! Moreover, do not hesitate to ping for LDAP issues if needed, I'll be using continuwuity + LDAP in near future and I'm willing to help wherever I can ^^

Nice! Moreover, do not hesitate to ping for LDAP issues if needed, I'll be using continuwuity + LDAP in near future and I'm willing to help wherever I can ^^
Jade approved these changes 2025-08-10 00:43:30 +00:00
Jade left a comment
Owner

From my late night phone review, it all looks pretty good to me. Just some minor tweaks. (I've also rambled a bit in some of the comments)

From my late night phone review, it all looks pretty good to me. Just some minor tweaks. (I've also rambled a bit in some of the comments)
@ -1777,0 +1838,4 @@
#
# example: "mail"
#
#mail_attribute = "mail"
Owner

I feel like this should be optional? We don't need email, and not every system will have it

I feel like this should be optional? We don't need email, and not every system will have it
Owner

Oh yeah we don't even use it in this diff afaict, probably worth removing entirely or hiding

Oh yeah we don't even use it in this diff afaict, probably worth removing entirely or hiding
Author
First-time contributor

This is a discussion in the tuwunel implementation: https://github.com/matrix-construct/tuwunel/issues/114.
I can remove it for now and add it back later if a way to store custom profile fields is added into continuwuity

This is a discussion in the tuwunel implementation: https://github.com/matrix-construct/tuwunel/issues/114. I can remove it for now and add it back later if a way to store custom profile fields is added into continuwuity
Author
First-time contributor

I removed it for now, it's always possible to add it back later

I removed it for now, it's always possible to add it back later
RatCornu marked this conversation as resolved
@ -1777,0 +1840,4 @@
#
#mail_attribute = "mail"
# Attribute containing the distinguished name of the user.
Owner

Distinguished name being display name? Might be better to use Matrix terminology here, if that's what you mean.

Distinguished name being display name? Might be better to use Matrix terminology here, if that's what you mean.
Author
First-time contributor

Indeed, distinguished name is the common terminology when dealing with LDAP, I change this to display name

Indeed, distinguished name is the common terminology when dealing with LDAP, I change this to display name
RatCornu marked this conversation as resolved
@ -1777,0 +1854,4 @@
#
#admin_base_dn = false
# The LDAP search filter to find administrative users for conduwuit.
Owner

Continuwuity

Continuwuity
Jade marked this conversation as resolved
@ -52,0 +75,4 @@
| Ok(hash) => (hash, user_id),
| Err(_) => services
.users
.password_hash(lowercased_user_id)
Owner

In what circumstances is this case sensitive, and when is it not? Might need some explainer comments here.

In what circumstances is this case sensitive, and when is it not? Might need some explainer comments here.
Owner

I see, this is copying logic from the original function. Ah well.

I see, this is copying logic from the original function. Ah well.
Jade marked this conversation as resolved
@ -52,0 +136,4 @@
// password is reserved for deactivated accounts. The conduwuit 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 {
services
Owner

Ugh this feels hacky and like it will bite in the future, I know it's a bit out of scope but definitely a thing to improve if we get the opportunity in future. In a new database version number we could do a migration for it.

Ugh this feels hacky and like it will bite in the future, I know it's a bit out of scope but definitely a thing to improve if we get the opportunity in future. In a new database version number we could do a migration for it.
Owner

Oh also in the event of a downgrade the logic behind this being unreachable doesn't work, because the account origin won't be checked anymore. It's still probably fine because it's all or nothing and people aren't likely to downgrade off an LDAP supporting version when their server relies on it, but this wouldn't work for OIDC for example, or for partial rather than total server management.

I would say that this requires an upgrade in database version number, but tuwunel didn't do it when they added this afaik, so... I just hope no one uses LDAP, downgrades to a version without it, and expects things to work.

Oh also in the event of a downgrade the logic behind this being unreachable doesn't work, because the account origin won't be checked anymore. It's still probably fine because it's all or nothing and people aren't likely to downgrade off an LDAP supporting version when their server relies on it, but this wouldn't work for OIDC for example, or for partial rather than total server management. I would say that this requires an upgrade in database version number, but tuwunel didn't do it when they added this afaik, so... I just hope no one uses LDAP, downgrades to a version without it, and expects things to work.
Jade marked this conversation as resolved
@ -52,0 +185,4 @@
}
if cfg!(feature = "ldap") && services.config.ldap.enable {
ldap_login(services, &user_id, &lowercased_user_id, password).await
Owner

That it's 'all or nothing' is probably something to note in any documentation.

That it's 'all or nothing' is probably something to note in any documentation.
Author
First-time contributor

It's also possible to try normal password login if LDAP login fails if you prefer, both implementations are possible

It's also possible to try normal password login if LDAP login fails if you prefer, both implementations are possible
@ -2044,0 +2120,4 @@
#[serde(default = "default_ldap_name_attribute")]
pub name_attribute: String,
/// Root of the searches for admin users.
Owner

All these ones without default at the last line should probably have it so the example config doesn't just say = false for each item.

All these ones without default at the last line should probably have it so the example config doesn't just say `= false` for each item.
Owner

OK so what I meant here @RatCornu is that for the example config, you can write default: something and that will show up in the config as option = something. Like in one of them you've got default: "(objectClass=*)" and in teh config it shows up as filter = "(objectClass=*)". In any case, I'm not sure why these were showing up as false when in other places that do the same they show as blank.

OK so what I meant here @RatCornu is that for the example config, you can write `default: something` and that will show up in the config as `option = something`. Like in one of them you've got `default: "(objectClass=*)"` and in teh config it shows up as `filter = "(objectClass=*)"`. In any case, I'm not sure why these were showing up as false when in other places that do the same they show as blank.
Owner

Oh, I've just noticed that formatting ci hasn't run for whatever reason. I'm going to need to run cargo format plus cargo clippy manually lol

Oh, I've just noticed that formatting ci hasn't run for whatever reason. I'm going to need to run cargo format plus cargo clippy manually lol
Owner

Isn't that part of the preflight check?

Isn't that part of the preflight check?
Owner

Nope, there are some formatting checks there, but in CI rustfmt has its own step

Nope, there are some formatting checks there, but in CI rustfmt has its own step
RatCornu added 1 commit 2025-08-10 10:50:30 +00:00
chore: remove unused LDAP mail attribute
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Failing after 0s
Checks / Prefligit / prefligit (pull_request) Successful in 24s
0d4c5adc5e
Jade force-pushed ldap from 0d4c5adc5e to 785789afb5 2025-08-10 19:37:42 +00:00 Compare
Jade added 2 commits 2025-08-10 19:54:16 +00:00
fix: Make builds without LDAP work correctly
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Failing after 0s
Checks / Prefligit / prefligit (pull_request) Successful in 14s
d39579ea47
Jade force-pushed ldap from d39579ea47 to 1a21f4a852 2025-08-10 20:09:56 +00:00 Compare
Owner

OK I've fixed some issues preventing it from building, etc. It should be good for testing now - it's now included in the default features.

OK I've fixed some issues preventing it from building, etc. It should be good for testing now - it's now included in the default features.
tcpipuk added 1 commit 2025-08-10 21:10:50 +00:00
Merge branch 'main' into ldap
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Failing after 0s
Checks / Prefligit / prefligit (pull_request) Successful in 24s
4df565dd77
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Failing after 0s
Checks / Prefligit / prefligit (pull_request) Successful in 24s
Required
Details
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u ldap:RatCornu-ldap
git checkout RatCornu-ldap
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
4 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: continuwuation/continuwuity#921
No description provided.