Repository: lldap/lldap (language: rust)

Issue:
[BUG] Uppercase names not searchable
**Describe the bug**
Groups (or even names possibly?) are case sensitive when LDAP isn't.

**To Reproduce**
Steps to reproduce the behavior:
1. Create a group with uppercase letters
2. Try to search for users with membership of that group
3. Fails?

**Expected behavior**
I expect comparisons to follow LDAP naming and check in lower case.

**Logs**

<details><summary>Working group logs</summary>
<p>

Group Name: `jellyfin_users`

```log
2024-02-24T23:37:21.278206211+00:00  INFO     LDAP session [ 59.7ms | 0.18% / 100.00% ]
2024-02-24T23:37:21.284303633+00:00  INFO     ┝━ LDAP request [ 59.3ms | 0.15% / 99.29% ]
2024-02-24T23:37:21.284310505+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 218, op: BindRequest(LdapBindRequest { dn: "uid=jellyfin,ou=people,dc=adyanth,dc=lan", cred: LdapBindCred::Simple }), ctrl: [] }
2024-02-24T23:37:21.284311933+00:00  DEBUG    │  ┝━ do_bind [ 59.2ms | 0.03% / 99.13% ] dn: uid=jellyfin,ou=people,dc=adyanth,dc=lan
2024-02-24T23:37:21.284316420+00:00  DEBUG    │  │  ┝━ bind [ 59.1ms | 0.01% / 98.90% ]
2024-02-24T23:37:21.284318797+00:00  DEBUG    │  │  │  ┝━ get_password_file_for_user [ 51.6µs | 0.09% ] user_id: UserId("jellyfin")
2024-02-24T23:37:21.284570519+00:00  DEBUG    │  │  │  ┕━ passwords_match [ 59.0ms | 98.80% ] username: jellyfin
2024-02-24T23:37:21.343611715+00:00  DEBUG    │  │  ┝━ get_user_groups [ 122µs | 0.20% ] user_id: "jellyfin"
2024-02-24T23:37:21.344096525+00:00  DEBUG    │  │  │  ┕━ 🐛 [debug]:  | return: {GroupDetails { group_id: GroupId(2), display_name: "lldap_password_manager", creation_date: 2024-02-24T16:31:16.507394050, uuid: Uuid("44b2524a-727e-3dc2-b333-04b8998c2eee"), attributes: [] }}
2024-02-24T23:37:21.344099523+00:00  DEBUG    │  │  ┕━ 🐛 [debug]: Success!
2024-02-24T23:37:21.344103415+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: BindResponse(LdapBindResponse { res: LdapResult { code: Success, matcheddn: "", message: "", referral: [] }, saslcreds: None })
2024-02-24T23:37:21.345724322+00:00  INFO     ┝━ LDAP request [ 315µs | 0.05% / 0.53% ]
2024-02-24T23:37:21.345730781+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 219, op: SearchRequest(LdapSearchRequest { base: "ou=people,dc=adyanth,dc=lan", scope: Subtree, aliases: Never, sizelimit: 1000, timelimit: 0, typesonly: false, filter: Equality("memberof", "cn=jellyfin_users,ou=groups,dc=adyanth,dc=lan"), attrs: ["uid", "uid"] }), ctrl: [] }
2024-02-24T23:37:21.345731668+00:00  DEBUG    │  ┝━ do_search [ 284µs | 0.14% / 0.47% ]
2024-02-24T23:37:21.345760+00:00     DEBUG    │  │  ┝━ 🐛 [debug]:  | request.base: "ou=people,dc=adyanth,dc=lan" | scope: Users
2024-02-24T23:37:21.345760726+00:00  DEBUG    │  │  ┝━ get_user_list [ 196µs | 0.02% / 0.33% ]
2024-02-24T23:37:21.345764222+00:00  DEBUG    │  │  │  ┝━ 🐛 [debug]:  | filters: MemberOf("jellyfin_users")
2024-02-24T23:37:21.345766960+00:00  DEBUG    │  │  │  ┕━ list_users [ 185µs | 0.31% ] filters: Some(MemberOf("jellyfin_users")) | _get_groups: false
2024-02-24T23:37:21.346135908+00:00  DEBUG    │  │  │     ┕━ 🐛 [debug]:  | return: [UserAndGroups { user: User { user_id: UserId("adyanth"), email: "me@adyanth.dev", display_name: Some("Adyanth"), creation_date: 2024-02-24T16:31:59.542882557, uuid: Uuid("4105d9ad-d726-306c-a6a8-5f8d65ccc6a2"), attributes: [AttributeValue { name: "first_name", value: Serialized("Adyanth") }, AttributeValue { name: "last_name", value: Serialized("Hosavalike") }] }, groups: Some([GroupDetails { group_id: GroupId(6), display_name: "JellyfinUsers", creation_date: 2024-02-24T23:16:56.041027157, uuid: Uuid("cbdc8048-829e-3562-b802-0eb40bf90e8e"), attributes: [] }, GroupDetails { group_id: GroupId(10), display_name: "jellyfin users", creation_date: 2024-02-24T23:36:28.306621145, uuid: Uuid("092abd59-ee10-3ea6-a322-cf9b6abf3dd8"), attributes: [] }, GroupDetails { group_id: GroupId(8), display_name: "jellyfin_admin", creation_date: 2024-02-24T23:27:48.302083528, uuid: Uuid("9c89c86e-24bd-32a4-bed2-65dcb34a94c0"), attributes: [] }, GroupDetails { group_id: GroupId(9), display_name: "jellyfin_users", creation_date: 2024-02-24T23:28:37.644324744, uuid: Uuid("1e4a989c-2841-3102-83ca-13723e255ffa"), attributes: [] }, GroupDetails { group_id: GroupId(1), display_name: "lldap_admin", creation_date: 2024-02-24T16:31:16.494817283, uuid: Uuid("fb70d8ee-29b4-3035-97bd-fb29b213116b"), attributes: [] }]) }]
2024-02-24T23:37:21.346236156+00:00  DEBUG    │  │  ┕━ expand_attribute_wildcards [ 1.86µs | 0.00% ] ldap_attributes: ["uid", "uid"]
2024-02-24T23:37:21.346237800+00:00  DEBUG    │  │     ┕━ 🐛 [debug]:  | resolved_attributes: ["uid"]
2024-02-24T23:37:21.346244088+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | response: SearchResultEntry(LdapSearchResultEntry { dn: "uid=adyanth,ou=people,dc=adyanth,dc=lan", attributes: [LdapPartialAttribute { atype: "uid", vals: ["adyanth"] }] })
2024-02-24T23:37:21.346257174+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: SearchResultDone(LdapResult { code: Success, matcheddn: "", message: "", referral: [] })
2024-02-24T23:37:21.389094133+00:00  INFO     ┕━ LDAP request [ 7.38µs | 0.01% ]
2024-02-24T23:37:21.389099726+00:00  DEBUG       ┕━ 🐛 [debug]:  | msg: LdapMsg { msgid: 220, op: UnbindRequest, ctrl: [] }
```

