af1152b001
Refactored all C# test files to use explicit namespace declarations and moved all using directives inside the namespace block for consistency. Updated assembly info and cache files to reflect the new build. Adjusted MvcTestingAppManifest.json to use fully qualified assembly names. No functional changes; all updates are related to code style, organization, and project metadata.
116 lines
4.4 KiB
C#
116 lines
4.4 KiB
C#
// <copyright file="DefaultAuthenticationProvider.cs" company="PlaceholderCompany">
|
|
// Copyright (c) PlaceholderCompany. All rights reserved.
|
|
// </copyright>
|
|
|
|
namespace Jellyfin.Server.Implementations.Users
|
|
{
|
|
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Globalization;
|
|
using System.Threading.Tasks;
|
|
using Jellyfin.Database.Implementations.Entities;
|
|
using MediaBrowser.Controller.Authentication;
|
|
using MediaBrowser.Model.Cryptography;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
/// <summary>
|
|
/// The default authentication provider.
|
|
/// </summary>
|
|
public class DefaultAuthenticationProvider : IAuthenticationProvider, IRequiresResolvedUser
|
|
{
|
|
private readonly ILogger<DefaultAuthenticationProvider> _logger;
|
|
private readonly ICryptoProvider _cryptographyProvider;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="DefaultAuthenticationProvider"/> class.
|
|
/// </summary>
|
|
/// <param name="logger">The logger.</param>
|
|
/// <param name="cryptographyProvider">The cryptography provider.</param>
|
|
public DefaultAuthenticationProvider(ILogger<DefaultAuthenticationProvider> logger, ICryptoProvider cryptographyProvider)
|
|
{
|
|
_logger = logger;
|
|
_cryptographyProvider = cryptographyProvider;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public string Name => "Default";
|
|
|
|
/// <inheritdoc />
|
|
public bool IsEnabled => true;
|
|
|
|
/// <inheritdoc />
|
|
// This is dumb and an artifact of the backwards way auth providers were designed.
|
|
// This version of authenticate was never meant to be called, but needs to be here for interface compat
|
|
// Only the providers that don't provide local user support use this
|
|
public Task<ProviderAuthenticationResult> Authenticate(string username, string password)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
// This is the version that we need to use for local users. Because reasons.
|
|
public Task<ProviderAuthenticationResult> Authenticate(string username, string password, User? resolvedUser)
|
|
{
|
|
[DoesNotReturn]
|
|
static void ThrowAuthenticationException()
|
|
{
|
|
throw new AuthenticationException("Invalid username or password");
|
|
}
|
|
|
|
if (resolvedUser is null)
|
|
{
|
|
ThrowAuthenticationException();
|
|
}
|
|
|
|
// As long as jellyfin supports password-less users, we need this little block here to accommodate
|
|
if (string.IsNullOrEmpty(resolvedUser.Password) && string.IsNullOrEmpty(password))
|
|
{
|
|
return Task.FromResult(new ProviderAuthenticationResult
|
|
{
|
|
Username = username
|
|
});
|
|
}
|
|
|
|
// Handle the case when the stored password is null, but the user tried to login with a password
|
|
if (resolvedUser.Password is null)
|
|
{
|
|
ThrowAuthenticationException();
|
|
}
|
|
|
|
PasswordHash readyHash = PasswordHash.Parse(resolvedUser.Password);
|
|
if (!_cryptographyProvider.Verify(readyHash, password))
|
|
{
|
|
ThrowAuthenticationException();
|
|
}
|
|
|
|
// Migrate old hashes to the new default
|
|
if (!string.Equals(readyHash.Id, _cryptographyProvider.DefaultHashMethod, StringComparison.Ordinal)
|
|
|| int.Parse(readyHash.Parameters["iterations"], CultureInfo.InvariantCulture) != Constants.DefaultIterations)
|
|
{
|
|
_logger.LogInformation("Migrating password hash of {User} to the latest default", username);
|
|
ChangePassword(resolvedUser, password);
|
|
}
|
|
|
|
return Task.FromResult(new ProviderAuthenticationResult
|
|
{
|
|
Username = username
|
|
});
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task ChangePassword(User user, string newPassword)
|
|
{
|
|
if (string.IsNullOrEmpty(newPassword))
|
|
{
|
|
user.Password = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
PasswordHash newPasswordHash = _cryptographyProvider.CreatePasswordHash(newPassword);
|
|
user.Password = newPasswordHash.ToString();
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
}
|