diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs
index f8817888e6..9378cfedb6 100644
--- a/Jellyfin.Api/Controllers/StartupController.cs
+++ b/Jellyfin.Api/Controllers/StartupController.cs
@@ -151,7 +151,7 @@ public class StartupController : BaseJellyfinApiController
if (!string.IsNullOrEmpty(startupUserDto.Password))
{
- await _userManager.ChangePassword(user, startupUserDto.Password).ConfigureAwait(false);
+ await _userManager.ChangePassword(user.Id, startupUserDto.Password).ConfigureAwait(false);
}
return NoContent();
diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs
index 5eadb7a831..4e1a06771b 100644
--- a/Jellyfin.Api/Controllers/UserController.cs
+++ b/Jellyfin.Api/Controllers/UserController.cs
@@ -288,7 +288,7 @@ public class UserController : BaseJellyfinApiController
if (request.ResetPassword)
{
- await _userManager.ResetPassword(user).ConfigureAwait(false);
+ await _userManager.ResetPassword(user.Id).ConfigureAwait(false);
}
else
{
@@ -306,7 +306,7 @@ public class UserController : BaseJellyfinApiController
}
}
- await _userManager.ChangePassword(user, request.NewPw ?? string.Empty).ConfigureAwait(false);
+ await _userManager.ChangePassword(user.Id, request.NewPw ?? string.Empty).ConfigureAwait(false);
var currentToken = User.GetToken();
@@ -545,7 +545,7 @@ public class UserController : BaseJellyfinApiController
// no need to authenticate password for new user
if (request.Password is not null)
{
- await _userManager.ChangePassword(newUser, request.Password).ConfigureAwait(false);
+ await _userManager.ChangePassword(newUser.Id, request.Password).ConfigureAwait(false);
}
var result = _userManager.GetUserDto(newUser, HttpContext.GetNormalizedRemoteIP().ToString());
diff --git a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs
index 49a9fda943..7371545914 100644
--- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs
+++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs
@@ -74,7 +74,7 @@ namespace Jellyfin.Server.Implementations.Users
var resetUser = userManager.GetUserByName(spr.UserName)
?? throw new ResourceNotFoundException($"User with a username of {spr.UserName} not found");
- await userManager.ChangePassword(resetUser, pin).ConfigureAwait(false);
+ await userManager.ChangePassword(resetUser.Id, pin).ConfigureAwait(false);
usersReset.Add(resetUser.Username);
File.Delete(resetFile);
}
diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs
index 44d998ef66..9fc6f2f4aa 100644
--- a/Jellyfin.Server.Implementations/Users/UserManager.cs
+++ b/Jellyfin.Server.Implementations/Users/UserManager.cs
@@ -335,43 +335,37 @@ namespace Jellyfin.Server.Implementations.Users
}
///
- public Task ResetPassword(User user)
+ public Task ResetPassword(Guid userId)
{
- return ChangePassword(user, string.Empty);
+ return ChangePassword(userId, string.Empty);
}
///
- public async Task ChangePassword(User user, string newPassword)
+ public async Task ChangePassword(Guid userId, string newPassword)
{
- ArgumentNullException.ThrowIfNull(user);
- if (user.HasPermission(PermissionKind.IsAdministrator) && string.IsNullOrWhiteSpace(newPassword))
- {
- throw new ArgumentException("Admin user passwords must not be empty", nameof(newPassword));
- }
-
- using (await _userLock.LockAsync(user.Id).ConfigureAwait(false))
+ User dbUser = null!;
+ using (await _userLock.LockAsync(userId).ConfigureAwait(false))
{
var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false);
await using (dbContext.ConfigureAwait(false))
{
- // Reload the user inside the lock to get the current RowVersion.
- // The incoming user may have been loaded with AsNoTracking() before this
- // lock was acquired; a concurrent write (e.g. a login updating LastLoginDate)
- // could have incremented RowVersion in the database in the meantime.
- // Since we now hold the per-user lock, no other write can race with us, so
- // the freshly loaded RowVersion is guaranteed to be current.
- var dbUser = await UserQuery(dbContext)
+ dbUser = await UserQuery(dbContext)
.AsTracking()
- .FirstOrDefaultAsync(u => u.Id == user.Id)
+ .FirstOrDefaultAsync(u => u.Id == userId)
.ConfigureAwait(false)
- ?? throw new ResourceNotFoundException(nameof(user.Id));
+ ?? throw new ResourceNotFoundException(nameof(userId));
+
+ if (dbUser.HasPermission(PermissionKind.IsAdministrator) && string.IsNullOrWhiteSpace(newPassword))
+ {
+ throw new ArgumentException("Admin user passwords must not be empty", nameof(newPassword));
+ }
await GetAuthenticationProvider(dbUser).ChangePassword(dbUser, newPassword).ConfigureAwait(false);
await dbContext.SaveChangesAsync().ConfigureAwait(false);
}
}
- await _eventManager.PublishAsync(new UserPasswordChangedEventArgs(user)).ConfigureAwait(false);
+ await _eventManager.PublishAsync(new UserPasswordChangedEventArgs(dbUser)).ConfigureAwait(false);
}
///
diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs
index ad0954db89..e2b54ea7a7 100644
--- a/MediaBrowser.Controller/Library/IUserManager.cs
+++ b/MediaBrowser.Controller/Library/IUserManager.cs
@@ -99,17 +99,17 @@ namespace MediaBrowser.Controller.Library
///
/// Resets the password.
///
- /// The user.
+ /// The users Id.
/// Task.
- Task ResetPassword(User user);
+ Task ResetPassword(Guid userId);
///
/// Changes the password.
///
- /// The user.
+ /// The users id.
/// New password to use.
/// Awaitable task.
- Task ChangePassword(User user, string newPassword);
+ Task ChangePassword(Guid userId, string newPassword);
///
/// Gets the user dto.