diff --git a/LDAP-Auth/Api/LdapController.cs b/LDAP-Auth/Api/LdapController.cs index b78711e..36f0508 100644 --- a/LDAP-Auth/Api/LdapController.cs +++ b/LDAP-Auth/Api/LdapController.cs @@ -158,7 +158,6 @@ public IActionResult LdapUserSearch([FromBody] UserSearchAttributes body) { var configuration = LdapPlugin.Instance.Configuration; configuration.LdapSearchAttributes = body.LdapSearchAttributes; - configuration.EnableCaseInsensitiveUsername = body.EnableCaseInsensitiveUsername; LdapPlugin.Instance.UpdateConfiguration(configuration); var response = new UserSearchResponse(); diff --git a/LDAP-Auth/Api/Models/UserFilterInfo.cs b/LDAP-Auth/Api/Models/UserFilterInfo.cs index 31d4513..23ffc3b 100644 --- a/LDAP-Auth/Api/Models/UserFilterInfo.cs +++ b/LDAP-Auth/Api/Models/UserFilterInfo.cs @@ -11,7 +11,6 @@ public class UserFilterInfo /// /// Gets or sets the ldap user search filter. /// - [Required] public string LdapSearchFilter { get; set; } /// diff --git a/LDAP-Auth/Api/Models/UserSearchAttributes.cs b/LDAP-Auth/Api/Models/UserSearchAttributes.cs index a830d57..683173c 100644 --- a/LDAP-Auth/Api/Models/UserSearchAttributes.cs +++ b/LDAP-Auth/Api/Models/UserSearchAttributes.cs @@ -12,14 +12,8 @@ public class UserSearchAttributes /// /// Gets or sets the ldap search attributes. /// - [Required] public string LdapSearchAttributes { get; set; } - /// - /// Gets or sets a value indicating whether to use case insensitive username comparison. - /// - public bool EnableCaseInsensitiveUsername { get; set; } - /// /// Gets or sets the username to search for as a test. /// diff --git a/LDAP-Auth/Config/PluginConfiguration.cs b/LDAP-Auth/Config/PluginConfiguration.cs index 379a1a4..69c6ba9 100644 --- a/LDAP-Auth/Config/PluginConfiguration.cs +++ b/LDAP-Auth/Config/PluginConfiguration.cs @@ -29,7 +29,6 @@ public PluginConfiguration() LdapClientCertPath = string.Empty; LdapClientKeyPath = string.Empty; LdapRootCaPath = string.Empty; - EnableCaseInsensitiveUsername = false; CreateUsersFromLdap = true; LdapUsernameAttribute = "uid"; LdapPasswordAttribute = "userPassword"; @@ -102,11 +101,6 @@ public PluginConfiguration() /// public string LdapSearchAttributes { get; set; } - /// - /// Gets or sets a value indicating whether to use case insensitive username comparison. - /// - public bool EnableCaseInsensitiveUsername { get; set; } - /// /// Gets or sets the ldap client cert path. /// diff --git a/LDAP-Auth/Config/configPage.html b/LDAP-Auth/Config/configPage.html index f59bf73..630b174 100644 --- a/LDAP-Auth/Config/configPage.html +++ b/LDAP-Auth/Config/configPage.html @@ -93,10 +93,30 @@

LDAP Settings:

+

Users

+

There are two methods possible to search for users.

+ +

At least one method must be chosen and configured below. If upgrading from plugin version 16 or newer, the second option will be used by default.

+

Note: Usernames are treated case-insensitive regardless of the method, as an LDAP search is not case-sensitive.

+
- -
The LDAP search filter to find users for Jellyfin, e.g. (objectClass=inetOrgPerson).
+ +
+ LDAP search filter to limit user searches.
+
+
+ +
+ A comma-separated list of attributes to filter the username by.
+
+
+
+ +

Administrators

The LDAP search base dn to find administrative users for Jellyfin, e.g. (cn=admins,dc=contoso,dc=com). Defaults to user dn if empty
@@ -115,22 +135,14 @@

LDAP Settings:

Enable Admin Filter 'memberUid' mode
+
+ +

Testing

-
-
- -
A comma-separated list of LDAP attributes to compare with entered usernames.
-
-
- -
Enable case insensitive username comparison
-
+
A user login to search the LDAP for to test attribute configuration.
@@ -152,7 +164,7 @@

LDAP Settings:

-
The LDAP attribute to create Jellyfin user names from.
+
The LDAP attribute to create Jellyfin user names from.
For example, 'uid' means we will use the LDAP 'uid' attribute as the Jellyfin username.
@@ -206,7 +218,6 @@

${HeaderLibraryAccess}

chkEnableLdapAdminFilterMemberUid: document.querySelector("#chkEnableLdapAdminFilterMemberUid"), divFilterTestResults: document.querySelector("#divFilterTestResults"), txtLdapSearchAttributes: document.querySelector("#txtLdapSearchAttributes"), - chkEnableCaseInsensitiveUsername: document.querySelector("#chkEnableCaseInsensitiveUsername"), txtLdapSearchTest: document.querySelector("#txtLdapSearchTest"), divSearchTestResults: document.querySelector("#divSearchTestResults"), txtLdapClientCertPath: document.querySelector("#txtLdapClientCertPath"), @@ -245,7 +256,6 @@

${HeaderLibraryAccess}

LdapConfigurationPage.txtLdapClientCertPath.value = config.LdapClientCertPath || ""; LdapConfigurationPage.txtLdapClientKeyPath.value = config.LdapClientKeyPath || ""; LdapConfigurationPage.txtLdapRootCaPath.value = config.LdapRootCaPath || ""; - LdapConfigurationPage.chkEnableCaseInsensitiveUsername.checked = config.EnableCaseInsensitiveUsername; LdapConfigurationPage.chkEnableUserCreation.checked = config.CreateUsersFromLdap; LdapConfigurationPage.txtLdapUsernameAttribute.value = config.LdapUsernameAttribute; LdapConfigurationPage.txtLdapPasswordAttribute.value = config.LdapPasswordAttribute; @@ -332,7 +342,6 @@

${HeaderLibraryAccess}

config.LdapClientCertPath = LdapConfigurationPage.txtLdapClientCertPath.value; config.LdapClientKeyPath = LdapConfigurationPage.txtLdapClientKeyPath.value; config.LdapRootCaPath = LdapConfigurationPage.txtLdapRootCaPath.value; - config.EnableCaseInsensitiveUsername = LdapConfigurationPage.chkEnableCaseInsensitiveUsername.checked; config.CreateUsersFromLdap = LdapConfigurationPage.chkEnableUserCreation.checked; config.LdapUsernameAttribute = LdapConfigurationPage.txtLdapUsernameAttribute.value; config.LdapPasswordAttribute = LdapConfigurationPage.txtLdapPasswordAttribute.value; @@ -473,7 +482,6 @@

${HeaderLibraryAccess}

const configUpdate = { LdapSearchAttributes: LdapConfigurationPage.txtLdapSearchAttributes.value, - EnableCaseInsensitiveUsername: LdapConfigurationPage.chkEnableCaseInsensitiveUsername.checked, TestSearchUsername: LdapConfigurationPage.txtLdapSearchTest.value, } diff --git a/LDAP-Auth/LDAPAuthenticationProviderPlugin.cs b/LDAP-Auth/LDAPAuthenticationProviderPlugin.cs index 517b85d..19c999d 100644 --- a/LDAP-Auth/LDAPAuthenticationProviderPlugin.cs +++ b/LDAP-Auth/LDAPAuthenticationProviderPlugin.cs @@ -344,8 +344,6 @@ public IEnumerable GetFilteredUsers(string filter) /// Thrown on failure to connect or bind to LDAP server. public LdapEntry LocateLdapUser(string username) { - var foundUser = false; - LdapEntry ldapUser = null; using var ldapClient = ConnectToLdap(); if (!ldapClient.Connected) @@ -358,55 +356,59 @@ public LdapEntry LocateLdapUser(string username) LdapPlugin.Instance.Configuration.LdapBindUser, LdapPlugin.Instance.Configuration.LdapBindPassword); + string realSearchFilter; + + if (SearchFilter.Contains("{username}")) + { + realSearchFilter = SearchFilter.Replace("{username}", username); + } + else + { + realSearchFilter = "(&" + SearchFilter + "(|"; + foreach (var attr in LdapUsernameAttributes) + { + realSearchFilter += "(" + attr + "=" + username + ")"; + } + + realSearchFilter += "))"; + } + + _logger.LogDebug("LDAP Search: {BaseDn} {realSearchFilter} @ {LdapServer}", LdapPlugin.Instance.Configuration.LdapBaseDn, realSearchFilter, LdapPlugin.Instance.Configuration.LdapServer); + ILdapSearchResults ldapUsers; try { ldapUsers = ldapClient.Search( LdapPlugin.Instance.Configuration.LdapBaseDn, LdapConnection.ScopeSub, - SearchFilter, + realSearchFilter, LdapUsernameAttributes, false); } catch (LdapException e) { - _logger.LogError(e, "Failed to filter users with: {Filter}", SearchFilter); + _logger.LogError(e, "Failed to filter users with: {Filter}", realSearchFilter); throw new AuthenticationException("Error completing LDAP login while applying user filter."); } - _logger.LogDebug("Search: {BaseDn} {SearchFilter} @ {LdapServer}", LdapPlugin.Instance.Configuration.LdapBaseDn, SearchFilter, LdapPlugin.Instance.Configuration.LdapServer); - - var usernameComparison = LdapPlugin.Instance.Configuration.EnableCaseInsensitiveUsername - ? StringComparison.OrdinalIgnoreCase - : StringComparison.Ordinal; - while (ldapUsers.HasMore() && foundUser == false) + if (ldapUsers.HasMore()) { - var currentUser = ldapUsers.Next(); - foreach (var attr in LdapUsernameAttributes) + LdapEntry ldapUser = ldapUsers.Next(); + + if (ldapUsers.HasMore()) { - var toCheck = GetAttribute(currentUser, attr); - if (toCheck?.StringValueArray != null) - { - foreach (var name in toCheck.StringValueArray) - { - if (string.Equals(username, name, usernameComparison)) - { - ldapUser = currentUser; - foundUser = true; - break; - } - } - } + _logger.LogWarning("More than one LDAP result matched; using first result only."); } - } - if (ldapUser == null) + _logger.LogDebug("LDAP User: {ldapUser}", ldapUser); + + return ldapUser; + } + else { _logger.LogError("Found no users matching {Username} in LDAP search", username); throw new AuthenticationException("Found no LDAP users matching provided username."); } - - return ldapUser; } ///