</p>
</details>

<details><summary>Non working group logs</summary>
<p>

Group Name: `JellyfinUsers`

```log
2024-02-24T23:39:00.356848110+00:00  INFO     LDAP session [ 60.4ms | 0.18% / 100.00% ]
2024-02-24T23:39:00.363142288+00:00  INFO     ┝━ LDAP request [ 60.1ms | 0.07% / 99.51% ]
2024-02-24T23:39:00.363149108+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 224, op: BindRequest(LdapBindRequest { dn: "uid=jellyfin,ou=people,dc=adyanth,dc=lan", cred: LdapBindCred::Simple }), ctrl: [] }
2024-02-24T23:39:00.363150585+00:00  DEBUG    │  ┝━ do_bind [ 60.0ms | 0.03% / 99.44% ] dn: uid=jellyfin,ou=people,dc=adyanth,dc=lan
2024-02-24T23:39:00.363155943+00:00  DEBUG    │  │  ┝━ bind [ 59.9ms | 0.01% / 99.24% ]
2024-02-24T23:39:00.363158516+00:00  DEBUG    │  │  │  ┝━ get_password_file_for_user [ 65.6µs | 0.11% ] user_id: UserId("jellyfin")
2024-02-24T23:39:00.363446850+00:00  DEBUG    │  │  │  ┕━ passwords_match [ 59.8ms | 99.12% ] username: jellyfin
2024-02-24T23:39:00.423290796+00:00  DEBUG    │  │  ┝━ get_user_groups [ 100µs | 0.17% ] user_id: "jellyfin"
2024-02-24T23:39:00.423772156+00:00  DEBUG    │  │  │  ┕━ 🐛 [debug]:  | return: {GroupDetails { group_id: GroupId(2), display_name: "lldap_password_manager", creation_date: 2024-02-24T16:31:16.507394050, uuid: Uuid("44b2524a-727e-3dc2-b333-04b8998c2eee"), attributes: [] }}
2024-02-24T23:39:00.423775069+00:00  DEBUG    │  │  ┕━ 🐛 [debug]: Success!
2024-02-24T23:39:00.423779307+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: BindResponse(LdapBindResponse { res: LdapResult { code: Success, matcheddn: "", message: "", referral: [] }, saslcreds: None })
2024-02-24T23:39:00.425504973+00:00  INFO     ┝━ LDAP request [ 187µs | 0.04% / 0.31% ]
2024-02-24T23:39:00.425511269+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 225, op: SearchRequest(LdapSearchRequest { base: "ou=people,dc=adyanth,dc=lan", scope: Subtree, aliases: Never, sizelimit: 1000, timelimit: 0, typesonly: false, filter: Equality("memberof", "cn=JellyfinUsers,ou=groups,dc=adyanth,dc=lan"), attrs: ["uid", "uid"] }), ctrl: [] }
2024-02-24T23:39:00.425512448+00:00  DEBUG    │  ┝━ do_search [ 164µs | 0.10% / 0.27% ]
2024-02-24T23:39:00.425530162+00:00  DEBUG    │  │  ┝━ 🐛 [debug]:  | request.base: "ou=people,dc=adyanth,dc=lan" | scope: Users
2024-02-24T23:39:00.425531126+00:00  DEBUG    │  │  ┕━ get_user_list [ 105µs | 0.02% / 0.17% ]
2024-02-24T23:39:00.425534659+00:00  DEBUG    │  │     ┝━ 🐛 [debug]:  | filters: MemberOf("jellyfinusers")
2024-02-24T23:39:00.425538247+00:00  DEBUG    │  │     ┕━ list_users [ 95.5µs | 0.16% ] filters: Some(MemberOf("jellyfinusers")) | _get_groups: false
2024-02-24T23:39:00.425736941+00:00  DEBUG    │  │        ┕━ 🐛 [debug]:  | return: []
2024-02-24T23:39:00.425831655+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: SearchResultDone(LdapResult { code: Success, matcheddn: "", message: "", referral: [] })
2024-02-24T23:39:00.426686948+00:00  INFO     ┕━ LDAP request [ 2.29µs | 0.00% ]
2024-02-24T23:39:00.426688853+00:00  DEBUG       ┕━ 🐛 [debug]:  | msg: LdapMsg { msgid: 226, op: UnbindRequest, ctrl: [] }
```

