in src/Zyborg.PassCore.PasswordProvider.LDAP/LdapPasswordChangeProvider.cs [66:146]
public ApiErrorItem? PerformPasswordChange(
string username,
string currentPassword,
string newPassword)
{
try
{
var cleanUsername = CleaningUsername(username);
var searchFilter = _options.LdapSearchFilter.Replace("{Username}", cleanUsername);
_logger.LogWarning("LDAP query: {0}", searchFilter);
using var ldap = BindToLdap();
var search = ldap.Search(
_options.LdapSearchBase,
LdapConnection.ScopeSub,
searchFilter,
new[] { "distinguishedName" },
false,
_searchConstraints);
// We cannot use search.Count here -- apparently it does not
// wait for the results to return before resolving the count
// but fortunately hasMore seems to block until final result
if (!search.HasMore())
{
_logger.LogWarning("Unable to find username: [{0}]", cleanUsername);
return new ApiErrorItem(
_options.HideUserNotFound ? ApiErrorCode.InvalidCredentials : ApiErrorCode.UserNotFound,
_options.HideUserNotFound ? "Invalid credentials" : "Username could not be located");
}
if (search.Count > 1)
{
_logger.LogWarning("Found multiple with same username: [{0}] - Count {1}", cleanUsername, search.Count);
// Hopefully this should not ever happen if AD is preserving SAM Account Name
// uniqueness constraint, but just in case, handling this corner case
return new ApiErrorItem(ApiErrorCode.UserNotFound, "Multiple matching user entries resolved");
}
var userDN = search.Next().Dn;
if (_options.LdapChangePasswordWithDelAdd)
{
ChangePasswordDelAdd(currentPassword, newPassword, ldap, userDN);
}
else
{
ChangePasswordReplace(newPassword, ldap, userDN);
}
if (_options.LdapStartTls)
ldap.StopTls();
ldap.Disconnect();
}
catch (LdapException ex)
{
var item = ParseLdapException(ex);
_logger.LogWarning(item.Message, ex);
return item;
}
catch (Exception ex)
{
var item = ex is ApiErrorException apiError
? apiError.ToApiErrorItem()
: new ApiErrorItem(ApiErrorCode.InvalidCredentials, $"Failed to update password: {ex.Message}");
_logger.LogWarning(item.Message, ex);
return item;
}
// Everything seems to have worked:
return null;
}