diff options
| author | Phallacy <Dragoonmac@gmail.com> | 2019-02-20 01:17:30 -0800 |
|---|---|---|
| committer | Phallacy <Dragoonmac@gmail.com> | 2019-02-20 01:17:30 -0800 |
| commit | 098de6b0501eaa0375fc5bfd7cff369815b57718 (patch) | |
| tree | 1c45413a635af79fdb208d8f0dcd4e572089f9a3 | |
| parent | a0d31a49a0047a39cb2c4f7d67be64153b0a3266 (diff) | |
made newlines into linux newlines
3 files changed, 590 insertions, 592 deletions
diff --git a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs index 2f2fd9592..ea719309c 100644 --- a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs +++ b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs @@ -1,149 +1,149 @@ -using System;
-using System.Collections.Generic;
+using System; +using System.Collections.Generic; using System.Globalization; -using System.IO;
-using System.Security.Cryptography;
-using System.Text;
-using MediaBrowser.Model.Cryptography;
-
-namespace Emby.Server.Implementations.Cryptography
-{
- public class CryptographyProvider : ICryptoProvider
- {
- private HashSet<string> SupportedHashMethods;
- public string DefaultHashMethod => "SHA256";
- private RandomNumberGenerator rng;
- private int defaultiterations = 1000;
- public CryptographyProvider()
- {
- //Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1
- //there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one
- SupportedHashMethods = new HashSet<string>()
- {
- "MD5"
- ,"System.Security.Cryptography.MD5"
- ,"SHA"
- ,"SHA1"
- ,"System.Security.Cryptography.SHA1"
- ,"SHA256"
- ,"SHA-256"
- ,"System.Security.Cryptography.SHA256"
- ,"SHA384"
- ,"SHA-384"
- ,"System.Security.Cryptography.SHA384"
- ,"SHA512"
- ,"SHA-512"
- ,"System.Security.Cryptography.SHA512"
- };
- rng = RandomNumberGenerator.Create();
- }
-
- public Guid GetMD5(string str)
- {
- return new Guid(ComputeMD5(Encoding.Unicode.GetBytes(str)));
- }
-
- public byte[] ComputeSHA1(byte[] bytes)
- {
- using (var provider = SHA1.Create())
- {
- return provider.ComputeHash(bytes);
- }
- }
-
- public byte[] ComputeMD5(Stream str)
- {
- using (var provider = MD5.Create())
- {
- return provider.ComputeHash(str);
- }
- }
-
- public byte[] ComputeMD5(byte[] bytes)
- {
- using (var provider = MD5.Create())
- {
- return provider.ComputeHash(bytes);
- }
- }
-
- public IEnumerable<string> GetSupportedHashMethods()
- {
- return SupportedHashMethods;
- }
-
- private byte[] PBKDF2(string method, byte[] bytes, byte[] salt, int iterations)
+using System.IO; +using System.Security.Cryptography; +using System.Text; +using MediaBrowser.Model.Cryptography; + +namespace Emby.Server.Implementations.Cryptography +{ + public class CryptographyProvider : ICryptoProvider + { + private HashSet<string> SupportedHashMethods; + public string DefaultHashMethod => "SHA256"; + private RandomNumberGenerator rng; + private int defaultiterations = 1000; + public CryptographyProvider() { - //downgrading for now as we need this library to be dotnetstandard compliant
- using (var r = new Rfc2898DeriveBytes(bytes, salt, iterations))
- {
- return r.GetBytes(32);
- }
- }
-
- public byte[] ComputeHash(string HashMethod, byte[] bytes)
- {
- return ComputeHash(HashMethod, bytes, new byte[0]);
- }
-
- public byte[] ComputeHashWithDefaultMethod(byte[] bytes)
- {
- return ComputeHash(DefaultHashMethod, bytes);
- }
-
- public byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt)
- {
- if (SupportedHashMethods.Contains(HashMethod))
- {
- if (salt.Length == 0)
- {
- using (var h = HashAlgorithm.Create(HashMethod))
- {
- return h.ComputeHash(bytes);
- }
- }
- else
- {
- return PBKDF2(HashMethod, bytes, salt, defaultiterations);
- }
- }
- else
- {
- throw new CryptographicException($"Requested hash method is not supported: {HashMethod}");
- }
- }
-
- public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt)
- {
- return PBKDF2(DefaultHashMethod, bytes, salt, defaultiterations);
- }
-
- public byte[] ComputeHash(PasswordHash hash)
- {
- int iterations = defaultiterations;
- if (!hash.Parameters.ContainsKey("iterations"))
- {
- hash.Parameters.Add("iterations", defaultiterations.ToString(CultureInfo.InvariantCulture));
- }
- else
- {
- try
- {
- iterations = int.Parse(hash.Parameters["iterations"]);
- }
- catch (Exception e)
- {
- throw new InvalidDataException($"Couldn't successfully parse iterations value from string: {hash.Parameters["iterations"]}", e);
- }
- }
- return PBKDF2(hash.Id, hash.HashBytes, hash.SaltBytes, iterations);
- }
-
- public byte[] GenerateSalt()
- {
- byte[] salt = new byte[64];
- rng.GetBytes(salt);
- return salt;
- }
- }
-}
+ //Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1 + //there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one + SupportedHashMethods = new HashSet<string>() + { + "MD5" + ,"System.Security.Cryptography.MD5" + ,"SHA" + ,"SHA1" + ,"System.Security.Cryptography.SHA1" + ,"SHA256" + ,"SHA-256" + ,"System.Security.Cryptography.SHA256" + ,"SHA384" + ,"SHA-384" + ,"System.Security.Cryptography.SHA384" + ,"SHA512" + ,"SHA-512" + ,"System.Security.Cryptography.SHA512" + }; + rng = RandomNumberGenerator.Create(); + } + + public Guid GetMD5(string str) + { + return new Guid(ComputeMD5(Encoding.Unicode.GetBytes(str))); + } + + public byte[] ComputeSHA1(byte[] bytes) + { + using (var provider = SHA1.Create()) + { + return provider.ComputeHash(bytes); + } + } + + public byte[] ComputeMD5(Stream str) + { + using (var provider = MD5.Create()) + { + return provider.ComputeHash(str); + } + } + + public byte[] ComputeMD5(byte[] bytes) + { + using (var provider = MD5.Create()) + { + return provider.ComputeHash(bytes); + } + } + + public IEnumerable<string> GetSupportedHashMethods() + { + return SupportedHashMethods; + } + + private byte[] PBKDF2(string method, byte[] bytes, byte[] salt, int iterations) + { + //downgrading for now as we need this library to be dotnetstandard compliant + using (var r = new Rfc2898DeriveBytes(bytes, salt, iterations)) + { + return r.GetBytes(32); + } + } + + public byte[] ComputeHash(string HashMethod, byte[] bytes) + { + return ComputeHash(HashMethod, bytes, new byte[0]); + } + + public byte[] ComputeHashWithDefaultMethod(byte[] bytes) + { + return ComputeHash(DefaultHashMethod, bytes); + } + + public byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt) + { + if (SupportedHashMethods.Contains(HashMethod)) + { + if (salt.Length == 0) + { + using (var h = HashAlgorithm.Create(HashMethod)) + { + return h.ComputeHash(bytes); + } + } + else + { + return PBKDF2(HashMethod, bytes, salt, defaultiterations); + } + } + else + { + throw new CryptographicException($"Requested hash method is not supported: {HashMethod}"); + } + } + + public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt) + { + return PBKDF2(DefaultHashMethod, bytes, salt, defaultiterations); + } + + public byte[] ComputeHash(PasswordHash hash) + { + int iterations = defaultiterations; + if (!hash.Parameters.ContainsKey("iterations")) + { + hash.Parameters.Add("iterations", defaultiterations.ToString(CultureInfo.InvariantCulture)); + } + else + { + try + { + iterations = int.Parse(hash.Parameters["iterations"]); + } + catch (Exception e) + { + throw new InvalidDataException($"Couldn't successfully parse iterations value from string: {hash.Parameters["iterations"]}", e); + } + } + return PBKDF2(hash.Id, hash.HashBytes, hash.SaltBytes, iterations); + } + + public byte[] GenerateSalt() + { + byte[] salt = new byte[64]; + rng.GetBytes(salt); + return salt; + } + } +} diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs index 3df91f71c..182df0edc 100644 --- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserRepository.cs @@ -1,264 +1,264 @@ -using System;
-using System.Collections.Generic;
-using System.IO;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Serialization;
-using Microsoft.Extensions.Logging;
-using SQLitePCL.pretty;
-
-namespace Emby.Server.Implementations.Data
-{
- /// <summary>
- /// Class SQLiteUserRepository
- /// </summary>
- public class SqliteUserRepository : BaseSqliteRepository, IUserRepository
- {
- private readonly IJsonSerializer _jsonSerializer;
-
- public SqliteUserRepository(
- ILoggerFactory loggerFactory,
- IServerApplicationPaths appPaths,
- IJsonSerializer jsonSerializer)
- : base(loggerFactory.CreateLogger(nameof(SqliteUserRepository)))
- {
- _jsonSerializer = jsonSerializer;
-
- DbFilePath = Path.Combine(appPaths.DataPath, "users.db");
- }
-
- /// <summary>
- /// Gets the name of the repository
- /// </summary>
- /// <value>The name.</value>
- public string Name => "SQLite";
-
- /// <summary>
- /// Opens the connection to the database
- /// </summary>
- /// <returns>Task.</returns>
- public void Initialize()
- {
- using (var connection = CreateConnection())
- {
- RunDefaultInitialization(connection);
-
- var localUsersTableExists = TableExists(connection, "LocalUsersv2");
-
- connection.RunQueries(new[] {
- "create table if not exists LocalUsersv2 (Id INTEGER PRIMARY KEY, guid GUID NOT NULL, data BLOB NOT NULL)",
- "drop index if exists idx_users"
- });
-
- if (!localUsersTableExists && TableExists(connection, "Users"))
- {
- TryMigrateToLocalUsersTable(connection);
+using System; +using System.Collections.Generic; +using System.IO; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Serialization; +using Microsoft.Extensions.Logging; +using SQLitePCL.pretty; + +namespace Emby.Server.Implementations.Data +{ + /// <summary> + /// Class SQLiteUserRepository + /// </summary> + public class SqliteUserRepository : BaseSqliteRepository, IUserRepository + { + private readonly IJsonSerializer _jsonSerializer; + + public SqliteUserRepository( + ILoggerFactory loggerFactory, + IServerApplicationPaths appPaths, + IJsonSerializer jsonSerializer) + : base(loggerFactory.CreateLogger(nameof(SqliteUserRepository))) + { + _jsonSerializer = jsonSerializer; + + DbFilePath = Path.Combine(appPaths.DataPath, "users.db"); + } + + /// <summary> + /// Gets the name of the repository + /// </summary> + /// <value>The name.</value> + public string Name => "SQLite"; + + /// <summary> + /// Opens the connection to the database + /// </summary> + /// <returns>Task.</returns> + public void Initialize() + { + using (var connection = CreateConnection()) + { + RunDefaultInitialization(connection); + + var localUsersTableExists = TableExists(connection, "LocalUsersv2"); + + connection.RunQueries(new[] { + "create table if not exists LocalUsersv2 (Id INTEGER PRIMARY KEY, guid GUID NOT NULL, data BLOB NOT NULL)", + "drop index if exists idx_users" + }); + + if (!localUsersTableExists && TableExists(connection, "Users")) + { + TryMigrateToLocalUsersTable(connection); } -
- RemoveEmptyPasswordHashes();
- }
- }
-
- private void TryMigrateToLocalUsersTable(ManagedConnection connection)
- {
- try
- {
- connection.RunQueries(new[]
- {
- "INSERT INTO LocalUsersv2 (guid, data) SELECT guid,data from users"
- });
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error migrating users database");
- }
- }
-
- private void RemoveEmptyPasswordHashes()
- {
- foreach (var user in RetrieveAllUsers())
- {
- // If the user password is the sha1 hash of the empty string, remove it
- if (!string.Equals(user.Password, "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal)
- || !string.Equals(user.Password, "$SHA1$DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal))
- {
- continue;
- }
-
- user.Password = null;
- var serialized = _jsonSerializer.SerializeToBytes(user);
-
- using (WriteLock.Write())
- using (var connection = CreateConnection())
- {
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId"))
- {
- statement.TryBind("@InternalId", user.InternalId);
- statement.TryBind("@data", serialized);
- statement.MoveNext();
- }
-
- }, TransactionMode);
- }
- }
-
- }
-
- /// <summary>
- /// Save a user in the repo
- /// </summary>
- public void CreateUser(User user)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- var serialized = _jsonSerializer.SerializeToBytes(user);
-
- using (WriteLock.Write())
- {
- using (var connection = CreateConnection())
- {
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)"))
- {
- statement.TryBind("@guid", user.Id.ToGuidBlob());
- statement.TryBind("@data", serialized);
-
- statement.MoveNext();
- }
-
- var createdUser = GetUser(user.Id, false);
-
- if (createdUser == null)
- {
- throw new ApplicationException("created user should never be null");
- }
-
- user.InternalId = createdUser.InternalId;
-
- }, TransactionMode);
- }
- }
- }
-
- public void UpdateUser(User user)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- var serialized = _jsonSerializer.SerializeToBytes(user);
-
- using (WriteLock.Write())
- {
- using (var connection = CreateConnection())
- {
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId"))
- {
- statement.TryBind("@InternalId", user.InternalId);
- statement.TryBind("@data", serialized);
- statement.MoveNext();
- }
-
- }, TransactionMode);
- }
- }
- }
-
- private User GetUser(Guid guid, bool openLock)
- {
- using (openLock ? WriteLock.Read() : null)
- {
- using (var connection = CreateConnection(true))
- {
- using (var statement = connection.PrepareStatement("select id,guid,data from LocalUsersv2 where guid=@guid"))
- {
- statement.TryBind("@guid", guid);
-
- foreach (var row in statement.ExecuteQuery())
- {
- return GetUser(row);
- }
- }
- }
- }
-
- return null;
- }
-
- private User GetUser(IReadOnlyList<IResultSetValue> row)
- {
- var id = row[0].ToInt64();
- var guid = row[1].ReadGuidFromBlob();
-
- using (var stream = new MemoryStream(row[2].ToBlob()))
- {
- stream.Position = 0;
- var user = _jsonSerializer.DeserializeFromStream<User>(stream);
- user.InternalId = id;
- user.Id = guid;
- return user;
- }
- }
-
- /// <summary>
- /// Retrieve all users from the database
- /// </summary>
- /// <returns>IEnumerable{User}.</returns>
- public List<User> RetrieveAllUsers()
- {
- var list = new List<User>();
-
- using (WriteLock.Read())
- {
- using (var connection = CreateConnection(true))
- {
- foreach (var row in connection.Query("select id,guid,data from LocalUsersv2"))
- {
- list.Add(GetUser(row));
- }
- }
- }
-
- return list;
- }
-
- /// <summary>
- /// Deletes the user.
- /// </summary>
- /// <param name="user">The user.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">user</exception>
- public void DeleteUser(User user)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- using (WriteLock.Write())
- {
- using (var connection = CreateConnection())
- {
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("delete from LocalUsersv2 where Id=@id"))
- {
- statement.TryBind("@id", user.InternalId);
- statement.MoveNext();
- }
- }, TransactionMode);
- }
- }
- }
- }
-}
+ + RemoveEmptyPasswordHashes(); + } + } + + private void TryMigrateToLocalUsersTable(ManagedConnection connection) + { + try + { + connection.RunQueries(new[] + { + "INSERT INTO LocalUsersv2 (guid, data) SELECT guid,data from users" + }); + } + catch (Exception ex) + { + Logger.LogError(ex, "Error migrating users database"); + } + } + + private void RemoveEmptyPasswordHashes() + { + foreach (var user in RetrieveAllUsers()) + { + // If the user password is the sha1 hash of the empty string, remove it + if (!string.Equals(user.Password, "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal) + || !string.Equals(user.Password, "$SHA1$DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal)) + { + continue; + } + + user.Password = null; + var serialized = _jsonSerializer.SerializeToBytes(user); + + using (WriteLock.Write()) + using (var connection = CreateConnection()) + { + connection.RunInTransaction(db => + { + using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId")) + { + statement.TryBind("@InternalId", user.InternalId); + statement.TryBind("@data", serialized); + statement.MoveNext(); + } + + }, TransactionMode); + } + } + + } + + /// <summary> + /// Save a user in the repo + /// </summary> + public void CreateUser(User user) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + + var serialized = _jsonSerializer.SerializeToBytes(user); + + using (WriteLock.Write()) + { + using (var connection = CreateConnection()) + { + connection.RunInTransaction(db => + { + using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)")) + { + statement.TryBind("@guid", user.Id.ToGuidBlob()); + statement.TryBind("@data", serialized); + + statement.MoveNext(); + } + + var createdUser = GetUser(user.Id, false); + + if (createdUser == null) + { + throw new ApplicationException("created user should never be null"); + } + + user.InternalId = createdUser.InternalId; + + }, TransactionMode); + } + } + } + + public void UpdateUser(User user) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + + var serialized = _jsonSerializer.SerializeToBytes(user); + + using (WriteLock.Write()) + { + using (var connection = CreateConnection()) + { + connection.RunInTransaction(db => + { + using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId")) + { + statement.TryBind("@InternalId", user.InternalId); + statement.TryBind("@data", serialized); + statement.MoveNext(); + } + + }, TransactionMode); + } + } + } + + private User GetUser(Guid guid, bool openLock) + { + using (openLock ? WriteLock.Read() : null) + { + using (var connection = CreateConnection(true)) + { + using (var statement = connection.PrepareStatement("select id,guid,data from LocalUsersv2 where guid=@guid")) + { + statement.TryBind("@guid", guid); + + foreach (var row in statement.ExecuteQuery()) + { + return GetUser(row); + } + } + } + } + + return null; + } + + private User GetUser(IReadOnlyList<IResultSetValue> row) + { + var id = row[0].ToInt64(); + var guid = row[1].ReadGuidFromBlob(); + + using (var stream = new MemoryStream(row[2].ToBlob())) + { + stream.Position = 0; + var user = _jsonSerializer.DeserializeFromStream<User>(stream); + user.InternalId = id; + user.Id = guid; + return user; + } + } + + /// <summary> + /// Retrieve all users from the database + /// </summary> + /// <returns>IEnumerable{User}.</returns> + public List<User> RetrieveAllUsers() + { + var list = new List<User>(); + + using (WriteLock.Read()) + { + using (var connection = CreateConnection(true)) + { + foreach (var row in connection.Query("select id,guid,data from LocalUsersv2")) + { + list.Add(GetUser(row)); + } + } + } + + return list; + } + + /// <summary> + /// Deletes the user. + /// </summary> + /// <param name="user">The user.</param> + /// <returns>Task.</returns> + /// <exception cref="ArgumentNullException">user</exception> + public void DeleteUser(User user) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + + using (WriteLock.Write()) + { + using (var connection = CreateConnection()) + { + connection.RunInTransaction(db => + { + using (var statement = db.PrepareStatement("delete from LocalUsersv2 where Id=@id")) + { + statement.TryBind("@id", user.InternalId); + statement.MoveNext(); + } + }, TransactionMode); + } + } + } + } +} diff --git a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs index 2ac3ef424..b58374adb 100644 --- a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs +++ b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs @@ -1,42 +1,42 @@ -using System;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Authentication;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Cryptography;
-
-namespace Emby.Server.Implementations.Library
-{
- public class DefaultAuthenticationProvider : IAuthenticationProvider, IRequiresResolvedUser
- {
- private readonly ICryptoProvider _cryptographyProvider;
- public DefaultAuthenticationProvider(ICryptoProvider crypto)
- {
- _cryptographyProvider = crypto;
- }
-
- public string Name => "Default";
-
- public bool IsEnabled => true;
-
-
- //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();
- }
-
-
- //This is the verson that we need to use for local users. Because reasons.
- public Task<ProviderAuthenticationResult> Authenticate(string username, string password, User resolvedUser)
- {
- bool success = false;
- if (resolvedUser == null)
- {
- throw new Exception("Invalid username or password");
+using System; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MediaBrowser.Controller.Authentication; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Cryptography; + +namespace Emby.Server.Implementations.Library +{ + public class DefaultAuthenticationProvider : IAuthenticationProvider, IRequiresResolvedUser + { + private readonly ICryptoProvider _cryptographyProvider; + public DefaultAuthenticationProvider(ICryptoProvider crypto) + { + _cryptographyProvider = crypto; + } + + public string Name => "Default"; + + public bool IsEnabled => true; + + + //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(); + } + + + //This is the verson that we need to use for local users. Because reasons. + public Task<ProviderAuthenticationResult> Authenticate(string username, string password, User resolvedUser) + { + bool success = false; + if (resolvedUser == null) + { + throw new Exception("Invalid username or password"); } //As long as jellyfin supports passwordless users, we need this little block here to accomodate @@ -47,166 +47,164 @@ namespace Emby.Server.Implementations.Library Username = username }); } -
- ConvertPasswordFormat(resolvedUser);
- byte[] passwordbytes = Encoding.UTF8.GetBytes(password);
-
- PasswordHash readyHash = new PasswordHash(resolvedUser.Password);
- byte[] CalculatedHash;
- string CalculatedHashString;
- if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id))
- {
- if (string.IsNullOrEmpty(readyHash.Salt))
- {
- CalculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes);
- CalculatedHashString = BitConverter.ToString(CalculatedHash).Replace("-", string.Empty);
- }
- else
- {
- CalculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes, readyHash.SaltBytes);
- CalculatedHashString = BitConverter.ToString(CalculatedHash).Replace("-", string.Empty);
+ + ConvertPasswordFormat(resolvedUser); + byte[] passwordbytes = Encoding.UTF8.GetBytes(password); + + PasswordHash readyHash = new PasswordHash(resolvedUser.Password); + byte[] CalculatedHash; + string CalculatedHashString; + if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id)) + { + if (string.IsNullOrEmpty(readyHash.Salt)) + { + CalculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes); + CalculatedHashString = BitConverter.ToString(CalculatedHash).Replace("-", string.Empty); + } + else + { + CalculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes, readyHash.SaltBytes); + CalculatedHashString = BitConverter.ToString(CalculatedHash).Replace("-", string.Empty); } -
- if (CalculatedHashString == readyHash.Hash)
- {
- success = true;
- //throw new Exception("Invalid username or password");
- }
- }
- else
- {
- throw new Exception(String.Format($"Requested crypto method not available in provider: {readyHash.Id}"));
- }
-
- //var success = string.Equals(GetPasswordHash(resolvedUser), GetHashedString(resolvedUser, password), StringComparison.OrdinalIgnoreCase);
-
- if (!success)
- {
- throw new Exception("Invalid username or password");
- }
-
- return Task.FromResult(new ProviderAuthenticationResult
- {
- Username = username
- });
- }
-
- //This allows us to move passwords forward to the newformat without breaking. They are still insecure, unsalted, and dumb before a password change
- //but at least they are in the new format.
- private void ConvertPasswordFormat(User user)
- {
- if (!string.IsNullOrEmpty(user.Password))
+ + if (CalculatedHashString == readyHash.Hash) + { + success = true; + //throw new Exception("Invalid username or password"); + } + } + else + { + throw new Exception(String.Format($"Requested crypto method not available in provider: {readyHash.Id}")); + } + + //var success = string.Equals(GetPasswordHash(resolvedUser), GetHashedString(resolvedUser, password), StringComparison.OrdinalIgnoreCase); + + if (!success) + { + throw new Exception("Invalid username or password"); + } + + return Task.FromResult(new ProviderAuthenticationResult + { + Username = username + }); + } + + //This allows us to move passwords forward to the newformat without breaking. They are still insecure, unsalted, and dumb before a password change + //but at least they are in the new format. + private void ConvertPasswordFormat(User user) + { + if (!string.IsNullOrEmpty(user.Password)) { return; } -
- if (!user.Password.Contains("$"))
- {
- string hash = user.Password;
- user.Password = String.Format("$SHA1${0}", hash);
- }
-
- if (user.EasyPassword != null && !user.EasyPassword.Contains("$"))
- {
- string hash = user.EasyPassword;
- user.EasyPassword = string.Format("$SHA1${0}", hash);
- }
- }
-
- public Task<bool> HasPassword(User user)
- {
- var hasConfiguredPassword = !IsPasswordEmpty(user, GetPasswordHash(user));
- return Task.FromResult(hasConfiguredPassword);
- }
-
- private bool IsPasswordEmpty(User user, string password)
+ + if (!user.Password.Contains("$")) + { + string hash = user.Password; + user.Password = String.Format("$SHA1${0}", hash); + } + + if (user.EasyPassword != null && !user.EasyPassword.Contains("$")) + { + string hash = user.EasyPassword; + user.EasyPassword = string.Format("$SHA1${0}", hash); + } + } + + public Task<bool> HasPassword(User user) + { + var hasConfiguredPassword = !IsPasswordEmpty(user, GetPasswordHash(user)); + return Task.FromResult(hasConfiguredPassword); + } + + private bool IsPasswordEmpty(User user, string password) { if (string.IsNullOrEmpty(user.Password)) { return string.IsNullOrEmpty(password); } - return false;
- }
-
- public Task ChangePassword(User user, string newPassword)
- {
+ return false; + } + + public Task ChangePassword(User user, string newPassword) + { ConvertPasswordFormat(user); //This is needed to support changing a no password user to a password user if (string.IsNullOrEmpty(user.Password)) { PasswordHash newPasswordHash = new PasswordHash(_cryptographyProvider); - newPasswordHash.SaltBytes = _cryptographyProvider.GenerateSalt();
- newPasswordHash.Salt = PasswordHash.ConvertToByteString(newPasswordHash.SaltBytes);
- newPasswordHash.Id = _cryptographyProvider.DefaultHashMethod;
+ newPasswordHash.SaltBytes = _cryptographyProvider.GenerateSalt(); + newPasswordHash.Salt = PasswordHash.ConvertToByteString(newPasswordHash.SaltBytes); + newPasswordHash.Id = _cryptographyProvider.DefaultHashMethod; newPasswordHash.Hash = GetHashedStringChangeAuth(newPassword, newPasswordHash); user.Password = newPasswordHash.ToString(); return Task.CompletedTask; } - PasswordHash passwordHash = new PasswordHash(user.Password);
- if (passwordHash.Id == "SHA1" && string.IsNullOrEmpty(passwordHash.Salt))
- {
- passwordHash.SaltBytes = _cryptographyProvider.GenerateSalt();
- passwordHash.Salt = PasswordHash.ConvertToByteString(passwordHash.SaltBytes);
- passwordHash.Id = _cryptographyProvider.DefaultHashMethod;
- passwordHash.Hash = GetHashedStringChangeAuth(newPassword, passwordHash);
- }
- else if (newPassword != null)
- {
- passwordHash.Hash = GetHashedString(user, newPassword);
- }
-
- if (string.IsNullOrWhiteSpace(passwordHash.Hash))
- {
- throw new ArgumentNullException(nameof(passwordHash.Hash));
- }
-
- user.Password = passwordHash.ToString();
-
- return Task.CompletedTask;
- }
-
- public string GetPasswordHash(User user)
- {
- return user.Password;
- }
-
- public string GetHashedStringChangeAuth(string newPassword, PasswordHash passwordHash)
- {
- passwordHash.HashBytes = Encoding.UTF8.GetBytes(newPassword);
- return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash));
- }
-
- /// <summary>
- /// Gets the hashed string.
- /// </summary>
- public string GetHashedString(User user, string str)
- {
- PasswordHash passwordHash;
- if (String.IsNullOrEmpty(user.Password))
- {
- passwordHash = new PasswordHash(_cryptographyProvider);
- }
- else
- {
- ConvertPasswordFormat(user);
- passwordHash = new PasswordHash(user.Password);
- } -
- if (passwordHash.SaltBytes != null)
- {
- //the password is modern format with PBKDF and we should take advantage of that
- passwordHash.HashBytes = Encoding.UTF8.GetBytes(str);
- return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash));
- }
- else
- {
- //the password has no salt and should be called with the older method for safety
- return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash.Id, Encoding.UTF8.GetBytes(str)));
- }
-
-
- }
- }
-}
+ PasswordHash passwordHash = new PasswordHash(user.Password); + if (passwordHash.Id == "SHA1" && string.IsNullOrEmpty(passwordHash.Salt)) + { + passwordHash.SaltBytes = _cryptographyProvider.GenerateSalt(); + passwordHash.Salt = PasswordHash.ConvertToByteString(passwordHash.SaltBytes); + passwordHash.Id = _cryptographyProvider.DefaultHashMethod; + passwordHash.Hash = GetHashedStringChangeAuth(newPassword, passwordHash); + } + else if (newPassword != null) + { + passwordHash.Hash = GetHashedString(user, newPassword); + } + + if (string.IsNullOrWhiteSpace(passwordHash.Hash)) + { + throw new ArgumentNullException(nameof(passwordHash.Hash)); + } + + user.Password = passwordHash.ToString(); + + return Task.CompletedTask; + } + + public string GetPasswordHash(User user) + { + return user.Password; + } + + public string GetHashedStringChangeAuth(string newPassword, PasswordHash passwordHash) + { + passwordHash.HashBytes = Encoding.UTF8.GetBytes(newPassword); + return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash)); + } + + /// <summary> + /// Gets the hashed string. + /// </summary> + public string GetHashedString(User user, string str) + { + PasswordHash passwordHash; + if (String.IsNullOrEmpty(user.Password)) + { + passwordHash = new PasswordHash(_cryptographyProvider); + } + else + { + ConvertPasswordFormat(user); + passwordHash = new PasswordHash(user.Password); + } + + if (passwordHash.SaltBytes != null) + { + //the password is modern format with PBKDF and we should take advantage of that + passwordHash.HashBytes = Encoding.UTF8.GetBytes(str); + return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash)); + } + else + { + //the password has no salt and should be called with the older method for safety + return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash.Id, Encoding.UTF8.GetBytes(str))); + } + } + } +} |