</p>
</details>

**Additional context**
Using Jellyfin LDAP plugin to test. 

Possible source of the issue here?
https://github.com/lldap/lldap/blob/959bb907d855071f33e771472b9f6643714e0a15/server/src/domain/sql_user_backend_handler.rs#L101



Discussion / hints:
Also LLDAP allows me to create duplicate groups? I can create two groups with the exact same name. That looks like it shouldn't be possible, because if it has different members, searches will be a union of the two.
All of that should be fixed in latest, have you tried?
I installed from the [LLDAP OBS package](https://software.opensuse.org//download.html?project=home%3AMasgalor%3ALLDAP&package=lldap), which seems to match the latest release. Do you mean compiling the main branch myself?

```shell
root@kratos-id:~# lldap --version
lldap 0.5.0
```
That's the latest stable release, but not the latest beta, e.g. the docker image tagged "latest".

We're working towards a stable release, but the web UI is not quite there yet.
 (Note that there's nothing _unstable_ about latest, there's just only partial support of custom attributes in the web UI)
I see. I am not using docker for lldap, I will compile main tomorrow and report back on how it goes. Thanks!
Does not work on 0.5.1-alpha either (Compiled commit 959bb90)

I made a group `JellyfinUsers`, added a test user. When filtering for JellyfinUsers from Jellyfin, I get 0 users. I make another group `jellyfinusers`, and that is detected without changing the filter.

Also, I am able to add duplicate group names.

My user and admin filter is set to `(memberof=cn=JellyfinUsers,ou=groups,dc=example,dc=com)`.

<details><summary>Logs with only JellyfinUsers (containing user test in LLDAP</summary>
<p>

```log
2024-02-25T21:07:59.758314135+00:00  INFO     LDAP session [ 63.0ms | 0.16% / 100.00% ]
2024-02-25T21:07:59.766913454+00:00  INFO     ┝━ LDAP request [ 62.6ms | 0.11% / 99.29% ]
2024-02-25T21:07:59.766942394+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 171, op: BindRequest(LdapBindRequest { dn: "uid=admin,ou=people,dc=example,dc=com", cred: LdapBindCred::Simple }), ctrl: [] }
2024-02-25T21:07:59.766944644+00:00  DEBUG    │  ┝━ do_bind [ 62.5ms | 0.06% / 99.17% ] dn: uid=admin,ou=people,dc=example,dc=com
2024-02-25T21:07:59.766962910+00:00  DEBUG    │  │  ┝━ bind [ 62.3ms | 0.01% / 98.90% ]
2024-02-25T21:07:59.766966305+00:00  DEBUG    │  │  │  ┝━ get_password_file_for_user [ 84.6µs | 0.13% ] user_id: UserId(CaseInsensitiveString("admin"))
2024-02-25T21:07:59.767232511+00:00  DEBUG    │  │  │  ┕━ passwords_match [ 62.2ms | 98.76% ] username: admin
2024-02-25T21:07:59.829457681+00:00  DEBUG    │  │  ┝━ get_user_groups [ 134µs | 0.21% ] user_id: "admin"
2024-02-25T21:07:59.830037845+00:00  DEBUG    │  │  │  ┕━ 🐛 [debug]:  | return: {GroupDetails { group_id: GroupId(1), display_name: GroupName("lldap_admin"), creation_date: 2024-02-25T20:47:06.781239809, uuid: Uuid("b7063b5b-9796-31e0-9107-35f8c9e59cac"), attributes: [] }}
2024-02-25T21:07:59.830041148+00:00  DEBUG    │  │  ┕━ 🐛 [debug]: Success!
2024-02-25T21:07:59.830045816+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: BindResponse(LdapBindResponse { res: LdapResult { code: Success, matcheddn: "", message: "", referral: [] }, saslcreds: None })
2024-02-25T21:07:59.831602463+00:00  INFO     ┝━ LDAP request [ 330µs | 0.09% / 0.52% ]
2024-02-25T21:07:59.831609615+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 172, op: SearchRequest(LdapSearchRequest { base: "ou=people,dc=example,dc=com", scope: Subtree, aliases: Never, sizelimit: 1000, timelimit: 0, typesonly: false, filter: Equality("memberof", "cn=JellyfinUsers,ou=groups,dc=example,dc=com"), attrs: ["uid", "uid"] }), ctrl: [] }
2024-02-25T21:07:59.831610500+00:00  DEBUG    │  ┝━ do_search [ 274µs | 0.24% / 0.44% ]
2024-02-25T21:07:59.832242246+00:00  DEBUG    │  │  ┝━ 🐛 [debug]:  | request.base: "ou=people,dc=example,dc=com" | scope: Users
2024-02-25T21:07:59.832243911+00:00  DEBUG    │  │  ┕━ get_user_list [ 126µs | 0.02% / 0.20% ]
2024-02-25T21:07:59.832248563+00:00  DEBUG    │  │     ┝━ 🐛 [debug]:  | filters: MemberOf(GroupName("jellyfinusers"))
2024-02-25T21:07:59.832251305+00:00  DEBUG    │  │     ┕━ list_users [ 115µs | 0.18% ] filters: Some(MemberOf(GroupName("jellyfinusers"))) | _get_groups: false
2024-02-25T21:07:59.832492067+00:00  DEBUG    │  │        ┕━ 🐛 [debug]:  | return: []
2024-02-25T21:07:59.832498945+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: SearchResultDone(LdapResult { code: Success, matcheddn: "", message: "", referral: [] })
2024-02-25T21:07:59.833296699+00:00  INFO     ┕━ LDAP request [ 16.2µs | 0.03% ]
2024-02-25T21:07:59.833312425+00:00  DEBUG       ┕━ 🐛 [debug]:  | msg: LdapMsg { msgid: 173, op: UnbindRequest, ctrl: [] }
2024-02-25T21:07:59.835044802+00:00  INFO     LDAP session [ 63.8ms | 0.14% / 100.00% ]
2024-02-25T21:07:59.841331605+00:00  INFO     ┝━ LDAP request [ 63.3ms | 0.08% / 99.19% ]
2024-02-25T21:07:59.841341698+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 174, op: BindRequest(LdapBindRequest { dn: "uid=admin,ou=people,dc=example,dc=com", cred: LdapBindCred::Simple }), ctrl: [] }
2024-02-25T21:07:59.841344662+00:00  DEBUG    │  ┝━ do_bind [ 63.3ms | 0.04% / 99.11% ] dn: uid=admin,ou=people,dc=example,dc=com
2024-02-25T21:07:59.841350931+00:00  DEBUG    │  │  ┝━ bind [ 63.1ms | 0.02% / 98.85% ]
2024-02-25T21:07:59.841354646+00:00  DEBUG    │  │  │  ┝━ get_password_file_for_user [ 104µs | 0.16% ] user_id: UserId(CaseInsensitiveString("admin"))
2024-02-25T21:07:59.841664410+00:00  DEBUG    │  │  │  ┕━ passwords_match [ 63.0ms | 98.67% ] username: admin
2024-02-25T21:07:59.904669024+00:00  DEBUG    │  │  ┝━ get_user_groups [ 139µs | 0.22% ] user_id: "admin"
2024-02-25T21:07:59.905370841+00:00  DEBUG    │  │  │  ┕━ 🐛 [debug]:  | return: {GroupDetails { group_id: GroupId(1), display_name: GroupName("lldap_admin"), creation_date: 2024-02-25T20:47:06.781239809, uuid: Uuid("b7063b5b-9796-31e0-9107-35f8c9e59cac"), attributes: [] }}
2024-02-25T21:07:59.905374791+00:00  DEBUG    │  │  ┕━ 🐛 [debug]: Success!
2024-02-25T21:07:59.905378652+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: BindResponse(LdapBindResponse { res: LdapResult { code: Success, matcheddn: "", message: "", referral: [] }, saslcreds: None })
2024-02-25T21:07:59.907299300+00:00  INFO     ┝━ LDAP request [ 421µs | 0.10% / 0.66% ]
2024-02-25T21:07:59.907308130+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 175, op: SearchRequest(LdapSearchRequest { base: "ou=people,dc=example,dc=com", scope: Subtree, aliases: Never, sizelimit: 1000, timelimit: 0, typesonly: false, filter: Equality("memberof", "cn=JellyfinUsers,ou=groups,dc=example,dc=com"), attrs: ["uid", "uid"] }), ctrl: [] }
2024-02-25T21:07:59.907309309+00:00  DEBUG    │  ┝━ do_search [ 359µs | 0.32% / 0.56% ]
2024-02-25T21:07:59.908102083+00:00  DEBUG    │  │  ┝━ 🐛 [debug]:  | request.base: "ou=people,dc=example,dc=com" | scope: Users
2024-02-25T21:07:59.908104071+00:00  DEBUG    │  │  ┕━ get_user_list [ 157µs | 0.02% / 0.25% ]
2024-02-25T21:07:59.908109570+00:00  DEBUG    │  │     ┝━ 🐛 [debug]:  | filters: MemberOf(GroupName("jellyfinusers"))
2024-02-25T21:07:59.908112598+00:00  DEBUG    │  │     ┕━ list_users [ 144µs | 0.23% ] filters: Some(MemberOf(GroupName("jellyfinusers"))) | _get_groups: false
2024-02-25T21:07:59.908432374+00:00  DEBUG    │  │        ┕━ 🐛 [debug]:  | return: []
2024-02-25T21:07:59.908439881+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: SearchResultDone(LdapResult { code: Success, matcheddn: "", message: "", referral: [] })
2024-02-25T21:07:59.909342747+00:00  INFO     ┕━ LDAP request [ 3.53µs | 0.01% ]
2024-02-25T21:07:59.909345710+00:00  DEBUG       ┕━ 🐛 [debug]:  | msg: LdapMsg { msgid: 176, op: UnbindRequest, ctrl: [] }
```

</p></details>

<details><summary>Logs with both JellyfinUsers (user test) and jellyfinusers (user test2) in LLDAP:</summary>
<p>

```log
2024-02-25T21:10:29.665324661+00:00  INFO     LDAP session [ 63.2ms | 0.17% / 100.00% ]
2024-02-25T21:10:29.671345797+00:00  INFO     ┝━ LDAP request [ 62.8ms | 0.08% / 99.33% ]
2024-02-25T21:10:29.671354970+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 183, op: BindRequest(LdapBindRequest { dn: "uid=admin,ou=people,dc=example,dc=com", cred: LdapBindCred::Simple }), ctrl: [] }
2024-02-25T21:10:29.671357343+00:00  DEBUG    │  ┝━ do_bind [ 62.8ms | 0.05% / 99.25% ] dn: uid=admin,ou=people,dc=example,dc=com
2024-02-25T21:10:29.671375496+00:00  DEBUG    │  │  ┝━ bind [ 62.6ms | 0.01% / 98.99% ]
2024-02-25T21:10:29.671378423+00:00  DEBUG    │  │  │  ┝━ get_password_file_for_user [ 54.4µs | 0.09% ] user_id: UserId(CaseInsensitiveString("admin"))
2024-02-25T21:10:29.671623020+00:00  DEBUG    │  │  │  ┕━ passwords_match [ 62.5ms | 98.89% ] username: admin
2024-02-25T21:10:29.734177287+00:00  DEBUG    │  │  ┝━ get_user_groups [ 131µs | 0.21% ] user_id: "admin"
2024-02-25T21:10:29.734762596+00:00  DEBUG    │  │  │  ┕━ 🐛 [debug]:  | return: {GroupDetails { group_id: GroupId(1), display_name: GroupName("lldap_admin"), creation_date: 2024-02-25T20:47:06.781239809, uuid: Uuid("b7063b5b-9796-31e0-9107-35f8c9e59cac"), attributes: [] }}
2024-02-25T21:10:29.734766091+00:00  DEBUG    │  │  ┕━ 🐛 [debug]: Success!
2024-02-25T21:10:29.734769784+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: BindResponse(LdapBindResponse { res: LdapResult { code: Success, matcheddn: "", message: "", referral: [] }, saslcreds: None })
2024-02-25T21:10:29.736414560+00:00  INFO     ┝━ LDAP request [ 311µs | 0.06% / 0.49% ]
2024-02-25T21:10:29.736434983+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 184, op: SearchRequest(LdapSearchRequest { base: "ou=people,dc=example,dc=com", scope: Subtree, aliases: Never, sizelimit: 1000, timelimit: 0, typesonly: false, filter: Equality("memberof", "cn=JellyfinUsers,ou=groups,dc=example,dc=com"), attrs: ["uid", "uid"] }), ctrl: [] }
2024-02-25T21:10:29.736435870+00:00  DEBUG    │  ┝━ do_search [ 270µs | 0.20% / 0.43% ]
2024-02-25T21:10:29.736777519+00:00  DEBUG    │  │  ┝━ 🐛 [debug]:  | request.base: "ou=people,dc=example,dc=com" | scope: Users
2024-02-25T21:10:29.736778973+00:00  DEBUG    │  │  ┝━ get_user_list [ 144µs | 0.02% / 0.23% ]
2024-02-25T21:10:29.736783258+00:00  DEBUG    │  │  │  ┝━ 🐛 [debug]:  | filters: MemberOf(GroupName("jellyfinusers"))
2024-02-25T21:10:29.736786283+00:00  DEBUG    │  │  │  ┕━ list_users [ 133µs | 0.21% ] filters: Some(MemberOf(GroupName("jellyfinusers"))) | _get_groups: false
2024-02-25T21:10:29.737050917+00:00  DEBUG    │  │  │     ┕━ 🐛 [debug]:  | return: [UserAndGroups { user: User { user_id: UserId(CaseInsensitiveString("test2")), email: Email("test@test.t"), display_name: Some("test2"), creation_date: 2024-02-25T20:58:11.333751119, uuid: Uuid("a135652b-abdb-31f8-9601-2140339b9bba"), attributes: [] }, groups: Some([GroupDetails { group_id: GroupId(9), display_name: GroupName("jellyfinusers"), creation_date: 2024-02-25T21:09:39.859380476, uuid: Uuid("f3610e5d-b5c3-3650-9432-4466d38364ac"), attributes: [] }]) }]
2024-02-25T21:10:29.737054414+00:00  DEBUG    │  │  ┕━ expand_attribute_wildcards [ 1.74µs | 0.00% ] ldap_attributes: ["uid", "uid"]
2024-02-25T21:10:29.737056153+00:00  DEBUG    │  │     ┕━ 🐛 [debug]:  | resolved_attributes: ["uid"]
2024-02-25T21:10:29.737063607+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | response: SearchResultEntry(LdapSearchResultEntry { dn: "uid=test2,ou=people,dc=example,dc=com", attributes: [LdapPartialAttribute { atype: "uid", vals: ["test2"] }] })
2024-02-25T21:10:29.737080411+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: SearchResultDone(LdapResult { code: Success, matcheddn: "", message: "", referral: [] })
2024-02-25T21:10:29.778986925+00:00  INFO     ┕━ LDAP request [ 8.68µs | 0.01% ]
2024-02-25T21:10:29.778994037+00:00  DEBUG       ┕━ 🐛 [debug]:  | msg: LdapMsg { msgid: 185, op: UnbindRequest, ctrl: [] }
2024-02-25T21:10:29.781152014+00:00  INFO     LDAP session [ 64.6ms | 0.14% / 100.00% ]
2024-02-25T21:10:29.787116265+00:00  INFO     ┝━ LDAP request [ 64.2ms | 0.07% / 99.32% ]
2024-02-25T21:10:29.787122121+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 186, op: BindRequest(LdapBindRequest { dn: "uid=admin,ou=people,dc=example,dc=com", cred: LdapBindCred::Simple }), ctrl: [] }
2024-02-25T21:10:29.787123972+00:00  DEBUG    │  ┝━ do_bind [ 64.1ms | 0.03% / 99.25% ] dn: uid=admin,ou=people,dc=example,dc=com
2024-02-25T21:10:29.787128553+00:00  DEBUG    │  │  ┝━ bind [ 64.0ms | 0.01% / 98.99% ]
2024-02-25T21:10:29.787131215+00:00  DEBUG    │  │  │  ┝━ get_password_file_for_user [ 51.6µs | 0.08% ] user_id: UserId(CaseInsensitiveString("admin"))
2024-02-25T21:10:29.787351998+00:00  DEBUG    │  │  │  ┕━ passwords_match [ 63.9ms | 98.90% ] username: admin
2024-02-25T21:10:29.851272098+00:00  DEBUG    │  │  ┝━ get_user_groups [ 143µs | 0.22% ] user_id: "admin"
2024-02-25T21:10:29.851883218+00:00  DEBUG    │  │  │  ┕━ 🐛 [debug]:  | return: {GroupDetails { group_id: GroupId(1), display_name: GroupName("lldap_admin"), creation_date: 2024-02-25T20:47:06.781239809, uuid: Uuid("b7063b5b-9796-31e0-9107-35f8c9e59cac"), attributes: [] }}
2024-02-25T21:10:29.851886587+00:00  DEBUG    │  │  ┕━ 🐛 [debug]: Success!
2024-02-25T21:10:29.851890703+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: BindResponse(LdapBindResponse { res: LdapResult { code: Success, matcheddn: "", message: "", referral: [] }, saslcreds: None })
2024-02-25T21:10:29.853712130+00:00  INFO     ┝━ LDAP request [ 342µs | 0.09% / 0.53% ]
2024-02-25T21:10:29.853732677+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 187, op: SearchRequest(LdapSearchRequest { base: "ou=people,dc=example,dc=com", scope: Subtree, aliases: Never, sizelimit: 1000, timelimit: 0, typesonly: false, filter: Equality("memberof", "cn=JellyfinUsers,ou=groups,dc=example,dc=com"), attrs: ["uid", "uid"] }), ctrl: [] }
2024-02-25T21:10:29.853733704+00:00  DEBUG    │  ┝━ do_search [ 285µs | 0.19% / 0.44% ]
2024-02-25T21:10:29.854142728+00:00  DEBUG    │  │  ┝━ 🐛 [debug]:  | request.base: "ou=people,dc=example,dc=com" | scope: Users
2024-02-25T21:10:29.854144064+00:00  DEBUG    │  │  ┝━ get_user_list [ 160µs | 0.02% / 0.25% ]
2024-02-25T21:10:29.854149124+00:00  DEBUG    │  │  │  ┝━ 🐛 [debug]:  | filters: MemberOf(GroupName("jellyfinusers"))
2024-02-25T21:10:29.854152155+00:00  DEBUG    │  │  │  ┕━ list_users [ 149µs | 0.23% ] filters: Some(MemberOf(GroupName("jellyfinusers"))) | _get_groups: false
2024-02-25T21:10:29.854493879+00:00  DEBUG    │  │  │     ┕━ 🐛 [debug]:  | return: [UserAndGroups { user: User { user_id: UserId(CaseInsensitiveString("test2")), email: Email("test@test.t"), display_name: Some("test2"), creation_date: 2024-02-25T20:58:11.333751119, uuid: Uuid("a135652b-abdb-31f8-9601-2140339b9bba"), attributes: [] }, groups: Some([GroupDetails { group_id: GroupId(9), display_name: GroupName("jellyfinusers"), creation_date: 2024-02-25T21:09:39.859380476, uuid: Uuid("f3610e5d-b5c3-3650-9432-4466d38364ac"), attributes: [] }]) }]
2024-02-25T21:10:29.854497716+00:00  DEBUG    │  │  ┕━ expand_attribute_wildcards [ 1.86µs | 0.00% ] ldap_attributes: ["uid", "uid"]
2024-02-25T21:10:29.854499416+00:00  DEBUG    │  │     ┕━ 🐛 [debug]:  | resolved_attributes: ["uid"]
2024-02-25T21:10:29.854507332+00:00  DEBUG    │  ┝━ 🐛 [debug]:  | response: SearchResultEntry(LdapSearchResultEntry { dn: "uid=test2,ou=people,dc=example,dc=com", attributes: [LdapPartialAttribute { atype: "uid", vals: ["test2"] }] })
2024-02-25T21:10:29.854526575+00:00  DEBUG    │  ┕━ 🐛 [debug]:  | response: SearchResultDone(LdapResult { code: Success, matcheddn: "", message: "", referral: [] })
2024-02-25T21:10:29.898881360+00:00  INFO     ┕━ LDAP request [ 8.72µs | 0.01% ]
2024-02-25T21:10:29.898888299+00:00  DEBUG       ┕━ 🐛 [debug]:  | msg: LdapMsg { msgid: 188, op: UnbindRequest, ctrl: [] }
```

</p></details>


Fix patch:
diff --git a/server/src/domain/ldap/user.rs b/server/src/domain/ldap/user.rs
index dc26a389..a16836fe 100644
--- a/server/src/domain/ldap/user.rs
+++ b/server/src/domain/ldap/user.rs
@@ -195,6 +195,10 @@ fn convert_user_filter(
                 UserFieldType::PrimaryField(UserColumn::UserId) => {
                     Ok(UserRequestFilter::UserId(UserId::new(&value)))
                 }
+                UserFieldType::PrimaryField(UserColumn::Email) => Ok(UserRequestFilter::Equality(
+                    UserColumn::LowercaseEmail,
+                    value,
+                )),
                 UserFieldType::PrimaryField(field) => Ok(UserRequestFilter::Equality(field, value)),
                 UserFieldType::Attribute(field, typ, is_list) => {
                     get_user_attribute_equality_filter(&field, typ, is_list, &value)
@@ -269,6 +273,10 @@ fn convert_user_filter(
                     ),
                 }),
                 UserFieldType::NoMatch => Ok(UserRequestFilter::from(false)),
+                UserFieldType::PrimaryField(UserColumn::Email) => Ok(UserRequestFilter::SubString(
+                    UserColumn::LowercaseEmail,
+                    substring_filter.clone().into(),
+                )),
                 UserFieldType::PrimaryField(field) => Ok(UserRequestFilter::SubString(
                     field,
                     substring_filter.clone().into(),
diff --git a/server/src/domain/sql_group_backend_handler.rs b/server/src/domain/sql_group_backend_handler.rs
index a0da301a..6f88fb27 100644
--- a/server/src/domain/sql_group_backend_handler.rs
+++ b/server/src/domain/sql_group_backend_handler.rs
@@ -67,7 +67,7 @@ fn get_group_filter_expr(filter: GroupRequestFilter) -> Cond {
             .into_condition(),
         DisplayNameSubString(filter) => SimpleExpr::FunctionCall(Func::lower(Expr::col((
             group_table,
-            GroupColumn::DisplayName,
+            GroupColumn::LowercaseDisplayName,
         ))))
         .like(filter.to_sql_filter())
         .into_condition(),
@@ -606,4 +606,25 @@ mod tests {
         let details = fixture.handler.get_group_details(group_id).await.unwrap();
         assert_eq!(details.attributes, Vec::new());
     }
+
+    #[tokio::test]
+    async fn test_create_group_duplicate_name() {
+        let fixture = TestFixture::new().await;
+        fixture
+            .handler
+            .create_group(CreateGroupRequest {
+                display_name: "New Group".into(),
+                ..Default::default()
+            })
+            .await
+            .unwrap();
+        fixture
+            .handler
+            .create_group(CreateGroupRequest {
+                display_name: "neW group".into(),
+                ..Default::default()
+            })
+            .await
+            .unwrap_err();
+    }
 }
diff --git a/server/src/domain/sql_migrations.rs b/server/src/domain/sql_migrations.rs
index 587971ef..4bd54cf2 100644
--- a/server/src/domain/sql_migrations.rs
+++ b/server/src/domain/sql_migrations.rs
@@ -1090,6 +1090,47 @@ async fn migrate_to_v9(transaction: DatabaseTransaction) -> Result<DatabaseTrans
     Ok(transaction)
 }
 
+async fn migrate_to_v10(transaction: DatabaseTransaction) -> Result<DatabaseTransaction, DbErr> {
+    let builder = transaction.get_database_backend();
+    if let Err(e) = transaction
+        .execute(
+            builder.build(
+                Index::create()
+                    .if_not_exists()
+                    .name("unique-group-id")
+                    .table(Groups::Table)
+                    .col(Groups::LowercaseDisplayName)
+                    .unique(),
+            ),
+        )
+        .await
+    {
+        error!(
+            r#"Found several groups with the same (case-insensitive) display name. Please delete the duplicates"#
+        );
+        return Err(e);
+    }
+    if let Err(e) = transaction
+        .execute(
+            builder.build(
+                Index::create()
+                    .if_not_exists()
+                    .name("unique-user-lower-email")
+                    .table(Users::Table)
+                    .col(Users::LowercaseEmail)
+                    .unique(),
+            ),
+        )
+        .await
+    {
+        error!(
+            r#"Found several users with the same (case-insensitive) email. Please delete the duplicates"#
+        );
+        return Err(e);
+    }
+    Ok(transaction)
+}
+
 // This is needed to make an array of async functions.
 macro_rules! to_sync {
     ($l:ident) => {
@@ -1119,6 +1160,7 @@ pub async fn migrate_from_version(
         to_sync!(migrate_to_v7),
         to_sync!(migrate_to_v8),
         to_sync!(migrate_to_v9),
+        to_sync!(migrate_to_v10),
     ];
     assert_eq!(migrations.len(), (LAST_SCHEMA_VERSION.0 - 1) as usize);
     for migration in 2..=last_version.0 {
diff --git a/server/src/domain/sql_tables.rs b/server/src/domain/sql_tables.rs
index 9b50d513..6745e611 100644
--- a/server/src/domain/sql_tables.rs
+++ b/server/src/domain/sql_tables.rs
@@ -11,7 +11,7 @@ pub type DbConnection = sea_orm::DatabaseConnection;
 #[derive(Copy, PartialEq, Eq, Debug, Clone, PartialOrd, Ord, DeriveValueType)]
 pub struct SchemaVersion(pub i16);
 
-pub const LAST_SCHEMA_VERSION: SchemaVersion = SchemaVersion(9);
+pub const LAST_SCHEMA_VERSION: SchemaVersion = SchemaVersion(10);
 
 #[derive(Copy, PartialEq, Eq, Debug, Clone, PartialOrd, Ord)]
 pub struct PrivateKeyHash(pub [u8; 32]);
diff --git a/server/src/domain/sql_user_backend_handler.rs b/server/src/domain/sql_user_backend_handler.rs
index ef53271d..5372a809 100644
--- a/server/src/domain/sql_user_backend_handler.rs
+++ b/server/src/domain/sql_user_backend_handler.rs
@@ -67,8 +67,8 @@ fn get_user_filter_expr(filter: UserRequestFilter) -> Cond {
             }
         }
         AttributeEquality(column, value) => attribute_condition(column, value),
-        MemberOf(group) => Expr::col((group_table, GroupColumn::DisplayName))
-            .eq(group)
+        MemberOf(group) => Expr::col((group_table, GroupColumn::LowercaseDisplayName))
+            .eq(group.as_str().to_lowercase())
             .into_condition(),
         MemberOfId(group_id) => Expr::col((group_table, GroupColumn::GroupId))
             .eq(group_id)
@@ -542,6 +542,12 @@ mod tests {
         )
         .await;
         assert_eq!(users, vec!["bob", "patrick"]);
+        let users = get_user_names(
+            &fixture.handler,
+            Some(UserRequestFilter::MemberOf("best grOUp".into())),
+        )
+        .await;
+        assert_eq!(users, vec!["bob", "patrick"]);
     }
 
     #[tokio::test]
@@ -1121,4 +1127,29 @@ mod tests {
             .await
             .expect_err("Should have failed");
     }
+
+    #[tokio::test]
+    async fn test_create_user_duplicate_email() {
+        let fixture = TestFixture::new().await;
+
+        fixture
+            .handler
+            .create_user(CreateUserRequest {
+                user_id: UserId::new("james"),
+                email: "email".into(),
+                ..Default::default()
+            })
+            .await
+            .unwrap();
+
+        fixture
+            .handler
+            .create_user(CreateUserRequest {
+                user_id: UserId::new("john"),
+                email: "eMail".into(),
+                ..Default::default()
+            })
+            .await
+            .unwrap_err();
+    }
 }


Test patch: